Fixed Issue3122 and extended sys.getsizeof tests for built-in types.

This commit is contained in:
Robert Schuppenies 2008-07-10 13:43:26 +00:00
parent 548db58e02
commit d2cd86ddd5
2 changed files with 182 additions and 78 deletions

View file

@ -398,8 +398,10 @@ class SizeofTest(unittest.TestCase):
# due to missing size_t information from struct, it is assumed that # due to missing size_t information from struct, it is assumed that
# sizeof(Py_ssize_t) = sizeof(void*) # sizeof(Py_ssize_t) = sizeof(void*)
self.header = 'PP' self.header = 'PP'
self.vheader = self.header + 'P'
if hasattr(sys, "gettotalrefcount"): if hasattr(sys, "gettotalrefcount"):
self.header += '2P' self.header += '2P'
self.vheader += '2P'
self.file = open(test.test_support.TESTFN, 'wb') self.file = open(test.test_support.TESTFN, 'wb')
def tearDown(self): def tearDown(self):
@ -424,44 +426,90 @@ class SizeofTest(unittest.TestCase):
""" """
return struct.calcsize(fmt + '0P') return struct.calcsize(fmt + '0P')
def test_standardtypes(self): def test_objecttypes(self):
# check all types defined in Objects/
h = self.header h = self.header
vh = self.vheader
size = self.calcsize size = self.calcsize
check = self.check_sizeof
# bool # bool
self.check_sizeof(True, size(h + 'l')) check(True, size(h + 'l'))
# buffer # buffer
self.check_sizeof(buffer(''), size(h + '2P2Pil')) check(buffer(''), size(h + '2P2Pil'))
# builtin_function_or_method
check(len, size(h + '3P'))
# cell # cell
def get_cell(): def get_cell():
x = 42 x = 42
def inner(): def inner():
return x return x
return inner return inner
self.check_sizeof(get_cell().func_closure[0], size(h + 'P')) check(get_cell().func_closure[0], size(h + 'P'))
# old-style class # classobj (old-style class)
class class_oldstyle(): class class_oldstyle():
def method(): def method():
pass pass
self.check_sizeof(class_oldstyle, size(h + '6P')) check(class_oldstyle, size(h + '6P'))
# instance # instance (old-style class)
self.check_sizeof(class_oldstyle(), size(h + '3P')) check(class_oldstyle(), size(h + '3P'))
# method # instancemethod (old-style class)
self.check_sizeof(class_oldstyle().method, size(h + '4P')) check(class_oldstyle().method, size(h + '4P'))
# code
self.check_sizeof(get_cell().func_code, size(h + '4i8Pi2P'))
# complex # complex
self.check_sizeof(complex(0,1), size(h + '2d')) check(complex(0,1), size(h + '2d'))
# code
check(get_cell().func_code, size(h + '4i8Pi2P'))
# BaseException
check(BaseException(), size(h + '3P'))
# UnicodeEncodeError
check(UnicodeEncodeError("", u"", 0, 0, ""), size(h + '5P2PP'))
# UnicodeDecodeError
check(UnicodeDecodeError("", "", 0, 0, ""), size(h + '5P2PP'))
# UnicodeTranslateError
check(UnicodeTranslateError(u"", 0, 1, ""), size(h + '5P2PP'))
# method_descriptor (descriptor object)
check(str.lower, size(h + '2PP'))
# classmethod_descriptor (descriptor object)
# XXX
# member_descriptor (descriptor object)
import datetime
check(datetime.timedelta.days, size(h + '2PP'))
# getset_descriptor (descriptor object)
import __builtin__
check(__builtin__.file.closed, size(h + '2PP'))
# wrapper_descriptor (descriptor object)
check(int.__add__, size(h + '2P2P'))
# dictproxy
class C(object): pass
check(C.__dict__, size(h + 'P'))
# method-wrapper (descriptor object)
check({}.__iter__, size(h + '2P'))
# dict
check({}, size(h + '3P2P') + 8*size('P2P'))
x = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8}
check(x, size(h + '3P2P') + (8+16)*size('P2P'))
# dictionary-keyiterator
check({}.iterkeys(), size(h + 'P2PPP'))
# dictionary-valueiterator
check({}.itervalues(), size(h + 'P2PPP'))
# dictionary-itemiterator
check({}.iteritems(), size(h + 'P2PPP'))
# ellipses
check(Ellipsis, size(h + ''))
# EncodingMap
import codecs, encodings.iso8859_3
x = codecs.charmap_build(encodings.iso8859_3.decoding_table)
check(x, size(h + '32B2iB'))
# enumerate # enumerate
self.check_sizeof(enumerate([]), size(h + 'l3P')) check(enumerate([]), size(h + 'l3P'))
# reverse
self.check_sizeof(reversed(''), size(h + 'PP'))
# file # file
self.check_sizeof(self.file, size(h + '4P2i4P3i3Pi')) check(self.file, size(h + '4P2i4P3i3Pi'))
# float # float
self.check_sizeof(float(0), size(h + 'd')) check(float(0), size(h + 'd'))
# sys.floatinfo
check(sys.float_info, size(vh) + self.P * len(sys.float_info))
# function # function
def func(): pass def func(): pass
self.check_sizeof(func, size(h + '9P')) check(func, size(h + '9P'))
class c(): class c():
@staticmethod @staticmethod
def foo(): def foo():
@ -470,40 +518,82 @@ class SizeofTest(unittest.TestCase):
def bar(cls): def bar(cls):
pass pass
# staticmethod # staticmethod
self.check_sizeof(foo, size(h + 'P')) check(foo, size(h + 'P'))
# classmethod # classmethod
self.check_sizeof(bar, size(h + 'P')) check(bar, size(h + 'P'))
# generator # generator
def get_gen(): yield 1 def get_gen(): yield 1
self.check_sizeof(get_gen(), size(h + 'Pi2P')) check(get_gen(), size(h + 'Pi2P'))
# integer # integer
self.check_sizeof(1, size(h + 'l')) check(1, size(h + 'l'))
# builtin_function_or_method check(100, size(h + 'l'))
self.check_sizeof(abs, size(h + '3P')) # iterator
check(iter('abc'), size(h + 'lP'))
# callable-iterator
import re
check(re.finditer('',''), size(h + '2P'))
# list
samples = [[], [1,2,3], ['1', '2', '3']]
for sample in samples:
check(sample, size(vh + 'PP') + len(sample)*self.P)
# sortwrapper (list)
# XXX
# cmpwrapper (list)
# XXX
# listiterator (list)
check(iter([]), size(h + 'lP'))
# listreverseiterator (list)
check(reversed([]), size(h + 'lP'))
# long
check(0L, size(vh + 'H'))
check(1L, size(vh + 'H'))
check(-1L, size(vh + 'H'))
check(32768L, size(vh + 'H') + self.H)
check(32768L*32768L-1, size(vh + 'H') + self.H)
check(32768L*32768L, size(vh + 'H') + 2*self.H)
# module # module
self.check_sizeof(unittest, size(h + 'P')) check(unittest, size(h + 'P'))
# xrange # None
self.check_sizeof(xrange(1), size(h + '3l')) check(None, size(h + ''))
# object
check(object(), size(h + ''))
# property (descriptor object)
class C(object):
def getx(self): return self.__x
def setx(self, value): self.__x = value
def delx(self): del self.__x
x = property(getx, setx, delx, "")
check(x, size(h + '4Pi'))
# PyCObject
# XXX
# rangeiterator
check(iter(xrange(1)), size(h + '4l'))
# reverse
check(reversed(''), size(h + 'PP'))
# slice # slice
self.check_sizeof(slice(0), size(h + '3P')) check(slice(1), size(h + '3P'))
# str
h += 'P' check('', size(vh + 'lic'))
# new-style class check('abc', size(vh + 'lic') + 3*self.c)
class class_newstyle(object): # super
def method(): check(super(int), size(h + '3P'))
pass # tuple
# type (PyTypeObject + PyNumberMethods + PyMappingMethods + check((), size(vh))
# PySequenceMethods + PyBufferProcs) check((1,2,3), size(vh) + 3*self.P)
self.check_sizeof(class_newstyle, size('P2P15Pl4PP9PP11PI') +\ # tupleiterator
size(h + '41P 10P 3P 6P')) check(iter(()), size(h + 'lP'))
# type
def test_specialtypes(self): # (PyTypeObject + PyNumberMethods + PyMappingMethods +
h = self.header # PySequenceMethods + PyBufferProcs)
size = self.calcsize s = size('P2P15Pl4PP9PP11PI') + size(vh + '41P 10P 3P 6P')
# dict class newstyleclass(object):
self.check_sizeof({}, size(h + '3P2P') + 8*size('P2P')) pass
longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8} check(newstyleclass, s)
self.check_sizeof(longdict, size(h + '3P2P') + (8+16)*size('P2P')) # builtin type
check(int, s)
# NotImplementedType
import types
check(types.NotImplementedType, s)
# unicode # unicode
usize = len(u'\0'.encode('unicode-internal')) usize = len(u'\0'.encode('unicode-internal'))
samples = [u'', u'1'*100] samples = [u'', u'1'*100]
@ -511,8 +601,7 @@ class SizeofTest(unittest.TestCase):
# has been cached # has been cached
for s in samples: for s in samples:
basicsize = size(h + 'PPlP') + usize * (len(s) + 1) basicsize = size(h + 'PPlP') + usize * (len(s) + 1)
self.check_sizeof(s, basicsize,\ check(s, basicsize, size2=basicsize + sys.getsizeof(str(s)))
size2=basicsize + sys.getsizeof(str(s)))
# XXX trigger caching encoded version as Python string # XXX trigger caching encoded version as Python string
s = samples[1] s = samples[1]
try: try:
@ -520,25 +609,41 @@ class SizeofTest(unittest.TestCase):
except AttributeError: except AttributeError:
pass pass
finally: finally:
self.check_sizeof(s, basicsize + sys.getsizeof(str(s))) check(s, basicsize + sys.getsizeof(str(s)))
# weakref
import weakref
check(weakref.ref(int), size(h + '2Pl2P'))
# weakproxy
# XXX
# weakcallableproxy
check(weakref.proxy(int), size(h + '2Pl2P'))
# xrange
check(xrange(1), size(h + '3l'))
check(xrange(66000), size(h + '3l'))
h += 'P' def test_pythontypes(self):
# list # check all types defined in Python/
self.check_sizeof([], size(h + 'PP')) h = self.header
self.check_sizeof([1, 2, 3], size(h + 'PP') + 3*self.P) vh = self.vheader
# long size = self.calcsize
self.check_sizeof(0L, size(h + 'H')) check = self.check_sizeof
self.check_sizeof(1L, size(h + 'H')) # _ast.AST
self.check_sizeof(-1L, size(h + 'H')) import _ast
self.check_sizeof(32768L, size(h + 'H') + self.H) check(_ast.AST(), size(h + ''))
self.check_sizeof(32768L*32768L-1, size(h + 'H') + self.H) # imp.NullImporter
self.check_sizeof(32768L*32768L, size(h + 'H') + 2*self.H) import imp
# string check(imp.NullImporter(self.file.name), size(h + ''))
self.check_sizeof('', size(h + 'lic')) try:
self.check_sizeof('abc', size(h + 'lic') + 3*self.c) raise TypeError
# tuple except TypeError:
self.check_sizeof((), size(h)) tb = sys.exc_info()[2]
self.check_sizeof((1,2,3), size(h) + 3*self.P) # traceback
if tb != None:
check(tb, size(h + '2P2i'))
# symtable entry
# XXX
# sys.flags
check(sys.flags, size(vh) + self.P * len(sys.flags))
def test_main(): def test_main():

