Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
68458bc
add patch from https://bugs.python.org/issue28607
eendebakpt Apr 16, 2022
f5ad0c3
add patch from https://bugs.python.org/issue28607
eendebakpt Apr 16, 2022
fefb5ac
fix clinic; add _copy to build
eendebakpt Apr 16, 2022
47824bd
refactor deepcopy c code
eendebakpt Jun 15, 2022
3d56fd3
validated tests
eendebakpt Jun 15, 2022
5507364
refactor code
eendebakpt Jun 15, 2022
a8f1792
Apply suggestions from code review
eendebakpt Jun 16, 2022
20e27ee
review comments
eendebakpt Jun 16, 2022
94b55cf
Merge branch 'deepcopy_c_implementation' of github.com:eendebakpt/cpy…
eendebakpt Jun 16, 2022
9a85e4a
address review comments
eendebakpt Jun 16, 2022
be33d78
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Jul 4, 2022
28f2467
fix regen
eendebakpt Jul 4, 2022
b72365a
use vectorcall for python callback
eendebakpt Jul 4, 2022
2548d12
fix windows build
eendebakpt Jul 4, 2022
65f4ea4
address review comments
eendebakpt Jul 4, 2022
73b1300
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Jul 16, 2022
5045ee2
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Aug 11, 2022
c9a21f0
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Aug 22, 2022
e21517c
fix AC
eendebakpt Aug 24, 2022
0e800fb
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Aug 24, 2022
032c915
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Sep 11, 2022
d9e94d9
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Sep 26, 2022
1a9dd78
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Oct 19, 2022
51a1aa8
remove setup.py
eendebakpt Oct 30, 2022
6b5216b
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Oct 30, 2022
f6cf26d
regen
eendebakpt Oct 31, 2022
bc3efa0
Merge branch 'deepcopy_c_implementation' of githubeendebakpt:eendebak…
eendebakpt Oct 31, 2022
b7d2d45
use Py_newRef
eendebakpt Nov 10, 2022
7cf1ea0
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Nov 10, 2022
9cf6181
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Dec 20, 2022
08be03a
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Jan 5, 2023
4e9a202
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Jan 6, 2023
b50e6e5
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Jan 18, 2023
132e2f3
wip
eendebakpt Feb 7, 2023
0e09898
Revert "wip"
eendebakpt Feb 7, 2023
8fa73a9
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Feb 7, 2023
c7545d2
pep7 - part1
eendebakpt Feb 8, 2023
93480be
pep7 - part 2
eendebakpt Feb 8, 2023
0f945d1
ac
eendebakpt Feb 8, 2023
1fcb19d
pep7
eendebakpt Feb 8, 2023
424df01
pep7
eendebakpt Feb 8, 2023
c556530
ac
eendebakpt Feb 8, 2023
808bc5d
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Feb 8, 2023
9275ea3
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Feb 20, 2023
2c1ddb4
pep7
eendebakpt Feb 28, 2023
a736d2e
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Feb 28, 2023
33eec1c
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Mar 18, 2023
75375cd
make global C variables fully const
eendebakpt Mar 19, 2023
4071339
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Jun 11, 2023
5915ead
fix merge issues
eendebakpt Jun 12, 2023
0228f64
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Jun 12, 2023
066afe2
fix merge issues
eendebakpt Jun 12, 2023
d622575
Merge branch 'deepcopy_c_implementation' of githubeendebakpt:eendebak…
eendebakpt Jun 12, 2023
c38e150
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Jun 28, 2023
1e43e5d
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Aug 2, 2023
d074603
update for changed c api
eendebakpt Aug 2, 2023
22e7610
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Sep 10, 2023
0e8f043
include pycore_dict.h header
eendebakpt Sep 12, 2023
83c2fdb
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Sep 12, 2023
b76a43c
fix _PyDict_NewPresized
eendebakpt Sep 12, 2023
ce5f28a
fix _PyDict_NewPresized
eendebakpt Sep 12, 2023
f155330
fix _PyDict_NewPresized
eendebakpt Sep 12, 2023
2be1c3b
align PR with addition of copy.replace
eendebakpt Sep 12, 2023
61ad279
pylint
eendebakpt Sep 12, 2023
74098d7
make _PyDict_NewPresized available in shared extensions
eendebakpt Sep 13, 2023
62b7c76
make regen-all
eendebakpt Sep 13, 2023
fb5e27a
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Oct 4, 2023
8f6aad7
resolve merge changes
eendebakpt Oct 4, 2023
ce8bed7
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Oct 16, 2023
93c2d57
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Nov 16, 2023
e6379d0
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Dec 14, 2023
0971be5
update argument clinic
eendebakpt Dec 14, 2023
6d13239
resolve merge conflicts
eendebakpt Dec 14, 2023
35cdca5
Merge branch 'main' into deepcopy_c_implementation
erlend-aasland Apr 4, 2024
6097604
Merge branch 'main' into deepcopy_c_implementation
Jun 9, 2024
fde2b83
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Jun 9, 2024
9bef684
Merge branch 'main' into deepcopy_c_implementation
eendebakpt Aug 29, 2024
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
Prev Previous commit
Next Next commit
wip
  • Loading branch information
