mirror of https://github.com/python/cpython
Merged revisions 60364-60378 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r60364 | neal.norwitz | 2008-01-27 19:09:48 +0100 (Sun, 27 Jan 2008) | 4 lines Update the comment and remove the close. If we close we can't flush anymore. We might still need to close after the for loop if flushing 6! times still doesn't cause the signal/exception. ........ r60365 | georg.brandl | 2008-01-27 19:14:43 +0100 (Sun, 27 Jan 2008) | 2 lines Remove effectless expression statement. ........ r60367 | neal.norwitz | 2008-01-27 19:19:04 +0100 (Sun, 27 Jan 2008) | 1 line Try to handle socket.errors properly in is_unavailable ........ r60370 | christian.heimes | 2008-01-27 20:01:45 +0100 (Sun, 27 Jan 2008) | 1 line Change isbasestring function as discussed on the cvs list a while ago ........ r60372 | neal.norwitz | 2008-01-27 21:03:13 +0100 (Sun, 27 Jan 2008) | 3 lines socket.error doesn't have a headers attribute like ProtocolError. Handle that situation where we catch socket.errors. ........ r60375 | georg.brandl | 2008-01-27 21:25:12 +0100 (Sun, 27 Jan 2008) | 2 lines Add refcounting extension to build config. ........ r60377 | jeffrey.yasskin | 2008-01-28 00:08:46 +0100 (Mon, 28 Jan 2008) | 6 lines Moved Rational._binary_float_to_ratio() to float.as_integer_ratio() because it's useful outside of rational numbers. This is my first C code that had to do anything significant. Please be more careful when looking over it. ........ r60378 | christian.heimes | 2008-01-28 00:34:59 +0100 (Mon, 28 Jan 2008) | 1 line Added clear cache methods to clear the internal type lookup cache for ref leak test runs. ........
This commit is contained in:
parent
7b69c6c3af
commit
2685563583
|
@ -33,6 +33,13 @@ Type Objects
|
|||
standard type object. Return false in all other cases.
|
||||
|
||||
|
||||
.. cfunction:: unsigned int PyType_ClearCache(void)
|
||||
|
||||
Clears the internal lookup cache. Return the current version tag.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
|
||||
.. cfunction:: int PyType_HasFeature(PyObject *o, int feature)
|
||||
|
||||
Return true if the type object *o* sets the feature *feature*. Type features
|
||||
|
|
|
@ -13,6 +13,8 @@ sys.path.append('tools/sphinxext')
|
|||
# General configuration
|
||||
# ---------------------
|
||||
|
||||
extensions = ['sphinx.addons.refcounting']
|
||||
|
||||
# General substitutions.
|
||||
project = 'Python'
|
||||
copyright = '1990-%s, Python Software Foundation' % time.strftime('%Y')
|
||||
|
|
|
@ -54,6 +54,13 @@ always available.
|
|||
A string containing the copyright pertaining to the Python interpreter.
|
||||
|
||||
|
||||
.. function:: _cleartypecache()
|
||||
|
||||
Clear the internal type lookup cache.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
|
||||
.. function:: _current_frames()
|
||||
|
||||
Return a dictionary mapping each thread's identifier to the topmost stack frame
|
||||
|
|
|
@ -428,6 +428,7 @@ PyAPI_FUNC(PyObject *) PyType_GenericAlloc(PyTypeObject *, Py_ssize_t);
|
|||
PyAPI_FUNC(PyObject *) PyType_GenericNew(PyTypeObject *,
|
||||
PyObject *, PyObject *);
|
||||
PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
|
||||
PyAPI_FUNC(unsigned int) PyType_ClearCache(void);
|
||||
|
||||
/* Generic operations on objects */
|
||||
PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
|
||||
|
|
|
@ -1203,7 +1203,6 @@ class TextDoc(Doc):
|
|||
else:
|
||||
tag = "inherited from %s" % classname(thisclass,
|
||||
object.__module__)
|
||||
filter(lambda t: not t[0].startswith('_'), attrs)
|
||||
|
||||
# Sort attrs by name.
|
||||
attrs.sort()
|
||||
|
|
|
@ -24,60 +24,6 @@ def gcd(a, b):
|
|||
return a
|
||||
|
||||
|
||||
def _binary_float_to_ratio(x):
|
||||
"""x -> (top, bot), a pair of ints s.t. x = top/bot.
|
||||
|
||||
The conversion is done exactly, without rounding.
|
||||
bot > 0 guaranteed.
|
||||
Some form of binary fp is assumed.
|
||||
Pass NaNs or infinities at your own risk.
|
||||
|
||||
>>> _binary_float_to_ratio(10.0)
|
||||
(10, 1)
|
||||
>>> _binary_float_to_ratio(0.0)
|
||||
(0, 1)
|
||||
>>> _binary_float_to_ratio(-.25)
|
||||
(-1, 4)
|
||||
"""
|
||||
# XXX Move this to floatobject.c with a name like
|
||||
# float.as_integer_ratio()
|
||||
|
||||
if x == 0:
|
||||
return 0, 1
|
||||
f, e = math.frexp(x)
|
||||
signbit = 1
|
||||
if f < 0:
|
||||
f = -f
|
||||
signbit = -1
|
||||
assert 0.5 <= f < 1.0
|
||||
# x = signbit * f * 2**e exactly
|
||||
|
||||
# Suck up CHUNK bits at a time; 28 is enough so that we suck
|
||||
# up all bits in 2 iterations for all known binary double-
|
||||
# precision formats, and small enough to fit in an int.
|
||||
CHUNK = 28
|
||||
top = 0
|
||||
# invariant: x = signbit * (top + f) * 2**e exactly
|
||||
while f:
|
||||
f = math.ldexp(f, CHUNK)
|
||||
digit = trunc(f)
|
||||
assert digit >> CHUNK == 0
|
||||
top = (top << CHUNK) | digit
|
||||
f = f - digit
|
||||
assert 0.0 <= f < 1.0
|
||||
e = e - CHUNK
|
||||
assert top
|
||||
|
||||
# Add in the sign bit.
|
||||
top = signbit * top
|
||||
|
||||
# now x = top * 2**e exactly; fold in 2**e
|
||||
if e>0:
|
||||
return (top * 2**e, 1)
|
||||
else:
|
||||
return (top, 2 ** -e)
|
||||
|
||||
|
||||
_RATIONAL_FORMAT = re.compile(
|
||||
r'^\s*(?P<sign>[-+]?)(?P<num>\d+)'
|
||||
r'(?:/(?P<denom>\d+)|\.(?P<decimal>\d+))?\s*$')
|
||||
|
@ -162,7 +108,7 @@ class Rational(RationalAbc):
|
|||
(cls.__name__, f, type(f).__name__))
|
||||
if math.isnan(f) or math.isinf(f):
|
||||
raise TypeError("Cannot convert %r to %s." % (f, cls.__name__))
|
||||
return cls(*_binary_float_to_ratio(f))
|
||||
return cls(*f.as_integer_ratio())
|
||||
|
||||
@classmethod
|
||||
def from_decimal(cls, dec):
|
||||
|
|
|
@ -752,6 +752,9 @@ def dash_R_cleanup(fs, ps, pic, abcs):
|
|||
sys.path_importer_cache.clear()
|
||||
sys.path_importer_cache.update(pic)
|
||||
|
||||
# clear type cache
|
||||
sys._cleartypecache()
|
||||
|
||||
# Clear ABC registries, restoring previously saved ABC registries.
|
||||
for abc in [getattr(_abcoll, a) for a in _abcoll.__all__]:
|
||||
if not issubclass(abc, _Abstract):
|
||||
|
|
|
@ -5,7 +5,7 @@ from test.test_support import fcmp, TESTFN, unlink, run_unittest, \
|
|||
run_with_locale
|
||||
from operator import neg
|
||||
|
||||
import sys, warnings, random, UserDict, io
|
||||
import sys, warnings, random, UserDict, io, rational
|
||||
warnings.filterwarnings("ignore", "hex../oct.. of negative int",
|
||||
FutureWarning, __name__)
|
||||
warnings.filterwarnings("ignore", "integer argument expected",
|
||||
|
@ -592,6 +592,25 @@ class BuiltinTest(unittest.TestCase):
|
|||
# make sure we can take a subclass of str as a format spec
|
||||
self.assertEqual(format(0, C('10')), ' 0')
|
||||
|
||||
def test_floatasratio(self):
|
||||
R = rational.Rational
|
||||
self.assertEqual(R(0, 1),
|
||||
R(*float(0.0).as_integer_ratio()))
|
||||
self.assertEqual(R(5, 2),
|
||||
R(*float(2.5).as_integer_ratio()))
|
||||
self.assertEqual(R(1, 2),
|
||||
R(*float(0.5).as_integer_ratio()))
|
||||
self.assertEqual(R(4728779608739021, 2251799813685248),
|
||||
R(*float(2.1).as_integer_ratio()))
|
||||
self.assertEqual(R(-4728779608739021, 2251799813685248),
|
||||
R(*float(-2.1).as_integer_ratio()))
|
||||
self.assertEqual(R(-2100, 1),
|
||||
R(*float(-2100.0).as_integer_ratio()))
|
||||
|
||||
self.assertRaises(OverflowError, float('inf').as_integer_ratio)
|
||||
self.assertRaises(OverflowError, float('-inf').as_integer_ratio)
|
||||
self.assertRaises(ValueError, float('nan').as_integer_ratio)
|
||||
|
||||
def test_getattr(self):
|
||||
import sys
|
||||
self.assert_(getattr(sys, 'stdout') is sys.stdout)
|
||||
|
|
|
@ -56,13 +56,12 @@ class ResourceTest(unittest.TestCase):
|
|||
f.flush()
|
||||
# On some systems (e.g., Ubuntu on hppa) the flush()
|
||||
# doesn't always cause the exception, but the close()
|
||||
# does eventually. Try closing several times in
|
||||
# does eventually. Try flushing several times in
|
||||
# an attempt to ensure the file is really synced and
|
||||
# the exception raised.
|
||||
for i in range(5):
|
||||
time.sleep(.1)
|
||||
f.flush()
|
||||
f.close()
|
||||
except IOError:
|
||||
if not limit_set:
|
||||
raise
|
||||
|
|
|
@ -312,9 +312,16 @@ def is_unavailable_exception(e):
|
|||
given by operations on non-blocking sockets.'''
|
||||
|
||||
# sometimes we get a -1 error code and/or empty headers
|
||||
if e.errcode == -1 or e.headers is None:
|
||||
return True
|
||||
try:
|
||||
if e.errcode == -1 or e.headers is None:
|
||||
return True
|
||||
exc_mess = e.headers.get('X-exception')
|
||||
except AttributeError:
|
||||
# Ignore socket.errors here.
|
||||
exc_mess = str(e)
|
||||
|
||||
if exc_mess and 'temporarily unavailable' in exc_mess.lower():
|
||||
return True
|
||||
|
||||
class SimpleServerTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
@ -349,7 +356,7 @@ class SimpleServerTestCase(unittest.TestCase):
|
|||
# ignore failures due to non-blocking socket 'unavailable' errors
|
||||
if not is_unavailable_exception(e):
|
||||
# protocol error; provide additional information in test output
|
||||
self.fail("%s\n%s" % (e, e.headers))
|
||||
self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
|
||||
|
||||
# [ch] The test 404 is causing lots of false alarms.
|
||||
def XXXtest_404(self):
|
||||
|
@ -375,7 +382,7 @@ class SimpleServerTestCase(unittest.TestCase):
|
|||
# ignore failures due to non-blocking socket 'unavailable' errors
|
||||
if not is_unavailable_exception(e):
|
||||
# protocol error; provide additional information in test output
|
||||
self.fail("%s\n%s" % (e, e.headers))
|
||||
self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
|
||||
|
||||
|
||||
def test_introspection2(self):
|
||||
|
@ -388,7 +395,7 @@ class SimpleServerTestCase(unittest.TestCase):
|
|||
# ignore failures due to non-blocking socket 'unavailable' errors
|
||||
if not is_unavailable_exception(e):
|
||||
# protocol error; provide additional information in test output
|
||||
self.fail("%s\n%s" % (e, e.headers))
|
||||
self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
|
||||
|
||||
def test_introspection3(self):
|
||||
try:
|
||||
|
@ -400,7 +407,7 @@ class SimpleServerTestCase(unittest.TestCase):
|
|||
# ignore failures due to non-blocking socket 'unavailable' errors
|
||||
if not is_unavailable_exception(e):
|
||||
# protocol error; provide additional information in test output
|
||||
self.fail("%s\n%s" % (e, e.headers))
|
||||
self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
|
||||
|
||||
def test_introspection4(self):
|
||||
# the SimpleXMLRPCServer doesn't support signatures, but
|
||||
|
@ -413,7 +420,7 @@ class SimpleServerTestCase(unittest.TestCase):
|
|||
# ignore failures due to non-blocking socket 'unavailable' errors
|
||||
if not is_unavailable_exception(e):
|
||||
# protocol error; provide additional information in test output
|
||||
self.fail("%s\n%s" % (e, e.headers))
|
||||
self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
|
||||
|
||||
def test_multicall(self):
|
||||
try:
|
||||
|
@ -430,7 +437,7 @@ class SimpleServerTestCase(unittest.TestCase):
|
|||
# ignore failures due to non-blocking socket 'unavailable' errors
|
||||
if not is_unavailable_exception(e):
|
||||
# protocol error; provide additional information in test output
|
||||
self.fail("%s\n%s" % (e, e.headers))
|
||||
self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
|
||||
|
||||
def test_non_existing_multicall(self):
|
||||
try:
|
||||
|
@ -451,7 +458,7 @@ class SimpleServerTestCase(unittest.TestCase):
|
|||
# ignore failures due to non-blocking socket 'unavailable' errors
|
||||
if not is_unavailable_exception(e):
|
||||
# protocol error; provide additional information in test output
|
||||
self.fail("%s\n%s" % (e, e.headers))
|
||||
self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
|
||||
|
||||
# This is a contrived way to make a failure occur on the server side
|
||||
# in order to test the _send_traceback_header flag on the server
|
||||
|
@ -498,7 +505,7 @@ class FailingServerTestCase(unittest.TestCase):
|
|||
# ignore failures due to non-blocking socket 'unavailable' errors
|
||||
if not is_unavailable_exception(e):
|
||||
# protocol error; provide additional information in test output
|
||||
self.fail("%s\n%s" % (e, e.headers))
|
||||
self.fail("%s\n%s" % (e, getattr(e, "headers", "")))
|
||||
|
||||
def test_fail_no_info(self):
|
||||
# use the broken message class
|
||||
|
@ -509,7 +516,7 @@ class FailingServerTestCase(unittest.TestCase):
|
|||
p.pow(6,8)
|
||||
except (xmlrpclib.ProtocolError, socket.error) as e:
|
||||
# ignore failures due to non-blocking socket 'unavailable' errors
|
||||
if not is_unavailable_exception(e):
|
||||
if not is_unavailable_exception(e) and hasattr(e, "headers"):
|
||||
# The two server-side error headers shouldn't be sent back in this case
|
||||
self.assertTrue(e.headers.get("X-exception") is None)
|
||||
self.assertTrue(e.headers.get("X-traceback") is None)
|
||||
|
@ -529,7 +536,7 @@ class FailingServerTestCase(unittest.TestCase):
|
|||
p.pow(6,8)
|
||||
except (xmlrpclib.ProtocolError, socket.error) as e:
|
||||
# ignore failures due to non-blocking socket 'unavailable' errors
|
||||
if not is_unavailable_exception(e):
|
||||
if not is_unavailable_exception(e) and hasattr(e, "headers"):
|
||||
# We should get error info in the response
|
||||
expected_err = "invalid literal for int() with base 10: 'I am broken'"
|
||||
self.assertEqual(e.headers.get("x-exception"), expected_err)
|
||||
|
|
|
@ -1073,6 +1073,163 @@ float_float(PyObject *v)
|
|||
return v;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
float_as_integer_ratio(PyObject *v)
|
||||
{
|
||||
double self;
|
||||
double float_part;
|
||||
int exponent;
|
||||
int is_negative;
|
||||
const int chunk_size = 28;
|
||||
PyObject *prev;
|
||||
PyObject *py_chunk = NULL;
|
||||
PyObject *py_exponent = NULL;
|
||||
PyObject *numerator = NULL;
|
||||
PyObject *denominator = NULL;
|
||||
PyObject *result_pair = NULL;
|
||||
PyNumberMethods *long_methods;
|
||||
|
||||
#define INPLACE_UPDATE(obj, call) \
|
||||
prev = obj; \
|
||||
obj = call; \
|
||||
Py_DECREF(prev); \
|
||||
|
||||
CONVERT_TO_DOUBLE(v, self);
|
||||
|
||||
if (Py_IS_INFINITY(self)) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"Cannot pass infinity to float.as_integer_ratio.");
|
||||
return NULL;
|
||||
}
|
||||
#ifdef Py_NAN
|
||||
if (Py_IS_NAN(self)) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"Cannot pass nan to float.as_integer_ratio.");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (self == 0) {
|
||||
numerator = PyLong_FromLong(0);
|
||||
if (numerator == NULL) goto error;
|
||||
denominator = PyLong_FromLong(1);
|
||||
if (denominator == NULL) goto error;
|
||||
result_pair = PyTuple_Pack(2, numerator, denominator);
|
||||
/* Hand ownership over to the tuple. If the tuple
|
||||
wasn't created successfully, we want to delete the
|
||||
ints anyway. */
|
||||
Py_DECREF(numerator);
|
||||
Py_DECREF(denominator);
|
||||
return result_pair;
|
||||
}
|
||||
|
||||
/* XXX: Could perhaps handle FLT_RADIX!=2 by using ilogb and
|
||||
scalbn, but those may not be in C89. */
|
||||
PyFPE_START_PROTECT("as_integer_ratio", goto error);
|
||||
float_part = frexp(self, &exponent);
|
||||
is_negative = 0;
|
||||
if (float_part < 0) {
|
||||
float_part = -float_part;
|
||||
is_negative = 1;
|
||||
/* 0.5 <= float_part < 1.0 */
|
||||
}
|
||||
PyFPE_END_PROTECT(float_part);
|
||||
/* abs(self) == float_part * 2**exponent exactly */
|
||||
|
||||
/* Suck up chunk_size bits at a time; 28 is enough so that we
|
||||
suck up all bits in 2 iterations for all known binary
|
||||
double-precision formats, and small enough to fit in a
|
||||
long. */
|
||||
numerator = PyLong_FromLong(0);
|
||||
if (numerator == NULL) goto error;
|
||||
|
||||
long_methods = PyLong_Type.tp_as_number;
|
||||
|
||||
py_chunk = PyLong_FromLong(chunk_size);
|
||||
if (py_chunk == NULL) goto error;
|
||||
|
||||
while (float_part != 0) {
|
||||
/* invariant: abs(self) ==
|
||||
(numerator + float_part) * 2**exponent exactly */
|
||||
long digit;
|
||||
PyObject *py_digit;
|
||||
|
||||
PyFPE_START_PROTECT("as_integer_ratio", goto error);
|
||||
/* Pull chunk_size bits out of float_part, into digits. */
|
||||
float_part = ldexp(float_part, chunk_size);
|
||||
digit = (long)float_part;
|
||||
float_part -= digit;
|
||||
/* 0 <= float_part < 1 */
|
||||
exponent -= chunk_size;
|
||||
PyFPE_END_PROTECT(float_part);
|
||||
|
||||
/* Shift digits into numerator. */
|
||||
// numerator <<= chunk_size
|
||||
INPLACE_UPDATE(numerator,
|
||||
long_methods->nb_lshift(numerator, py_chunk));
|
||||
if (numerator == NULL) goto error;
|
||||
|
||||
// numerator |= digit
|
||||
py_digit = PyLong_FromLong(digit);
|
||||
if (py_digit == NULL) goto error;
|
||||
INPLACE_UPDATE(numerator,
|
||||
long_methods->nb_or(numerator, py_digit));
|
||||
Py_DECREF(py_digit);
|
||||
if (numerator == NULL) goto error;
|
||||
}
|
||||
|
||||
/* Add in the sign bit. */
|
||||
if (is_negative) {
|
||||
INPLACE_UPDATE(numerator,
|
||||
long_methods->nb_negative(numerator));
|
||||
if (numerator == NULL) goto error;
|
||||
}
|
||||
|
||||
/* now self = numerator * 2**exponent exactly; fold in 2**exponent */
|
||||
denominator = PyLong_FromLong(1);
|
||||
py_exponent = PyLong_FromLong(labs(exponent));
|
||||
if (py_exponent == NULL) goto error;
|
||||
INPLACE_UPDATE(py_exponent,
|
||||
long_methods->nb_lshift(denominator, py_exponent));
|
||||
if (py_exponent == NULL) goto error;
|
||||
if (exponent > 0) {
|
||||
INPLACE_UPDATE(numerator,
|
||||
long_methods->nb_multiply(numerator,
|
||||
py_exponent));
|
||||
if (numerator == NULL) goto error;
|
||||
}
|
||||
else {
|
||||
Py_DECREF(denominator);
|
||||
denominator = py_exponent;
|
||||
py_exponent = NULL;
|
||||
}
|
||||
|
||||
result_pair = PyTuple_Pack(2, numerator, denominator);
|
||||
|
||||
#undef INPLACE_UPDATE
|
||||
error:
|
||||
Py_XDECREF(py_exponent);
|
||||
Py_XDECREF(py_chunk);
|
||||
Py_XDECREF(denominator);
|
||||
Py_XDECREF(numerator);
|
||||
return result_pair;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(float_as_integer_ratio_doc,
|
||||
"float.as_integer_ratio() -> (int, int)\n"
|
||||
"\n"
|
||||
"Returns a pair of integers, not necessarily in lowest terms, whose\n"
|
||||
"ratio is exactly equal to the original float. This method raises an\n"
|
||||
"OverflowError on infinities and a ValueError on nans. The resulting\n"
|
||||
"denominator will be positive.\n"
|
||||
"\n"
|
||||
">>> (10.0).as_integer_ratio()\n"
|
||||
"(167772160L, 16777216L)\n"
|
||||
">>> (0.0).as_integer_ratio()\n"
|
||||
"(0, 1)\n"
|
||||
">>> (-.25).as_integer_ratio()\n"
|
||||
"(-134217728L, 536870912L)");
|
||||
|
||||
|
||||
static PyObject *
|
||||
float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
|
||||
|
@ -1281,6 +1438,8 @@ static PyMethodDef float_methods[] = {
|
|||
{"__round__", (PyCFunction)float_round, METH_VARARGS,
|
||||
"Returns the Integral closest to x, rounding half toward even.\n"
|
||||
"When an argument is passed, works like built-in round(x, ndigits)."},
|
||||
{"as_integer_ratio", (PyCFunction)float_as_integer_ratio, METH_NOARGS,
|
||||
float_as_integer_ratio_doc},
|
||||
{"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS},
|
||||
{"__getformat__", (PyCFunction)float_getformat,
|
||||
METH_O|METH_CLASS, float_getformat_doc},
|
||||
|
|
|
@ -33,6 +33,24 @@ struct method_cache_entry {
|
|||
|
||||
static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP];
|
||||
static unsigned int next_version_tag = 0;
|
||||
static void type_modified(PyTypeObject *);
|
||||
|
||||
unsigned int
|
||||
PyType_ClearCache(void)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
unsigned int cur_version_tag = next_version_tag - 1;
|
||||
|
||||
for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) {
|
||||
method_cache[i].version = 0;
|
||||
Py_CLEAR(method_cache[i].name);
|
||||
method_cache[i].value = NULL;
|
||||
}
|
||||
next_version_tag = 0;
|
||||
/* mark all version tags as invalid */
|
||||
type_modified(&PyBaseObject_Type);
|
||||
return cur_version_tag;
|
||||
}
|
||||
|
||||
static void
|
||||
type_modified(PyTypeObject *type)
|
||||
|
|
|
@ -404,6 +404,9 @@ Py_Finalize(void)
|
|||
Py_XDECREF(warnings_module);
|
||||
warnings_module = NULL;
|
||||
|
||||
/* Clear type lookup cache */
|
||||
PyType_ClearCache();
|
||||
|
||||
/* Collect garbage. This may call finalizers; it's nice to call these
|
||||
* before all modules are destroyed.
|
||||
* XXX If a __del__ or weakref callback is triggered here, and tries to
|
||||
|
|
|
@ -730,6 +730,17 @@ a 11-tuple where the entries in the tuple are counts of:\n\
|
|||
10. Number of stack pops performed by call_function()"
|
||||
);
|
||||
|
||||
static PyObject *
|
||||
sys_cleartypecache(PyObject* self, PyObject* args)
|
||||
{
|
||||
PyType_ClearCache();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(cleartypecache_doc,
|
||||
"_cleartypecache() -> None\n\
|
||||
Clear the internal type lookup cache.");
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -752,6 +763,8 @@ static PyMethodDef sys_methods[] = {
|
|||
/* Might as well keep this in alphabetic order */
|
||||
{"callstats", (PyCFunction)PyEval_GetCallStats, METH_NOARGS,
|
||||
callstats_doc},
|
||||
{"_cleartypecache", sys_cleartypecache, METH_NOARGS,
|
||||
cleartypecache_doc},
|
||||
{"_current_frames", sys_current_frames, METH_NOARGS,
|
||||
current_frames_doc},
|
||||
{"displayhook", sys_displayhook, METH_O, displayhook_doc},
|
||||
|
|
Loading…
Reference in New Issue