View file

@ -651,8 +651,15 @@ sys_getsizeof(PyObject *self, PyObject *args)
return NULL; return NULL;
} }
/* Type objects */ /* Make sure the type is initialized. float gets initialized late */
if (PyType_Check(args)){ if (PyType_Ready(Py_TYPE(args)) < 0)
return NULL;
/* Instance of old-style class */
if (PyInstance_Check(args))
return PyInt_FromSsize_t(PyInstance_Type.tp_basicsize);
/* all other objects */
else {
PyObject *method = _PyType_Lookup(Py_TYPE(args), PyObject *method = _PyType_Lookup(Py_TYPE(args),
str__sizeof__); str__sizeof__);
if (method == NULL) { if (method == NULL) {
@ -662,15 +669,7 @@ sys_getsizeof(PyObject *self, PyObject *args)
return NULL; return NULL;
} }
return PyObject_CallFunctionObjArgs(method, args, NULL); return PyObject_CallFunctionObjArgs(method, args, NULL);
} }
/* Instance of old-style classes */
else if (PyInstance_Check(args))
return PyInt_FromSsize_t(PyInstance_Type.tp_basicsize);
/* Old-style classes */
else if (PyClass_Check(args))
return PyInt_FromSsize_t(PyClass_Type.tp_basicsize);
else
return PyObject_CallMethod(args, "__sizeof__", NULL);
} }
PyDoc_STRVAR(getsizeof_doc, PyDoc_STRVAR(getsizeof_doc,