eendebakpt committed Feb 7, 2023
commit 132e2f3416c7de83d7fc186f949792e7abdba520
7 changes: 4 additions & 3 deletions Lib/copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,11 @@ class Error(Exception):

__all__ = ["Error", "copy", "deepcopy"]

def copy(x):
def _copy_fallback(x):
"""Shallow copy operation on arbitrary Python objects.

See the module's __doc__ string for more info.
"""

cls = type(x)

copier = _copy_dispatch.get(cls)
Expand Down Expand Up @@ -169,11 +168,13 @@ def _deepcopy_fallback(x, memo=None, _nil=[]):
return y

try:
from _copy import deepcopy
from _copy import deepcopy, copy
except ImportError:
# the fallback is for projects like PyPy that reuse the stdlib
deepcopy = _deepcopy_fallback
Comment thread
eendebakpt marked this conversation as resolved.
Outdated
deepcopy.__name__ = 'deepcopy'
copy = _copy_fallback
copy.__name__ = 'copy'

_deepcopy_dispatch = d = {}

Expand Down
213 changes: 212 additions & 1 deletion Modules/_copy.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Python.h"
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "clinic/_copy.c.h"
#include "listobject.h"

/*[clinic input]
module _copy
Expand All @@ -15,7 +16,11 @@ module _copy

typedef struct {
PyObject *python_copy_module;
PyObject *str_private_reconstruct;
PyObject *str_deepcopy_fallback;
PyObject *str_copy_fallback;
PyObject *copy_dispatch;
PyObject *copyreg_dispatch_table;
} copy_module_state;

static inline copy_module_state*
Expand Down Expand Up @@ -66,6 +71,15 @@ do_deepcopy_fallback(PyObject* module, PyObject* x, PyObject* memo)
return PyObject_VectorcallMethod(state->str_deepcopy_fallback, args, 3, NULL);
}

static PyObject*
do_copy_fallback(PyObject* module, PyObject* x)
{
copy_module_state *state = get_copy_module_state(module);
PyObject *args[] = {state->python_copy_module, x};

return PyObject_VectorcallMethod(state->str_copy_fallback, args, 2, NULL);
}

static PyObject*
deepcopy_list(PyObject* module, PyObject* x, PyObject* memo, PyObject* id_x, Py_hash_t hash_id_x)
{
Expand Down Expand Up @@ -389,8 +403,190 @@ _copy_deepcopy_impl(PyObject *module, PyObject *x, PyObject *memo)
return result;
}

PyObject *_create_copy_dispatch()
{
PyObject *d = PyDict_New();

// special cases: copy will return a reference
PyDict_SetItem(d, (PyObject *)(&_PyNone_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyLong_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyFloat_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyBool_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyComplex_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyUnicode_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyTuple_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyBytes_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyFrozenSet_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyType_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyRange_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PySlice_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyProperty_Type), (PyObject *)Py_True);
//PyDict_SetItem(d, (PyObject *)(&BuiltinFunctionType), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&PyEllipsis_Type), (PyObject *)Py_True);
PyDict_SetItem(d, (PyObject *)(&_PyNotImplemented_Type), (PyObject *)Py_True);
//PyDict_SetItem(d, (PyObject *)(&_FunctionType_Type), (PyObject *)Py_True);
//PyDict_SetItem(d, (PyObject *)(&types.CodeType), (PyObject *)Py_True);
//PyDict_SetItem(d, (PyObject *)(&weakref.ref), (PyObject *)Py_True);

PyObject * list_copy=PyObject_GetAttrString((PyObject *)(&PyList_Type), "copy");
PyDict_SetItem(d, (PyObject *)(&PyList_Type), (PyObject *)list_copy);
PyObject * dict_copy=PyObject_GetAttrString((PyObject *)(&PyDict_Type), "copy");
PyDict_SetItem(d, (PyObject *)(&PyDict_Type), (PyObject *)dict_copy);
PyObject * set_copy=PyObject_GetAttrString((PyObject *)(&PySet_Type), "copy");
PyDict_SetItem(d, (PyObject *)(&PySet_Type), (PyObject *)set_copy);
PyObject * bytearray_copy=PyObject_GetAttrString((PyObject *)(&PyByteArray_Type), "copy");
PyDict_SetItem(d, (PyObject *)(&PySet_Type), (PyObject *)bytearray_copy);

return d;
}

static void print_str(PyObject *o)
{
PyObject_Print(o, stdout, Py_PRINT_RAW);
}


static PyObject *
_copy_copy_impl(PyObject *module, PyObject *arg)
{
PyTypeObject *cls = Py_TYPE(arg);
copy_module_state *state = get_copy_module_state(module);

PyObject *dispatcher = PyDict_GetItem(state->copy_dispatch, (PyObject *)cls); // do we need a reference here, or can we borrow?
if (dispatcher==Py_True) {
// immutable argument
Py_DECREF(dispatcher);
return Py_NewRef(arg);
}
else if (dispatcher!=0) {
// we have a dispatcher
PyObject *c = PyObject_CallOneArg(dispatcher, arg);
Py_DECREF(dispatcher);
return c;
}
//Py_DECREF(dispatcher);

if (PyObject_IsSubclass((PyObject*)cls, (PyObject*)&PyType_Type)) {
// treat it as a regular class
return Py_NewRef(arg);
}

{
PyObject * xx= PyUnicode_InternFromString("__reduce__");
//reductor = PyObject_GenericGetAttr(arg, xx); // could we use the PyObject_GetAttr here?
PyObject *reductor = PyObject_GetAttr(arg, xx);
PyObject * ex= PyUnicode_InternFromString("__reduce_ex__");
//reductor = PyObject_GenericGetAttr(arg, xx); // could we use the PyObject_GetAttr here?
PyObject *reductor_ex = PyObject_GetAttr(arg, ex);
printf(" __reduce__: %ld %ld\n", (long)reductor, (long)(reductor_ex) );
//Py_XDECREF(reductor);
}

//return do_copy_fallback(module, arg);
PyObject * copier=PyObject_GetAttrString((PyObject *)cls, "__copy__");
if (copier!=0) {
PyObject *c = PyObject_CallOneArg(copier, arg);
Py_DECREF(copier);
return c;
}
//return do_copy_fallback(module, arg);



printf("going to reductors\n");
PyObject *rv=0;
PyObject *reductor = PyDict_GetItem(state->copyreg_dispatch_table, (PyObject *)cls); // borrowed reference
{
PyObject * xx= PyUnicode_InternFromString("__reduce__");
//reductor = PyObject_GenericGetAttr(arg, xx); // could we use the PyObject_GetAttr here?
PyObject *reductor = PyObject_GetAttr(arg, xx);
//printf(" __reduce__: %ld\n", (long)reductor);
//Py_XDECREF(reductor);
}
if (reductor!=0) {
Py_INCREF(reductor); // not sure we need this, but to be safe
rv = _PyObject_CallOneArg(reductor, arg);
Py_DECREF(reductor);
printf("rv from copyreg dispatch table\n");
} else {

PyObject * reduce_ex_str= PyUnicode_InternFromString("__reduce_ex__");
reductor = PyObject_GetAttr(arg, reduce_ex_str);
printf(" reductor from reduce_ex: %ld\n", (long)reductor);
//return do_copy_fallback(module, arg);
printf("huh\n");
if (reductor!=0) {
printf("rv from reduce_ex_str\n");
PyObject * four = (PyLong_FromUnsignedLong(4));
//rv = PyObject_Vectorcall(reductor, &(four), 1, 0);
rv = PyObject_CallMethodOneArg(arg, reduce_ex_str, four);
printf("rv from reduce_ex_str\n");
Py_DECREF(reductor);
}
else {
// fallback
Py_XDECREF(reductor);

PyObject * xx= PyUnicode_InternFromString("__reduce__");
//reductor = PyObject_GenericGetAttr(arg, xx); // could we use the PyObject_GetAttr here?
reductor = PyObject_GetAttr(arg, xx);
//Py_XDECREF(reductor);
printf("fb! %ld\n", (long)reductor);
reductor = PyObject_GetAttr(arg, xx);
printf("fb! %ld\n", (long)reductor);
return do_copy_fallback(module, arg);

if (reductor!=0) {
rv = PyObject_CallNoArgs(reductor);
Py_DECREF(reductor);
printf("rv from __reduce__ : %ld\n", (long)rv);
}
else {
printf("bad path: ");
print_str(arg);
printf("\n");
print_str(cls);
printf("\n");

PyErr_SetString(PyExc_TypeError, "un(shallow)copyable object of type %s"); // TODO: include cls in string
return 0;
}
}
printf("okay\n");
}
// fallback
printf("fb!\n");
return do_copy_fallback(module, arg);

if (PyObject_IsInstance(rv, (PyObject *)(&PyUnicode_Type)) ) {
Py_DECREF(rv);
return Py_NewRef(arg);
}

// rv is now a tuple-like object
PyObject *rv_tuple = PySequence_Tuple(rv); // be safe, make if really a tuple. perhaps some __reduce__ methods return tuple subclass or lists
Py_DECREF(rv);
assert(PyTuple_Size(rv_tuple)== 2);

PyObject *args[] = {state->python_copy_module, arg, Py_None, PyTuple_GET_ITEM(rv_tuple, 0), PyTuple_GET_ITEM(rv_tuple, 1)};
printf("last reduce: _reconstruct\n");
PyObject *c = PyObject_VectorcallMethod(state->str_private_reconstruct, args, 5, NULL);
Py_DECREF(rv_tuple);
return c;
// return _reconstruct(x, None, *rv)

// fallback
printf("fb!\n");
return do_copy_fallback(module, arg);



return arg;
}

static PyMethodDef copy_functions[] = {
_COPY_DEEPCOPY_METHODDEF
_COPY_DEEPCOPY_METHODDEF,
_COPY_COPY_METHODDEF,
{NULL, NULL}
};

Expand All @@ -412,11 +608,26 @@ copy_free(void *module)
static int copy_module_exec(PyObject *module)
{
copy_module_state *state = get_copy_module_state(module);
state->str_private_reconstruct = PyUnicode_InternFromString("_reconstruct");
if (state->str_private_reconstruct == NULL) {
return -1;
}
state->str_deepcopy_fallback = PyUnicode_InternFromString("_deepcopy_fallback");
if (state->str_deepcopy_fallback == NULL) {
return -1;
}
state->str_copy_fallback = PyUnicode_InternFromString("_copy_fallback");
if (state->str_copy_fallback == NULL) {
return -1;
}

PyObject *copyregmodule = PyImport_ImportModule("copyreg");
if (copyregmodule == NULL) {
return -1;
}
state->copyreg_dispatch_table = (PyObject *)PyObject_GetAttrString(copyregmodule, "dispatch_table");
assert(PyDict_CheckExact(state->copyreg_dispatch_table));
state->copy_dispatch = _create_copy_dispatch();
PyObject *copymodule = PyImport_ImportModule("copy");
if (copymodule == NULL)
return -1;
Expand Down
22 changes: 21 additions & 1 deletion Modules/clinic/_copy.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.