Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
4d9d9387
Commit
4d9d9387
authored
Dec 16, 2014
by
Serhiy Storchaka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #15513: Added a __sizeof__ implementation for pickle classes.
parent
a9ae77ab
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
184 additions
and
4 deletions
+184
-4
Lib/test/test_pickle.py
Lib/test/test_pickle.py
+69
-1
Misc/NEWS
Misc/NEWS
+3
-1
Modules/_pickle.c
Modules/_pickle.c
+57
-1
Modules/clinic/_pickle.c.h
Modules/clinic/_pickle.c.h
+55
-1
No files found.
Lib/test/test_pickle.py
View file @
4d9d9387
import
pickle
import
io
import
collections
import
struct
import
sys
import
unittest
from
test
import
support
from
test.pickletester
import
AbstractPickleTests
...
...
@@ -138,6 +141,71 @@ if has_c_implementation:
def
get_dispatch_table
(
self
):
return
collections
.
ChainMap
({},
pickle
.
dispatch_table
)
@
support
.
cpython_only
class
SizeofTests
(
unittest
.
TestCase
):
check_sizeof
=
support
.
check_sizeof
def
test_pickler
(
self
):
basesize
=
support
.
calcobjsize
(
'5P2n3i2n3iP'
)
p
=
_pickle
.
Pickler
(
io
.
BytesIO
())
self
.
assertEqual
(
object
.
__sizeof__
(
p
),
basesize
)
MT_size
=
struct
.
calcsize
(
'3nP0n'
)
ME_size
=
struct
.
calcsize
(
'Pn0P'
)
check
=
self
.
check_sizeof
check
(
p
,
basesize
+
MT_size
+
8
*
ME_size
+
# Minimal memo table size.
sys
.
getsizeof
(
b'x'
*
4096
))
# Minimal write buffer size.
for
i
in
range
(
6
):
p
.
dump
(
chr
(
i
))
check
(
p
,
basesize
+
MT_size
+
32
*
ME_size
+
# Size of memo table required to
# save references to 6 objects.
0
)
# Write buffer is cleared after every dump().
def
test_unpickler
(
self
):
basesize
=
support
.
calcobjsize
(
'2Pn2P 2P2n2i5P 2P3n6P2n2i'
)
unpickler
=
_pickle
.
Unpickler
P
=
struct
.
calcsize
(
'P'
)
# Size of memo table entry.
n
=
struct
.
calcsize
(
'n'
)
# Size of mark table entry.
check
=
self
.
check_sizeof
for
encoding
in
'ASCII'
,
'UTF-16'
,
'latin-1'
:
for
errors
in
'strict'
,
'replace'
:
u
=
unpickler
(
io
.
BytesIO
(),
encoding
=
encoding
,
errors
=
errors
)
self
.
assertEqual
(
object
.
__sizeof__
(
u
),
basesize
)
check
(
u
,
basesize
+
32
*
P
+
# Minimal memo table size.
len
(
encoding
)
+
1
+
len
(
errors
)
+
1
)
stdsize
=
basesize
+
len
(
'ASCII'
)
+
1
+
len
(
'strict'
)
+
1
def
check_unpickler
(
data
,
memo_size
,
marks_size
):
dump
=
pickle
.
dumps
(
data
)
u
=
unpickler
(
io
.
BytesIO
(
dump
),
encoding
=
'ASCII'
,
errors
=
'strict'
)
u
.
load
()
check
(
u
,
stdsize
+
memo_size
*
P
+
marks_size
*
n
)
check_unpickler
(
0
,
32
,
0
)
# 20 is minimal non-empty mark stack size.
check_unpickler
([
0
]
*
100
,
32
,
20
)
# 128 is memo table size required to save references to 100 objects.
check_unpickler
([
chr
(
i
)
for
i
in
range
(
100
)],
128
,
20
)
def
recurse
(
deep
):
data
=
0
for
i
in
range
(
deep
):
data
=
[
data
,
data
]
return
data
check_unpickler
(
recurse
(
0
),
32
,
0
)
check_unpickler
(
recurse
(
1
),
32
,
20
)
check_unpickler
(
recurse
(
20
),
32
,
58
)
check_unpickler
(
recurse
(
50
),
64
,
58
)
check_unpickler
(
recurse
(
100
),
128
,
134
)
u
=
unpickler
(
io
.
BytesIO
(
pickle
.
dumps
(
'a'
,
0
)),
encoding
=
'ASCII'
,
errors
=
'strict'
)
u
.
load
()
check
(
u
,
stdsize
+
32
*
P
+
2
+
1
)
def
test_main
():
tests
=
[
PickleTests
,
PyPicklerTests
,
PyPersPicklerTests
,
...
...
@@ -148,7 +216,7 @@ def test_main():
PyPicklerUnpicklerObjectTests
,
CPicklerUnpicklerObjectTests
,
CDispatchTableTests
,
CChainDispatchTableTests
,
InMemoryPickleTests
])
InMemoryPickleTests
,
SizeofTests
])
support
.
run_unittest
(
*
tests
)
support
.
run_doctest
(
pickle
)
...
...
Misc/NEWS
View file @
4d9d9387
...
...
@@ -41,7 +41,9 @@ Core and Builtins
Library
-------
- Issue #19858: pickletools.optimize() now aware of the MEMOIZE opcode, can
- Issue #15513: Added a __sizeof__ implementation for pickle classes.
- Issue #19858: pickletools.optimize() now aware of the MEMOIZE opcode, can
produce more compact result and no longer produces invalid output if input
data contains MEMOIZE opcodes together with PUT or BINPUT opcodes.
...
...
Modules/_pickle.c
View file @
4d9d9387
...
...
@@ -375,7 +375,7 @@ static PyTypeObject Pdata_Type = {
PyVarObject_HEAD_INIT
(
NULL
,
0
)
"_pickle.Pdata"
,
/*tp_name*/
sizeof
(
Pdata
),
/*tp_basicsize*/
0
,
/*tp_itemsize*/
sizeof
(
PyObject
*
),
/*tp_itemsize*/
(
destructor
)
Pdata_dealloc
,
/*tp_dealloc*/
};
...
...
@@ -3930,9 +3930,37 @@ _pickle_Pickler_dump(PicklerObject *self, PyObject *obj)
Py_RETURN_NONE
;
}
/*[clinic input]
_pickle.Pickler.__sizeof__ -> Py_ssize_t
Returns size in memory, in bytes.
[clinic start generated code]*/
static
Py_ssize_t
_pickle_Pickler___sizeof___impl
(
PicklerObject
*
self
)
/*[clinic end generated code: output=106edb3123f332e1 input=8cbbec9bd5540d42]*/
{
Py_ssize_t
res
,
s
;
res
=
sizeof
(
PicklerObject
);
if
(
self
->
memo
!=
NULL
)
{
res
+=
sizeof
(
PyMemoTable
);
res
+=
self
->
memo
->
mt_allocated
*
sizeof
(
PyMemoEntry
);
}
if
(
self
->
output_buffer
!=
NULL
)
{
s
=
_PySys_GetSizeOf
(
self
->
output_buffer
);
if
(
s
==
-
1
)
return
-
1
;
res
+=
s
;
}
return
res
;
}
static
struct
PyMethodDef
Pickler_methods
[]
=
{
_PICKLE_PICKLER_DUMP_METHODDEF
_PICKLE_PICKLER_CLEAR_MEMO_METHODDEF
_PICKLE_PICKLER___SIZEOF___METHODDEF
{
NULL
,
NULL
}
/* sentinel */
};
...
...
@@ -6289,9 +6317,37 @@ _pickle_Unpickler_find_class_impl(UnpicklerObject *self, PyObject *module_name,
return
global
;
}
/*[clinic input]
_pickle.Unpickler.__sizeof__ -> Py_ssize_t
Returns size in memory, in bytes.
[clinic start generated code]*/
static
Py_ssize_t
_pickle_Unpickler___sizeof___impl
(
UnpicklerObject
*
self
)
/*[clinic end generated code: output=119d9d03ad4c7651 input=13333471fdeedf5e]*/
{
Py_ssize_t
res
;
res
=
sizeof
(
UnpicklerObject
);
if
(
self
->
memo
!=
NULL
)
res
+=
self
->
memo_size
*
sizeof
(
PyObject
*
);
if
(
self
->
marks
!=
NULL
)
res
+=
self
->
marks_size
*
sizeof
(
Py_ssize_t
);
if
(
self
->
input_line
!=
NULL
)
res
+=
strlen
(
self
->
input_line
)
+
1
;
if
(
self
->
encoding
!=
NULL
)
res
+=
strlen
(
self
->
encoding
)
+
1
;
if
(
self
->
errors
!=
NULL
)
res
+=
strlen
(
self
->
errors
)
+
1
;
return
res
;
}
static
struct
PyMethodDef
Unpickler_methods
[]
=
{
_PICKLE_UNPICKLER_LOAD_METHODDEF
_PICKLE_UNPICKLER_FIND_CLASS_METHODDEF
_PICKLE_UNPICKLER___SIZEOF___METHODDEF
{
NULL
,
NULL
}
/* sentinel */
};
...
...
Modules/clinic/_pickle.c.h
View file @
4d9d9387
...
...
@@ -34,6 +34,33 @@ PyDoc_STRVAR(_pickle_Pickler_dump__doc__,
#define _PICKLE_PICKLER_DUMP_METHODDEF \
{"dump", (PyCFunction)_pickle_Pickler_dump, METH_O, _pickle_Pickler_dump__doc__},
PyDoc_STRVAR
(
_pickle_Pickler___sizeof____doc__
,
"__sizeof__($self, /)
\n
"
"--
\n
"
"
\n
"
"Returns size in memory, in bytes."
);
#define _PICKLE_PICKLER___SIZEOF___METHODDEF \
{"__sizeof__", (PyCFunction)_pickle_Pickler___sizeof__, METH_NOARGS, _pickle_Pickler___sizeof____doc__},
static
Py_ssize_t
_pickle_Pickler___sizeof___impl
(
PicklerObject
*
self
);
static
PyObject
*
_pickle_Pickler___sizeof__
(
PicklerObject
*
self
,
PyObject
*
Py_UNUSED
(
ignored
))
{
PyObject
*
return_value
=
NULL
;
Py_ssize_t
_return_value
;
_return_value
=
_pickle_Pickler___sizeof___impl
(
self
);
if
((
_return_value
==
-
1
)
&&
PyErr_Occurred
())
goto
exit
;
return_value
=
PyLong_FromSsize_t
(
_return_value
);
exit:
return
return_value
;
}
PyDoc_STRVAR
(
_pickle_Pickler___init____doc__
,
"Pickler(file, protocol=None, fix_imports=True)
\n
"
"--
\n
"
...
...
@@ -191,6 +218,33 @@ exit:
return
return_value
;
}
PyDoc_STRVAR
(
_pickle_Unpickler___sizeof____doc__
,
"__sizeof__($self, /)
\n
"
"--
\n
"
"
\n
"
"Returns size in memory, in bytes."
);
#define _PICKLE_UNPICKLER___SIZEOF___METHODDEF \
{"__sizeof__", (PyCFunction)_pickle_Unpickler___sizeof__, METH_NOARGS, _pickle_Unpickler___sizeof____doc__},
static
Py_ssize_t
_pickle_Unpickler___sizeof___impl
(
UnpicklerObject
*
self
);
static
PyObject
*
_pickle_Unpickler___sizeof__
(
UnpicklerObject
*
self
,
PyObject
*
Py_UNUSED
(
ignored
))
{
PyObject
*
return_value
=
NULL
;
Py_ssize_t
_return_value
;
_return_value
=
_pickle_Unpickler___sizeof___impl
(
self
);
if
((
_return_value
==
-
1
)
&&
PyErr_Occurred
())
goto
exit
;
return_value
=
PyLong_FromSsize_t
(
_return_value
);
exit:
return
return_value
;
}
PyDoc_STRVAR
(
_pickle_Unpickler___init____doc__
,
"Unpickler(file, *, fix_imports=True, encoding=
\'
ASCII
\'
, errors=
\'
strict
\'
)
\n
"
"--
\n
"
...
...
@@ -488,4 +542,4 @@ _pickle_loads(PyModuleDef *module, PyObject *args, PyObject *kwargs)
exit:
return
return_value
;
}
/*[clinic end generated code: output=
f965b6c7018c898d
input=a9049054013a1b77]*/
/*[clinic end generated code: output=
3aba79576e240c62
input=a9049054013a1b77]*/
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment