[PyCall] append!() returns PyError (:PyList_Append) bad argument to internal function error

pycall

#1

I am trying to port in Julia the above python code:

from ezodf import newdoc, Sheet

ods = newdoc(doctype='ods', filename='spreadsheet.ods')
sheet = Sheet('SHEET', size=(10, 10))
ods.sheets += sheet
sheet['A1'].set_value("1.5")
ods.save()

The problem is with the += (python extend) part:

using PyCall
@pyimport ezodf
filename="testspreadsheet.ods"
destDoc = ezodf.newdoc(doctype="ods", filename=filename)
sheet = ezodf.Sheet("SHEET", size=(10, 10))
append!(destDoc[:sheets],sheet)
# a = PyVector(destDoc[:sheets])
# append!(a,sheet) # same error
PyError (:PyList_Append) <type 'exceptions.SystemError'>
SystemError('../Objects/listobject.c:290: bad argument to internal function',)

 in pyerr_check at exception.jl:56 [inlined]
 in pyerr_check at exception.jl:61 [inlined]
 in macro expansion at exception.jl:81 [inlined]
 in push!(::PyCall.PyObject, ::PyCall.PyObject) at PyCall.jl:657
 in append!(::PyCall.PyObject, ::PyCall.PyObject) at PyCall.jl:679
 in include_string(::String, ::String) at loading.jl:441
 in include_string(::String, ::String, ::Int64) at eval.jl:28
 in include_string(::Module, ::String, ::String, ::Int64, ::Vararg{Int64,N}) at eval.jl:32
 in (::Atom.##53#56{String,Int64,String})() at eval.jl:50
 in withpath(::Atom.##53#56{String,Int64,String}, ::String) at utils.jl:30
 in withpath(::Function, ::String) at eval.jl:38
 in macro expansion at eval.jl:49 [inlined]
 in (::Atom.##52#55{Dict{String,Any}})() at task.jl:60

Any hint ? Thank you…
(I di try with push!) and converting all to PyVector() but the error remains the same)


#2

This looks like a bug in append!(a::PyObject, b::PyObject). I’ll try to push a fix soon.


#3

The issue is that the PyCall append! function only works for Python list objects, which is not what you have here. As a fallback, I guess it should call the __iadd__ method, since that is what += really does in Python.

As a workaround, you can call destDoc[:sheets][:__iadd__](sheet).


#4

I’m not sure it is safe for me to define append! to call __iadd__ in general, since += in Python is not necessarily appending to a list.

However, I could define the a .+= b operator on a PyObject to call __iadd__ in Julia 0.6, which would have the added benefit of closely resembling the Python syntax.


#5

Ah, there is a PySequence_InPlaceConcat API function that I should be using here, instead of the PyList API, which should work for any object implementing the sequence protocol.


#6

Thank you… I confirm that calling directly iadd works:

using PyCall
@pyimport ezodf
filename="testspreadsheet.ods"
destDoc = ezodf.newdoc(doctype="ods", filename=filename)
sheet = ezodf.Sheet("SHEET", size=(10, 10))
destDoc[:sheets][:__iadd__](sheet)
sheet[1,1][:set_value](1.5)
destDoc[:save]()