Skip to content

adds julia.SetValue #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/cpython/CPython.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ include("juliaany.jl")
include("juliaiterator.jl")
include("juliatype.jl")
include("juliadict.jl")
include("juliaset.jl")
include("juliaarray.jl")
include("juliavector.jl")
include("juliamodule.jl")
Expand Down
43 changes: 43 additions & 0 deletions src/cpython/collections.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,49 @@ for n in [:Container, :Hashable, :Iterable, :Iterator, :Reversible, :Generator,
end
end

"""
PyIterable_Collect(xs::PyPtr, T::Type, [skip=false]) :: Vector{T}

Convert the elements of `xs` to type `T` and collect them into a vector.
On error, an empty vector is returned.

If `skip` then elements which cannot be converted to a `T` are skipped over,
instead of raising an error. Other errors are still propagated.
"""
PyIterable_Collect(xso::PyPtr, ::Type{T}, skip::Bool=false) where {T} = begin
xs = T[]
it = PyObject_GetIter(xso)
isnull(it) && return xs
try
while true
xo = PyIter_Next(it)
if !isnull(xo)
if skip
r = PyObject_TryConvert(xo, T)
Py_DecRef(xo)
r == -1 && (empty!(xs); break)
r == 0 && continue
else
r = PyObject_Convert(xo, T)
Py_DecRef(xo)
r == -1 && (empty!(xs); break)
end
x = takeresult(T)
push!(xs, x)
else
PyErr_IsSet() && empty!(xs)
break
end
end
catch err
empty!(xs)
PyErr_SetJuliaError(err)
finally
Py_DecRef(it)
end
return xs
end

PyIterable_ConvertRule_vector(o, ::Type{S}) where {S<:Vector} = begin
it = PyObject_GetIter(o)
isnull(it) && return -1
Expand Down
2 changes: 1 addition & 1 deletion src/cpython/complex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ PyComplexable_TryConvertRule_convert(o, ::Type{S}) where {S} = begin
end

PyComplexable_TryConvertRule_tryconvert(o, ::Type{S}) where {S} = begin
x = PyComplexable_AsComplex(o)
x = PyComplex_AsComplex(o)
ism1(x) && PyErr_IsSet() && return -1
putresult(tryconvert(S, x))
end
250 changes: 250 additions & 0 deletions src/cpython/juliaset.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
const PyJuliaSetValue_Type__ref = Ref(PyPtr())
PyJuliaSetValue_Type() = begin
ptr = PyJuliaSetValue_Type__ref[]
if isnull(ptr)
c = []
base = PyJuliaAnyValue_Type()
isnull(base) && return PyPtr()
t = fill(PyType_Create(c,
name = "julia.SetValue",
base = base,
methods = [
(name="add", flags=Py_METH_O, meth=pyjlset_add),
(name="clear", flags=Py_METH_NOARGS, meth=pyjlset_clear),
(name="copy", flags=Py_METH_NOARGS, meth=pyjlset_copy),
(name="difference", flags=Py_METH_O, meth=pyjlset_difference),
(name="difference_update", flags=Py_METH_O, meth=pyjlset_difference_update),
(name="discard", flags=Py_METH_O, meth=pyjlset_discard),
(name="intersection", flags=Py_METH_O, meth=pyjlset_intersection),
(name="intersection_update", flags=Py_METH_O, meth=pyjlset_intersection_update),
# (name="isdisjoint", flags=Py_METH_O, meth=pyjlset_isdisjoint),
# (name="issubset", flags=Py_METH_O, meth=pyjlset_issubset),
# (name="issuperset", flags=Py_METH_O, meth=pyjlset_issuperset),
(name="pop", flags=Py_METH_NOARGS, meth=pyjlset_pop),
(name="remove", flags=Py_METH_O, meth=pyjlset_remove),
(name="symmetric_difference", flags=Py_METH_O, meth=pyjlset_symmetric_difference),
(name="symmetric_difference_update", flags=Py_METH_O, meth=pyjlset_symmetric_difference_update),
(name="union", flags=Py_METH_O, meth=pyjlset_union),
(name="update", flags=Py_METH_O, meth=pyjlset_update),
],
as_number = (
or = pyjlset_or,
and = pyjlset_and,
xor = pyjlset_xor,
subtract = pyjlset_sub,
inplace_or = pyjlset_ior,
inplace_and = pyjlset_iand,
inplace_xor = pyjlset_ixor,
inplace_subtract = pyjlset_isub,
),
))
ptr = PyPtr(pointer(t))
err = PyType_Ready(ptr)
ism1(err) && return PyPtr()
abc = PyMutableSetABC_Type()
isnull(abc) && return PyPtr()
ism1(PyABC_Register(ptr, abc)) && return PyPtr()
PYJLGCCACHE[ptr] = push!(c, t)
PyJuliaSetValue_Type__ref[] = ptr
end
ptr
end

PyJuliaSetValue_New(x::AbstractSet) = PyJuliaValue_New(PyJuliaSetValue_Type(), x)
PyJuliaValue_From(x::AbstractSet) = PyJuliaSetValue_New(x)

pyjlset_add(xo::PyPtr, vo::PyPtr) = begin
x = PyJuliaValue_GetValue(xo)::AbstractSet
ism1(PyObject_Convert(vo, eltype(x))) && return PyPtr()
v = takeresult(eltype(x))
try
push!(x, v)
PyNone_New()
catch err
PyErr_SetJuliaError(err)
PyPtr()
end
end

pyjlset_discard(xo::PyPtr, vo::PyPtr) = begin
x = PyJuliaValue_GetValue(xo)::AbstractSet
r = PyObject_TryConvert(vo, eltype(x))
r == -1 && return PyPtr()
r == 0 && return PyNone_New()
v = takeresult(eltype(x))
try
delete!(x, v)
PyNone_New()
catch err
PyErr_SetJuliaError(err)
PyPtr()
end
end

pyjlset_clear(xo::PyPtr, _::PyPtr) = begin
x = PyJuliaValue_GetValue(xo)::AbstractSet
try
empty!(x)
PyNone_New()
catch err
PyErr_SetJuliaError(err)
PyPtr()
end
end

pyjlset_copy(xo::PyPtr, _::PyPtr) = begin
x = PyJuliaValue_GetValue(xo)::AbstractSet
try
PyObject_From(copy(x))
catch err
PyErr_SetJuliaError(err)
PyPtr()
end
end

pyjlset_pop(xo::PyPtr, _::PyPtr) = begin
x = PyJuliaValue_GetValue(xo)::AbstractSet
try
if isempty(x)
PyErr_SetString(PyExc_KeyError(), "pop from an empty set")
PyPtr()
else
PyObject_From(pop!(x))
end
catch err
PyErr_SetJuliaError(err)
PyPtr()
end
end

pyjlset_remove(xo::PyPtr, vo::PyPtr) = begin
x = PyJuliaValue_GetValue(xo)::AbstractSet
r = PyObject_TryConvert(vo, eltype(x))
if r == -1
return PyPtr()
elseif r == 0
PyErr_SetObject(PyExc_KeyError(), vo)
return PyPtr()
end
v = takeresult(eltype(x))
try
if v in x
delete!(x, v)
PyNone_New()
else
PyErr_SetObject(PyExc_KeyError(), vo)
PyPtr()
end
catch err
PyErr_SetJuliaError(err)
PyPtr()
end
end

pyjlset_ibinop_named(xo, yo, op, skip) = begin
x = PyJuliaValue_GetValue(xo)::AbstractSet
y = PyIterable_Collect(yo, eltype(x), skip)
isempty(y) && PyErr_IsSet() && return PyPtr()
try
op(x, y)
PyNone_New()
catch err
PyErr_SetJuliaError(err)
PyPtr()
end
end
pyjlset_update(xo, yo) = pyjlset_ibinop_named(xo, yo, union!, false)
pyjlset_difference_update(xo, yo) = pyjlset_ibinop_named(xo, yo, setdiff!, true)
pyjlset_symmetric_difference_update(xo, yo) = pyjlset_ibinop_named(xo, yo, symdiff!, false)
pyjlset_intersection_update(xo, yo) = pyjlset_ibinop_named(xo, yo, intersect!, true)

pyjlset_ibinop_operator(xo, yo, op, skip) = begin
r = PySetABC_Check(yo)
r == -1 && return PyPtr()
r == 0 && return PyNotImplemented_New()
x = PyJuliaValue_GetValue(xo)::AbstractSet
y = PyIterable_Collect(yo, eltype(x), skip)
isempty(y) && PyErr_IsSet() && return PyPtr()
try
PyObject_From(op(x, y))
catch err
PyErr_SetJuliaError(err)
PyPtr()
end
end
pyjlset_ior(xo, yo) = pyjlset_ibinop_operator(xo, yo, union!, false)
pyjlset_isub(xo, yo) = pyjlset_ibinop_operator(xo, yo, setdiff!, true)
pyjlset_ixor(xo, yo) = pyjlset_ibinop_operator(xo, yo, symdiff!, false)
pyjlset_iand(xo, yo) = pyjlset_ibinop_operator(xo, yo, intersect!, true)

pyjlset_binop_generic(xo::PyPtr, yo::PyPtr, op) = begin
xo2 = PySet_New(xo)
isnull(xo2) && return PyPtr()
yo2 = PySet_New(yo)
isnull(yo2) && (Py_DecRef(xo2); return PyPtr())
ro = op(xo2, yo2)
Py_DecRef(xo2)
Py_DecRef(yo2)
ro
end
pyjlset_or_generic(xo, yo) = pyjlset_binop_generic(xo, yo, PyNumber_InPlaceOr)
pyjlset_xor_generic(xo, yo) = pyjlset_binop_generic(xo, yo, PyNumber_InPlaceXor)
pyjlset_and_generic(xo, yo) = pyjlset_binop_generic(xo, yo, PyNumber_InPlaceAnd)
pyjlset_sub_generic(xo, yo) = pyjlset_binop_generic(xo, yo, PyNumber_InPlaceSubtract)

pyjlset_binop_special(xo::PyPtr, yo::PyPtr, op) = begin
x = PyJuliaValue_GetValue(xo)::AbstractSet
y = PyJuliaValue_GetValue(yo)::AbstractSet
try
PyObject_From(op(x, y))
catch err
PyErr_SetJuliaError(err)
PyPtr()
end
end
pyjlset_or_special(xo, yo) = pyjlset_binop_special(xo, yo, union)
pyjlset_xor_special(xo, yo) = pyjlset_binop_special(xo, yo, symdiff)
pyjlset_and_special(xo, yo) = pyjlset_binop_special(xo, yo, intersect)
pyjlset_sub_special(xo, yo) = pyjlset_binop_special(xo, yo, setdiff)

pyjlset_binop_operator(xo::PyPtr, yo::PyPtr, gop, sop) = begin
t = PyJuliaSetValue_Type()
isnull(t) && return PyPtr()
if (r=PyObject_IsInstance(xo, t); ism1(r) && return PyPtr(); r!=0)
if (r=PyObject_IsInstance(yo, t); ism1(r) && return PyPtr(); r!=0)
sop(xo, yo)
elseif (r=PySetABC_Check(yo); ism1(r) && return PyPtr(); r!=0)
gop(xo, yo)
else
PyNotImplemented_New()
end
elseif (r=PyObject_IsInstance(yo, t); ism1(r) && return PyPtr(); r!=0)
if (r=PySetABC_Check(xo); ism1(r) && return PyPtr(); r!=0)
gop(xo, yo)
else
PyNotImplemented_New()
end
else
PyNotImplemented_New()
end
end
pyjlset_or(xo, yo) = pyjlset_binop_operator(xo, yo, pyjlset_or_generic, pyjlset_or_special)
pyjlset_xor(xo, yo) = pyjlset_binop_operator(xo, yo, pyjlset_xor_generic, pyjlset_xor_special)
pyjlset_and(xo, yo) = pyjlset_binop_operator(xo, yo, pyjlset_and_generic, pyjlset_and_special)
pyjlset_sub(xo, yo) = pyjlset_binop_operator(xo, yo, pyjlset_sub_generic, pyjlset_sub_special)

pyjlset_binop_named(xo, yo, gop, sop) = begin
t = PyJuliaSetValue_Type()
isnull(t) && return PyPtr()
if (r=PyObject_IsInstance(yo, t); ism1(r) && return PyPtr(); r!=0)
sop(xo, yo)
elseif (r=PySetABC_Check(yo); ism1(r) && return PyPtr(); r!=0)
gop(xo, yo)
else
PyNotImplemented_New()
end
end
pyjlset_union(xo, yo) = pyjlset_binop_named(xo, yo, pyjlset_or_generic, pyjlset_or_special)
pyjlset_symmetric_difference(xo, yo) = pyjlset_binop_named(xo, yo, pyjlset_xor_generic, pyjlset_xor_special)
pyjlset_intersection(xo, yo) = pyjlset_binop_named(xo, yo, pyjlset_and_generic, pyjlset_and_special)
pyjlset_difference(xo, yo) = pyjlset_binop_named(xo, yo, pyjlset_sub_generic, pyjlset_sub_special)
48 changes: 47 additions & 1 deletion src/cpython/newtype.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,53 @@ end
### PROTOCOLS

PyNumberMethods_Create(c, x::PyNumberMethods) = x
PyNumberMethods_Create(c; opts...) = C.PyNumberMethods(; [k => (v isa Ptr ? v : v isa Base.CFunction ? cacheptr!(c, v) : error()) for (k,v) in pairs(opts)]...)
PyNumberMethods_Create(c;
add=C_NULL, subtract=C_NULL, multiply=C_NULL, remainder=C_NULL, divmod=C_NULL, power=C_NULL,
negative=C_NULL, positive=C_NULL, absolute=C_NULL, bool=C_NULL, invert=C_NULL,
lshift=C_NULL, rshift=C_NULL, and=C_NULL, or=C_NULL, xor=C_NULL, int=C_NULL, float=C_NULL,
inplace_add=C_NULL, inplace_subtract=C_NULL, inplace_multiply=C_NULL,
inplace_remainder=C_NULL, inplace_power=C_NULL, inplace_lshift=C_NULL, inplace_rshift=C_NULL,
inplace_and=C_NULL, inplace_xor=C_NULL, inplace_or=C_NULL, floordivide=C_NULL,
truedivide=C_NULL, inplace_floordivide=C_NULL, inplace_truedivide=C_NULL, index=C_NULL,
matrixmultiply=C_NULL, inplace_matrixmultiply=C_NULL
) =
PyNumberMethods(
add = @cachefuncptr!(c, add, PyPtr, (PyPtr, PyPtr)),
subtract = @cachefuncptr!(c, subtract, PyPtr, (PyPtr, PyPtr)),
multiply = @cachefuncptr!(c, multiply, PyPtr, (PyPtr, PyPtr)),
remainder = @cachefuncptr!(c, remainder, PyPtr, (PyPtr, PyPtr)),
divmod = @cachefuncptr!(c, divmod, PyPtr, (PyPtr, PyPtr)),
power = @cachefuncptr!(c, power, PyPtr, (PyPtr, PyPtr, PyPtr)),
negative = @cachefuncptr!(c, negative, PyPtr, (PyPtr,)),
positive = @cachefuncptr!(c, positive, PyPtr, (PyPtr,)),
absolute = @cachefuncptr!(c, absolute, PyPtr, (PyPtr,)),
bool = @cachefuncptr!(c, bool, Cint, (PyPtr,)),
invert = @cachefuncptr!(c, invert, PyPtr, (PyPtr,)),
lshift = @cachefuncptr!(c, lshift, PyPtr, (PyPtr, PyPtr)),
rshift = @cachefuncptr!(c, rshift, PyPtr, (PyPtr, PyPtr)),
and = @cachefuncptr!(c, and, PyPtr, (PyPtr, PyPtr)),
xor = @cachefuncptr!(c, xor, PyPtr, (PyPtr, PyPtr)),
or = @cachefuncptr!(c, or, PyPtr, (PyPtr, PyPtr)),
int = @cachefuncptr!(c, int, PyPtr, (PyPtr,)),
float = @cachefuncptr!(c, float, PyPtr, (PyPtr,)),
inplace_add = @cachefuncptr!(c, inplace_add, PyPtr, (PyPtr, PyPtr)),
inplace_subtract = @cachefuncptr!(c, inplace_subtract, PyPtr, (PyPtr, PyPtr)),
inplace_multiply = @cachefuncptr!(c, inplace_multiply, PyPtr, (PyPtr, PyPtr)),
inplace_remainder = @cachefuncptr!(c, inplace_remainder, PyPtr, (PyPtr, PyPtr)),
inplace_power = @cachefuncptr!(c, inplace_power, PyPtr, (PyPtr, PyPtr, PyPtr)),
inplace_lshift = @cachefuncptr!(c, inplace_lshift, PyPtr, (PyPtr, PyPtr)),
inplace_rshift = @cachefuncptr!(c, inplace_rshift, PyPtr, (PyPtr, PyPtr)),
inplace_and = @cachefuncptr!(c, inplace_and, PyPtr, (PyPtr, PyPtr)),
inplace_xor = @cachefuncptr!(c, inplace_xor, PyPtr, (PyPtr, PyPtr)),
inplace_or = @cachefuncptr!(c, inplace_or, PyPtr, (PyPtr, PyPtr)),
floordivide = @cachefuncptr!(c, floordivide, PyPtr, (PyPtr, PyPtr)),
truedivide = @cachefuncptr!(c, truedivide, PyPtr, (PyPtr, PyPtr)),
inplace_floordivide = @cachefuncptr!(c, inplace_floordivide, PyPtr, (PyPtr, PyPtr)),
inplace_truedivide = @cachefuncptr!(c, inplace_truedivide, PyPtr, (PyPtr, PyPtr)),
index = @cachefuncptr!(c, index, PyPtr, (PyPtr,)),
matrixmultiply = @cachefuncptr!(c, matrixmultiply, PyPtr, (PyPtr, PyPtr)),
inplace_matrixmultiply = @cachefuncptr!(c, inplace_matrixmultiply, PyPtr, (PyPtr, PyPtr)),
)
PyNumberMethods_Create(c, x::Dict) = PyNumberMethods_Create(c; x...)
PyNumberMethods_Create(c, x::NamedTuple) = PyNumberMethods_Create(c; x...)

Expand Down
5 changes: 3 additions & 2 deletions src/cpython/object.jl
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ PyObject_TryConvert_CompileRule(::Type{T}, t::PyPtr) where {T} = begin
end
if xb != PyPtr()
push!(basetypes, xt)
push!(basemros, [xb; PyType_MROAsVector(xt)])
xmro = PyType_MROAsVector(xt)
push!(basemros, xb in xmro ? xmro : [xb; xmro])
end
end
for b in basetypes[2:end]
Expand All @@ -176,7 +177,7 @@ PyObject_TryConvert_CompileRule(::Type{T}, t::PyPtr) where {T} = begin
break
end
end
ok || error("Fatal inheritence error: could not merge MROs")
ok || error("Fatal inheritence error: could not merge MROs (alltypes=$alltypes, basemros=$basemros)")
# add it to the list
push!(alltypes, b)
# remove it from consideration
Expand Down