mirror of https://github.com/python/cpython
GH-114695: Add `sys._clear_internal_caches` (GH-115152)
This commit is contained in:
parent
54bde5dcc3
commit
235cacff81
|
@ -195,6 +195,17 @@ always available.
|
||||||
|
|
||||||
This function should be used for internal and specialized purposes only.
|
This function should be used for internal and specialized purposes only.
|
||||||
|
|
||||||
|
.. deprecated:: 3.13
|
||||||
|
Use the more general :func:`_clear_internal_caches` function instead.
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: _clear_internal_caches()
|
||||||
|
|
||||||
|
Clear all internal performance-related caches. Use this function *only* to
|
||||||
|
release unnecessary references and memory blocks when hunting for leaks.
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
|
||||||
.. function:: _current_frames()
|
.. function:: _current_frames()
|
||||||
|
|
||||||
|
@ -724,7 +735,7 @@ always available.
|
||||||
regardless of their size. This function is mainly useful for tracking
|
regardless of their size. This function is mainly useful for tracking
|
||||||
and debugging memory leaks. Because of the interpreter's internal
|
and debugging memory leaks. Because of the interpreter's internal
|
||||||
caches, the result can vary from call to call; you may have to call
|
caches, the result can vary from call to call; you may have to call
|
||||||
:func:`_clear_type_cache()` and :func:`gc.collect()` to get more
|
:func:`_clear_internal_caches()` and :func:`gc.collect()` to get more
|
||||||
predictable results.
|
predictable results.
|
||||||
|
|
||||||
If a Python build or implementation cannot reasonably compute this
|
If a Python build or implementation cannot reasonably compute this
|
||||||
|
|
|
@ -24,9 +24,10 @@ typedef struct {
|
||||||
uint8_t opcode;
|
uint8_t opcode;
|
||||||
uint8_t oparg;
|
uint8_t oparg;
|
||||||
uint8_t valid;
|
uint8_t valid;
|
||||||
uint8_t linked;
|
int index; // Index of ENTER_EXECUTOR (if code isn't NULL, below).
|
||||||
_PyBloomFilter bloom;
|
_PyBloomFilter bloom;
|
||||||
_PyExecutorLinkListNode links;
|
_PyExecutorLinkListNode links;
|
||||||
|
PyCodeObject *code; // Weak (NULL if no corresponding ENTER_EXECUTOR).
|
||||||
} _PyVMData;
|
} _PyVMData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -201,8 +201,8 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs):
|
||||||
# Clear caches
|
# Clear caches
|
||||||
clear_caches()
|
clear_caches()
|
||||||
|
|
||||||
# Clear type cache at the end: previous function calls can modify types
|
# Clear other caches last (previous function calls can re-populate them):
|
||||||
sys._clear_type_cache()
|
sys._clear_internal_caches()
|
||||||
|
|
||||||
|
|
||||||
def warm_caches():
|
def warm_caches():
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import contextlib
|
import contextlib
|
||||||
import opcode
|
import opcode
|
||||||
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
@ -181,6 +182,21 @@ class TestExecutorInvalidation(unittest.TestCase):
|
||||||
_testinternalcapi.invalidate_executors(f.__code__)
|
_testinternalcapi.invalidate_executors(f.__code__)
|
||||||
self.assertFalse(exe.is_valid())
|
self.assertFalse(exe.is_valid())
|
||||||
|
|
||||||
|
def test_sys__clear_internal_caches(self):
|
||||||
|
def f():
|
||||||
|
for _ in range(1000):
|
||||||
|
pass
|
||||||
|
opt = _testinternalcapi.get_uop_optimizer()
|
||||||
|
with temporary_optimizer(opt):
|
||||||
|
f()
|
||||||
|
exe = get_first_executor(f)
|
||||||
|
self.assertIsNotNone(exe)
|
||||||
|
self.assertTrue(exe.is_valid())
|
||||||
|
sys._clear_internal_caches()
|
||||||
|
self.assertFalse(exe.is_valid())
|
||||||
|
exe = get_first_executor(f)
|
||||||
|
self.assertIsNone(exe)
|
||||||
|
|
||||||
class TestUops(unittest.TestCase):
|
class TestUops(unittest.TestCase):
|
||||||
|
|
||||||
def test_basic_loop(self):
|
def test_basic_loop(self):
|
||||||
|
|
|
@ -10,6 +10,7 @@ import io
|
||||||
import tempfile
|
import tempfile
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import os_helper
|
from test.support import os_helper
|
||||||
|
from test.support import refleak_helper
|
||||||
from test.support import socket_helper
|
from test.support import socket_helper
|
||||||
import unittest
|
import unittest
|
||||||
import textwrap
|
import textwrap
|
||||||
|
@ -2443,6 +2444,9 @@ class MiscTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def tearDownModule():
|
def tearDownModule():
|
||||||
support.reap_children()
|
support.reap_children()
|
||||||
|
# reap_children may have re-populated caches:
|
||||||
|
if refleak_helper.hunting_for_refleaks():
|
||||||
|
sys._clear_internal_caches()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Add :func:`sys._clear_internal_caches`, which clears all internal
|
||||||
|
performance-related caches (and deprecate the less-general
|
||||||
|
:func:`sys._clear_type_cache` function).
|
|
@ -1489,27 +1489,19 @@ PyCode_GetFreevars(PyCodeObject *code)
|
||||||
static void
|
static void
|
||||||
clear_executors(PyCodeObject *co)
|
clear_executors(PyCodeObject *co)
|
||||||
{
|
{
|
||||||
|
assert(co->co_executors);
|
||||||
for (int i = 0; i < co->co_executors->size; i++) {
|
for (int i = 0; i < co->co_executors->size; i++) {
|
||||||
Py_CLEAR(co->co_executors->executors[i]);
|
if (co->co_executors->executors[i]) {
|
||||||
|
_Py_ExecutorClear(co->co_executors->executors[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PyMem_Free(co->co_executors);
|
PyMem_Free(co->co_executors);
|
||||||
co->co_executors = NULL;
|
co->co_executors = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_PyCode_Clear_Executors(PyCodeObject *code) {
|
_PyCode_Clear_Executors(PyCodeObject *code)
|
||||||
int code_len = (int)Py_SIZE(code);
|
{
|
||||||
for (int i = 0; i < code_len; i += _PyInstruction_GetLength(code, i)) {
|
|
||||||
_Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
|
|
||||||
uint8_t opcode = instr->op.code;
|
|
||||||
uint8_t oparg = instr->op.arg;
|
|
||||||
if (opcode == ENTER_EXECUTOR) {
|
|
||||||
_PyExecutorObject *exec = code->co_executors->executors[oparg];
|
|
||||||
assert(exec->vm_data.opcode != ENTER_EXECUTOR);
|
|
||||||
instr->op.code = exec->vm_data.opcode;
|
|
||||||
instr->op.arg = exec->vm_data.oparg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clear_executors(code);
|
clear_executors(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2360,10 +2352,10 @@ _PyCode_ConstantKey(PyObject *op)
|
||||||
void
|
void
|
||||||
_PyStaticCode_Fini(PyCodeObject *co)
|
_PyStaticCode_Fini(PyCodeObject *co)
|
||||||
{
|
{
|
||||||
deopt_code(co, _PyCode_CODE(co));
|
|
||||||
if (co->co_executors != NULL) {
|
if (co->co_executors != NULL) {
|
||||||
clear_executors(co);
|
clear_executors(co);
|
||||||
}
|
}
|
||||||
|
deopt_code(co, _PyCode_CODE(co));
|
||||||
PyMem_Free(co->co_extra);
|
PyMem_Free(co->co_extra);
|
||||||
if (co->_co_cached != NULL) {
|
if (co->_co_cached != NULL) {
|
||||||
Py_CLEAR(co->_co_cached->_co_code);
|
Py_CLEAR(co->_co_cached->_co_code);
|
||||||
|
|
|
@ -2370,24 +2370,13 @@ dummy_func(
|
||||||
CHECK_EVAL_BREAKER();
|
CHECK_EVAL_BREAKER();
|
||||||
|
|
||||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||||
_PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
|
current_executor = code->co_executors->executors[oparg & 255];
|
||||||
if (executor->vm_data.valid) {
|
assert(current_executor->vm_data.index == INSTR_OFFSET() - 1);
|
||||||
Py_INCREF(executor);
|
assert(current_executor->vm_data.code == code);
|
||||||
current_executor = executor;
|
assert(current_executor->vm_data.valid);
|
||||||
|
Py_INCREF(current_executor);
|
||||||
GOTO_TIER_TWO();
|
GOTO_TIER_TWO();
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
/* ENTER_EXECUTOR will be the first code unit of the instruction */
|
|
||||||
assert(oparg < 256);
|
|
||||||
code->co_executors->executors[oparg] = NULL;
|
|
||||||
opcode = this_instr->op.code = executor->vm_data.opcode;
|
|
||||||
this_instr->op.arg = executor->vm_data.oparg;
|
|
||||||
oparg = executor->vm_data.oparg;
|
|
||||||
Py_DECREF(executor);
|
|
||||||
next_instr = this_instr;
|
|
||||||
DISPATCH_GOTO();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
replaced op(_POP_JUMP_IF_FALSE, (cond -- )) {
|
replaced op(_POP_JUMP_IF_FALSE, (cond -- )) {
|
||||||
assert(PyBool_Check(cond));
|
assert(PyBool_Check(cond));
|
||||||
|
|
|
@ -1131,6 +1131,24 @@ sys__clear_type_cache(PyObject *module, PyObject *Py_UNUSED(ignored))
|
||||||
return sys__clear_type_cache_impl(module);
|
return sys__clear_type_cache_impl(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(sys__clear_internal_caches__doc__,
|
||||||
|
"_clear_internal_caches($module, /)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
|
"Clear all internal performance-related caches.");
|
||||||
|
|
||||||
|
#define SYS__CLEAR_INTERNAL_CACHES_METHODDEF \
|
||||||
|
{"_clear_internal_caches", (PyCFunction)sys__clear_internal_caches, METH_NOARGS, sys__clear_internal_caches__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
sys__clear_internal_caches_impl(PyObject *module);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
sys__clear_internal_caches(PyObject *module, PyObject *Py_UNUSED(ignored))
|
||||||
|
{
|
||||||
|
return sys__clear_internal_caches_impl(module);
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(sys_is_finalizing__doc__,
|
PyDoc_STRVAR(sys_is_finalizing__doc__,
|
||||||
"is_finalizing($module, /)\n"
|
"is_finalizing($module, /)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
|
@ -1486,4 +1504,4 @@ exit:
|
||||||
#ifndef SYS_GETANDROIDAPILEVEL_METHODDEF
|
#ifndef SYS_GETANDROIDAPILEVEL_METHODDEF
|
||||||
#define SYS_GETANDROIDAPILEVEL_METHODDEF
|
#define SYS_GETANDROIDAPILEVEL_METHODDEF
|
||||||
#endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */
|
#endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */
|
||||||
/*[clinic end generated code: output=3dc3b2cb0ce38ebb input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=b8b1c53e04c3b20c input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -2363,29 +2363,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
TARGET(ENTER_EXECUTOR) {
|
TARGET(ENTER_EXECUTOR) {
|
||||||
_Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr;
|
frame->instr_ptr = next_instr;
|
||||||
next_instr += 1;
|
next_instr += 1;
|
||||||
INSTRUCTION_STATS(ENTER_EXECUTOR);
|
INSTRUCTION_STATS(ENTER_EXECUTOR);
|
||||||
TIER_ONE_ONLY
|
TIER_ONE_ONLY
|
||||||
CHECK_EVAL_BREAKER();
|
CHECK_EVAL_BREAKER();
|
||||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||||
_PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
|
current_executor = code->co_executors->executors[oparg & 255];
|
||||||
if (executor->vm_data.valid) {
|
assert(current_executor->vm_data.index == INSTR_OFFSET() - 1);
|
||||||
Py_INCREF(executor);
|
assert(current_executor->vm_data.code == code);
|
||||||
current_executor = executor;
|
assert(current_executor->vm_data.valid);
|
||||||
|
Py_INCREF(current_executor);
|
||||||
GOTO_TIER_TWO();
|
GOTO_TIER_TWO();
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* ENTER_EXECUTOR will be the first code unit of the instruction */
|
|
||||||
assert(oparg < 256);
|
|
||||||
code->co_executors->executors[oparg] = NULL;
|
|
||||||
opcode = this_instr->op.code = executor->vm_data.opcode;
|
|
||||||
this_instr->op.arg = executor->vm_data.oparg;
|
|
||||||
oparg = executor->vm_data.oparg;
|
|
||||||
Py_DECREF(executor);
|
|
||||||
next_instr = this_instr;
|
|
||||||
DISPATCH_GOTO();
|
|
||||||
}
|
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,25 +73,21 @@ insert_executor(PyCodeObject *code, _Py_CODEUNIT *instr, int index, _PyExecutorO
|
||||||
Py_INCREF(executor);
|
Py_INCREF(executor);
|
||||||
if (instr->op.code == ENTER_EXECUTOR) {
|
if (instr->op.code == ENTER_EXECUTOR) {
|
||||||
assert(index == instr->op.arg);
|
assert(index == instr->op.arg);
|
||||||
_PyExecutorObject *old = code->co_executors->executors[index];
|
_Py_ExecutorClear(code->co_executors->executors[index]);
|
||||||
executor->vm_data.opcode = old->vm_data.opcode;
|
|
||||||
executor->vm_data.oparg = old->vm_data.oparg;
|
|
||||||
old->vm_data.opcode = 0;
|
|
||||||
code->co_executors->executors[index] = executor;
|
|
||||||
Py_DECREF(old);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(code->co_executors->size == index);
|
assert(code->co_executors->size == index);
|
||||||
assert(code->co_executors->capacity > index);
|
assert(code->co_executors->capacity > index);
|
||||||
|
code->co_executors->size++;
|
||||||
|
}
|
||||||
executor->vm_data.opcode = instr->op.code;
|
executor->vm_data.opcode = instr->op.code;
|
||||||
executor->vm_data.oparg = instr->op.arg;
|
executor->vm_data.oparg = instr->op.arg;
|
||||||
|
executor->vm_data.code = code;
|
||||||
|
executor->vm_data.index = (int)(instr - _PyCode_CODE(code));
|
||||||
code->co_executors->executors[index] = executor;
|
code->co_executors->executors[index] = executor;
|
||||||
assert(index < MAX_EXECUTORS_SIZE);
|
assert(index < MAX_EXECUTORS_SIZE);
|
||||||
instr->op.code = ENTER_EXECUTOR;
|
instr->op.code = ENTER_EXECUTOR;
|
||||||
instr->op.arg = index;
|
instr->op.arg = index;
|
||||||
code->co_executors->size++;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -1071,7 +1067,7 @@ link_executor(_PyExecutorObject *executor)
|
||||||
}
|
}
|
||||||
head->vm_data.links.next = executor;
|
head->vm_data.links.next = executor;
|
||||||
}
|
}
|
||||||
executor->vm_data.linked = true;
|
executor->vm_data.valid = true;
|
||||||
/* executor_list_head must be first in list */
|
/* executor_list_head must be first in list */
|
||||||
assert(interp->executor_list_head->vm_data.links.previous == NULL);
|
assert(interp->executor_list_head->vm_data.links.previous == NULL);
|
||||||
}
|
}
|
||||||
|
@ -1079,7 +1075,7 @@ link_executor(_PyExecutorObject *executor)
|
||||||
static void
|
static void
|
||||||
unlink_executor(_PyExecutorObject *executor)
|
unlink_executor(_PyExecutorObject *executor)
|
||||||
{
|
{
|
||||||
if (!executor->vm_data.linked) {
|
if (!executor->vm_data.valid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_PyExecutorLinkListNode *links = &executor->vm_data.links;
|
_PyExecutorLinkListNode *links = &executor->vm_data.links;
|
||||||
|
@ -1097,7 +1093,7 @@ unlink_executor(_PyExecutorObject *executor)
|
||||||
assert(interp->executor_list_head == executor);
|
assert(interp->executor_list_head == executor);
|
||||||
interp->executor_list_head = next;
|
interp->executor_list_head = next;
|
||||||
}
|
}
|
||||||
executor->vm_data.linked = false;
|
executor->vm_data.valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This must be called by optimizers before using the executor */
|
/* This must be called by optimizers before using the executor */
|
||||||
|
@ -1116,12 +1112,24 @@ void
|
||||||
_Py_ExecutorClear(_PyExecutorObject *executor)
|
_Py_ExecutorClear(_PyExecutorObject *executor)
|
||||||
{
|
{
|
||||||
unlink_executor(executor);
|
unlink_executor(executor);
|
||||||
|
PyCodeObject *code = executor->vm_data.code;
|
||||||
|
if (code == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_Py_CODEUNIT *instruction = &_PyCode_CODE(code)[executor->vm_data.index];
|
||||||
|
assert(instruction->op.code == ENTER_EXECUTOR);
|
||||||
|
int index = instruction->op.arg;
|
||||||
|
assert(code->co_executors->executors[index] == executor);
|
||||||
|
instruction->op.code = executor->vm_data.opcode;
|
||||||
|
instruction->op.arg = executor->vm_data.oparg;
|
||||||
|
executor->vm_data.code = NULL;
|
||||||
|
Py_CLEAR(code->co_executors->executors[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
_Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj)
|
_Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj)
|
||||||
{
|
{
|
||||||
assert(executor->vm_data.valid = true);
|
assert(executor->vm_data.valid);
|
||||||
_Py_BloomFilter_Add(&executor->vm_data.bloom, obj);
|
_Py_BloomFilter_Add(&executor->vm_data.bloom, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1140,8 +1148,7 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj)
|
||||||
assert(exec->vm_data.valid);
|
assert(exec->vm_data.valid);
|
||||||
_PyExecutorObject *next = exec->vm_data.links.next;
|
_PyExecutorObject *next = exec->vm_data.links.next;
|
||||||
if (bloom_filter_may_contain(&exec->vm_data.bloom, &obj_filter)) {
|
if (bloom_filter_may_contain(&exec->vm_data.bloom, &obj_filter)) {
|
||||||
exec->vm_data.valid = false;
|
_Py_ExecutorClear(exec);
|
||||||
unlink_executor(exec);
|
|
||||||
}
|
}
|
||||||
exec = next;
|
exec = next;
|
||||||
}
|
}
|
||||||
|
@ -1151,15 +1158,14 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj)
|
||||||
void
|
void
|
||||||
_Py_Executors_InvalidateAll(PyInterpreterState *interp)
|
_Py_Executors_InvalidateAll(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
/* Walk the list of executors */
|
while (interp->executor_list_head) {
|
||||||
for (_PyExecutorObject *exec = interp->executor_list_head; exec != NULL;) {
|
_PyExecutorObject *executor = interp->executor_list_head;
|
||||||
assert(exec->vm_data.valid);
|
if (executor->vm_data.code) {
|
||||||
_PyExecutorObject *next = exec->vm_data.links.next;
|
// Clear the entire code object so its co_executors array be freed:
|
||||||
exec->vm_data.links.next = NULL;
|
_PyCode_Clear_Executors(executor->vm_data.code);
|
||||||
exec->vm_data.links.previous = NULL;
|
}
|
||||||
exec->vm_data.valid = false;
|
else {
|
||||||
exec->vm_data.linked = false;
|
_Py_ExecutorClear(executor);
|
||||||
exec = next;
|
}
|
||||||
}
|
}
|
||||||
interp->executor_list_head = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2127,6 +2127,22 @@ sys__clear_type_cache_impl(PyObject *module)
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*[clinic input]
|
||||||
|
sys._clear_internal_caches
|
||||||
|
|
||||||
|
Clear all internal performance-related caches.
|
||||||
|
[clinic start generated code]*/
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
sys__clear_internal_caches_impl(PyObject *module)
|
||||||
|
/*[clinic end generated code: output=0ee128670a4966d6 input=253e741ca744f6e8]*/
|
||||||
|
{
|
||||||
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
|
_Py_Executors_InvalidateAll(interp);
|
||||||
|
PyType_ClearCache();
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Note that, for now, we do not have a per-interpreter equivalent
|
/* Note that, for now, we do not have a per-interpreter equivalent
|
||||||
for sys.is_finalizing(). */
|
for sys.is_finalizing(). */
|
||||||
|
|
||||||
|
@ -2461,6 +2477,7 @@ static PyMethodDef sys_methods[] = {
|
||||||
{"audit", _PyCFunction_CAST(sys_audit), METH_FASTCALL, audit_doc },
|
{"audit", _PyCFunction_CAST(sys_audit), METH_FASTCALL, audit_doc },
|
||||||
{"breakpointhook", _PyCFunction_CAST(sys_breakpointhook),
|
{"breakpointhook", _PyCFunction_CAST(sys_breakpointhook),
|
||||||
METH_FASTCALL | METH_KEYWORDS, breakpointhook_doc},
|
METH_FASTCALL | METH_KEYWORDS, breakpointhook_doc},
|
||||||
|
SYS__CLEAR_INTERNAL_CACHES_METHODDEF
|
||||||
SYS__CLEAR_TYPE_CACHE_METHODDEF
|
SYS__CLEAR_TYPE_CACHE_METHODDEF
|
||||||
SYS__CURRENT_FRAMES_METHODDEF
|
SYS__CURRENT_FRAMES_METHODDEF
|
||||||
SYS__CURRENT_EXCEPTIONS_METHODDEF
|
SYS__CURRENT_EXCEPTIONS_METHODDEF
|
||||||
|
|
Loading…
Reference in New Issue