diff --git a/Project.toml b/Project.toml index f2462d16..133a026d 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PyCall" uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" authors = ["Steven G. Johnson ", "Yichao Yu ", "Takafumi Arakaki ", "Simon Kornblith ", "Páll Haraldsson ", "Jon Malmaud ", "Jake Bolewski ", "Keno Fischer ", "Joel Mason ", "Jameson Nash ", "The JuliaPy development team"] -version = "1.95.2" +version = "1.96.0" [deps] Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d" diff --git a/src/PyCall.jl b/src/PyCall.jl index 0c155fef..182abb13 100644 --- a/src/PyCall.jl +++ b/src/PyCall.jl @@ -979,6 +979,16 @@ include("serialize.jl") include("pyinit.jl") +const _deepcopy = PyNULL() + +function Base.deepcopy_internal(obj::PyObject, stackdict::Base.IdDict) + haskey(stackdict, obj) && return stackdict[obj] + ispynull(_deepcopy) && copy!(_deepcopy, pyimport("copy")["deepcopy"]) + ret = pycall(_deepcopy, PyObject, obj) + stackdict[obj] = ret + ret +end + ######################################################################### include("precompile.jl") diff --git a/test/runtests.jl b/test/runtests.jl index 2e5c915a..b718ee23 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -620,6 +620,45 @@ const PyInt = pyversion < v"3" ? Int : Clonglong @test_throws ArgumentError float(pybuiltin("type")) end +@testset "deepcopy #757" begin + l = py"[1,2,3]"o + l2 = deepcopy(l) + @test l == l2 + l2.append(4) + @test l != l2 + @test collect(l2) == [1,2,3,4] + @test collect(l) == [1,2,3] + + obj = py""" + class C757: + def __init__(self, a, b): + self.a = a + self.b = b + """ + obj = py"C757(C757(1,2), C757(3,4))"o + obj2 = deepcopy(obj) + @test PyPtr(obj) != PyPtr(obj2) # make sure a new Python object is created + @test obj.a.a == obj2.a.a + @test obj.a.b == obj2.a.b + @test obj.b.a == obj2.b.a + @test obj.b.b == obj2.b.b + obj.a = 3 + @test obj.a == 3 + @test obj2.a.a == 1 + @test obj2.a.b == 2 + + struct S;a;b;end + + c = py"C757(1,2)" + obj = S(c, c) + obj2 = deepcopy(obj) + @test obj.a === obj.b + @test obj2.a === obj2.b + obj.a.a = 4 + @test obj.a.a == 4 + @test obj2.a.a == 1 +end + ###################################################################### #@pydef tests: type declarations need to happen at top level @@ -855,3 +894,4 @@ end @test_throws PyCall.PyError a.a = 0 @test_throws KeyError a.a = 1 end +