diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 100644 index 00000000..d35240c3 --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1,8 @@ +ignore = [ + "examples", + ".git", + ".CondaPkg", + ".ipynb_checkpoints", + ".pytest_cache", + ".venv", +] diff --git a/bump.jl b/bump.jl index 553550c5..f02f6913 100644 --- a/bump.jl +++ b/bump.jl @@ -9,7 +9,7 @@ function bump(file, oldpat, newpat) oldtext = read(file, String) newtext = replace(oldtext, oldpat => newpat) @assert newtext != oldtext - write(file, newtext) + write(file, newtext) end function bumpver(file, pattern, oldver, newver) diff --git a/docs/customdocs.jl b/docs/customdocs.jl index 8b02ea6f..fd3bc9d4 100644 --- a/docs/customdocs.jl +++ b/docs/customdocs.jl @@ -53,8 +53,8 @@ function runner(::Type{CustomDocExpander}, node, page, doc) Dict{Symbol,Any}( # NOTE: Not sure about what to put here. :module => Main, # This is supposed to be tracking python code. :path => "", - :linenumber => 0 - ) + :linenumber => 0, + ), )::Docs.DocStr # NOTE: This was modified because the original Documenter.create_docsnode was generating unreachable links @@ -80,12 +80,10 @@ function _parse_docs(code::AbstractString) m = match(r"^(.+?)\s*-\s*(.+?)\s*(\n[\s\S]*)$", strip(code)) if isnothing(m) - error( - """ - Invalid docstring: - $(code) - """ - ) + error(""" + Invalid docstring: + $(code) + """) end name = Symbol(m[1]) @@ -134,4 +132,4 @@ function _create_docsnode(docstring, result, object, page, doc) return MarkdownAST.Node(docsnode) end -end # module CustomDocs \ No newline at end of file +end # module CustomDocs diff --git a/docs/make.jl b/docs/make.jl index 9b6c07a3..605d204d 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -5,20 +5,14 @@ include("customdocs.jl") makedocs( sitename = "PythonCall & JuliaCall", modules = [PythonCall], - format = Documenter.HTML( - assets = ["assets/favicon.ico"], - ), + format = Documenter.HTML(assets = ["assets/favicon.ico"]), warnonly = [:missing_docs], # avoid raising error when docs are missing pages = [ "Home" => "index.md", - "The Julia module PythonCall" => [ - "Guide" => "pythoncall.md", - "Reference" => "pythoncall-reference.md", - ], - "The Python module JuliaCall" => [ - "Guide" => "juliacall.md", - "Reference" => "juliacall-reference.md", - ], + "The Julia module PythonCall" => + ["Guide" => "pythoncall.md", "Reference" => "pythoncall-reference.md"], + "The Python module JuliaCall" => + ["Guide" => "juliacall.md", "Reference" => "juliacall-reference.md"], "Conversion" => [ "Julia to Python" => "conversion-to-python.md", "Python to Julia" => "conversion-to-julia.md", @@ -27,10 +21,7 @@ makedocs( "faq.md", "pycall.md", "releasenotes.md", - ] + ], ) -deploydocs( - repo = raw"github.com/JuliaPy/PythonCall.jl.git", - push_preview = true -) +deploydocs(repo = raw"github.com/JuliaPy/PythonCall.jl.git", push_preview = true) diff --git a/src/C/C.jl b/src/C/C.jl index 4ceda829..64207763 100644 --- a/src/C/C.jl +++ b/src/C/C.jl @@ -10,7 +10,8 @@ using UnsafePointers: UnsafePtr using CondaPkg: CondaPkg using Pkg: Pkg using Requires: @require -using Libdl: dlpath, dlopen, dlopen_e, dlclose, dlsym, dlsym_e, RTLD_LAZY, RTLD_DEEPBIND, RTLD_GLOBAL +using Libdl: + dlpath, dlopen, dlopen_e, dlclose, dlsym, dlsym_e, RTLD_LAZY, RTLD_DEEPBIND, RTLD_GLOBAL include("consts.jl") include("pointers.jl") diff --git a/src/C/context.jl b/src/C/context.jl index 66122cfb..b6e99949 100644 --- a/src/C/context.jl +++ b/src/C/context.jl @@ -4,20 +4,20 @@ A handle to a loaded instance of libpython, its interpreter, function pointers, etc. """ @kwdef mutable struct Context - is_embedded :: Bool = false - is_initialized :: Bool = false - is_preinitialized :: Bool = false - lib_ptr :: Ptr{Cvoid} = C_NULL - exe_path :: Union{String, Missing} = missing - lib_path :: Union{String, Missing} = missing - dlopen_flags :: UInt32 = RTLD_LAZY | RTLD_DEEPBIND | RTLD_GLOBAL - pyprogname :: Union{String, Missing} = missing - pyprogname_w :: Any = missing - pyhome :: Union{String, Missing} = missing - pyhome_w :: Any = missing - which :: Symbol = :unknown # :CondaPkg, :PyCall, :embedded or :unknown - version :: Union{VersionNumber, Missing} = missing - matches_pycall :: Union{Bool, Missing} = missing + is_embedded::Bool = false + is_initialized::Bool = false + is_preinitialized::Bool = false + lib_ptr::Ptr{Cvoid} = C_NULL + exe_path::Union{String,Missing} = missing + lib_path::Union{String,Missing} = missing + dlopen_flags::UInt32 = RTLD_LAZY | RTLD_DEEPBIND | RTLD_GLOBAL + pyprogname::Union{String,Missing} = missing + pyprogname_w::Any = missing + pyhome::Union{String,Missing} = missing + pyhome_w::Any = missing + which::Symbol = :unknown # :CondaPkg, :PyCall, :embedded or :unknown + version::Union{VersionNumber,Missing} = missing + matches_pycall::Union{Bool,Missing} = missing end const CTX = Context() @@ -60,7 +60,9 @@ function init_context() exe_path::String else # By default, we use Python installed by CondaPkg. - exe_path = Sys.iswindows() ? joinpath(CondaPkg.envdir(), "python.exe") : joinpath(CondaPkg.envdir(), "bin", "python") + exe_path = + Sys.iswindows() ? joinpath(CondaPkg.envdir(), "python.exe") : + joinpath(CondaPkg.envdir(), "bin", "python") # It's not sufficient to only activate the env while Python is initialising, # it must also be active when loading extension modules (e.g. numpy). So we # activate the environment globally. @@ -83,7 +85,7 @@ function init_context() # Ensure Python is runnable try - run(pipeline(`$exe_path --version`, stdout=devnull, stderr=devnull)) + run(pipeline(`$exe_path --version`, stdout = devnull, stderr = devnull)) catch error("Python executable $(repr(exe_path)) is not executable.") end @@ -99,9 +101,9 @@ function init_context() # Find and open Python library lib_path = something( - CTX.lib_path===missing ? nothing : CTX.lib_path, + CTX.lib_path === missing ? nothing : CTX.lib_path, get(ENV, "JULIA_PYTHONCALL_LIB", nothing), - Some(nothing) + Some(nothing), ) if lib_path !== nothing lib_ptr = dlopen_e(lib_path, CTX.dlopen_flags) @@ -112,7 +114,9 @@ function init_context() CTX.lib_ptr = lib_ptr end else - for lib_path in readlines(python_cmd([joinpath(@__DIR__, "find_libpython.py"), "--list-all"])) + for lib_path in readlines( + python_cmd([joinpath(@__DIR__, "find_libpython.py"), "--list-all"]), + ) lib_ptr = dlopen_e(lib_path, CTX.dlopen_flags) if lib_ptr == C_NULL @warn "Python library $(repr(lib_path)) could not be opened." @@ -138,7 +142,7 @@ function init_context() init_pointers() # Compare libpath with PyCall - @require PyCall="438e738f-606a-5dbb-bf0a-cddfbfd45ab0" init_pycall(PyCall) + @require PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" init_pycall(PyCall) # Initialize the interpreter with_gil() do diff --git a/src/C/extras.jl b/src/C/extras.jl index e84ebed7..bc8679df 100644 --- a/src/C/extras.jl +++ b/src/C/extras.jl @@ -1,11 +1,12 @@ Py_Type(x::PyPtr) = PyPtr(UnsafePtr(x).type[!]) -PyObject_Type(x::PyPtr) = (t=Py_Type(x); Py_IncRef(t); t) +PyObject_Type(x::PyPtr) = (t = Py_Type(x); Py_IncRef(t); t) Py_TypeCheck(o::PyPtr, t::PyPtr) = PyType_IsSubtype(Py_Type(o), t) Py_TypeCheckFast(o::PyPtr, f::Integer) = PyType_IsSubtypeFast(Py_Type(o), f) -PyType_IsSubtypeFast(t::PyPtr, f::Integer) = Cint(!iszero(UnsafePtr{PyTypeObject}(t).flags[] & f)) +PyType_IsSubtypeFast(t::PyPtr, f::Integer) = + Cint(!iszero(UnsafePtr{PyTypeObject}(t).flags[] & f)) PyMemoryView_GET_BUFFER(m::PyPtr) = Ptr{Py_buffer}(UnsafePtr{PyMemoryViewObject}(m).view) diff --git a/src/C/pointers.jl b/src/C/pointers.jl index 4d63c578..dd0476fc 100644 --- a/src/C/pointers.jl +++ b/src/C/pointers.jl @@ -1,4 +1,4 @@ -const CAPI_FUNC_SIGS = Dict{Symbol, Pair{Tuple, Type}}( +const CAPI_FUNC_SIGS = Dict{Symbol,Pair{Tuple,Type}}( # INITIALIZE :Py_Initialize => () => Cvoid, :Py_InitializeEx => (Cint,) => Cvoid, @@ -270,29 +270,33 @@ const CAPI_OBJECTS = Set([ ]) @eval @kwdef mutable struct CAPIPointers - $([:($name :: Ptr{Cvoid} = C_NULL) for name in CAPI_FUNCS]...) - $([:($name :: PyPtr = C_NULL) for name in CAPI_EXCEPTIONS]...) - $([:($name :: PyPtr = C_NULL) for name in CAPI_OBJECTS]...) - PyOS_InputHookPtr :: Ptr{Ptr{Cvoid}} = C_NULL + $([:($name::Ptr{Cvoid} = C_NULL) for name in CAPI_FUNCS]...) + $([:($name::PyPtr = C_NULL) for name in CAPI_EXCEPTIONS]...) + $([:($name::PyPtr = C_NULL) for name in CAPI_OBJECTS]...) + PyOS_InputHookPtr::Ptr{Ptr{Cvoid}} = C_NULL end const POINTERS = CAPIPointers() -@eval init_pointers(p::CAPIPointers=POINTERS, lib::Ptr=CTX.lib_ptr) = begin +@eval init_pointers(p::CAPIPointers = POINTERS, lib::Ptr = CTX.lib_ptr) = begin $([ if name == :Py_FinalizeEx :(p.$name = dlsym_e(lib, $(QuoteNode(name)))) else :(p.$name = dlsym(lib, $(QuoteNode(name)))) - end - for name in CAPI_FUNCS + end for name in CAPI_FUNCS ]...) - $([:(p.$name = Base.unsafe_load(Ptr{PyPtr}(dlsym(lib, $(QuoteNode(name)))::Ptr))) for name in CAPI_EXCEPTIONS]...) + $( + [ + :(p.$name = + Base.unsafe_load(Ptr{PyPtr}(dlsym(lib, $(QuoteNode(name)))::Ptr))) for name in CAPI_EXCEPTIONS + ]... + ) $([:(p.$name = dlsym(lib, $(QuoteNode(name)))) for name in CAPI_OBJECTS]...) p.PyOS_InputHookPtr = dlsym(CTX.lib_ptr, :PyOS_InputHook) end for (name, (argtypes, rettype)) in CAPI_FUNC_SIGS - args = [Symbol("x", i) for (i,_) in enumerate(argtypes)] + args = [Symbol("x", i) for (i, _) in enumerate(argtypes)] @eval $name($(args...)) = ccall(POINTERS.$name, $rettype, ($(argtypes...),), $(args...)) end diff --git a/src/Compat/Compat.jl b/src/Compat/Compat.jl index ede2bcf8..487fe8a3 100644 --- a/src/Compat/Compat.jl +++ b/src/Compat/Compat.jl @@ -4,28 +4,41 @@ Misc bits and bobs for compatibility. """ module Compat - using ..PythonCall: PythonCall # needed for docstring cross-refs - using ..Core - using ..Core: Core, C, Utils, pynew, incref, getptr, pycopy!, pymodulehooks, pyisnull, pybytes_asvector, pysysmodule, pyosmodule, pystr_fromUTF8 - using ..Convert: pyconvert, @pyconvert - using ..Wrap: PyArray, PyPandasDataFrame - using Serialization: Serialization, AbstractSerializer, serialize, deserialize - using Tables: Tables - using Requires: @require +using ..PythonCall: PythonCall # needed for docstring cross-refs +using ..Core +using ..Core: + Core, + C, + Utils, + pynew, + incref, + getptr, + pycopy!, + pymodulehooks, + pyisnull, + pybytes_asvector, + pysysmodule, + pyosmodule, + pystr_fromUTF8 +using ..Convert: pyconvert, @pyconvert +using ..Wrap: PyArray, PyPandasDataFrame +using Serialization: Serialization, AbstractSerializer, serialize, deserialize +using Tables: Tables +using Requires: @require - include("gui.jl") - include("ipython.jl") - include("multimedia.jl") - include("serialization.jl") - include("tables.jl") - include("pycall.jl") +include("gui.jl") +include("ipython.jl") +include("multimedia.jl") +include("serialization.jl") +include("tables.jl") +include("pycall.jl") - function __init__() - C.with_gil() do - init_gui() - init_pyshow() - init_tables() - end - @require PyCall="438e738f-606a-5dbb-bf0a-cddfbfd45ab0" init_pycall(PyCall) +function __init__() + C.with_gil() do + init_gui() + init_pyshow() + init_tables() end + @require PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" init_pycall(PyCall) +end end diff --git a/src/Compat/gui.jl b/src/Compat/gui.jl index 8132fe87..9cfca3bf 100644 --- a/src/Compat/gui.jl +++ b/src/Compat/gui.jl @@ -62,75 +62,79 @@ function init_gui() if !C.CTX.is_embedded # define callbacks g = pydict() - pyexec(""" - def new_event_loop_callback(g, interval=0.04): - if g in ("pyqt4","pyqt5","pyside","pyside2"): - if g == "pyqt4": - import PyQt4.QtCore as QtCore - elif g == "pyqt5": - import PyQt5.QtCore as QtCore - elif g == "pyside": - import PySide.QtCore as QtCore - elif g == "pyside2": - import PySide2.QtCore as QtCore - instance = QtCore.QCoreApplication.instance - AllEvents = QtCore.QEventLoop.AllEvents - processEvents = QtCore.QCoreApplication.processEvents - maxtime = int(interval * 1000) - def callback(): - app = instance() - if app is not None: - app._in_event_loop = True - processEvents(AllEvents, maxtime) - elif g in ("gtk","gtk3"): - if g == "gtk3": - import gi - if gi.get_required_version("Gtk") is None: - gi.require_version("Gtk", "3.0") - import gi.repository.Gtk as gtk - elif g == "gtk": - import gtk - events_pending = gtk.events_pending - main_iteration = gtk.main_iteration - def callback(): - while events_pending(): - main_iteration() - elif g == "wx": - import wx - GetApp = wx.GetApp - EventLoop = wx.EventLoop - EventLoopActivator = wx.EventLoopActivator - def callback(): - app = GetApp() - if app is not None: - app._in_event_loop = True - evtloop = EventLoop() - ea = EventLoopActivator(evtloop) - Pending = evtloop.Pending - Dispatch = evtloop.Dispatch - while Pending(): - Dispatch() - app.ProcessIdle() - elif g == "tkinter": - import tkinter, _tkinter - flag = _tkinter.ALL_EVENTS | _tkinter.DONT_WAIT - root = None - def callback(): - global root - new_root = tkinter._default_root - if new_root is not None: - root = new_root - if root is not None: - while root.dooneevent(flag): - pass - else: - raise ValueError("invalid event loop name: {}".format(g)) - return callback - """, g) + pyexec( + """ + def new_event_loop_callback(g, interval=0.04): + if g in ("pyqt4","pyqt5","pyside","pyside2"): + if g == "pyqt4": + import PyQt4.QtCore as QtCore + elif g == "pyqt5": + import PyQt5.QtCore as QtCore + elif g == "pyside": + import PySide.QtCore as QtCore + elif g == "pyside2": + import PySide2.QtCore as QtCore + instance = QtCore.QCoreApplication.instance + AllEvents = QtCore.QEventLoop.AllEvents + processEvents = QtCore.QCoreApplication.processEvents + maxtime = int(interval * 1000) + def callback(): + app = instance() + if app is not None: + app._in_event_loop = True + processEvents(AllEvents, maxtime) + elif g in ("gtk","gtk3"): + if g == "gtk3": + import gi + if gi.get_required_version("Gtk") is None: + gi.require_version("Gtk", "3.0") + import gi.repository.Gtk as gtk + elif g == "gtk": + import gtk + events_pending = gtk.events_pending + main_iteration = gtk.main_iteration + def callback(): + while events_pending(): + main_iteration() + elif g == "wx": + import wx + GetApp = wx.GetApp + EventLoop = wx.EventLoop + EventLoopActivator = wx.EventLoopActivator + def callback(): + app = GetApp() + if app is not None: + app._in_event_loop = True + evtloop = EventLoop() + ea = EventLoopActivator(evtloop) + Pending = evtloop.Pending + Dispatch = evtloop.Dispatch + while Pending(): + Dispatch() + app.ProcessIdle() + elif g == "tkinter": + import tkinter, _tkinter + flag = _tkinter.ALL_EVENTS | _tkinter.DONT_WAIT + root = None + def callback(): + global root + new_root = tkinter._default_root + if new_root is not None: + root = new_root + if root is not None: + while root.dooneevent(flag): + pass + else: + raise ValueError("invalid event loop name: {}".format(g)) + return callback + """, + g, + ) pycopy!(new_event_loop_callback, g["new_event_loop_callback"]) # add a hook to automatically call fix_qt_plugin_path() - fixqthook = Py(() -> (Core.CONFIG.auto_fix_qt_plugin_path && fix_qt_plugin_path(); nothing)) + fixqthook = + Py(() -> (Core.CONFIG.auto_fix_qt_plugin_path && fix_qt_plugin_path(); nothing)) pymodulehooks.add_hook("PyQt4", fixqthook) pymodulehooks.add_hook("PyQt5", fixqthook) pymodulehooks.add_hook("PySide", fixqthook) diff --git a/src/Compat/ipython.jl b/src/Compat/ipython.jl index 5c26eb9d..e3716a98 100644 --- a/src/Compat/ipython.jl +++ b/src/Compat/ipython.jl @@ -8,7 +8,7 @@ struct PythonDisplay <: AbstractDisplay end function Base.display(d::PythonDisplay, m::MIME, @nospecialize(x)) istextmime(m) || throw(MethodError(display, (d, m, x))) buf = IOBuffer() - io = IOContext(buf, :limit=>true) + io = IOContext(buf, :limit => true) try show(io, m, x) catch @@ -33,7 +33,7 @@ struct IPythonDisplay <: AbstractDisplay end function Base.display(d::IPythonDisplay, m::MIME, @nospecialize(x)) ipy = pyimport("IPython") buf = IOBuffer() - io = IOContext(buf, :limit=>true) + io = IOContext(buf, :limit => true) dict = pydict() try show(io, m, x) @@ -42,7 +42,7 @@ function Base.display(d::IPythonDisplay, m::MIME, @nospecialize(x)) end data = take!(buf) dict[string(m)] = istextmime(m) ? pystr_fromUTF8(data) : pybytes(data) - ipy.display.display(dict, raw=true) + ipy.display.display(dict, raw = true) return end @@ -53,7 +53,7 @@ function Base.display(d::IPythonDisplay, @nospecialize(x)) return end buf = IOBuffer() - io = IOContext(buf, :limit=>true) + io = IOContext(buf, :limit => true) dict = pydict() for m in Utils.mimes_for(x) try @@ -65,6 +65,6 @@ function Base.display(d::IPythonDisplay, @nospecialize(x)) dict[m] = istextmime(m) ? pystr_fromUTF8(data) : pybytes(data) end length(dict) == 0 && throw(MethodError(display, (d, x))) - ipy.display.display(dict, raw=true) + ipy.display.display(dict, raw = true) return end diff --git a/src/Compat/multimedia.jl b/src/Compat/multimedia.jl index 419472fe..2642c97e 100644 --- a/src/Compat/multimedia.jl +++ b/src/Compat/multimedia.jl @@ -33,7 +33,7 @@ end function pyshow_rule_mimebundle(io::IO, mime::String, x::Py) pyhasattr(x, "_repr_mimebundle_") || return false try - ans = pytype(x)._repr_mimebundle_(x, include=pylist([mime])) + ans = pytype(x)._repr_mimebundle_(x, include = pylist([mime])) if pyisinstance(ans, pybuiltins.tuple) data = ans[0][mime] else @@ -110,7 +110,7 @@ function pyshow_rule_savefig(io::IO, mime::String, x::Py) fig = fig.figure end buf = pyimport("io").BytesIO() - x.savefig(buf, format=format, bbox_inches="tight") + x.savefig(buf, format = format, bbox_inches = "tight") data = @pyconvert(Vector{UInt8}, buf.getvalue(), return false) write(io, data) plt.close(fig) @@ -142,10 +142,11 @@ Base.showable(mime::MIME, o::Py) = pyshowable(mime, o) function Base.show(io::IO, mime::MIME"text/plain", df::PyPandasDataFrame) nrows = pyconvert(Int, Py(df).shape[0]) ncols = pyconvert(Int, Py(df).shape[1]) - printstyled(io, nrows, '×', ncols, ' ', typeof(df), '\n', bold=true) + printstyled(io, nrows, '×', ncols, ' ', typeof(df), '\n', bold = true) pyshow(io, mime, df) end Base.show(io::IO, mime::MIME, df::PyPandasDataFrame) = pyshow(io, mime, df) Base.show(io::IO, mime::MIME"text/csv", df::PyPandasDataFrame) = pyshow(io, mime, df) -Base.show(io::IO, mime::MIME"text/tab-separated-values", df::PyPandasDataFrame) = pyshow(io, mime, df) +Base.show(io::IO, mime::MIME"text/tab-separated-values", df::PyPandasDataFrame) = + pyshow(io, mime, df) Base.showable(mime::MIME, df::PyPandasDataFrame) = pyshowable(mime, df) diff --git a/src/Compat/serialization.jl b/src/Compat/serialization.jl index c36158d2..a401e9c8 100644 --- a/src/Compat/serialization.jl +++ b/src/Compat/serialization.jl @@ -43,7 +43,8 @@ function Serialization.serialize(s::AbstractSerializer, x::PyException) serialize_py(s, x.v) end -Serialization.deserialize(s::AbstractSerializer, ::Type{PyException}) = PyException(deserialize_py(s)) +Serialization.deserialize(s::AbstractSerializer, ::Type{PyException}) = + PyException(deserialize_py(s)) ### PyArray # @@ -58,5 +59,5 @@ end function Serialization.deserialize(s::AbstractSerializer, ::Type{T}) where {T<:PyArray} # TODO: set buffer and array args too? - T(deserialize_py(s); copy=false) + T(deserialize_py(s); copy = false) end diff --git a/src/Compat/tables.jl b/src/Compat/tables.jl index f7cc376f..475f2dcc 100644 --- a/src/Compat/tables.jl +++ b/src/Compat/tables.jl @@ -12,7 +12,7 @@ The `format` controls the type of the resulting table, and is one of: - `:rows`: A `list` of rows, which are `namedtuple`s. - `:rowdicts`: A `list` of rows, which are `dict`s. """ -function pytable(src, format=:pandas; opts...) +function pytable(src, format = :pandas; opts...) format = Symbol(format) if format == :pandas _pytable_pandas(src; opts...) @@ -28,53 +28,50 @@ function pytable(src, format=:pandas; opts...) end export pytable -function _pytable_columns(src, cols=Tables.columns(src)) +function _pytable_columns(src, cols = Tables.columns(src)) pydict( - pystr(String(n)) => asvector(Tables.getcolumn(cols, n)) - for n in Tables.columnnames(cols) + pystr(String(n)) => asvector(Tables.getcolumn(cols, n)) for + n in Tables.columnnames(cols) ) end -function _pytable_rows(src, rows=Tables.rows(src)) +function _pytable_rows(src, rows = Tables.rows(src)) names = Tables.columnnames(rows) - t = pyimport("collections"=>"namedtuple")("Row", pylist(pystr(string(n)) for n in names)) - pylist( - t(map(n->Tables.getcolumn(row, n), names)...) - for row in rows + t = pyimport("collections" => "namedtuple")( + "Row", + pylist(pystr(string(n)) for n in names), ) + pylist(t(map(n -> Tables.getcolumn(row, n), names)...) for row in rows) end -function _pytable_rowdicts(src, rows=Tables.rows(src)) +function _pytable_rowdicts(src, rows = Tables.rows(src)) names = Tables.columnnames(rows) pynames = [pystr(string(n)) for n in names] pylist( - pydict( - p => Tables.getcolumn(row, n) - for (n,p) in zip(names, pynames) - ) - for row in rows + pydict(p => Tables.getcolumn(row, n) for (n, p) in zip(names, pynames)) for + row in rows ) end aspandasvector(x) = asvector(x) -function _pytable_pandas(src, cols=Tables.columns(src); opts...) +function _pytable_pandas(src, cols = Tables.columns(src); opts...) pyimport("pandas").DataFrame( pydict( - pystr(string(n)) => aspandasvector(Tables.getcolumn(cols, n)) - for n in Tables.columnnames(cols) + pystr(string(n)) => aspandasvector(Tables.getcolumn(cols, n)) for + n in Tables.columnnames(cols) ); - opts... + opts..., ) end function init_tables() - @require CategoricalArrays="324d7699-5711-5eae-9e2f-1d82baa6b597" @eval begin + @require CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597" @eval begin aspandasvector(x::CategoricalArrays.CategoricalArray) = begin - codes = map(x -> x===missing ? -1 : Int(CategoricalArrays.levelcode(x))-1, x) + codes = map(x -> x === missing ? -1 : Int(CategoricalArrays.levelcode(x)) - 1, x) cats = CategoricalArrays.levels(x) ordered = x.pool.ordered - pyimport("pandas").Categorical.from_codes(codes, cats, ordered=ordered) + pyimport("pandas").Categorical.from_codes(codes, cats, ordered = ordered) end end end diff --git a/src/Convert/Convert.jl b/src/Convert/Convert.jl index 0cccbf58..81b7260f 100644 --- a/src/Convert/Convert.jl +++ b/src/Convert/Convert.jl @@ -6,7 +6,44 @@ Implements `pyconvert`. module Convert using ..Core -using ..Core: C, Utils, @autopy, getptr, incref, pynew, PyNULL, pyisnull, pydel!, pyisint, iserrset_ambig, pyisnone, pyisTrue, pyisFalse, pyfloat_asdouble, pycomplex_ascomplex, pyisstr, pystr_asstring, pyisbytes, pybytes_asvector, pybytes_asUTF8string, pyisfloat, pyisrange, pytuple_getitem, unsafe_pynext, pyistuple, pydatetimetype, pytime_isaware, pydatetime_isaware, _base_pydatetime, _base_datetime, errmatches, errclear, errset, pyiscomplex, pythrow, pybool_asbool +using ..Core: + C, + Utils, + @autopy, + getptr, + incref, + pynew, + PyNULL, + pyisnull, + pydel!, + pyisint, + iserrset_ambig, + pyisnone, + pyisTrue, + pyisFalse, + pyfloat_asdouble, + pycomplex_ascomplex, + pyisstr, + pystr_asstring, + pyisbytes, + pybytes_asvector, + pybytes_asUTF8string, + pyisfloat, + pyisrange, + pytuple_getitem, + unsafe_pynext, + pyistuple, + pydatetimetype, + pytime_isaware, + pydatetime_isaware, + _base_pydatetime, + _base_datetime, + errmatches, + errclear, + errset, + pyiscomplex, + pythrow, + pybool_asbool using Dates: Date, Time, DateTime, Second, Millisecond, Microsecond, Nanosecond import ..Core: pyconvert diff --git a/src/Convert/ctypes.jl b/src/Convert/ctypes.jl index b9b47c93..d081f563 100644 --- a/src/Convert/ctypes.jl +++ b/src/Convert/ctypes.jl @@ -33,7 +33,7 @@ const CTYPES_SIMPLE_TYPES = [ ] function init_ctypes() - for (t,T) in CTYPES_SIMPLE_TYPES + for (t, T) in CTYPES_SIMPLE_TYPES isptr = endswith(t, "_p") isreal = !isptr isnumber = isreal @@ -42,15 +42,17 @@ function init_ctypes() isuint = isint && (startswith(t, "u") || t == "size_t") name = "ctypes:c_$t" - rule = pyconvert_rule_ctypessimplevalue{T, false}() - saferule = pyconvert_rule_ctypessimplevalue{T, true}() + rule = pyconvert_rule_ctypessimplevalue{T,false}() + saferule = pyconvert_rule_ctypessimplevalue{T,true}() t == "char_p" && pyconvert_add_rule(name, Cstring, saferule) t == "wchar_p" && pyconvert_add_rule(name, Cwstring, saferule) pyconvert_add_rule(name, T, saferule) isuint && pyconvert_add_rule(name, UInt, sizeof(T) ≤ sizeof(UInt) ? saferule : rule) isuint && pyconvert_add_rule(name, Int, sizeof(T) < sizeof(Int) ? saferule : rule) - isint && !isuint && pyconvert_add_rule(name, Int, sizeof(T) ≤ sizeof(Int) ? saferule : rule) + isint && + !isuint && + pyconvert_add_rule(name, Int, sizeof(T) ≤ sizeof(Int) ? saferule : rule) isint && pyconvert_add_rule(name, Integer, rule) isfloat && pyconvert_add_rule(name, Float64, saferule) isreal && pyconvert_add_rule(name, Real, rule) diff --git a/src/Convert/numpy.jl b/src/Convert/numpy.jl index f9dadbd4..adb621cc 100644 --- a/src/Convert/numpy.jl +++ b/src/Convert/numpy.jl @@ -44,7 +44,9 @@ function init_numpy() pyconvert_add_rule(name, T, saferule, PYCONVERT_PRIORITY_ARRAY) isuint && pyconvert_add_rule(name, UInt, sizeof(T) ≤ sizeof(UInt) ? saferule : rule) isuint && pyconvert_add_rule(name, Int, sizeof(T) < sizeof(Int) ? saferule : rule) - isint && !isuint && pyconvert_add_rule(name, Int, sizeof(T) ≤ sizeof(Int) ? saferule : rule) + isint && + !isuint && + pyconvert_add_rule(name, Int, sizeof(T) ≤ sizeof(Int) ? saferule : rule) isint && pyconvert_add_rule(name, Integer, rule) isfloat && pyconvert_add_rule(name, Float64, saferule) isreal && pyconvert_add_rule(name, Real, rule) diff --git a/src/Convert/pandas.jl b/src/Convert/pandas.jl index b936c57c..65786f1c 100644 --- a/src/Convert/pandas.jl +++ b/src/Convert/pandas.jl @@ -2,6 +2,11 @@ pyconvert_rule_pandas_na(::Type{Nothing}, x::Py) = pyconvert_return(nothing) pyconvert_rule_pandas_na(::Type{Missing}, x::Py) = pyconvert_return(missing) function init_pandas() - pyconvert_add_rule("pandas._libs.missing:NAType", Missing, pyconvert_rule_pandas_na, PYCONVERT_PRIORITY_CANONICAL) + pyconvert_add_rule( + "pandas._libs.missing:NAType", + Missing, + pyconvert_rule_pandas_na, + PYCONVERT_PRIORITY_CANONICAL, + ) pyconvert_add_rule("pandas._libs.missing:NAType", Nothing, pyconvert_rule_pandas_na) end diff --git a/src/Convert/pyconvert.jl b/src/Convert/pyconvert.jl index 9963940f..c4061b1d 100644 --- a/src/Convert/pyconvert.jl +++ b/src/Convert/pyconvert.jl @@ -62,9 +62,17 @@ given Python type. Other priorities are reserved for internal use. """ -function pyconvert_add_rule(pytypename::String, type::Type, func::Function, priority::PyConvertPriority=PYCONVERT_PRIORITY_NORMAL) +function pyconvert_add_rule( + pytypename::String, + type::Type, + func::Function, + priority::PyConvertPriority = PYCONVERT_PRIORITY_NORMAL, +) @nospecialize type func - push!(get!(Vector{PyConvertRule}, PYCONVERT_RULES, pytypename), PyConvertRule(type, func, priority)) + push!( + get!(Vector{PyConvertRule}, PYCONVERT_RULES, pytypename), + PyConvertRule(type, func, priority), + ) empty!.(values(PYCONVERT_RULES_CACHE)) return end @@ -86,7 +94,8 @@ elseif false @inline pyconvert_unconverted() = false @inline pyconvert_returntype(::Type{T}) where {T} = Bool @inline pyconvert_isunconverted(r::Bool) = !r - @inline pyconvert_result(::Type{T}, r::Bool) where {T} = (ans = PYCONVERT_RESULT[]::T; PYCONVERT_RESULT[] = nothing; ans) + @inline pyconvert_result(::Type{T}, r::Bool) where {T} = + (ans = PYCONVERT_RESULT[]::T; PYCONVERT_RESULT[] = nothing; ans) else # Same as the previous scheme, but with special handling for bits types. # This is global state, probably best avoided. @@ -188,7 +197,9 @@ function _pyconvert_get_rules(pytype::Py) break end end - ok || error("Fatal inheritance error: could not merge MROs (mro=$mro, basemros=$basemros)") + ok || error( + "Fatal inheritance error: could not merge MROs (mro=$mro, basemros=$basemros)", + ) # add it to the list push!(mro, b) # remove it from consideration @@ -237,10 +248,13 @@ function _pyconvert_get_rules(pytype::Py) mro = String[x for xs in xmro for x in xs] # get corresponding rules - rules = PyConvertRule[rule for tname in mro for rule in get!(Vector{PyConvertRule}, PYCONVERT_RULES, tname)] + rules = PyConvertRule[ + rule for tname in mro for + rule in get!(Vector{PyConvertRule}, PYCONVERT_RULES, tname) + ] # order the rules by priority, then by original order - order = sort(axes(rules, 1), by=i -> (rules[i].priority, -i), rev=true) + order = sort(axes(rules, 1), by = i -> (rules[i].priority, -i), rev = true) rules = rules[order] @debug "pyconvert" pytype mro = join(mro, " ") @@ -265,16 +279,27 @@ function pyconvert_get_rules(type::Type, pytype::Py) rules = _pyconvert_get_rules(pytype) # intersect rules with type - rules = PyConvertRule[PyConvertRule(typeintersect(rule.type, type), rule.func, rule.priority) for rule in rules] + rules = PyConvertRule[ + PyConvertRule(typeintersect(rule.type, type), rule.func, rule.priority) for + rule in rules + ] # explode out unions - rules = [PyConvertRule(type, rule.func, rule.priority) for rule in rules for type in Utils.explode_union(rule.type)] + rules = [ + PyConvertRule(type, rule.func, rule.priority) for rule in rules for + type in Utils.explode_union(rule.type) + ] # filter out empty rules rules = [rule for rule in rules if rule.type != Union{}] # filter out repeated rules - rules = [rule for (i, rule) in enumerate(rules) if !any((rule.func === rules[j].func) && ((rule.type) <: (rules[j].type)) for j in 1:(i-1))] + rules = [ + rule for (i, rule) in enumerate(rules) if !any( + (rule.func === rules[j].func) && ((rule.type) <: (rules[j].type)) for + j = 1:(i-1) + ) + ] @debug "pyconvert" type rules return Function[pyconvert_fix(rule.type, rule.func) for rule in rules] @@ -284,7 +309,8 @@ pyconvert_fix(::Type{T}, func) where {T} = x -> func(T, x) const PYCONVERT_RULES_CACHE = Dict{Type,Dict{C.PyPtr,Vector{Function}}}() -@generated pyconvert_rules_cache(::Type{T}) where {T} = get!(Dict{C.PyPtr,Vector{Function}}, PYCONVERT_RULES_CACHE, T) +@generated pyconvert_rules_cache(::Type{T}) where {T} = + get!(Dict{C.PyPtr,Vector{Function}}, PYCONVERT_RULES_CACHE, T) function pyconvert_rule_fast(::Type{T}, x::Py) where {T} if T isa Union @@ -349,7 +375,7 @@ Convert the Python object `x` to a `T`. On failure, evaluates to `onfail`, which defaults to `return pyconvert_unconverted()` (mainly useful for writing conversion rules). """ -macro pyconvert(T, x, onfail=:(return $pyconvert_unconverted())) +macro pyconvert(T, x, onfail = :(return $pyconvert_unconverted())) quote T = $(esc(T)) x = $(esc(x)) @@ -370,7 +396,9 @@ Convert the Python object `x` to a `T`. If `d` is specified, it is returned on failure instead of throwing an error. """ -pyconvert(::Type{T}, x) where {T} = @autopy x @pyconvert T x_ error("cannot convert this Python '$(pytype(x_).__name__)' to a Julia '$T'") +pyconvert(::Type{T}, x) where {T} = @autopy x @pyconvert T x_ error( + "cannot convert this Python '$(pytype(x_).__name__)' to a Julia '$T'", +) pyconvert(::Type{T}, x, d) where {T} = @autopy x @pyconvert T x_ d export pyconvert @@ -382,32 +410,71 @@ Convert the Python object `x` to a `T`. On failure, throws a Python `TypeError` saying that the argument `name` could not be converted. """ pyconvertarg(::Type{T}, x, name) where {T} = @autopy x @pyconvert T x_ begin - errset(pybuiltins.TypeError, "Cannot convert argument '$name' to a Julia '$T', got a '$(pytype(x_).__name__)'") + errset( + pybuiltins.TypeError, + "Cannot convert argument '$name' to a Julia '$T', got a '$(pytype(x_).__name__)'", + ) pythrow() end function init_pyconvert() push!(PYCONVERT_EXTRATYPES, pyimport("io" => "IOBase")) - push!(PYCONVERT_EXTRATYPES, pyimport("numbers" => ("Number", "Complex", "Real", "Rational", "Integral"))...) - push!(PYCONVERT_EXTRATYPES, pyimport("collections.abc" => ("Iterable", "Sequence", "Set", "Mapping"))...) + push!( + PYCONVERT_EXTRATYPES, + pyimport("numbers" => ("Number", "Complex", "Real", "Rational", "Integral"))..., + ) + push!( + PYCONVERT_EXTRATYPES, + pyimport("collections.abc" => ("Iterable", "Sequence", "Set", "Mapping"))..., + ) priority = PYCONVERT_PRIORITY_CANONICAL pyconvert_add_rule("builtins:NoneType", Nothing, pyconvert_rule_none, priority) pyconvert_add_rule("builtins:bool", Bool, pyconvert_rule_bool, priority) pyconvert_add_rule("builtins:float", Float64, pyconvert_rule_float, priority) - pyconvert_add_rule("builtins:complex", Complex{Float64}, pyconvert_rule_complex, priority) + pyconvert_add_rule( + "builtins:complex", + Complex{Float64}, + pyconvert_rule_complex, + priority, + ) pyconvert_add_rule("numbers:Integral", Integer, pyconvert_rule_int, priority) pyconvert_add_rule("builtins:str", String, pyconvert_rule_str, priority) - pyconvert_add_rule("builtins:bytes", Base.CodeUnits{UInt8,String}, pyconvert_rule_bytes, priority) - pyconvert_add_rule("builtins:range", StepRange{<:Integer,<:Integer}, pyconvert_rule_range, priority) - pyconvert_add_rule("numbers:Rational", Rational{<:Integer}, pyconvert_rule_fraction, priority) + pyconvert_add_rule( + "builtins:bytes", + Base.CodeUnits{UInt8,String}, + pyconvert_rule_bytes, + priority, + ) + pyconvert_add_rule( + "builtins:range", + StepRange{<:Integer,<:Integer}, + pyconvert_rule_range, + priority, + ) + pyconvert_add_rule( + "numbers:Rational", + Rational{<:Integer}, + pyconvert_rule_fraction, + priority, + ) pyconvert_add_rule("builtins:tuple", NamedTuple, pyconvert_rule_iterable, priority) pyconvert_add_rule("builtins:tuple", Tuple, pyconvert_rule_iterable, priority) pyconvert_add_rule("datetime:datetime", DateTime, pyconvert_rule_datetime, priority) pyconvert_add_rule("datetime:date", Date, pyconvert_rule_date, priority) pyconvert_add_rule("datetime:time", Time, pyconvert_rule_time, priority) - pyconvert_add_rule("datetime:timedelta", Microsecond, pyconvert_rule_timedelta, priority) - pyconvert_add_rule("builtins:BaseException", PyException, pyconvert_rule_exception, priority) + pyconvert_add_rule( + "datetime:timedelta", + Microsecond, + pyconvert_rule_timedelta, + priority, + ) + pyconvert_add_rule( + "builtins:BaseException", + PyException, + pyconvert_rule_exception, + priority, + ) priority = PYCONVERT_PRIORITY_NORMAL pyconvert_add_rule("builtins:NoneType", Missing, pyconvert_rule_none, priority) @@ -420,17 +487,37 @@ function init_pyconvert() pyconvert_add_rule("builtins:str", Symbol, pyconvert_rule_str, priority) pyconvert_add_rule("builtins:str", Char, pyconvert_rule_str, priority) pyconvert_add_rule("builtins:bytes", Vector{UInt8}, pyconvert_rule_bytes, priority) - pyconvert_add_rule("builtins:range", UnitRange{<:Integer}, pyconvert_rule_range, priority) + pyconvert_add_rule( + "builtins:range", + UnitRange{<:Integer}, + pyconvert_rule_range, + priority, + ) pyconvert_add_rule("numbers:Rational", Number, pyconvert_rule_fraction, priority) - pyconvert_add_rule("collections.abc:Iterable", Vector, pyconvert_rule_iterable, priority) + pyconvert_add_rule( + "collections.abc:Iterable", + Vector, + pyconvert_rule_iterable, + priority, + ) pyconvert_add_rule("collections.abc:Iterable", Tuple, pyconvert_rule_iterable, priority) pyconvert_add_rule("collections.abc:Iterable", Pair, pyconvert_rule_iterable, priority) pyconvert_add_rule("collections.abc:Iterable", Set, pyconvert_rule_iterable, priority) - pyconvert_add_rule("collections.abc:Sequence", Vector, pyconvert_rule_iterable, priority) + pyconvert_add_rule( + "collections.abc:Sequence", + Vector, + pyconvert_rule_iterable, + priority, + ) pyconvert_add_rule("collections.abc:Sequence", Tuple, pyconvert_rule_iterable, priority) pyconvert_add_rule("collections.abc:Set", Set, pyconvert_rule_iterable, priority) pyconvert_add_rule("collections.abc:Mapping", Dict, pyconvert_rule_mapping, priority) - pyconvert_add_rule("datetime:timedelta", Millisecond, pyconvert_rule_timedelta, priority) + pyconvert_add_rule( + "datetime:timedelta", + Millisecond, + pyconvert_rule_timedelta, + priority, + ) pyconvert_add_rule("datetime:timedelta", Second, pyconvert_rule_timedelta, priority) pyconvert_add_rule("datetime:timedelta", Nanosecond, pyconvert_rule_timedelta, priority) diff --git a/src/Convert/rules.jl b/src/Convert/rules.jl index 829a796a..d1028685 100644 --- a/src/Convert/rules.jl +++ b/src/Convert/rules.jl @@ -4,7 +4,8 @@ pyconvert_rule_object(::Type{Py}, x::Py) = pyconvert_return(x) ### Exception -pyconvert_rule_exception(::Type{R}, x::Py) where {R<:PyException} = pyconvert_return(PyException(x)) +pyconvert_rule_exception(::Type{R}, x::Py) where {R<:PyException} = + pyconvert_return(PyException(x)) ### None @@ -15,7 +16,20 @@ pyconvert_rule_none(::Type{Missing}, x::Py) = pyconvert_return(missing) function pyconvert_rule_bool(::Type{T}, x::Py) where {T<:Number} val = pybool_asbool(x) - if T in (Bool, Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128, BigInt) + if T in ( + Bool, + Int8, + Int16, + Int32, + Int64, + Int128, + UInt8, + UInt16, + UInt32, + UInt64, + UInt128, + BigInt, + ) pyconvert_return(T(val)) else pyconvert_tryconvert(T, val) @@ -37,14 +51,18 @@ end ### bytes -pyconvert_rule_bytes(::Type{Vector{UInt8}}, x::Py) = pyconvert_return(copy(pybytes_asvector(x))) -pyconvert_rule_bytes(::Type{Base.CodeUnits{UInt8,String}}, x::Py) = pyconvert_return(codeunits(pybytes_asUTF8string(x))) +pyconvert_rule_bytes(::Type{Vector{UInt8}}, x::Py) = + pyconvert_return(copy(pybytes_asvector(x))) +pyconvert_rule_bytes(::Type{Base.CodeUnits{UInt8,String}}, x::Py) = + pyconvert_return(codeunits(pybytes_asUTF8string(x))) ### int pyconvert_rule_int(::Type{T}, x::Py) where {T<:Number} = begin # first try to convert to Clonglong (or Culonglong if unsigned) - v = T <: Unsigned ? C.PyLong_AsUnsignedLongLong(getptr(x)) : C.PyLong_AsLongLong(getptr(x)) + v = + T <: Unsigned ? C.PyLong_AsUnsignedLongLong(getptr(x)) : + C.PyLong_AsLongLong(getptr(x)) if !iserrset_ambig(v) # success return pyconvert_tryconvert(T, v) @@ -126,7 +144,12 @@ end ### range -function pyconvert_rule_range(::Type{R}, x::Py, ::Type{StepRange{T0,S0}}=Utils._type_lb(R), ::Type{StepRange{T1,S1}}=Utils._type_ub(R)) where {R<:StepRange,T0,S0,T1,S1} +function pyconvert_rule_range( + ::Type{R}, + x::Py, + ::Type{StepRange{T0,S0}} = Utils._type_lb(R), + ::Type{StepRange{T1,S1}} = Utils._type_ub(R), +) where {R<:StepRange,T0,S0,T1,S1} a = @pyconvert(Utils._typeintersect(Integer, T1), x.start) b = @pyconvert(Utils._typeintersect(Integer, S1), x.step) c = @pyconvert(Utils._typeintersect(Integer, T1), x.stop) @@ -136,7 +159,12 @@ function pyconvert_rule_range(::Type{R}, x::Py, ::Type{StepRange{T0,S0}}=Utils._ pyconvert_return(StepRange{T2,S2}(a′, b, c′)) end -function pyconvert_rule_range(::Type{R}, x::Py, ::Type{UnitRange{T0}}=Utils._type_lb(R), ::Type{UnitRange{T1}}=Utils._type_ub(R)) where {R<:UnitRange,T0,T1} +function pyconvert_rule_range( + ::Type{R}, + x::Py, + ::Type{UnitRange{T0}} = Utils._type_lb(R), + ::Type{UnitRange{T1}} = Utils._type_ub(R), +) where {R<:UnitRange,T0,T1} b = @pyconvert(Int, x.step) b == 1 || return pyconvert_unconverted() a = @pyconvert(Utils._typeintersect(Integer, T1), x.start) @@ -149,7 +177,12 @@ end ### fraction # works for any collections.abc.Rational -function pyconvert_rule_fraction(::Type{R}, x::Py, ::Type{Rational{T0}}=Utils._type_lb(R), ::Type{Rational{T1}}=Utils._type_ub(R)) where {R<:Rational,T0,T1} +function pyconvert_rule_fraction( + ::Type{R}, + x::Py, + ::Type{Rational{T0}} = Utils._type_lb(R), + ::Type{Rational{T1}} = Utils._type_ub(R), +) where {R<:Rational,T0,T1} a = @pyconvert(Utils._typeintersect(Integer, T1), x.numerator) b = @pyconvert(Utils._typeintersect(Integer, T1), x.denominator) a, b = promote(a, b) @@ -184,7 +217,12 @@ function _pyconvert_rule_iterable(ans::Vector{T0}, it::Py, ::Type{T1}) where {T0 return _pyconvert_rule_iterable(ans2, it, T1) end -function pyconvert_rule_iterable(::Type{R}, x::Py, ::Type{Vector{T0}}=Utils._type_lb(R), ::Type{Vector{T1}}=Utils._type_ub(R)) where {R<:Vector,T0,T1} +function pyconvert_rule_iterable( + ::Type{R}, + x::Py, + ::Type{Vector{T0}} = Utils._type_lb(R), + ::Type{Vector{T1}} = Utils._type_ub(R), +) where {R<:Vector,T0,T1} it = pyiter(x) ans = Vector{T0}() return _pyconvert_rule_iterable(ans, it, T1) @@ -210,7 +248,12 @@ function _pyconvert_rule_iterable(ans::Set{T0}, it::Py, ::Type{T1}) where {T0,T1 return _pyconvert_rule_iterable(ans2, it, T1) end -function pyconvert_rule_iterable(::Type{R}, x::Py, ::Type{Set{T0}}=Utils._type_lb(R), ::Type{Set{T1}}=Utils._type_ub(R)) where {R<:Set,T0,T1} +function pyconvert_rule_iterable( + ::Type{R}, + x::Py, + ::Type{Set{T0}} = Utils._type_lb(R), + ::Type{Set{T1}} = Utils._type_ub(R), +) where {R<:Set,T0,T1} it = pyiter(x) ans = Set{T0}() return _pyconvert_rule_iterable(ans, it, T1) @@ -218,7 +261,13 @@ end # Dict -function _pyconvert_rule_mapping(ans::Dict{K0,V0}, x::Py, it::Py, ::Type{K1}, ::Type{V1}) where {K0,V0,K1,V1} +function _pyconvert_rule_mapping( + ans::Dict{K0,V0}, + x::Py, + it::Py, + ::Type{K1}, + ::Type{V1}, +) where {K0,V0,K1,V1} @label again k_ = unsafe_pynext(it) if pyisnull(k_) @@ -239,7 +288,12 @@ function _pyconvert_rule_mapping(ans::Dict{K0,V0}, x::Py, it::Py, ::Type{K1}, :: return _pyconvert_rule_mapping(ans2, x, it, K1, V1) end -function pyconvert_rule_mapping(::Type{R}, x::Py, ::Type{Dict{K0,V0}}=Utils._type_lb(R), ::Type{Dict{K1,V1}}=Utils._type_ub(R)) where {R<:Dict,K0,V0,K1,V1} +function pyconvert_rule_mapping( + ::Type{R}, + x::Py, + ::Type{Dict{K0,V0}} = Utils._type_lb(R), + ::Type{Dict{K1,V1}} = Utils._type_ub(R), +) where {R<:Dict,K0,V0,K1,V1} it = pyiter(x) ans = Dict{K0,V0}() return _pyconvert_rule_mapping(ans, x, it, K1, V1) @@ -249,7 +303,8 @@ end function pyconvert_rule_iterable(::Type{T}, xs::Py) where {T<:Tuple} T isa DataType || return pyconvert_unconverted() - if T != Tuple{} && Tuple{T.parameters[end]} == Base.tuple_type_tail(Tuple{T.parameters[end]}) + if T != Tuple{} && + Tuple{T.parameters[end]} == Base.tuple_type_tail(Tuple{T.parameters[end]}) isvararg = true vartype = Base.tuple_type_head(Tuple{T.parameters[end]}) ts = T.parameters[1:end-1] @@ -273,31 +328,38 @@ function pyconvert_rule_iterable(::Type{T}, xs::Py) where {T<:Tuple} return length(zs) < length(ts) ? pyconvert_unconverted() : pyconvert_return(T(zs)) end -for N in 0:16 - Ts = [Symbol("T", n) for n in 1:N] - zs = [Symbol("z", n) for n in 1:N] +for N = 0:16 + Ts = [Symbol("T", n) for n = 1:N] + zs = [Symbol("z", n) for n = 1:N] # Tuple with N elements @eval function pyconvert_rule_iterable(::Type{Tuple{$(Ts...)}}, xs::Py) where {$(Ts...)} xs = pytuple(xs) n = pylen(xs) n == $N || return pyconvert_unconverted() - $(( - :($z = @pyconvert($T, pytuple_getitem(xs, $(i - 1)))) - for (i, T, z) in zip(1:N, Ts, zs) - )...) + $( + ( + :($z = @pyconvert($T, pytuple_getitem(xs, $(i - 1)))) for + (i, T, z) in zip(1:N, Ts, zs) + )... + ) return pyconvert_return(($(zs...),)) end # Tuple with N elements plus Vararg - @eval function pyconvert_rule_iterable(::Type{Tuple{$(Ts...),Vararg{V}}}, xs::Py) where {$(Ts...),V} + @eval function pyconvert_rule_iterable( + ::Type{Tuple{$(Ts...),Vararg{V}}}, + xs::Py, + ) where {$(Ts...),V} xs = pytuple(xs) n = pylen(xs) n ≥ $N || return pyconvert_unconverted() - $(( - :($z = @pyconvert($T, pytuple_getitem(xs, $(i - 1)))) - for (i, T, z) in zip(1:N, Ts, zs) - )...) + $( + ( + :($z = @pyconvert($T, pytuple_getitem(xs, $(i - 1)))) for + (i, T, z) in zip(1:N, Ts, zs) + )... + ) vs = V[] - for i in $(N + 1):n + for i = $(N + 1):n v = @pyconvert(V, pytuple_getitem(xs, i - 1)) push!(vs, v) end @@ -307,7 +369,12 @@ end # Pair -function pyconvert_rule_iterable(::Type{R}, x::Py, ::Type{Pair{K0,V0}}=Utils._type_lb(R), ::Type{Pair{K1,V1}}=Utils._type_ub(R)) where {R<:Pair,K0,V0,K1,V1} +function pyconvert_rule_iterable( + ::Type{R}, + x::Py, + ::Type{Pair{K0,V0}} = Utils._type_lb(R), + ::Type{Pair{K1,V1}} = Utils._type_ub(R), +) where {R<:Pair,K0,V0,K1,V1} it = pyiter(x) k_ = unsafe_pynext(it) if pyisnull(k_) @@ -341,7 +408,8 @@ end _nt_names_types(::Type) = nothing _nt_names_types(::Type{NamedTuple}) = (nothing, nothing) _nt_names_types(::Type{NamedTuple{names}}) where {names} = (names, nothing) -_nt_names_types(::Type{NamedTuple{names,types} where {names}}) where {types} = (nothing, types) +_nt_names_types(::Type{NamedTuple{names,types} where {names}}) where {types} = + (nothing, types) _nt_names_types(::Type{NamedTuple{names,types}}) where {names,types} = (names, types) function pyconvert_rule_iterable(::Type{R}, x::Py) where {R<:NamedTuple} @@ -380,7 +448,9 @@ function pyconvert_rule_time(::Type{Time}, x::Py) minute = pyconvert(Int, x.minute) second = pyconvert(Int, x.second) microsecond = pyconvert(Int, x.microsecond) - return pyconvert_return(Time(hour, minute, second, div(microsecond, 1000), mod(microsecond, 1000))) + return pyconvert_return( + Time(hour, minute, second, div(microsecond, 1000), mod(microsecond, 1000)), + ) end function pyconvert_rule_datetime(::Type{DateTime}, x::Py) @@ -393,7 +463,10 @@ function pyconvert_rule_datetime(::Type{DateTime}, x::Py) microseconds = pyconvert(Int, d.microseconds) pydel!(d) iszero(mod(microseconds, 1000)) || return pyconvert_unconverted() - return pyconvert_return(_base_datetime + Millisecond(div(microseconds, 1000) + 1000 * (seconds + 60 * 60 * 24 * days))) + return pyconvert_return( + _base_datetime + + Millisecond(div(microseconds, 1000) + 1000 * (seconds + 60 * 60 * 24 * days)), + ) end function pyconvert_rule_timedelta(::Type{Nanosecond}, x::Py) diff --git a/src/Core/Core.jl b/src/Core/Core.jl index a6e27c37..13f3f675 100644 --- a/src/Core/Core.jl +++ b/src/Core/Core.jl @@ -13,7 +13,19 @@ using ..C: C using ..GC: GC using ..Utils: Utils using Base: @propagate_inbounds, @kwdef -using Dates: Date, Time, DateTime, year, month, day, hour, minute, second, millisecond, microsecond, nanosecond +using Dates: + Date, + Time, + DateTime, + year, + month, + day, + hour, + minute, + second, + millisecond, + microsecond, + nanosecond using MacroTools: MacroTools, @capture using Markdown: Markdown diff --git a/src/Core/Py.jl b/src/Core/Py.jl index 396b39d8..e56d74fa 100644 --- a/src/Core/Py.jl +++ b/src/Core/Py.jl @@ -38,7 +38,7 @@ Such an object supports attribute access (`obj.attr`), indexing (`obj[idx]`), ca return `Py`. """ mutable struct Py - ptr :: C.PyPtr + ptr::C.PyPtr Py(::Val{:new}, ptr::C.PyPtr) = finalizer(py_finalizer, new(ptr)) end export Py @@ -136,16 +136,25 @@ end Py(x::Py) = x Py(x::Nothing) = pybuiltins.None Py(x::Bool) = x ? pybuiltins.True : pybuiltins.False -Py(x::Union{String, SubString{String}, Char}) = pystr(x) -Py(x::Base.CodeUnits{UInt8, String}) = pybytes(x) -Py(x::Base.CodeUnits{UInt8, SubString{String}}) = pybytes(x) +Py(x::Union{String,SubString{String},Char}) = pystr(x) +Py(x::Base.CodeUnits{UInt8,String}) = pybytes(x) +Py(x::Base.CodeUnits{UInt8,SubString{String}}) = pybytes(x) Py(x::Tuple) = pytuple_fromiter(x) Py(x::Pair) = pytuple_fromiter(x) -Py(x::Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}) = pyint(x) -Py(x::Rational{<:Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}}) = pyfraction(x) +Py(x::Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}) = + pyint(x) +Py( + x::Rational{ + <:Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}, + }, +) = pyfraction(x) Py(x::Union{Float16,Float32,Float64}) = pyfloat(x) Py(x::Complex{<:Union{Float16,Float32,Float64}}) = pycomplex(x) -Py(x::AbstractRange{<:Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}}) = pyrange_fromrange(x) +Py( + x::AbstractRange{ + <:Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}, + }, +) = pyrange_fromrange(x) Py(x::Date) = pydate(x) Py(x::Time) = pytime(x) Py(x::DateTime) = pydatetime(x) @@ -183,12 +192,14 @@ function Base.show(io::IO, ::MIME"text/plain", o::Py) hasprefix = (get(io, :typeinfo, Any) != Py)::Bool compact = get(io, :compact, false)::Bool multiline = '\n' in str - prefix = hasprefix ? compact ? "Py:$(multiline ? '\n' : ' ')" : "Python:$(multiline ? '\n' : ' ')" : "" + prefix = + hasprefix ? + compact ? "Py:$(multiline ? '\n' : ' ')" : "Python:$(multiline ? '\n' : ' ')" : "" print(io, prefix) h, w = displaysize(io) if get(io, :limit, true) h, w = displaysize(io) - h = max(h-3, 5) # use 3 fewer lines to allow for the prompt, but always allow at least 5 lines + h = max(h - 3, 5) # use 3 fewer lines to allow for the prompt, but always allow at least 5 lines if multiline h -= 1 # for the prefix lines = split(str, '\n') @@ -198,7 +209,7 @@ function Base.show(io::IO, ::MIME"text/plain", o::Py) println(io) end if length(line) > w - print(io, line[1:nextind(line, 0, w-1)], '…') + print(io, line[1:nextind(line, 0, w - 1)], '…') else print(io, line) end @@ -207,8 +218,8 @@ function Base.show(io::IO, ::MIME"text/plain", o::Py) if length(lines) ≤ h printlines(io, lines, w) else - h0 = cld(h-1, 2) - h1 = h-1-h0 + h0 = cld(h - 1, 2) + h1 = h - 1 - h0 i0 = h0 i1 = length(lines) - h1 + 1 # this indent computation tries to center the "more lines" message near the @@ -226,22 +237,27 @@ function Base.show(io::IO, ::MIME"text/plain", o::Py) indent = max(0, fld(maxlen + indent - length(msg), 2)) printlines(io, lines[1:h0], w) println(io) - printstyled(io, " "^indent, msg, color=:light_black) + printstyled(io, " "^indent, msg, color = :light_black) println(io) printlines(io, lines[end-h1+1:end], w) end else - maxlen = h*w - length(prefix) + maxlen = h * w - length(prefix) if length(str) ≤ maxlen print(io, str) else - h0 = cld(h-1, 2) - i0 = nextind(str, 0, h0*w-length(prefix)) - h1 = h-1-h0 - i1 = prevind(str, ncodeunits(str)+1, h1*w) + h0 = cld(h - 1, 2) + i0 = nextind(str, 0, h0 * w - length(prefix)) + h1 = h - 1 - h0 + i1 = prevind(str, ncodeunits(str) + 1, h1 * w) println(io, str[1:i0]) msg = "... $(length(str[nextind(str,i0):prevind(str,i1)])) more chars ..." - printstyled(io, " "^max(0, fld(w-length(msg), 2)), msg, color=:light_black) + printstyled( + io, + " "^max(0, fld(w - length(msg), 2)), + msg, + color = :light_black, + ) println(io) print(io, str[i1:end]) end @@ -263,7 +279,7 @@ Base.hasproperty(x::Py, k::String) = pyhasattr(x, k) Base.setproperty!(x::Py, k::Symbol, v) = pysetattr(x, string(k), v) Base.setproperty!(x::Py, k::String, v) = pysetattr(x, k, v) -function Base.propertynames(x::Py, private::Bool=false) +function Base.propertynames(x::Py, private::Bool = false) # this follows the logic of rlcompleter.py function classmembers(c) r = pydir(c) @@ -306,21 +322,23 @@ function Base.get(f::Base.Callable, x::Py, i) v === nothing ? f() : v end -Base.get!(x::Py, i, d) = get(x, i) do - pysetitem(x, i, d) - pygetitem(x, i) -end +Base.get!(x::Py, i, d) = + get(x, i) do + pysetitem(x, i, d) + pygetitem(x, i) + end -Base.get!(f::Base.Callable, x::Py, i) = get(x, i) do - pysetitem(x, i, f()) - pygetitem(x, i) -end +Base.get!(f::Base.Callable, x::Py, i) = + get(x, i) do + pysetitem(x, i, f()) + pygetitem(x, i) + end Base.eltype(::Type{Py}) = Py Base.IteratorSize(::Type{Py}) = Base.SizeUnknown() -function Base.iterate(x::Py, it::Py=pyiter(x)) +function Base.iterate(x::Py, it::Py = pyiter(x)) v = unsafe_pynext(it) if pyisnull(v) pydel!(it) @@ -342,9 +360,9 @@ Base.broadcastable(x::Py) = Ref(x) Base.:(==)(x::Py, y::Py) = pyeq(x, y) Base.:(!=)(x::Py, y::Py) = pyne(x, y) Base.:(<=)(x::Py, y::Py) = pyle(x, y) -Base.:(< )(x::Py, y::Py) = pylt(x, y) +Base.:(<)(x::Py, y::Py) = pylt(x, y) Base.:(>=)(x::Py, y::Py) = pyge(x, y) -Base.:(> )(x::Py, y::Py) = pygt(x, y) +Base.:(>)(x::Py, y::Py) = pygt(x, y) Base.isless(x::Py, y::Py) = pylt(Bool, x, y) Base.isequal(x::Py, y::Py) = pyeq(Bool, x, y) @@ -352,18 +370,18 @@ Base.isequal(x::Py, y::Py) = pyeq(Bool, x, y) Base.:(==)(x::Py, y::Number) = pyeq(x, y) Base.:(!=)(x::Py, y::Number) = pyne(x, y) Base.:(<=)(x::Py, y::Number) = pyle(x, y) -Base.:(< )(x::Py, y::Number) = pylt(x, y) +Base.:(<)(x::Py, y::Number) = pylt(x, y) Base.:(>=)(x::Py, y::Number) = pyge(x, y) -Base.:(> )(x::Py, y::Number) = pygt(x, y) +Base.:(>)(x::Py, y::Number) = pygt(x, y) Base.isless(x::Py, y::Number) = pylt(Bool, x, y) Base.isequal(x::Py, y::Number) = pyeq(Bool, x, y) Base.:(==)(x::Number, y::Py) = pyeq(x, y) Base.:(!=)(x::Number, y::Py) = pyne(x, y) Base.:(<=)(x::Number, y::Py) = pyle(x, y) -Base.:(< )(x::Number, y::Py) = pylt(x, y) +Base.:(<)(x::Number, y::Py) = pylt(x, y) Base.:(>=)(x::Number, y::Py) = pyge(x, y) -Base.:(> )(x::Number, y::Py) = pygt(x, y) +Base.:(>)(x::Number, y::Py) = pygt(x, y) Base.isless(x::Number, y::Py) = pylt(Bool, x, y) Base.isequal(x::Number, y::Py) = pyeq(Bool, x, y) @@ -432,7 +450,7 @@ Base.powermod(x::Number, y::Py, z::Number) = pypow(x, y, z) Base.powermod(x::Py, y::Number, z::Number) = pypow(x, y, z) # documentation -function Base.Docs.getdoc(x::Py, @nospecialize(sig)=Union{}) +function Base.Docs.getdoc(x::Py, @nospecialize(sig) = Union{}) pyisnull(x) && return nothing parts = [] inspect = pyimport("inspect") @@ -467,5 +485,5 @@ function Base.Docs.getdoc(x::Py, @nospecialize(sig)=Union{}) end return Markdown.MD(parts) end -Base.Docs.doc(x::Py, sig::Type=Union{}) = Base.Docs.getdoc(x, sig) +Base.Docs.doc(x::Py, sig::Type = Union{}) = Base.Docs.getdoc(x, sig) Base.Docs.Binding(x::Py, k::Symbol) = getproperty(x, k) diff --git a/src/Core/builtins.jl b/src/Core/builtins.jl index 165e281c..6a501526 100644 --- a/src/Core/builtins.jl +++ b/src/Core/builtins.jl @@ -16,7 +16,7 @@ pyisnot(x, y) = !pyis(x, y) Equivalent to `repr(x)` in Python. """ pyrepr(x) = pynew(errcheck(@autopy x C.PyObject_Repr(getptr(x_)))) -pyrepr(::Type{String}, x) = (s=pyrepr(x); ans=pystr_asstring(s); pydel!(s); ans) +pyrepr(::Type{String}, x) = (s = pyrepr(x); ans = pystr_asstring(s); pydel!(s); ans) export pyrepr """ @@ -25,7 +25,7 @@ export pyrepr Equivalent to `ascii(x)` in Python. """ pyascii(x) = pynew(errcheck(@autopy x C.PyObject_ASCII(getptr(x_)))) -pyascii(::Type{String}, x) = (s=pyascii(x); ans=pystr_asstring(s); pydel!(s); ans) +pyascii(::Type{String}, x) = (s = pyascii(x); ans = pystr_asstring(s); pydel!(s); ans) export pyascii """ @@ -80,7 +80,9 @@ export pygetattr Equivalent to `setattr(x, k, v)` or `x.k = v` in Python. """ -pysetattr(x, k, v) = (errcheck(@autopy x k v C.PyObject_SetAttr(getptr(x_), getptr(k_), getptr(v_))); nothing) +pysetattr(x, k, v) = ( + errcheck(@autopy x k v C.PyObject_SetAttr(getptr(x_), getptr(k_), getptr(v_))); nothing +) export pysetattr """ @@ -88,7 +90,8 @@ export pysetattr Equivalent to `delattr(x, k)` or `del x.k` in Python. """ -pydelattr(x, k) = (errcheck(@autopy x k C.PyObject_SetAttr(getptr(x_), getptr(k_), C.PyNULL)); nothing) +pydelattr(x, k) = + (errcheck(@autopy x k C.PyObject_SetAttr(getptr(x_), getptr(k_), C.PyNULL)); nothing) export pydelattr """ @@ -96,7 +99,8 @@ export pydelattr Test if `s` is a subclass of `t`. Equivalent to `issubclass(s, t)` in Python. """ -pyissubclass(s, t) = errcheck(@autopy s t C.PyObject_IsSubclass(getptr(s_), getptr(t_))) == 1 +pyissubclass(s, t) = + errcheck(@autopy s t C.PyObject_IsSubclass(getptr(s_), getptr(t_))) == 1 export pyissubclass """ @@ -104,7 +108,8 @@ export pyissubclass Test if `x` is of type `t`. Equivalent to `isinstance(x, t)` in Python. """ -pyisinstance(x, t) = errcheck(@autopy x t C.PyObject_IsInstance(getptr(x_), getptr(t_))) == 1 +pyisinstance(x, t) = + errcheck(@autopy x t C.PyObject_IsInstance(getptr(x_), getptr(t_))) == 1 export pyisinstance """ @@ -189,7 +194,9 @@ export pygetitem Equivalent to `setitem(x, k, v)` or `x[k] = v` in Python. """ -pysetitem(x, k, v) = (errcheck(@autopy x k v C.PyObject_SetItem(getptr(x_), getptr(k_), getptr(v_))); nothing) +pysetitem(x, k, v) = ( + errcheck(@autopy x k v C.PyObject_SetItem(getptr(x_), getptr(k_), getptr(v_))); nothing +) export pysetitem """ @@ -197,7 +204,8 @@ export pysetitem Equivalent to `delitem(x, k)` or `del x[k]` in Python. """ -pydelitem(x, k) = (errcheck(@autopy x k C.PyObject_DelItem(getptr(x_), getptr(k_))); nothing) +pydelitem(x, k) = + (errcheck(@autopy x k C.PyObject_DelItem(getptr(x_), getptr(k_))); nothing) export pydelitem """ @@ -209,8 +217,13 @@ pydir(x) = pynew(errcheck(@autopy x C.PyObject_Dir(getptr(x_)))) export pydir pycallargs(f) = pynew(errcheck(@autopy f C.PyObject_CallObject(getptr(f_), C.PyNULL))) -pycallargs(f, args) = pynew(errcheck(@autopy f args C.PyObject_CallObject(getptr(f_), getptr(args_)))) -pycallargs(f, args, kwargs) = pynew(errcheck(@autopy f args kwargs C.PyObject_Call(getptr(f_), getptr(args_), getptr(kwargs_)))) +pycallargs(f, args) = + pynew(errcheck(@autopy f args C.PyObject_CallObject(getptr(f_), getptr(args_)))) +pycallargs(f, args, kwargs) = pynew( + errcheck( + @autopy f args kwargs C.PyObject_Call(getptr(f_), getptr(args_), getptr(kwargs_)) + ), +) """ pycall(f, args...; kwargs...) @@ -241,7 +254,8 @@ export pycall Equivalent to `x == y` in Python. The second form converts to `Bool`. """ -pyeq(x, y) = pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_EQ))) +pyeq(x, y) = + pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_EQ))) """ pyne(x, y) @@ -249,7 +263,8 @@ pyeq(x, y) = pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getpt Equivalent to `x != y` in Python. The second form converts to `Bool`. """ -pyne(x, y) = pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_NE))) +pyne(x, y) = + pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_NE))) """ pyle(x, y) @@ -257,7 +272,8 @@ pyne(x, y) = pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getpt Equivalent to `x <= y` in Python. The second form converts to `Bool`. """ -pyle(x, y) = pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_LE))) +pyle(x, y) = + pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_LE))) """ pylt(x, y) @@ -265,7 +281,8 @@ pyle(x, y) = pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getpt Equivalent to `x < y` in Python. The second form converts to `Bool`. """ -pylt(x, y) = pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_LT))) +pylt(x, y) = + pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_LT))) """ pyge(x, y) @@ -273,7 +290,8 @@ pylt(x, y) = pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getpt Equivalent to `x >= y` in Python. The second form converts to `Bool`. """ -pyge(x, y) = pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_GE))) +pyge(x, y) = + pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_GE))) """ pygt(x, y) @@ -281,13 +299,20 @@ pyge(x, y) = pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getpt Equivalent to `x > y` in Python. The second form converts to `Bool`. """ -pygt(x, y) = pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_GT))) -pyeq(::Type{Bool}, x, y) = errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_EQ)) == 1 -pyne(::Type{Bool}, x, y) = errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_NE)) == 1 -pyle(::Type{Bool}, x, y) = errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_LE)) == 1 -pylt(::Type{Bool}, x, y) = errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_LT)) == 1 -pyge(::Type{Bool}, x, y) = errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_GE)) == 1 -pygt(::Type{Bool}, x, y) = errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_GT)) == 1 +pygt(x, y) = + pynew(errcheck(@autopy x y C.PyObject_RichCompare(getptr(x_), getptr(y_), C.Py_GT))) +pyeq(::Type{Bool}, x, y) = + errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_EQ)) == 1 +pyne(::Type{Bool}, x, y) = + errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_NE)) == 1 +pyle(::Type{Bool}, x, y) = + errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_LE)) == 1 +pylt(::Type{Bool}, x, y) = + errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_LT)) == 1 +pyge(::Type{Bool}, x, y) = + errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_GE)) == 1 +pygt(::Type{Bool}, x, y) = + errcheck(@autopy x y C.PyObject_RichCompareBool(getptr(x_), getptr(y_), C.Py_GT)) == 1 export pyeq, pyne, pyle, pylt, pyge, pygt """ @@ -367,13 +392,15 @@ pymul(x, y) = pynew(errcheck(@autopy x y C.PyNumber_Multiply(getptr(x_), getptr( Equivalent to `x @ y` in Python. """ -pymatmul(x, y) = pynew(errcheck(@autopy x y C.PyNumber_MatrixMultiply(getptr(x_), getptr(y_)))) +pymatmul(x, y) = + pynew(errcheck(@autopy x y C.PyNumber_MatrixMultiply(getptr(x_), getptr(y_)))) """ pyfloordiv(x, y) Equivalent to `x // y` in Python. """ -pyfloordiv(x, y) = pynew(errcheck(@autopy x y C.PyNumber_FloorDivide(getptr(x_), getptr(y_)))) +pyfloordiv(x, y) = + pynew(errcheck(@autopy x y C.PyNumber_FloorDivide(getptr(x_), getptr(y_)))) """ pytruediv(x, y) @@ -422,7 +449,19 @@ pyxor(x, y) = pynew(errcheck(@autopy x y C.PyNumber_Xor(getptr(x_), getptr(y_))) Equivalent to `x | y` in Python. """ pyor(x, y) = pynew(errcheck(@autopy x y C.PyNumber_Or(getptr(x_), getptr(y_)))) -export pyadd, pysub, pymul, pymatmul, pyfloordiv, pytruediv, pymod, pydivmod, pylshift, pyrshift, pyand, pyxor, pyor +export pyadd, + pysub, + pymul, + pymatmul, + pyfloordiv, + pytruediv, + pymod, + pydivmod, + pylshift, + pyrshift, + pyand, + pyxor, + pyor # binary in-place """ @@ -436,49 +475,57 @@ pyiadd(x, y) = pynew(errcheck(@autopy x y C.PyNumber_InPlaceAdd(getptr(x_), getp In-place subtract. `x = pyisub(x, y)` is equivalent to `x -= y` in Python. """ -pyisub(x, y) = pynew(errcheck(@autopy x y C.PyNumber_InPlaceSubtract(getptr(x_), getptr(y_)))) +pyisub(x, y) = + pynew(errcheck(@autopy x y C.PyNumber_InPlaceSubtract(getptr(x_), getptr(y_)))) """ pyimul(x, y) In-place multiply. `x = pyimul(x, y)` is equivalent to `x *= y` in Python. """ -pyimul(x, y) = pynew(errcheck(@autopy x y C.PyNumber_InPlaceMultiply(getptr(x_), getptr(y_)))) +pyimul(x, y) = + pynew(errcheck(@autopy x y C.PyNumber_InPlaceMultiply(getptr(x_), getptr(y_)))) """ pyimatmul(x, y) In-place matrix multiply. `x = pyimatmul(x, y)` is equivalent to `x @= y` in Python. """ -pyimatmul(x, y) = pynew(errcheck(@autopy x y C.PyNumber_InPlaceMatrixMultiply(getptr(x_), getptr(y_)))) +pyimatmul(x, y) = + pynew(errcheck(@autopy x y C.PyNumber_InPlaceMatrixMultiply(getptr(x_), getptr(y_)))) """ pyifloordiv(x, y) In-place floor divide. `x = pyifloordiv(x, y)` is equivalent to `x //= y` in Python. """ -pyifloordiv(x, y) = pynew(errcheck(@autopy x y C.PyNumber_InPlaceFloorDivide(getptr(x_), getptr(y_)))) +pyifloordiv(x, y) = + pynew(errcheck(@autopy x y C.PyNumber_InPlaceFloorDivide(getptr(x_), getptr(y_)))) """ pyitruediv(x, y) In-place true division. `x = pyitruediv(x, y)` is equivalent to `x /= y` in Python. """ -pyitruediv(x, y) = pynew(errcheck(@autopy x y C.PyNumber_InPlaceTrueDivide(getptr(x_), getptr(y_)))) +pyitruediv(x, y) = + pynew(errcheck(@autopy x y C.PyNumber_InPlaceTrueDivide(getptr(x_), getptr(y_)))) """ pyimod(x, y) In-place subtraction. `x = pyimod(x, y)` is equivalent to `x %= y` in Python. """ -pyimod(x, y) = pynew(errcheck(@autopy x y C.PyNumber_InPlaceRemainder(getptr(x_), getptr(y_)))) +pyimod(x, y) = + pynew(errcheck(@autopy x y C.PyNumber_InPlaceRemainder(getptr(x_), getptr(y_)))) """ pyilshift(x, y) In-place left shift. `x = pyilshift(x, y)` is equivalent to `x <<= y` in Python. """ -pyilshift(x, y) = pynew(errcheck(@autopy x y C.PyNumber_InPlaceLshift(getptr(x_), getptr(y_)))) +pyilshift(x, y) = + pynew(errcheck(@autopy x y C.PyNumber_InPlaceLshift(getptr(x_), getptr(y_)))) """ pyirshift(x, y) In-place right shift. `x = pyirshift(x, y)` is equivalent to `x >>= y` in Python. """ -pyirshift(x, y) = pynew(errcheck(@autopy x y C.PyNumber_InPlaceRshift(getptr(x_), getptr(y_)))) +pyirshift(x, y) = + pynew(errcheck(@autopy x y C.PyNumber_InPlaceRshift(getptr(x_), getptr(y_)))) """ pyiand(x, y) @@ -497,7 +544,18 @@ pyixor(x, y) = pynew(errcheck(@autopy x y C.PyNumber_InPlaceXor(getptr(x_), getp In-place or. `x = pyior(x, y)` is equivalent to `x |= y` in Python. """ pyior(x, y) = pynew(errcheck(@autopy x y C.PyNumber_InPlaceOr(getptr(x_), getptr(y_)))) -export pyiadd, pyisub, pyimul, pyimatmul, pyifloordiv, pyitruediv, pyimod, pyilshift, pyirshift, pyiand, pyixor, pyior +export pyiadd, + pyisub, + pyimul, + pyimatmul, + pyifloordiv, + pyitruediv, + pyimod, + pyilshift, + pyirshift, + pyiand, + pyixor, + pyior # power """ @@ -505,13 +563,16 @@ export pyiadd, pyisub, pyimul, pyimatmul, pyifloordiv, pyitruediv, pyimod, pyils Equivalent to `x ** y` or `pow(x, y, z)` in Python. """ -pypow(x, y, z=pybuiltins.None) = pynew(errcheck(@autopy x y z C.PyNumber_Power(getptr(x_), getptr(y_), getptr(z_)))) +pypow(x, y, z = pybuiltins.None) = + pynew(errcheck(@autopy x y z C.PyNumber_Power(getptr(x_), getptr(y_), getptr(z_)))) """ pyipow(x, y, z=None) In-place power. `x = pyipow(x, y)` is equivalent to `x **= y` in Python. """ -pyipow(x, y, z=pybuiltins.None) = pynew(errcheck(@autopy x y z C.PyNumber_InPlacePower(getptr(x_), getptr(y_), getptr(z_)))) +pyipow(x, y, z = pybuiltins.None) = pynew( + errcheck(@autopy x y z C.PyNumber_InPlacePower(getptr(x_), getptr(y_), getptr(z_))), +) export pypow, pyipow ### iter @@ -550,7 +611,7 @@ pyisnone(x) = pyis(x, pybuiltins.None) Convert `x` to a Python `bool`. """ -pybool(x::Bool=false) = pynew(x ? pybuiltins.True : pybuiltins.False) +pybool(x::Bool = false) = pynew(x ? pybuiltins.True : pybuiltins.False) pybool(x::Number) = pybool(!iszero(x)) pybool(x) = pybuiltins.bool(x) export pybool @@ -583,12 +644,15 @@ pystr(x) = pynew(errcheck(@autopy x C.PyObject_Str(getptr(x_)))) pystr(x::String) = pystr_fromUTF8(x) pystr(x::SubString{String}) = pystr_fromUTF8(x) pystr(x::Char) = pystr(string(x)) -pystr(::Type{String}, x) = (s=pystr(x); ans=pystr_asstring(s); pydel!(s); ans) +pystr(::Type{String}, x) = (s = pystr(x); ans = pystr_asstring(s); pydel!(s); ans) export pystr -pystr_asUTF8bytes(x::Py) = Base.GC.@preserve x pynew(errcheck(C.PyUnicode_AsUTF8String(getptr(x)))) -pystr_asUTF8vector(x::Py) = (b=pystr_asUTF8bytes(x); ans=pybytes_asvector(b); pydel!(b); ans) -pystr_asstring(x::Py) = (b=pystr_asUTF8bytes(x); ans=pybytes_asUTF8string(b); pydel!(b); ans) +pystr_asUTF8bytes(x::Py) = + Base.GC.@preserve x pynew(errcheck(C.PyUnicode_AsUTF8String(getptr(x)))) +pystr_asUTF8vector(x::Py) = + (b = pystr_asUTF8bytes(x); ans = pybytes_asvector(b); pydel!(b); ans) +pystr_asstring(x::Py) = + (b = pystr_asUTF8bytes(x); ans = pybytes_asUTF8string(b); pydel!(b); ans) function pystr_intern!(x::Py) ptr = Ref(getptr(x)) @@ -610,10 +674,12 @@ Convert `x` to a Python `bytes`. """ pybytes(x) = pynew(errcheck(@autopy x C.PyObject_Bytes(getptr(x_)))) pybytes(x::Vector{UInt8}) = pybytes_fromdata(x) -pybytes(x::Base.CodeUnits{UInt8, String}) = pybytes_fromdata(x) -pybytes(x::Base.CodeUnits{UInt8, SubString{String}}) = pybytes_fromdata(x) -pybytes(::Type{T}, x) where {Vector{UInt8} <: T <: Vector} = (b=pybytes(x); ans=pybytes_asvector(b); pydel!(b); ans) -pybytes(::Type{T}, x) where {Base.CodeUnits{UInt8,String} <: T <: Base.CodeUnits} = (b=pybytes(x); ans=Base.CodeUnits(pybytes_asUTF8string(b)); pydel!(b); ans) +pybytes(x::Base.CodeUnits{UInt8,String}) = pybytes_fromdata(x) +pybytes(x::Base.CodeUnits{UInt8,SubString{String}}) = pybytes_fromdata(x) +pybytes(::Type{T}, x) where {Vector{UInt8} <: T <: Vector} = + (b = pybytes(x); ans = pybytes_asvector(b); pydel!(b); ans) +pybytes(::Type{T}, x) where {Base.CodeUnits{UInt8,String} <: T <: Base.CodeUnits} = + (b = pybytes(x); ans = Base.CodeUnits(pybytes_asUTF8string(b)); pydel!(b); ans) export pybytes pyisbytes(x) = pytypecheckfast(x, C.Py_TPFLAGS_BYTES_SUBCLASS) @@ -637,8 +703,9 @@ end ### int -pyint_fallback(x::Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}) = - pynew(errcheck(C.PyLong_FromString(string(x, base=32), C_NULL, 32))) +pyint_fallback( + x::Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}, +) = pynew(errcheck(C.PyLong_FromString(string(x, base = 32), C_NULL, 32))) pyint_fallback(x::Integer) = pyint_fallback(BigInt(x)) """ @@ -646,7 +713,7 @@ pyint_fallback(x::Integer) = pyint_fallback(BigInt(x)) Convert `x` to a Python `int`. """ -function pyint(x::Integer=0) +function pyint(x::Integer = 0) y = mod(x, Clonglong) if x == y pynew(errcheck(C.PyLong_FromLongLong(y))) @@ -674,7 +741,7 @@ pyisint(x) = pytypecheckfast(x, C.Py_TPFLAGS_LONG_SUBCLASS) Convert `x` to a Python `float`. """ -pyfloat(x::Real=0.0) = pynew(errcheck(C.PyFloat_FromDouble(x))) +pyfloat(x::Real = 0.0) = pynew(errcheck(C.PyFloat_FromDouble(x))) pyfloat(x) = @autopy x pynew(errcheck(C.PyNumber_Float(getptr(x_)))) export pyfloat @@ -690,7 +757,7 @@ pyfloat_asdouble(x) = errcheck_ambig(@autopy x C.PyFloat_AsDouble(getptr(x_))) Convert `x` to a Python `complex`, or create one from given real and imaginary parts. """ -pycomplex(x::Real=0.0, y::Real=0.0) = pynew(errcheck(C.PyComplex_FromDoubles(x, y))) +pycomplex(x::Real = 0.0, y::Real = 0.0) = pynew(errcheck(C.PyComplex_FromDoubles(x, y))) pycomplex(x::Complex) = pycomplex(real(x), imag(x)) pycomplex(x) = pybuiltins.complex(x) pycomplex(x, y) = pybuiltins.complex(x, y) @@ -781,7 +848,9 @@ Foo = pytype("Foo", (), [ """ function pytype(name, bases, dict) bases2 = ispy(bases) ? bases : pytuple(bases) - dict2 = ispy(dict) ? dict : pydict(ispy(item) ? (pygetattr(item, "__name__") => item) : item for item in dict) + dict2 = + ispy(dict) ? dict : + pydict(ispy(item) ? (pygetattr(item, "__name__") => item) : item for item in dict) pybuiltins.type(name, bases2, dict2) end @@ -797,7 +866,8 @@ pytypecheckfast(x, f) = (@autopy x C.Py_TypeCheckFast(getptr(x_), f)) == 1 Construct a Python `slice`. Unspecified arguments default to `None`. """ -pyslice(x, y, z=pybuiltins.None) = pynew(errcheck(@autopy x y z C.PySlice_New(getptr(x_), getptr(y_), getptr(z_)))) +pyslice(x, y, z = pybuiltins.None) = + pynew(errcheck(@autopy x y z C.PySlice_New(getptr(x_), getptr(y_), getptr(z_)))) pyslice(y) = pyslice(pybuiltins.None, y, pybuiltins.None) export pyslice @@ -838,7 +908,7 @@ function pytuple_fromiter(xs) # length known, e.g. Tuple, Pair, Vector ans = pynulltuple(length(xs)) for (i, x) in enumerate(xs) - pytuple_setitem(ans, i-1, x) + pytuple_setitem(ans, i - 1, x) end return ans else @@ -854,8 +924,8 @@ end n = length(xs.parameters) code = [] push!(code, :(ans = pynulltuple($n))) - for i in 1:n - push!(code, :(pytuple_setitem(ans, $(i-1), xs[$i]))) + for i = 1:n + push!(code, :(pytuple_setitem(ans, $(i - 1), xs[$i]))) end push!(code, :(return ans)) return Expr(:block, code...) @@ -894,7 +964,7 @@ function pylist_fromiter(xs) # length known ans = pynulllist(length(xs)) for (i, x) in enumerate(xs) - pylist_setitem(ans, i-1, x) + pylist_setitem(ans, i - 1, x) end return ans else @@ -931,7 +1001,7 @@ function pycollist(x::AbstractArray{T,N}) where {T,N} ans = pynulllist(length(ax)) for (i, j) in enumerate(ax) y = pycollist(selectdim(x, d, j)) - pylist_setitem(ans, i-1, y) + pylist_setitem(ans, i - 1, y) pydel!(y) end return ans @@ -950,7 +1020,7 @@ function pyrowlist(x::AbstractArray{T,N}) where {T,N} ans = pynulllist(length(ax)) for (i, j) in enumerate(ax) y = pyrowlist(selectdim(x, d, j)) - pylist_setitem(ans, i-1, y) + pylist_setitem(ans, i - 1, y) pydel!(y) end return ans @@ -996,7 +1066,8 @@ export pyfrozenset ### dict -pydict_setitem(x::Py, k, v) = errcheck(@autopy k v C.PyDict_SetItem(getptr(x), getptr(k_), getptr(v_))) +pydict_setitem(x::Py, k, v) = + errcheck(@autopy k v C.PyDict_SetItem(getptr(x), getptr(k_), getptr(v_))) function pydict_fromiter(kvs) ans = pydict() @@ -1023,7 +1094,8 @@ Convert `x` to a Python `dict`. In the second form, the keys are strings. If `x` is a Python object, this is equivalent to `dict(x)` in Python. Otherwise `x` must iterate over key-value pairs. """ -pydict(; kwargs...) = isempty(kwargs) ? pynew(errcheck(C.PyDict_New())) : pystrdict_fromiter(kwargs) +pydict(; kwargs...) = + isempty(kwargs) ? pynew(errcheck(C.PyDict_New())) : pystrdict_fromiter(kwargs) pydict(x) = ispy(x) ? pybuiltins.dict(x) : pydict_fromiter(x) pydict(x::NamedTuple) = pydict(; x...) export pydict @@ -1043,17 +1115,47 @@ pydate(year, month, day) = pydatetype(year, month, day) pydate(x::Date) = pydate(year(x), month(x), day(x)) export pydate -pytime(_hour=0, _minute=0, _second=0, _microsecond=0, _tzinfo=nothing; hour=_hour, minute=_minute, second=_second, microsecond=_microsecond, tzinfo=_tzinfo, fold=0) = pytimetype(hour, minute, second, microsecond, tzinfo, fold=fold) +pytime( + _hour = 0, + _minute = 0, + _second = 0, + _microsecond = 0, + _tzinfo = nothing; + hour = _hour, + minute = _minute, + second = _second, + microsecond = _microsecond, + tzinfo = _tzinfo, + fold = 0, +) = pytimetype(hour, minute, second, microsecond, tzinfo, fold = fold) pytime(x::Time) = if iszero(nanosecond(x)) pytime(hour(x), minute(x), second(x), millisecond(x) * 1000 + microsecond(x)) else - errset(pybuiltins.ValueError, "cannot create 'datetime.time' with less than microsecond resolution") + errset( + pybuiltins.ValueError, + "cannot create 'datetime.time' with less than microsecond resolution", + ) pythrow() end export pytime -pydatetime(year, month, day, _hour=0, _minute=0, _second=0, _microsecond=0, _tzinfo=nothing; hour=_hour, minute=_minute, second=_second, microsecond=_microsecond, tzinfo=_tzinfo, fold=0) = pydatetimetype(year, month, day, hour, minute, second, microsecond, tzinfo, fold=fold) +pydatetime( + year, + month, + day, + _hour = 0, + _minute = 0, + _second = 0, + _microsecond = 0, + _tzinfo = nothing; + hour = _hour, + minute = _minute, + second = _second, + microsecond = _microsecond, + tzinfo = _tzinfo, + fold = 0, +) = pydatetimetype(year, month, day, hour, minute, second, microsecond, tzinfo, fold = fold) function pydatetime(x::DateTime) # compute time since _base_datetime # this accounts for fold @@ -1152,28 +1254,40 @@ The following computes `1.1+2.2` in the `Main` module as a `Float64`: pyeval(Float64, "x+y", Main, (x=1.1, y=2.2)) # returns 3.3 ``` """ -function pyeval(::Type{T}, code, globals, locals=nothing) where {T} +function pyeval(::Type{T}, code, globals, locals = nothing) where {T} code_, globals_, locals_ = _pyeval_args(code, globals, locals) ans = pybuiltins.eval(code_, globals_, locals_) pydel!(locals_) return pyconvert(T, ans) end -pyeval(code, globals, locals=nothing) = pyeval(Py, code, globals, locals) +pyeval(code, globals, locals = nothing) = pyeval(Py, code, globals, locals) export pyeval _pyexec_ans(::Type{Nothing}, globals, locals) = nothing -@generated function _pyexec_ans(::Type{NamedTuple{names, types}}, globals, locals) where {names, types} +@generated function _pyexec_ans( + ::Type{NamedTuple{names,types}}, + globals, + locals, +) where {names,types} # TODO: use precomputed interned strings # TODO: try to load from globals too n = length(names) code = [] vars = Symbol[] - for i in 1:n + for i = 1:n v = Symbol(:ans, i) push!(vars, v) - push!(code, :($v = pyconvert($(types.parameters[i]), pygetitem(locals, $(string(names[i])))))) + push!( + code, + :( + $v = pyconvert( + $(types.parameters[i]), + pygetitem(locals, $(string(names[i]))), + ) + ), + ) end - push!(code, :(return $(NamedTuple{names, types})(($(vars...),)))) + push!(code, :(return $(NamedTuple{names,types})(($(vars...),)))) return Expr(:block, code...) end @@ -1207,14 +1321,14 @@ pyexec("global x; x=12", Main) pyeval(Int, "x", Main) # returns 12 ``` """ -function pyexec(::Type{T}, code, globals, locals=nothing) where {T} +function pyexec(::Type{T}, code, globals, locals = nothing) where {T} code_, globals_, locals_ = _pyeval_args(code, globals, locals) pydel!(pybuiltins.exec(code_, globals_, locals_)) ans = _pyexec_ans(T, globals_, locals_) pydel!(locals_) return ans end -pyexec(code, globals, locals=nothing) = pyexec(Nothing, code, globals, locals) +pyexec(code, globals, locals = nothing) = pyexec(Nothing, code, globals, locals) export pyexec function _pyeval_macro_code(arg) @@ -1278,7 +1392,7 @@ function _pyeval_macro_args(arg, filename, mode) error("invalid input: $input") end end - locals = :(($([:($var = $ex) for (var,ex) in locals]...),)) + locals = :(($([:($var = $ex) for (var, ex) in locals]...),)) end # done return locals, code, outputs @@ -1304,7 +1418,8 @@ The following computes `1.1+2.2` and returns a `Float64`: ``` """ macro pyeval(arg) - locals, code, outputs = _pyeval_macro_args(arg, "$(__source__.file):$(__source__.line)", "eval") + locals, code, outputs = + _pyeval_macro_args(arg, "$(__source__.file):$(__source__.line)", "eval") if outputs === nothing outputs = Py end @@ -1343,7 +1458,8 @@ in subsequent invocations: ``` """ macro pyexec(arg) - locals, code, outputs = _pyeval_macro_args(arg, "$(__source__.file):$(__source__.line)", "exec") + locals, code, outputs = + _pyeval_macro_args(arg, "$(__source__.file):$(__source__.line)", "exec") if outputs === nothing outputs = Nothing esc(:($pyexec(Nothing, $code, $__module__, $locals))) @@ -1366,7 +1482,7 @@ macro pyexec(arg) else pyvar = missing end - if @capture(output, lhs_ :: rhs_) + if @capture(output, lhs_::rhs_) outtype = rhs output = lhs else @@ -1380,13 +1496,14 @@ macro pyexec(arg) push!(jlvars, output) push!(types, outtype) end - outtype = :($NamedTuple{($(map(QuoteNode, pyvars)...),), Tuple{$(types...),}}) + outtype = :($NamedTuple{($(map(QuoteNode, pyvars)...),),Tuple{$(types...)}}) ans = :($pyexec($outtype, $code, $__module__, $locals)) if oneoutput ans = :($(jlvars[1]) = $ans[1]) else if pyvars != jlvars - outtype2 = :($NamedTuple{($(map(QuoteNode, jlvars)...),), Tuple{$(types...),}}) + outtype2 = + :($NamedTuple{($(map(QuoteNode, jlvars)...),),Tuple{$(types...)}}) ans = :($outtype2($ans)) end ans = :(($(jlvars...),) = $ans) @@ -1442,8 +1559,9 @@ Import a module `m`, or an attribute `k`, or a tuple of attributes. If several arguments are given, return the results of importing each one in a tuple. """ pyimport(m) = pynew(errcheck(@autopy m C.PyImport_Import(getptr(m_)))) -pyimport((m,k)::Pair) = (m_=pyimport(m); k_=pygetattr(m_,k); pydel!(m_); k_) -pyimport((m,ks)::Pair{<:Any,<:Tuple}) = (m_=pyimport(m); ks_=map(k->pygetattr(m_,k), ks); pydel!(m_); ks_) +pyimport((m, k)::Pair) = (m_ = pyimport(m); k_ = pygetattr(m_, k); pydel!(m_); k_) +pyimport((m, ks)::Pair{<:Any,<:Tuple}) = + (m_ = pyimport(m); ks_ = map(k -> pygetattr(m_, k), ks); pydel!(m_); ks_) pyimport(m1, m2, ms...) = map(pyimport, (m1, m2, ms...)) export pyimport diff --git a/src/Core/config.jl b/src/Core/config.jl index 53eb2454..55154cd3 100644 --- a/src/Core/config.jl +++ b/src/Core/config.jl @@ -1,7 +1,7 @@ @kwdef mutable struct Config - meta :: String = "" - auto_sys_last_traceback :: Bool = true - auto_fix_qt_plugin_path :: Bool = true + meta::String = "" + auto_sys_last_traceback::Bool = true + auto_fix_qt_plugin_path::Bool = true end const CONFIG = Config() diff --git a/src/Core/consts.jl b/src/Core/consts.jl index e43f74a6..0067aaad 100644 --- a/src/Core/consts.jl +++ b/src/Core/consts.jl @@ -9,7 +9,7 @@ const INIT_MODULES = Dict( :pycollectionsabcmodule => "collections.abc", ) -for (j,m) in INIT_MODULES +for (j, m) in INIT_MODULES @eval const $j = pynew() push!(INIT_CONSTS_CODE, :(pycopy!($j, pyimport($m)))) end @@ -22,7 +22,7 @@ const INIT_ATTRS = Dict( :pytimedeltatype => "datetime" => "timedelta", ) -for (j,k) in INIT_ATTRS +for (j, k) in INIT_ATTRS @eval const $j = pynew() push!(INIT_CONSTS_CODE, :(pycopy!($j, pyimport($k)))) end @@ -169,7 +169,7 @@ const BUILTINS = Set([ ]) @eval baremodule pybuiltins - $([:(const $k = $pynew()) for k in BUILTINS]...) +$([:(const $k = $pynew()) for k in BUILTINS]...) end """ pybuiltins @@ -186,9 +186,18 @@ for k in BUILTINS # help is only available in interactive contexts (imported by the 'site' module) # see: https://docs.python.org/3/library/functions.html#help # see: https://github.com/JuliaPy/PythonCall.jl/issues/248 - push!(INIT_CONSTS_CODE, :(pycopy!(pybuiltins.$k, pygetattr(pybuiltinsmodule, $(string(k)), pybuiltins.None)))) + push!( + INIT_CONSTS_CODE, + :(pycopy!( + pybuiltins.$k, + pygetattr(pybuiltinsmodule, $(string(k)), pybuiltins.None), + )), + ) else - push!(INIT_CONSTS_CODE, :(pycopy!(pybuiltins.$k, pygetattr(pybuiltinsmodule, $(string(k)))))) + push!( + INIT_CONSTS_CODE, + :(pycopy!(pybuiltins.$k, pygetattr(pybuiltinsmodule, $(string(k))))), + ) end end diff --git a/src/Core/err.jl b/src/Core/err.jl index 37f67748..1895bcb7 100644 --- a/src/Core/err.jl +++ b/src/Core/err.jl @@ -49,12 +49,12 @@ end Wraps the Python exception `x` as a Julia `Exception`. """ mutable struct PyException <: Exception - _t :: Py - _v :: Py - _b :: Py - _isnormalized :: Bool + _t::Py + _v::Py + _b::Py + _isnormalized::Bool end -function PyException(v::Py=pybuiltins.None) +function PyException(v::Py = pybuiltins.None) if pyisnone(v) t = b = v elseif pyisinstance(v, pybuiltins.BaseException) @@ -104,11 +104,12 @@ file_to_pymodule(fname::String) = begin end end -Base.showerror(io::IO, e::PyException) = _showerror(io, e, nothing, backtrace=false) +Base.showerror(io::IO, e::PyException) = _showerror(io, e, nothing, backtrace = false) -Base.showerror(io::IO, e::PyException, bt; backtrace=true) = _showerror(io, e, bt; backtrace=backtrace) +Base.showerror(io::IO, e::PyException, bt; backtrace = true) = + _showerror(io, e, bt; backtrace = backtrace) -function _showerror(io::IO, e::PyException, bt; backtrace=true) +function _showerror(io::IO, e::PyException, bt; backtrace = true) print(io, "Python: ") if pyisnone(e.t) @@ -136,7 +137,7 @@ function _showerror(io::IO, e::PyException, bt; backtrace=true) je, jb = pyconvert(Tuple{Any,Any}, e.v.args) print(io, "Julia: ") if je isa Exception - showerror(io, je, jb, backtrace=backtrace && jb !== nothing) + showerror(io, je, jb, backtrace = backtrace && jb !== nothing) else print(io, je) backtrace && jb !== nothing && Base.show_backtrace(io, jb) @@ -171,7 +172,13 @@ function _showerror(io::IO, e::PyException, bt; backtrace=true) printstyled(io, " none") else try - fs = [(pystr(String, x.name), pystr(String, x.filename), pystr(String, x.lineno)) for x in pyimport("traceback").extract_tb(e.b)] + fs = [ + ( + pystr(String, x.name), + pystr(String, x.filename), + pystr(String, x.lineno), + ) for x in pyimport("traceback").extract_tb(e.b) + ] if Base.VERSION < v"1.6.0-rc1" for (i, (name, fname, lineno)) in enumerate(reverse(fs)) println(io) @@ -181,8 +188,9 @@ function _showerror(io::IO, e::PyException, bt; backtrace=true) printstyled(io, fname, ":", lineno, bold = true) end else - mcdict = Dict{String, Symbol}() - mccyclyer = Iterators.Stateful(Iterators.cycle(Base.STACKTRACE_MODULECOLORS)) + mcdict = Dict{String,Symbol}() + mccyclyer = + Iterators.Stateful(Iterators.cycle(Base.STACKTRACE_MODULECOLORS)) # skip a couple as a basic attempt to make the colours different from the Julia stacktrace popfirst!(mccyclyer) popfirst!(mccyclyer) @@ -195,16 +203,18 @@ function _showerror(io::IO, e::PyException, bt; backtrace=true) mod = file_to_pymodule(fname) if mod !== nothing # print the module, with colour determined by the top level name - tmod = first(split(mod, ".", limit=2)) + tmod = first(split(mod, ".", limit = 2)) color = get!(mcdict, tmod) do popfirst!(mccyclyer) end printstyled(io, mod, " ", color = color) end - if isfile(fname) && :stacktrace_contract_userdir in names(Base, all=true) && Base.stacktrace_contract_userdir() - if :replaceuserpath in names(Base, all=true) + if isfile(fname) && + :stacktrace_contract_userdir in names(Base, all = true) && + Base.stacktrace_contract_userdir() + if :replaceuserpath in names(Base, all = true) fname = Base.replaceuserpath(fname) - elseif :contractuser in names(Base.Filesystem, all=true) + elseif :contractuser in names(Base.Filesystem, all = true) fname = Base.Filesystem.contractuser(fname) end end diff --git a/src/Core/juliacall.jl b/src/Core/juliacall.jl index 15945f6b..6a9db0e7 100644 --- a/src/Core/juliacall.jl +++ b/src/Core/juliacall.jl @@ -25,7 +25,8 @@ function init_juliacall() # import juliacall pycopy!(jl, pyimport("juliacall")) # check the version - @assert realpath(pystr_asstring(jl.__path__[0])) == realpath(joinpath(ROOT_DIR, "pysrc", "juliacall")) + @assert realpath(pystr_asstring(jl.__path__[0])) == + realpath(joinpath(ROOT_DIR, "pysrc", "juliacall")) @assert pystr_asstring(jl.__version__) == string(VERSION) @assert !pybool_asbool(jl.CONFIG["init"]) end diff --git a/src/Core/stdlib.jl b/src/Core/stdlib.jl index c1157539..98ddcce1 100644 --- a/src/Core/stdlib.jl +++ b/src/Core/stdlib.jl @@ -4,7 +4,8 @@ function init_stdlib() # check word size pywordsize = pygt(Bool, pysysmodule.maxsize, Int64(2)^32) ? 64 : 32 - pywordsize == Sys.WORD_SIZE || error("Julia is $(Sys.WORD_SIZE)-bit but Python is $(pywordsize)-bit") + pywordsize == Sys.WORD_SIZE || + error("Julia is $(Sys.WORD_SIZE)-bit but Python is $(pywordsize)-bit") if C.CTX.is_embedded @@ -33,26 +34,29 @@ function init_stdlib() # add hook to perform certain actions when certain modules are loaded g = pydict() - pyexec(""" - import sys - class JuliaCompatHooks: - def __init__(self): - self.hooks = {} - def find_module(self, name, path=None): - hs = self.hooks.get(name) - if hs is not None: - for h in hs: - h() - def add_hook(self, name, h): - if name not in self.hooks: - self.hooks[name] = [h] - else: - self.hooks[name].append(h) - if name in sys.modules: - h() - JULIA_COMPAT_HOOKS = JuliaCompatHooks() - sys.meta_path.insert(0, JULIA_COMPAT_HOOKS) - """, g) + pyexec( + """ + import sys + class JuliaCompatHooks: + def __init__(self): + self.hooks = {} + def find_module(self, name, path=None): + hs = self.hooks.get(name) + if hs is not None: + for h in hs: + h() + def add_hook(self, name, h): + if name not in self.hooks: + self.hooks[name] = [h] + else: + self.hooks[name].append(h) + if name in sys.modules: + h() + JULIA_COMPAT_HOOKS = JuliaCompatHooks() + sys.meta_path.insert(0, JULIA_COMPAT_HOOKS) + """, + g, + ) pycopy!(pymodulehooks, g["JULIA_COMPAT_HOOKS"]) end diff --git a/src/JlWrap/C.jl b/src/JlWrap/C.jl index e90dc478..ed1ab655 100644 --- a/src/JlWrap/C.jl +++ b/src/JlWrap/C.jl @@ -78,9 +78,15 @@ const PYJLBUFCACHE = Dict{Ptr{Cvoid},Any}() suboffsets::NTuple{N,Int} = ntuple(i -> -1, N) end -_pyjl_get_buffer_impl(obj::C.PyPtr, buf::Ptr{C.Py_buffer}, flags::Cint, x, f) = _pyjl_get_buffer_impl(obj, buf, flags, f(x)::PyBufferInfo) - -function _pyjl_get_buffer_impl(obj::C.PyPtr, buf::Ptr{C.Py_buffer}, flags::Cint, info::PyBufferInfo{N}) where {N} +_pyjl_get_buffer_impl(obj::C.PyPtr, buf::Ptr{C.Py_buffer}, flags::Cint, x, f) = + _pyjl_get_buffer_impl(obj, buf, flags, f(x)::PyBufferInfo) + +function _pyjl_get_buffer_impl( + obj::C.PyPtr, + buf::Ptr{C.Py_buffer}, + flags::Cint, + info::PyBufferInfo{N}, +) where {N} b = UnsafePtr(buf) c = [] @@ -126,7 +132,10 @@ function _pyjl_get_buffer_impl(obj::C.PyPtr, buf::Ptr{C.Py_buffer}, flags::Cint, elseif Utils.size_to_cstrides(info.itemsize, info.shape) == info.strides b.strides[] = C_NULL else - C.PyErr_SetString(C.POINTERS.PyExc_BufferError, "not C contiguous and strides not requested") + C.PyErr_SetString( + C.POINTERS.PyExc_BufferError, + "not C contiguous and strides not requested", + ) return Cint(-1) end @@ -138,7 +147,10 @@ function _pyjl_get_buffer_impl(obj::C.PyPtr, buf::Ptr{C.Py_buffer}, flags::Cint, push!(c, suboffsets) b.suboffsets[] = pointer(suboffsets) else - C.PyErr_SetString(C.POINTERS.PyExc_BufferError, "indirect array and suboffsets not requested") + C.PyErr_SetString( + C.POINTERS.PyExc_BufferError, + "indirect array and suboffsets not requested", + ) return Cint(-1) end @@ -176,7 +188,9 @@ end function _pyjl_get_buffer(o::C.PyPtr, buf::Ptr{C.Py_buffer}, flags::Cint) num_ = C.PyObject_GetAttrString(o, "_jl_buffer_info") - num_ == C_NULL && (C.PyErr_Clear(); C.PyErr_SetString(C.POINTERS.PyExc_BufferError, "not a buffer"); return Cint(-1)) + num_ == C_NULL && ( + C.PyErr_Clear(); C.PyErr_SetString(C.POINTERS.PyExc_BufferError, "not a buffer"); return Cint(-1) + ) num = C.PyLong_AsLongLong(num_) C.Py_DecRef(num_) num == -1 && return Cint(-1) @@ -186,7 +200,10 @@ function _pyjl_get_buffer(o::C.PyPtr, buf::Ptr{C.Py_buffer}, flags::Cint) return _pyjl_get_buffer_impl(o, buf, flags, x, f)::Cint catch exc @debug "error getting the buffer" exc - C.PyErr_SetString(C.POINTERS.PyExc_BufferError, "some error occurred getting the buffer") + C.PyErr_SetString( + C.POINTERS.PyExc_BufferError, + "some error occurred getting the buffer", + ) return Cint(-1) end end @@ -263,7 +280,8 @@ const _pyjlbase_as_buffer = fill(C.PyBufferProcs()) function init_c() empty!(_pyjlbase_methods) - push!(_pyjlbase_methods, + push!( + _pyjlbase_methods, C.PyMethodDef( name = pointer(_pyjlbase_callmethod_name), meth = @cfunction(_pyjl_callmethod, C.PyPtr, (C.PyPtr, C.PyPtr)), @@ -316,7 +334,7 @@ function init_c() end function __init__() - C.with_gil() do + C.with_gil() do init_c() end end @@ -344,7 +362,10 @@ end PyJuliaValue_New(t::C.PyPtr, @nospecialize(v)) = begin if C.PyType_IsSubtype(t, PyJuliaBase_Type[]) != 1 - C.PyErr_SetString(C.POINTERS.PyExc_TypeError, "Expecting a subtype of 'juliacall.ValueBase'") + C.PyErr_SetString( + C.POINTERS.PyExc_TypeError, + "Expecting a subtype of 'juliacall.ValueBase'", + ) return C.PyNULL end o = C.PyObject_CallObject(t, C.PyNULL) diff --git a/src/JlWrap/JlWrap.jl b/src/JlWrap/JlWrap.jl index 498cc382..aff3e833 100644 --- a/src/JlWrap/JlWrap.jl +++ b/src/JlWrap/JlWrap.jl @@ -7,8 +7,40 @@ module JlWrap using ..PythonCall: PythonCall using ..Core -using ..Core: C, Utils, pynew, @autopy, incref, decref, setptr!, getptr, pyjuliacallmodule, pycopy!, errcheck, errset, PyNULL, pyistuple, pyisnull, pyJuliaError, pydel!, pyistype, pytypecheck, pythrow, pytuple_getitem, pyisslice, pystr_asstring, pyosmodule, pyisstr -using ..Convert: pyconvert, @pyconvert, PYCONVERT_PRIORITY_WRAP, pyconvert_add_rule, pyconvert_tryconvert, pyconvertarg, pyconvert_result +using ..Core: + C, + Utils, + pynew, + @autopy, + incref, + decref, + setptr!, + getptr, + pyjuliacallmodule, + pycopy!, + errcheck, + errset, + PyNULL, + pyistuple, + pyisnull, + pyJuliaError, + pydel!, + pyistype, + pytypecheck, + pythrow, + pytuple_getitem, + pyisslice, + pystr_asstring, + pyosmodule, + pyisstr +using ..Convert: + pyconvert, + @pyconvert, + PYCONVERT_PRIORITY_WRAP, + pyconvert_add_rule, + pyconvert_tryconvert, + pyconvertarg, + pyconvert_result using ..GC: GC using Pkg: Pkg @@ -33,7 +65,7 @@ include("set.jl") include("callback.jl") function __init__() - Cjl.C.with_gil() do + Cjl.C.with_gil() do init_base() init_raw() init_any() diff --git a/src/JlWrap/any.jl b/src/JlWrap/any.jl index 92a53a2b..d5cad426 100644 --- a/src/JlWrap/any.jl +++ b/src/JlWrap/any.jl @@ -2,7 +2,11 @@ const pyjlanytype = pynew() # pyjlany_repr(self) = Py("") function pyjlany_repr(self) - str = repr(MIME("text/plain"), self; context=IOContext(devnull, :limit=>true, :displaysize=>(23,80))) + str = repr( + MIME("text/plain"), + self; + context = IOContext(devnull, :limit => true, :displaysize => (23, 80)), + ) # type = self isa Function ? "Function" : self isa Type ? "Type" : nameof(typeof(self)) sep = '\n' in str ? '\n' : ' ' Py("Julia:$sep$str") @@ -44,7 +48,8 @@ function pyjlany_call(self, args_::Py, kwargs_::Py) pydel!(kwargs_) ans end -pyjl_handle_error_type(::typeof(pyjlany_call), self, exc) = exc isa MethodError && exc.f === self ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(::typeof(pyjlany_call), self, exc) = + exc isa MethodError && exc.f === self ? pybuiltins.TypeError : PyNULL function pyjlany_getitem(self, k_::Py) if pyistuple(k_) @@ -56,7 +61,9 @@ function pyjlany_getitem(self, k_::Py) Py(self[k]) end end -pyjl_handle_error_type(::typeof(pyjlany_getitem), self, exc) = exc isa BoundsError ? pybuiltins.IndexError : exc isa KeyError ? pybuiltins.KeyError : PyNULL +pyjl_handle_error_type(::typeof(pyjlany_getitem), self, exc) = + exc isa BoundsError ? pybuiltins.IndexError : + exc isa KeyError ? pybuiltins.KeyError : PyNULL function pyjlany_setitem(self, k_::Py, v_::Py) v = pyconvert(Any, v_) @@ -70,7 +77,9 @@ function pyjlany_setitem(self, k_::Py, v_::Py) end Py(nothing) end -pyjl_handle_error_type(::typeof(pyjlany_setitem), self, exc) = exc isa BoundsError ? pybuiltins.IndexError : exc isa KeyError ? pybuiltins.KeyError : PyNULL +pyjl_handle_error_type(::typeof(pyjlany_setitem), self, exc) = + exc isa BoundsError ? pybuiltins.IndexError : + exc isa KeyError ? pybuiltins.KeyError : PyNULL function pyjlany_delitem(self, k_::Py) if pyistuple(k_) @@ -83,13 +92,16 @@ function pyjlany_delitem(self, k_::Py) end Py(nothing) end -pyjl_handle_error_type(::typeof(pyjlany_delitem), self, exc) = exc isa BoundsError ? pybuiltins.IndexError : exc isa KeyError ? pybuiltins.KeyError : PyNULL +pyjl_handle_error_type(::typeof(pyjlany_delitem), self, exc) = + exc isa BoundsError ? pybuiltins.IndexError : + exc isa KeyError ? pybuiltins.KeyError : PyNULL pyjlany_contains(self, v::Py) = Py(@pyconvert(eltype(self), v, return Py(false)) in self) -pyjl_handle_error_type(::typeof(pyjlany_contains), self, exc) = exc isa MethodError && exc.f === in ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(::typeof(pyjlany_contains), self, exc) = + exc isa MethodError && exc.f === in ? pybuiltins.TypeError : PyNULL struct pyjlany_op{OP} - op :: OP + op::OP end (op::pyjlany_op)(self) = Py(op.op(self)) function (op::pyjlany_op)(self, other_::Py) @@ -112,10 +124,11 @@ function (op::pyjlany_op)(self, other_::Py, other2_::Py) pybuiltins.NotImplemented end end -pyjl_handle_error_type(op::pyjlany_op, self, exc) = exc isa MethodError && exc.f === op.op ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(op::pyjlany_op, self, exc) = + exc isa MethodError && exc.f === op.op ? pybuiltins.TypeError : PyNULL struct pyjlany_rev_op{OP} - op :: OP + op::OP end function (op::pyjlany_rev_op)(self, other_::Py) if pyisjl(other_) @@ -137,10 +150,12 @@ function (op::pyjlany_rev_op)(self, other_::Py, other2_::Py) pybuiltins.NotImplemented end end -pyjl_handle_error_type(op::pyjlany_rev_op, self, exc) = exc isa MethodError && exc.f === op.op ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(op::pyjlany_rev_op, self, exc) = + exc isa MethodError && exc.f === op.op ? pybuiltins.TypeError : PyNULL pyjlany_name(self) = Py(string(nameof(self))) -pyjl_handle_error_type(::typeof(pyjlany_name), self, exc) = exc isa MethodError && exc.f === nameof ? pybuiltins.AttributeError : PyNULL +pyjl_handle_error_type(::typeof(pyjlany_name), self, exc) = + exc isa MethodError && exc.f === nameof ? pybuiltins.AttributeError : PyNULL function pyjlany_display(self, mime_::Py) mime = pyconvertarg(Union{Nothing,String}, mime_, "mime") @@ -176,7 +191,7 @@ function pyjlany_mimebundle(self, include::Py, exclude::Py) for m in mimes try io = IOBuffer() - show(IOContext(io, :limit=>true), MIME(m), self) + show(IOContext(io, :limit => true), MIME(m), self) v = take!(io) ans[m] = vo = istextmime(m) ? pystr(String(v)) : pybytes(v) pydel!(vo) @@ -189,142 +204,149 @@ end function init_any() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class AnyValue(ValueBase): - __slots__ = () - def __repr__(self): - if self._jl_isnull(): - return "" - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlany_repr))) - def __str__(self): - if self._jl_isnull(): - return "NULL" - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlany_str))) - def __getattr__(self, k): + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class AnyValue(ValueBase): + __slots__ = () + def __repr__(self): + if self._jl_isnull(): + return "" + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlany_repr))) + def __str__(self): + if self._jl_isnull(): + return "NULL" + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlany_str))) + def __getattr__(self, k): + if k.startswith("__") and k.endswith("__"): + raise AttributeError(k) + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlany_getattr)), k) + def __setattr__(self, k, v): + try: + ValueBase.__setattr__(self, k, v) + except AttributeError: if k.startswith("__") and k.endswith("__"): - raise AttributeError(k) - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlany_getattr)), k) - def __setattr__(self, k, v): - try: - ValueBase.__setattr__(self, k, v) - except AttributeError: - if k.startswith("__") and k.endswith("__"): - raise - else: - return - self._jl_callmethod($(pyjl_methodnum(pyjlany_setattr)), k, v) - def __dir__(self): - return ValueBase.__dir__(self) + self._jl_callmethod($(pyjl_methodnum(pyjlany_dir))) - def __call__(self, *args, **kwargs): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_call)), args, kwargs) - def __bool__(self): - return True - def __len__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(length)))) - def __getitem__(self, k): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_getitem)), k) - def __setitem__(self, k, v): - self._jl_callmethod($(pyjl_methodnum(pyjlany_setitem)), k, v) - def __delitem__(self, k): - self._jl_callmethod($(pyjl_methodnum(pyjlany_delitem)), k) - def __iter__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(Iterator)))) - def __reversed__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(reverse)))) - def __contains__(self, v): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_contains)), v) - def __pos__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(+)))) - def __neg__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(-)))) - def __abs__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(abs)))) - def __invert__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(~)))) - def __add__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(+))), other) - def __sub__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(-))), other) - def __mul__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(*))), other) - def __truediv__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(/))), other) - def __floordiv__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(÷))), other) - def __mod__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(%))), other) - def __pow__(self, other, modulo=None): - if modulo is None: - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(^))), other) - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(powermod))), other, modulo) - def __lshift__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(<<))), other) - def __rshift__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(>>))), other) - def __and__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(&))), other) - def __xor__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(⊻))), other) - def __or__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(|))), other) - def __radd__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(+))), other) - def __rsub__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(-))), other) - def __rmul__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(*))), other) - def __rtruediv__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(/))), other) - def __rfloordiv__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(÷))), other) - def __rmod__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(%))), other) - def __rpow__(self, other, modulo=None): - if modulo is None: - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(^))), other) - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(powermod))), other, modulo) - def __rlshift__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(<<))), other) - def __rrshift__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(>>))), other) - def __rand__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(&))), other) - def __rxor__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(⊻))), other) - def __ror__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(|))), other) - def __eq__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(==))), other) - def __ne__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(!=))), other) - def __le__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(≤))), other) - def __lt__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(<))), other) - def __ge__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(≥))), other) - def __gt__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(>))), other) - def __hash__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(hash)))) - @property - def __name__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_name))) - def _jl_raw(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlraw))) - def _jl_display(self, mime=None): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_display)), mime) - def _jl_help(self, mime=None): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_help)), mime) - def _repr_mimebundle_(self, include=None, exclude=None): - return self._jl_callmethod($(pyjl_methodnum(pyjlany_mimebundle)), include, exclude) - """, @__FILE__(), "exec"), jl.__dict__) + raise + else: + return + self._jl_callmethod($(pyjl_methodnum(pyjlany_setattr)), k, v) + def __dir__(self): + return ValueBase.__dir__(self) + self._jl_callmethod($(pyjl_methodnum(pyjlany_dir))) + def __call__(self, *args, **kwargs): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_call)), args, kwargs) + def __bool__(self): + return True + def __len__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(length)))) + def __getitem__(self, k): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_getitem)), k) + def __setitem__(self, k, v): + self._jl_callmethod($(pyjl_methodnum(pyjlany_setitem)), k, v) + def __delitem__(self, k): + self._jl_callmethod($(pyjl_methodnum(pyjlany_delitem)), k) + def __iter__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(Iterator)))) + def __reversed__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(reverse)))) + def __contains__(self, v): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_contains)), v) + def __pos__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(+)))) + def __neg__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(-)))) + def __abs__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(abs)))) + def __invert__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(~)))) + def __add__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(+))), other) + def __sub__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(-))), other) + def __mul__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(*))), other) + def __truediv__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(/))), other) + def __floordiv__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(÷))), other) + def __mod__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(%))), other) + def __pow__(self, other, modulo=None): + if modulo is None: + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(^))), other) + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(powermod))), other, modulo) + def __lshift__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(<<))), other) + def __rshift__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(>>))), other) + def __and__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(&))), other) + def __xor__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(⊻))), other) + def __or__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(|))), other) + def __radd__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(+))), other) + def __rsub__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(-))), other) + def __rmul__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(*))), other) + def __rtruediv__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(/))), other) + def __rfloordiv__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(÷))), other) + def __rmod__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(%))), other) + def __rpow__(self, other, modulo=None): + if modulo is None: + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(^))), other) + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(powermod))), other, modulo) + def __rlshift__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(<<))), other) + def __rrshift__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(>>))), other) + def __rand__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(&))), other) + def __rxor__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(⊻))), other) + def __ror__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_rev_op(|))), other) + def __eq__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(==))), other) + def __ne__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(!=))), other) + def __le__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(≤))), other) + def __lt__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(<))), other) + def __ge__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(≥))), other) + def __gt__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(>))), other) + def __hash__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_op(hash)))) + @property + def __name__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_name))) + def _jl_raw(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlraw))) + def _jl_display(self, mime=None): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_display)), mime) + def _jl_help(self, mime=None): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_help)), mime) + def _repr_mimebundle_(self, include=None, exclude=None): + return self._jl_callmethod($(pyjl_methodnum(pyjlany_mimebundle)), include, exclude) +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjlanytype, jl.AnyValue) end diff --git a/src/JlWrap/array.jl b/src/JlWrap/array.jl index 2cb33bbc..c46b6a0d 100644 --- a/src/JlWrap/array.jl +++ b/src/JlWrap/array.jl @@ -46,7 +46,10 @@ function pyjl_getaxisindex(x::AbstractUnitRange{<:Integer}, k::Py) end else j = @pyconvert Int k begin - errset(pybuiltins.TypeError, "index must be slice or integer, got '$(pytype(k).__name__)'") + errset( + pybuiltins.TypeError, + "index must be slice or integer, got '$(pytype(k).__name__)'", + ) pythrow() end r = Int(j < 0 ? (last(x) + j + 1) : (first(x) + j)) @@ -63,7 +66,7 @@ function pyjl_getarrayindices(x::AbstractArray{T,N}, ks::Py) where {T,N} if pyistuple(ks) if pylen(ks) == N return ntuple(N) do i - k = pytuple_getitem(ks, i-1) + k = pytuple_getitem(ks, i - 1) ans = pyjl_getaxisindex(axes(x, i), k) pydel!(k) return ans @@ -113,7 +116,8 @@ function pyjlarray_delitem(x::AbstractArray{T,N}, k_::Py) where {T,N} end return Py(nothing) end -pyjl_handle_error_type(::typeof(pyjlarray_delitem), x, exc::MethodError) = exc.f === deleteat! ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(::typeof(pyjlarray_delitem), x, exc::MethodError) = + exc.f === deleteat! ? pybuiltins.TypeError : PyNULL function pyjlarray_reshape(x::AbstractArray, shape_::Py) shape = pyconvertarg(Union{Int,Vector{Int}}, shape_, "shape") @@ -163,43 +167,44 @@ end const PYBUFFERFORMAT = IdDict{Type,String}() -pybufferformat(::Type{T}) where {T} = get!(PYBUFFERFORMAT, T) do - T == Cchar ? "b" : - T == Cuchar ? "B" : - T == Cshort ? "h" : - T == Cushort ? "H" : - T == Cint ? "i" : - T == Cuint ? "I" : - T == Clong ? "l" : - T == Culong ? "L" : - T == Clonglong ? "q" : - T == Culonglong ? "Q" : - T == Float16 ? "e" : - T == Cfloat ? "f" : - T == Cdouble ? "d" : - T == Complex{Float16} ? "Ze" : - T == Complex{Cfloat} ? "Zf" : - T == Complex{Cdouble} ? "Zd" : - T == Bool ? "?" : - T == Ptr{Cvoid} ? "P" : - if isstructtype(T) && isconcretetype(T) && allocatedinline(T) - n = fieldcount(T) - flds = [] - for i = 1:n - nm = fieldname(T, i) - tp = fieldtype(T, i) - push!(flds, string(pybufferformat(tp), nm isa Symbol ? ":$nm:" : "")) - d = - (i == n ? sizeof(T) : fieldoffset(T, i + 1)) - - (fieldoffset(T, i) + sizeof(tp)) - @assert d ≥ 0 - d > 0 && push!(flds, "$(d)x") +pybufferformat(::Type{T}) where {T} = + get!(PYBUFFERFORMAT, T) do + T == Cchar ? "b" : + T == Cuchar ? "B" : + T == Cshort ? "h" : + T == Cushort ? "H" : + T == Cint ? "i" : + T == Cuint ? "I" : + T == Clong ? "l" : + T == Culong ? "L" : + T == Clonglong ? "q" : + T == Culonglong ? "Q" : + T == Float16 ? "e" : + T == Cfloat ? "f" : + T == Cdouble ? "d" : + T == Complex{Float16} ? "Ze" : + T == Complex{Cfloat} ? "Zf" : + T == Complex{Cdouble} ? "Zd" : + T == Bool ? "?" : + T == Ptr{Cvoid} ? "P" : + if isstructtype(T) && isconcretetype(T) && allocatedinline(T) + n = fieldcount(T) + flds = [] + for i = 1:n + nm = fieldname(T, i) + tp = fieldtype(T, i) + push!(flds, string(pybufferformat(tp), nm isa Symbol ? ":$nm:" : "")) + d = + (i == n ? sizeof(T) : fieldoffset(T, i + 1)) - + (fieldoffset(T, i) + sizeof(tp)) + @assert d ≥ 0 + d > 0 && push!(flds, "$(d)x") + end + string("T{", join(flds, " "), "}") + else + "$(sizeof(T))x" end - string("T{", join(flds, " "), "}") - else - "$(sizeof(T))x" end -end pyjlarray_isarrayabletype(::Type{T}) where {T} = T in ( UInt8, @@ -227,44 +232,47 @@ pyjlarray_isarrayabletype(::Type{NamedTuple{names,types}}) where {names,types} = const PYTYPESTRDESCR = IdDict{Type,Tuple{String,Py}}() -pytypestrdescr(::Type{T}) where {T} = get!(PYTYPESTRDESCR, T) do - c = Utils.islittleendian() ? '<' : '>' - T == Bool ? ("$(c)b$(sizeof(Bool))", PyNULL) : - T == Int8 ? ("$(c)i1", PyNULL) : - T == UInt8 ? ("$(c)u1", PyNULL) : - T == Int16 ? ("$(c)i2", PyNULL) : - T == UInt16 ? ("$(c)u2", PyNULL) : - T == Int32 ? ("$(c)i4", PyNULL) : - T == UInt32 ? ("$(c)u4", PyNULL) : - T == Int64 ? ("$(c)i8", PyNULL) : - T == UInt64 ? ("$(c)u8", PyNULL) : - T == Float16 ? ("$(c)f2", PyNULL) : - T == Float32 ? ("$(c)f4", PyNULL) : - T == Float64 ? ("$(c)f8", PyNULL) : - T == Complex{Float16} ? ("$(c)c4", PyNULL) : - T == Complex{Float32} ? ("$(c)c8", PyNULL) : - T == Complex{Float64} ? ("$(c)c16", PyNULL) : - if isstructtype(T) && isconcretetype(T) && Base.allocatedinline(T) - n = fieldcount(T) - flds = [] - for i = 1:n - nm = fieldname(T, i) - tp = fieldtype(T, i) - ts, ds = pytypestrdescr(tp) - isempty(ts) && return ("", PyNULL) - push!( - flds, - (nm isa Integer ? "f$(nm-1)" : string(nm), pyisnull(ds) ? ts : ds), - ) - d = (i == n ? sizeof(T) : fieldoffset(T, i + 1)) - (fieldoffset(T, i) + sizeof(tp)) - @assert d ≥ 0 - d > 0 && push!(flds, ("", "|V$(d)")) +pytypestrdescr(::Type{T}) where {T} = + get!(PYTYPESTRDESCR, T) do + c = Utils.islittleendian() ? '<' : '>' + T == Bool ? ("$(c)b$(sizeof(Bool))", PyNULL) : + T == Int8 ? ("$(c)i1", PyNULL) : + T == UInt8 ? ("$(c)u1", PyNULL) : + T == Int16 ? ("$(c)i2", PyNULL) : + T == UInt16 ? ("$(c)u2", PyNULL) : + T == Int32 ? ("$(c)i4", PyNULL) : + T == UInt32 ? ("$(c)u4", PyNULL) : + T == Int64 ? ("$(c)i8", PyNULL) : + T == UInt64 ? ("$(c)u8", PyNULL) : + T == Float16 ? ("$(c)f2", PyNULL) : + T == Float32 ? ("$(c)f4", PyNULL) : + T == Float64 ? ("$(c)f8", PyNULL) : + T == Complex{Float16} ? ("$(c)c4", PyNULL) : + T == Complex{Float32} ? ("$(c)c8", PyNULL) : + T == Complex{Float64} ? ("$(c)c16", PyNULL) : + if isstructtype(T) && isconcretetype(T) && Base.allocatedinline(T) + n = fieldcount(T) + flds = [] + for i = 1:n + nm = fieldname(T, i) + tp = fieldtype(T, i) + ts, ds = pytypestrdescr(tp) + isempty(ts) && return ("", PyNULL) + push!( + flds, + (nm isa Integer ? "f$(nm-1)" : string(nm), pyisnull(ds) ? ts : ds), + ) + d = + (i == n ? sizeof(T) : fieldoffset(T, i + 1)) - + (fieldoffset(T, i) + sizeof(tp)) + @assert d ≥ 0 + d > 0 && push!(flds, ("", "|V$(d)")) + end + ("|$(sizeof(T))V", pylist(flds)) + else + ("", PyNULL) end - ("|$(sizeof(T))V", pylist(flds)) - else - ("", PyNULL) end -end pyjlarray_array__array(x::AbstractArray) = x isa Array ? Py(nothing) : pyjl(Array(x)) pyjlarray_array__pyobjectarray(x::AbstractArray) = pyjl(PyObjectArray(x)) @@ -289,56 +297,64 @@ function pyjlarray_array_interface(x::AbstractArray{T,N}) where {T,N} errset(pybuiltins.AttributeError, "__array_interface__") return PyNULL end -pyjl_handle_error_type(::typeof(pyjlarray_array_interface), x, exc) = pybuiltins.AttributeError +pyjl_handle_error_type(::typeof(pyjlarray_array_interface), x, exc) = + pybuiltins.AttributeError function init_array() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class ArrayValue(AnyValue): - __slots__ = () - _jl_buffer_info = $(pyjl_methodnum(pyjlarray_buffer_info)) - @property - def ndim(self): - return self._jl_callmethod($(pyjl_methodnum(Py ∘ ndims))) - @property - def shape(self): - return self._jl_callmethod($(pyjl_methodnum(Py ∘ size))) - def copy(self): - return self._jl_callmethod($(pyjl_methodnum(Py ∘ copy))) - def reshape(self, shape): - return self._jl_callmethod($(pyjl_methodnum(pyjlarray_reshape)), shape) - def __bool__(self): - return bool(len(self)) - def __getitem__(self, k): - return self._jl_callmethod($(pyjl_methodnum(pyjlarray_getitem)), k) - def __setitem__(self, k, v): - self._jl_callmethod($(pyjl_methodnum(pyjlarray_setitem)), k, v) - def __delitem__(self, k): - self._jl_callmethod($(pyjl_methodnum(pyjlarray_delitem)), k) - @property - def __array_interface__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlarray_array_interface))) - def __array__(self, dtype=None): - # convert to an array-like object - arr = self + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class ArrayValue(AnyValue): + __slots__ = () + _jl_buffer_info = $(pyjl_methodnum(pyjlarray_buffer_info)) + @property + def ndim(self): + return self._jl_callmethod($(pyjl_methodnum(Py ∘ ndims))) + @property + def shape(self): + return self._jl_callmethod($(pyjl_methodnum(Py ∘ size))) + def copy(self): + return self._jl_callmethod($(pyjl_methodnum(Py ∘ copy))) + def reshape(self, shape): + return self._jl_callmethod($(pyjl_methodnum(pyjlarray_reshape)), shape) + def __bool__(self): + return bool(len(self)) + def __getitem__(self, k): + return self._jl_callmethod($(pyjl_methodnum(pyjlarray_getitem)), k) + def __setitem__(self, k, v): + self._jl_callmethod($(pyjl_methodnum(pyjlarray_setitem)), k, v) + def __delitem__(self, k): + self._jl_callmethod($(pyjl_methodnum(pyjlarray_delitem)), k) + @property + def __array_interface__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlarray_array_interface))) + def __array__(self, dtype=None): + # convert to an array-like object + arr = self + if not (hasattr(arr, "__array_interface__") or hasattr(arr, "__array_struct__")): + # the first attempt collects into an Array + arr = self._jl_callmethod($(pyjl_methodnum(pyjlarray_array__array))) if not (hasattr(arr, "__array_interface__") or hasattr(arr, "__array_struct__")): - # the first attempt collects into an Array - arr = self._jl_callmethod($(pyjl_methodnum(pyjlarray_array__array))) - if not (hasattr(arr, "__array_interface__") or hasattr(arr, "__array_struct__")): - # the second attempt collects into a PyObjectArray - arr = self._jl_callmethod($(pyjl_methodnum(pyjlarray_array__pyobjectarray))) - # convert to a numpy array if numpy is available - try: - import numpy - arr = numpy.array(arr, dtype=dtype) - except ImportError: - pass - return arr - def to_numpy(self, dtype=None, copy=True, order="K"): + # the second attempt collects into a PyObjectArray + arr = self._jl_callmethod($(pyjl_methodnum(pyjlarray_array__pyobjectarray))) + # convert to a numpy array if numpy is available + try: import numpy - return numpy.array(self, dtype=dtype, copy=copy, order=order) - """, @__FILE__(), "exec"), jl.__dict__) + arr = numpy.array(arr, dtype=dtype) + except ImportError: + pass + return arr + def to_numpy(self, dtype=None, copy=True, order="K"): + import numpy + return numpy.array(self, dtype=dtype, copy=copy, order=order) +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjlarraytype, jl.ArrayValue) end diff --git a/src/JlWrap/base.jl b/src/JlWrap/base.jl index 08793e63..008d3342 100644 --- a/src/JlWrap/base.jl +++ b/src/JlWrap/base.jl @@ -45,7 +45,8 @@ function init_base() pyconvert_add_rule("juliacall:ValueBase", Any, pyconvert_rule_jlvalue, priority) end -pyconvert_rule_jlvalue(::Type{T}, x::Py) where {T} = pyconvert_tryconvert(T, _pyjl_getvalue(x)) +pyconvert_rule_jlvalue(::Type{T}, x::Py) where {T} = + pyconvert_tryconvert(T, _pyjl_getvalue(x)) function Cjl._pyjl_callmethod(f, self_::C.PyPtr, args_::C.PyPtr, nargs::C.Py_ssize_t) @nospecialize f @@ -79,19 +80,29 @@ function Cjl._pyjl_callmethod(f, self_::C.PyPtr, args_::C.PyPtr, nargs::C.Py_ssi ans = f(self, arg1, arg2, arg3)::Py in_f = false else - errset(pybuiltins.NotImplementedError, "__jl_callmethod not implemented for this many arguments") + errset( + pybuiltins.NotImplementedError, + "__jl_callmethod not implemented for this many arguments", + ) end return incref(getptr(ans)) catch exc if exc isa PyException - Base.GC.@preserve exc C.PyErr_Restore(incref(getptr(exc._t)), incref(getptr(exc._v)), incref(getptr(exc._b))) + Base.GC.@preserve exc C.PyErr_Restore( + incref(getptr(exc._t)), + incref(getptr(exc._v)), + incref(getptr(exc._b)), + ) return C.PyNULL else try if in_f return pyjl_handle_error(f, self, exc) else - errset(pyJuliaError, pytuple((pyjlraw(exc), pyjlraw(catch_backtrace())))) + errset( + pyJuliaError, + pytuple((pyjlraw(exc), pyjlraw(catch_backtrace()))), + ) return C.PyNULL end catch diff --git a/src/JlWrap/callback.jl b/src/JlWrap/callback.jl index c25c10dd..4082f121 100644 --- a/src/JlWrap/callback.jl +++ b/src/JlWrap/callback.jl @@ -33,29 +33,40 @@ function pyjlcallback_call(self, args_::Py, kwargs_::Py) pydel!(kwargs_) ans end -pyjl_handle_error_type(::typeof(pyjlcallback_call), self, exc::MethodError) = exc.f === self ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(::typeof(pyjlcallback_call), self, exc::MethodError) = + exc.f === self ? pybuiltins.TypeError : PyNULL function init_callback() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class CallbackValue(ValueBase): - __slots__ = () - def __repr__(self): - if self._jl_isnull(): - return "" - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlcallback_repr))) - def __str__(self): - if self._jl_isnull(): - return "NULL" - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlcallback_str))) - def __call__(self, *args, **kwargs): - return self._jl_callmethod($(pyjl_methodnum(pyjlcallback_call)), args, kwargs) - """, @__FILE__(), "exec"), jl.__dict__) + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class CallbackValue(ValueBase): + __slots__ = () + def __repr__(self): + if self._jl_isnull(): + return "" + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlcallback_repr))) + def __str__(self): + if self._jl_isnull(): + return "NULL" + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlcallback_str))) + def __call__(self, *args, **kwargs): + return self._jl_callmethod($(pyjl_methodnum(pyjlcallback_call)), args, kwargs) +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjlcallbacktype, jl.CallbackValue) - pycopy!(pywrapcallback, pybuiltins.eval("lambda f: lambda *args, **kwargs: f(*args, **kwargs)", pydict())) + pycopy!( + pywrapcallback, + pybuiltins.eval("lambda f: lambda *args, **kwargs: f(*args, **kwargs)", pydict()), + ) end pyjlcallback(f) = pyjl(pyjlcallbacktype, f) @@ -71,7 +82,14 @@ The name, qualname, docstring or signature can optionally be set with `name`, `q Unlike `Py(f)` (or `pyjl(f)`), the arguments passed to `f` are always of type `Py`, i.e. they are never converted. """ -function pyfunc(f; name=nothing, qualname=name, doc=nothing, signature=nothing, wrap=pywrapcallback) +function pyfunc( + f; + name = nothing, + qualname = name, + doc = nothing, + signature = nothing, + wrap = pywrapcallback, +) f2 = ispy(f) ? f : pyjlcallback(f) if wrap isa Pair wrapargs, wrapfunc = wrap @@ -129,12 +147,12 @@ If `get`, `set` or `del` is not a Python object (e.g. if it is a `Function`) the converted to one with [`pyfunc`](@ref PythonCall.pyfunc). In particular this means the arguments passed to it are always of type `Py`. """ -pyproperty(; get=nothing, set=nothing, del=nothing, doc=nothing) = +pyproperty(; get = nothing, set = nothing, del = nothing, doc = nothing) = pybuiltins.property( fget = ispy(get) || get === nothing ? get : pyfunc(get), fset = ispy(set) || set === nothing ? set : pyfunc(set), fdel = ispy(del) || del === nothing ? del : pyfunc(del), doc = doc, ) -pyproperty(get) = pyproperty(get=get) +pyproperty(get) = pyproperty(get = get) export pyproperty diff --git a/src/JlWrap/dict.jl b/src/JlWrap/dict.jl index 4d01674a..52a61fe3 100644 --- a/src/JlWrap/dict.jl +++ b/src/JlWrap/dict.jl @@ -11,19 +11,23 @@ Base.in(v::Tuple{Any,Any}, x::DictPairSet) = Pair(v[1], v[2]) in x.dict pyjldict_iter(x::AbstractDict) = Py(Iterator(keys(x))) -pyjldict_contains(x::AbstractDict, k::Py) = Py(haskey(x, @pyconvert(keytype(x), k, return Py(false)))) +pyjldict_contains(x::AbstractDict, k::Py) = + Py(haskey(x, @pyconvert(keytype(x), k, return Py(false)))) pyjldict_clear(x::AbstractDict) = (empty!(x); Py(nothing)) pyjldict_getitem(x::AbstractDict, k::Py) = Py(x[pyconvert(keytype(x), k)]) -pyjldict_setitem(x::AbstractDict, k::Py, v::Py) = (x[pyconvertarg(keytype(x), k, "key")] = pyconvertarg(valtype(x), v, "value"); Py(nothing)) +pyjldict_setitem(x::AbstractDict, k::Py, v::Py) = + (x[pyconvertarg(keytype(x), k, "key")] = pyconvertarg(valtype(x), v, "value"); + Py(nothing)) -pyjldict_delitem(x::AbstractDict, k::Py) = (delete!(x, pyconvert(keytype(x), k)); Py(nothing)) +pyjldict_delitem(x::AbstractDict, k::Py) = + (delete!(x, pyconvert(keytype(x), k)); Py(nothing)) function pyjldict_update(x::AbstractDict, items_::Py) for item_ in items_ - (k, v) = pyconvert(Tuple{keytype(x), valtype(x)}, item_) + (k, v) = pyconvert(Tuple{keytype(x),valtype(x)}, item_) x[k] = v end Py(nothing) @@ -33,77 +37,84 @@ const pyjldicttype = pynew() function init_dict() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class DictValue(AnyValue): - __slots__ = () - _jl_undefined_ = object() - def __bool__(self): - return bool(len(self)) - def __iter__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjldict_iter))) - def __contains__(self, key): - return self._jl_callmethod($(pyjl_methodnum(pyjldict_contains)), key) - def __getitem__(self, key): - if key in self: - return self._jl_callmethod($(pyjl_methodnum(pyjldict_getitem)), key) - else: - raise KeyError(key) - def __setitem__(self, key, value): - return self._jl_callmethod($(pyjl_methodnum(pyjldict_setitem)), key, value) - def __delitem__(self, key): - if key in self: - return self._jl_callmethod($(pyjl_methodnum(pyjldict_delitem)), key) - else: - raise KeyError(key) - def keys(self): - return self._jl_callmethod($(pyjl_methodnum(Py ∘ keys))) - def values(self): - return self._jl_callmethod($(pyjl_methodnum(Py ∘ values))) - def items(self): - return self._jl_callmethod($(pyjl_methodnum(Py ∘ DictPairSet))) - def get(self, key, default=None): - if key in self: - return self[key] - else: - return default - def setdefault(self, key, default=None): - if key not in self: - self[key] = default + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class DictValue(AnyValue): + __slots__ = () + _jl_undefined_ = object() + def __bool__(self): + return bool(len(self)) + def __iter__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjldict_iter))) + def __contains__(self, key): + return self._jl_callmethod($(pyjl_methodnum(pyjldict_contains)), key) + def __getitem__(self, key): + if key in self: + return self._jl_callmethod($(pyjl_methodnum(pyjldict_getitem)), key) + else: + raise KeyError(key) + def __setitem__(self, key, value): + return self._jl_callmethod($(pyjl_methodnum(pyjldict_setitem)), key, value) + def __delitem__(self, key): + if key in self: + return self._jl_callmethod($(pyjl_methodnum(pyjldict_delitem)), key) + else: + raise KeyError(key) + def keys(self): + return self._jl_callmethod($(pyjl_methodnum(Py ∘ keys))) + def values(self): + return self._jl_callmethod($(pyjl_methodnum(Py ∘ values))) + def items(self): + return self._jl_callmethod($(pyjl_methodnum(Py ∘ DictPairSet))) + def get(self, key, default=None): + if key in self: return self[key] - def clear(self): - return self._jl_callmethod($(pyjl_methodnum(pyjldict_clear))) - def pop(self, key, default=_jl_undefined_): - if key in self: - ans = self[key] - del self[key] - return ans - elif default is self._jl_undefined_: - raise KeyError(key) - else: - return default - def popitem(self): - if len(self): - return self._jl_callmethod($(pyjl_methodnum(Py ∘ pop!))) - else: - raise KeyError() - def update(self, other=_jl_undefined_, **kwargs): - if other is self._jl_undefined_: - pass + else: + return default + def setdefault(self, key, default=None): + if key not in self: + self[key] = default + return self[key] + def clear(self): + return self._jl_callmethod($(pyjl_methodnum(pyjldict_clear))) + def pop(self, key, default=_jl_undefined_): + if key in self: + ans = self[key] + del self[key] + return ans + elif default is self._jl_undefined_: + raise KeyError(key) + else: + return default + def popitem(self): + if len(self): + return self._jl_callmethod($(pyjl_methodnum(Py ∘ pop!))) + else: + raise KeyError() + def update(self, other=_jl_undefined_, **kwargs): + if other is self._jl_undefined_: + pass + else: + if hasattr(other, "keys"): + items = ((k, other[k]) for k in other.keys()) else: - if hasattr(other, "keys"): - items = ((k, other[k]) for k in other.keys()) - else: - items = other - self._jl_callmethod($(pyjl_methodnum(pyjldict_update)), items) - if kwargs: - self.update(kwargs) - def copy(self): - return self._jl_callmethod($(pyjl_methodnum(Py ∘ copy))) - import collections.abc - collections.abc.MutableMapping.register(DictValue) - del collections - """, @__FILE__(), "exec"), jl.__dict__) + items = other + self._jl_callmethod($(pyjl_methodnum(pyjldict_update)), items) + if kwargs: + self.update(kwargs) + def copy(self): + return self._jl_callmethod($(pyjl_methodnum(Py ∘ copy))) +import collections.abc +collections.abc.MutableMapping.register(DictValue) +del collections +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjldicttype, jl.DictValue) end diff --git a/src/JlWrap/io.jl b/src/JlWrap/io.jl index 85785fee..49d9547f 100644 --- a/src/JlWrap/io.jl +++ b/src/JlWrap/io.jl @@ -3,21 +3,26 @@ const pyjlbinaryiotype = pynew() const pyjltextiotype = pynew() pyjlio_close(io::IO) = (close(io); Py(nothing)) -pyjl_handle_error_type(::typeof(pyjlio_close), io, exc) = exc isa MethodError && exc.f === close ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlio_close), io, exc) = + exc isa MethodError && exc.f === close ? pybuiltins.ValueError : PyNULL pyjlio_closed(io::IO) = Py(!isopen(io)) -pyjl_handle_error_type(::typeof(pyjlio_closed), io, exc) = exc isa MethodError && exc.f === isopen ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlio_closed), io, exc) = + exc isa MethodError && exc.f === isopen ? pybuiltins.ValueError : PyNULL pyjlio_fileno(io::IO) = Py(fd(io)) -pyjl_handle_error_type(::typeof(pyjlio_fileno), io, exc) = exc isa MethodError && exc.f === fd ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlio_fileno), io, exc) = + exc isa MethodError && exc.f === fd ? pybuiltins.ValueError : PyNULL pyjlio_flush(io::IO) = (flush(io); Py(nothing)) -pyjl_handle_error_type(::typeof(pyjlio_flush), io, exc) = exc isa MethodError && exc.f === flush ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlio_flush), io, exc) = + exc isa MethodError && exc.f === flush ? pybuiltins.ValueError : PyNULL pyjlio_isatty(io::IO) = Py(io isa Base.TTY) pyjlio_readable(io::IO) = Py(isreadable(io)) -pyjl_handle_error_type(::typeof(pyjlio_readable), io, exc) = exc isa MethodError && exc.f === isreadable ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlio_readable), io, exc) = + exc isa MethodError && exc.f === isreadable ? pybuiltins.ValueError : PyNULL function pyjlio_seek(io::IO, offset_::Py, whence_::Py) offset = pyconvertarg(Int, offset_, "offset") @@ -36,10 +41,13 @@ function pyjlio_seek(io::IO, offset_::Py, whence_::Py) seek(io, pos) Py(position(io)) end -pyjl_handle_error_type(::typeof(pyjlio_seek), io, exc) = exc isa MethodError && (exc.f === position || exc.f === seek || exc.f === seekend) ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlio_seek), io, exc) = + exc isa MethodError && (exc.f === position || exc.f === seek || exc.f === seekend) ? + pybuiltins.ValueError : PyNULL pyjlio_tell(io::IO) = Py(position(io)) -pyjl_handle_error_type(::typeof(pyjlio_tell), io, exc) = exc isa MethodError && exc.f === position ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlio_tell), io, exc) = + exc isa MethodError && exc.f === position ? pybuiltins.ValueError : PyNULL function pyjlio_truncate(io::IO, size_::Py) size = pyconvertarg(Union{Int,Nothing}, size_, "size") @@ -49,10 +57,13 @@ function pyjlio_truncate(io::IO, size_::Py) truncate(io, size) Py(size) end -pyjl_handle_error_type(::typeof(pyjlio_truncate), io, exc) = exc isa MethodError && (exc.f === position || exc.f === truncate) ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlio_truncate), io, exc) = + exc isa MethodError && (exc.f === position || exc.f === truncate) ? + pybuiltins.ValueError : PyNULL pyjlio_writable(io::IO) = Py(iswritable(io)) -pyjl_handle_error_type(::typeof(pyjlio_writable), io, exc) = exc isa MethodError && exc.f === iswritable ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlio_writable), io, exc) = + exc isa MethodError && exc.f === iswritable ? pybuiltins.ValueError : PyNULL function pyjlbinaryio_read(io::IO, size_::Py) size = pyconvertarg(Union{Int,Nothing}, size_, "size") @@ -63,7 +74,8 @@ function pyjlbinaryio_read(io::IO, size_::Py) end pybytes(buf) end -pyjl_handle_error_type(::typeof(pyjlbinaryio_read), io, exc) = exc isa MethodError && exc.f === read ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlbinaryio_read), io, exc) = + exc isa MethodError && exc.f === read ? pybuiltins.ValueError : PyNULL function pyjlbinaryio_readline(io::IO, size_::Py) size = pyconvertarg(Union{Int,Nothing}, size_, "size") @@ -78,7 +90,8 @@ function pyjlbinaryio_readline(io::IO, size_::Py) end pybytes(buf) end -pyjl_handle_error_type(::typeof(pyjlbinaryio_readline), io, exc) = exc isa MethodError && exc.f === read ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlbinaryio_readline), io, exc) = + exc isa MethodError && exc.f === read ? pybuiltins.ValueError : PyNULL function pyjlbinaryio_readinto(io::IO, b::Py) m = pybuiltins.memoryview(b) @@ -100,7 +113,8 @@ function pyjlbinaryio_readinto(io::IO, b::Py) pydel!(m) return Py(nb) end -pyjl_handle_error_type(::typeof(pyjlbinaryio_readinto), io, exc) = exc isa MethodError && exc.f === readbytes! ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlbinaryio_readinto), io, exc) = + exc isa MethodError && exc.f === readbytes! ? pybuiltins.ValueError : PyNULL function pyjlbinaryio_write(io::IO, b::Py) m = pybuiltins.memoryview(b) @@ -117,7 +131,8 @@ function pyjlbinaryio_write(io::IO, b::Py) pydel!(m) return Py(buf.len) end -pyjl_handle_error_type(::typeof(pyjlbinaryio_write), io, exc) = exc isa MethodError && exc.f === write ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjlbinaryio_write), io, exc) = + exc isa MethodError && exc.f === write ? pybuiltins.ValueError : PyNULL function pyjltextio_read(io::IO, size_::Py) size = pyconvertarg(Union{Int,Nothing}, size_, "size") @@ -139,7 +154,8 @@ function pyjltextio_read(io::IO, size_::Py) end Py(String(take!(buf))) end -pyjl_handle_error_type(::typeof(pyjltextio_read), io, exc) = exc isa MethodError && exc.f === read ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjltextio_read), io, exc) = + exc isa MethodError && exc.f === read ? pybuiltins.ValueError : PyNULL function pyjltextio_readline(io::IO, size_::Py) size = pyconvertarg(Union{Int,Nothing}, size_, "size") @@ -167,7 +183,8 @@ function pyjltextio_readline(io::IO, size_::Py) end Py(String(take!(buf))) end -pyjl_handle_error_type(::typeof(pyjltextio_readline), io, exc) = exc isa MethodError && exc.f === read ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjltextio_readline), io, exc) = + exc isa MethodError && exc.f === read ? pybuiltins.ValueError : PyNULL function pyjltextio_write(io::IO, s_::Py) if pyisstr(s_) @@ -195,105 +212,116 @@ function pyjltextio_write(io::IO, s_::Py) # TODO: is this the number of source characters, or the number of output characters? Py(length(s)) else - errset(pybuiltins.TypeError, "Argument 's' must be a 'str', got a '$(pytype(s_).__name__)'") + errset( + pybuiltins.TypeError, + "Argument 's' must be a 'str', got a '$(pytype(s_).__name__)'", + ) PyNULL end end -pyjl_handle_error_type(::typeof(pyjltextio_write), io, exc) = exc isa MethodError && exc.f === write ? pybuiltins.ValueError : PyNULL +pyjl_handle_error_type(::typeof(pyjltextio_write), io, exc) = + exc isa MethodError && exc.f === write ? pybuiltins.ValueError : PyNULL function init_io() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class IOValueBase(AnyValue): - __slots__ = () - def close(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlio_close))) - @property - def closed(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlio_closed))) - def fileno(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlio_fileno))) - def flush(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlio_flush))) - def isatty(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlio_isatty))) - def readable(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlio_readable))) - def readlines(self, hint=-1): - lines = [] - total = 0 - while hint < 0 or total < hint: - line = self.readline() - if line: - lines.append(line) - total += len(line) - else: - break - return lines - def seek(self, offset, whence=0): - return self._jl_callmethod($(pyjl_methodnum(pyjlio_seek)), offset, whence) - def seekable(self): - return True - def tell(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlio_tell))) - def truncate(self, size=None): - return self._jl_callmethod($(pyjl_methodnum(pyjlio_truncate)), size) - def writable(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlio_writable))) - def writelines(self, lines): - for line in lines: - self.write(line) - def __enter__(self): - return self - def __exit__(self, t, v, b): - self.close() - def __iter__(self): - return self - def __next__(self): + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class IOValueBase(AnyValue): + __slots__ = () + def close(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlio_close))) + @property + def closed(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlio_closed))) + def fileno(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlio_fileno))) + def flush(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlio_flush))) + def isatty(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlio_isatty))) + def readable(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlio_readable))) + def readlines(self, hint=-1): + lines = [] + total = 0 + while hint < 0 or total < hint: line = self.readline() if line: - return line + lines.append(line) + total += len(line) else: - raise StopIteration - class BinaryIOValue(IOValueBase): - __slots__ = () - def detach(self): - raise ValueError("Cannot detach '{}'.".format(type(self))) - def read(self, size=-1): - return self._jl_callmethod($(pyjl_methodnum(pyjlbinaryio_read)), size) - def read1(self, size=-1): - return self.read(size) - def readline(self, size=-1): - return self._jl_callmethod($(pyjl_methodnum(pyjlbinaryio_readline)), size) - def readinto(self, b): - return self._jl_callmethod($(pyjl_methodnum(pyjlbinaryio_readinto)), b) - def readinto1(self, b): - return self.readinto(b) - def write(self, b): - return self._jl_callmethod($(pyjl_methodnum(pyjlbinaryio_write)), b) - class TextIOValue(IOValueBase): - __slots__ = () - @property - def encoding(self): - return "UTF-8" - @property - def errors(self): - return "strict" - def detach(self): - raise ValueError("Cannot detach '{}'.".format(type(self))) - def read(self, size=-1): - return self._jl_callmethod($(pyjl_methodnum(pyjltextio_read)), size) - def readline(self, size=-1): - return self._jl_callmethod($(pyjl_methodnum(pyjltextio_readline)), size) - def write(self, s): - return self._jl_callmethod($(pyjl_methodnum(pyjltextio_write)), s) - import io - io.IOBase.register(IOValueBase) - io.BufferedIOBase.register(BinaryIOValue) - io.TextIOBase.register(TextIOValue) - del io - """, @__FILE__(), "exec"), jl.__dict__) + break + return lines + def seek(self, offset, whence=0): + return self._jl_callmethod($(pyjl_methodnum(pyjlio_seek)), offset, whence) + def seekable(self): + return True + def tell(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlio_tell))) + def truncate(self, size=None): + return self._jl_callmethod($(pyjl_methodnum(pyjlio_truncate)), size) + def writable(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlio_writable))) + def writelines(self, lines): + for line in lines: + self.write(line) + def __enter__(self): + return self + def __exit__(self, t, v, b): + self.close() + def __iter__(self): + return self + def __next__(self): + line = self.readline() + if line: + return line + else: + raise StopIteration +class BinaryIOValue(IOValueBase): + __slots__ = () + def detach(self): + raise ValueError("Cannot detach '{}'.".format(type(self))) + def read(self, size=-1): + return self._jl_callmethod($(pyjl_methodnum(pyjlbinaryio_read)), size) + def read1(self, size=-1): + return self.read(size) + def readline(self, size=-1): + return self._jl_callmethod($(pyjl_methodnum(pyjlbinaryio_readline)), size) + def readinto(self, b): + return self._jl_callmethod($(pyjl_methodnum(pyjlbinaryio_readinto)), b) + def readinto1(self, b): + return self.readinto(b) + def write(self, b): + return self._jl_callmethod($(pyjl_methodnum(pyjlbinaryio_write)), b) +class TextIOValue(IOValueBase): + __slots__ = () + @property + def encoding(self): + return "UTF-8" + @property + def errors(self): + return "strict" + def detach(self): + raise ValueError("Cannot detach '{}'.".format(type(self))) + def read(self, size=-1): + return self._jl_callmethod($(pyjl_methodnum(pyjltextio_read)), size) + def readline(self, size=-1): + return self._jl_callmethod($(pyjl_methodnum(pyjltextio_readline)), size) + def write(self, s): + return self._jl_callmethod($(pyjl_methodnum(pyjltextio_write)), s) +import io +io.IOBase.register(IOValueBase) +io.BufferedIOBase.register(BinaryIOValue) +io.TextIOBase.register(TextIOValue) +del io +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjliobasetype, jl.IOValueBase) pycopy!(pyjlbinaryiotype, jl.BinaryIOValue) pycopy!(pyjltextiotype, jl.TextIOValue) diff --git a/src/JlWrap/iter.jl b/src/JlWrap/iter.jl index 90d24537..787bd46f 100644 --- a/src/JlWrap/iter.jl +++ b/src/JlWrap/iter.jl @@ -27,15 +27,22 @@ end function init_iter() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class IteratorValue(AnyValue): - __slots__ = () - def __iter__(self): - return self - def __next__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjliter_next))) - """, @__FILE__(), "exec"), jl.__dict__) + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class IteratorValue(AnyValue): + __slots__ = () + def __iter__(self): + return self + def __next__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjliter_next))) +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjlitertype, jl.IteratorValue) end diff --git a/src/JlWrap/module.jl b/src/JlWrap/module.jl index 8d879ae5..2f636e08 100644 --- a/src/JlWrap/module.jl +++ b/src/JlWrap/module.jl @@ -15,15 +15,22 @@ end function init_module() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class ModuleValue(AnyValue): - __slots__ = () - def __dir__(self): - return ValueBase.__dir__(self) + self._jl_callmethod($(pyjl_methodnum(pyjlmodule_dir))) - def seval(self, expr): - return self._jl_callmethod($(pyjl_methodnum(pyjlmodule_seval)), expr) - """, @__FILE__(), "exec"), jl.__dict__) + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class ModuleValue(AnyValue): + __slots__ = () + def __dir__(self): + return ValueBase.__dir__(self) + self._jl_callmethod($(pyjl_methodnum(pyjlmodule_dir))) + def seval(self, expr): + return self._jl_callmethod($(pyjl_methodnum(pyjlmodule_seval)), expr) +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjlmoduletype, jl.ModuleValue) end diff --git a/src/JlWrap/number.jl b/src/JlWrap/number.jl index 1ed4013c..ebc5b2a6 100644 --- a/src/JlWrap/number.jl +++ b/src/JlWrap/number.jl @@ -5,7 +5,7 @@ const pyjlrationaltype = pynew() const pyjlintegertype = pynew() struct pyjlnumber_op{OP} - op :: OP + op::OP end (op::pyjlnumber_op)(self) = Py(op.op(self)) function (op::pyjlnumber_op)(self, other_::Py) @@ -32,10 +32,11 @@ function (op::pyjlnumber_op)(self, other_::Py, other2_::Py) end Py(op.op(self, other, other2)) end -pyjl_handle_error_type(op::pyjlnumber_op, self, exc) = exc isa MethodError && exc.f === op.op ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(op::pyjlnumber_op, self, exc) = + exc isa MethodError && exc.f === op.op ? pybuiltins.TypeError : PyNULL struct pyjlnumber_rev_op{OP} - op :: OP + op::OP end function (op::pyjlnumber_rev_op)(self, other_::Py) if pyisjl(other_) @@ -61,16 +62,20 @@ function (op::pyjlnumber_rev_op)(self, other_::Py, other2_::Py) end Py(op.op(other, self, other2)) end -pyjl_handle_error_type(op::pyjlnumber_rev_op, self, exc) = exc isa MethodError && exc.f === op.op ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(op::pyjlnumber_rev_op, self, exc) = + exc isa MethodError && exc.f === op.op ? pybuiltins.TypeError : PyNULL pyjlreal_trunc(self::Real) = Py(trunc(Integer, self)) -pyjl_handle_error_type(::typeof(pyjlreal_trunc), self, exc::MethodError) = exc.f === trunc ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(::typeof(pyjlreal_trunc), self, exc::MethodError) = + exc.f === trunc ? pybuiltins.TypeError : PyNULL pyjlreal_floor(self::Real) = Py(floor(Integer, self)) -pyjl_handle_error_type(::typeof(pyjlreal_floor), self, exc::MethodError) = exc.f === floor ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(::typeof(pyjlreal_floor), self, exc::MethodError) = + exc.f === floor ? pybuiltins.TypeError : PyNULL pyjlreal_ceil(self::Real) = Py(ceil(Integer, self)) -pyjl_handle_error_type(::typeof(pyjlreal_ceil), self, exc::MethodError) = exc.f === ceil ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(::typeof(pyjlreal_ceil), self, exc::MethodError) = + exc.f === ceil ? pybuiltins.TypeError : PyNULL function pyjlreal_round(self::Real, ndigits_::Py) ndigits = pyconvertarg(Union{Int,Nothing}, ndigits_, "ndigits") @@ -81,144 +86,152 @@ function pyjlreal_round(self::Real, ndigits_::Py) Py(round(self; digits = ndigits)) end end -pyjl_handle_error_type(::typeof(pyjlreal_round), self, exc::MethodError) = exc.f === round ? pybuiltins.TypeError : PyNULL +pyjl_handle_error_type(::typeof(pyjlreal_round), self, exc::MethodError) = + exc.f === round ? pybuiltins.TypeError : PyNULL function init_number() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class NumberValue(AnyValue): - __slots__ = () - def __bool__(self): - return not self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(iszero)))) - def __add__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(+))), other) - def __sub__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(-))), other) - def __mul__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(*))), other) - def __truediv__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(/))), other) - def __floordiv__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(÷))), other) - def __mod__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(%))), other) - def __pow__(self, other, modulo=None): - if modulo is None: - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(^))), other) - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(powermod))), other, modulo) - def __lshift__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(<<))), other) - def __rshift__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(>>))), other) - def __and__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(&))), other) - def __xor__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(⊻))), other) - def __or__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(|))), other) - def __radd__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(+))), other) - def __rsub__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(-))), other) - def __rmul__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(*))), other) - def __rtruediv__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(/))), other) - def __rfloordiv__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(÷))), other) - def __rmod__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(%))), other) - def __rpow__(self, other, modulo=None): - if modulo is None: - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(^))), other) - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(powermod))), other, modulo) - def __rlshift__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(<<))), other) - def __rrshift__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(>>))), other) - def __rand__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(&))), other) - def __rxor__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(⊻))), other) - def __ror__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(|))), other) - def __eq__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(==))), other) - def __ne__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(!=))), other) - def __le__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(≤))), other) - def __lt__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(<))), other) - def __ge__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(≥))), other) - def __gt__(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(>))), other) - class ComplexValue(NumberValue): - __slots__ = () - def __complex__(self): - return self._jl_callmethod($(pyjl_methodnum(pycomplex))) - @property - def real(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(real)))) - @property - def imag(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(imag)))) - def conjugate(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(conj)))) - class RealValue(ComplexValue): - __slots__ = () - def __float__(self): - return self._jl_callmethod($(pyjl_methodnum(pyfloat))) - @property - def real(self): - return self - @property - def imag(self): - return 0 - def conjugate(self): - return self - def __complex__(self): - return complex(float(self)) - def __trunc__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlreal_trunc))) - def __floor__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlreal_floor))) - def __ceil__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlreal_ceil))) - def __round__(self, ndigits=None): - return self._jl_callmethod($(pyjl_methodnum(pyjlreal_round)), ndigits) - class RationalValue(RealValue): - __slots__ = () - @property - def numerator(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(numerator)))) - @property - def denominator(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(denominator)))) - class IntegerValue(RationalValue): - __slots__ = () - def __int__(self): - return self._jl_callmethod($(pyjl_methodnum(pyint))) - def __index__(self): - return self.__int__() - @property - def numerator(self): - return self - @property - def denominator(self): - return 1 - import numbers - numbers.Number.register(NumberValue) - numbers.Complex.register(ComplexValue) - numbers.Real.register(RealValue) - numbers.Rational.register(RationalValue) - numbers.Integral.register(IntegerValue) - del numbers - """, @__FILE__(), "exec"), jl.__dict__) + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class NumberValue(AnyValue): + __slots__ = () + def __bool__(self): + return not self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(iszero)))) + def __add__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(+))), other) + def __sub__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(-))), other) + def __mul__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(*))), other) + def __truediv__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(/))), other) + def __floordiv__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(÷))), other) + def __mod__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(%))), other) + def __pow__(self, other, modulo=None): + if modulo is None: + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(^))), other) + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(powermod))), other, modulo) + def __lshift__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(<<))), other) + def __rshift__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(>>))), other) + def __and__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(&))), other) + def __xor__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(⊻))), other) + def __or__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(|))), other) + def __radd__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(+))), other) + def __rsub__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(-))), other) + def __rmul__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(*))), other) + def __rtruediv__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(/))), other) + def __rfloordiv__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(÷))), other) + def __rmod__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(%))), other) + def __rpow__(self, other, modulo=None): + if modulo is None: + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(^))), other) + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(powermod))), other, modulo) + def __rlshift__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(<<))), other) + def __rrshift__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(>>))), other) + def __rand__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(&))), other) + def __rxor__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(⊻))), other) + def __ror__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_rev_op(|))), other) + def __eq__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(==))), other) + def __ne__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(!=))), other) + def __le__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(≤))), other) + def __lt__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(<))), other) + def __ge__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(≥))), other) + def __gt__(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(>))), other) +class ComplexValue(NumberValue): + __slots__ = () + def __complex__(self): + return self._jl_callmethod($(pyjl_methodnum(pycomplex))) + @property + def real(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(real)))) + @property + def imag(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(imag)))) + def conjugate(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(conj)))) +class RealValue(ComplexValue): + __slots__ = () + def __float__(self): + return self._jl_callmethod($(pyjl_methodnum(pyfloat))) + @property + def real(self): + return self + @property + def imag(self): + return 0 + def conjugate(self): + return self + def __complex__(self): + return complex(float(self)) + def __trunc__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlreal_trunc))) + def __floor__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlreal_floor))) + def __ceil__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlreal_ceil))) + def __round__(self, ndigits=None): + return self._jl_callmethod($(pyjl_methodnum(pyjlreal_round)), ndigits) +class RationalValue(RealValue): + __slots__ = () + @property + def numerator(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(numerator)))) + @property + def denominator(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlnumber_op(denominator)))) +class IntegerValue(RationalValue): + __slots__ = () + def __int__(self): + return self._jl_callmethod($(pyjl_methodnum(pyint))) + def __index__(self): + return self.__int__() + @property + def numerator(self): + return self + @property + def denominator(self): + return 1 +import numbers +numbers.Number.register(NumberValue) +numbers.Complex.register(ComplexValue) +numbers.Real.register(RealValue) +numbers.Rational.register(RationalValue) +numbers.Integral.register(IntegerValue) +del numbers +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjlnumbertype, jl.NumberValue) pycopy!(pyjlcomplextype, jl.ComplexValue) pycopy!(pyjlrealtype, jl.RealValue) diff --git a/src/JlWrap/objectarray.jl b/src/JlWrap/objectarray.jl index 2aab4be2..a98189e8 100644 --- a/src/JlWrap/objectarray.jl +++ b/src/JlWrap/objectarray.jl @@ -17,10 +17,14 @@ const PyObjectVector = PyObjectArray{1} const PyObjectMatrix = PyObjectArray{2} export PyObjectVector, PyObjectMatrix, PyObjectArray -PyObjectArray{N}(undef::UndefInitializer, dims::Vararg{Integer,N}) where {N} = PyObjectArray(undef, dims) -PyObjectArray(undef::UndefInitializer, dims::NTuple{N,Integer}) where {N} = PyObjectArray{N}(undef, dims) -PyObjectArray(undef::UndefInitializer, dims::Vararg{Integer,N}) where {N} = PyObjectArray{N}(undef, dims) -PyObjectArray{N}(x::AbstractArray{T,N}) where {T,N} = copyto!(PyObjectArray{N}(undef, size(x)), x) +PyObjectArray{N}(undef::UndefInitializer, dims::Vararg{Integer,N}) where {N} = + PyObjectArray(undef, dims) +PyObjectArray(undef::UndefInitializer, dims::NTuple{N,Integer}) where {N} = + PyObjectArray{N}(undef, dims) +PyObjectArray(undef::UndefInitializer, dims::Vararg{Integer,N}) where {N} = + PyObjectArray{N}(undef, dims) +PyObjectArray{N}(x::AbstractArray{T,N}) where {T,N} = + copyto!(PyObjectArray{N}(undef, size(x)), x) PyObjectArray(x::AbstractArray{T,N}) where {T,N} = PyObjectArray{N}(x) pyobjectarray_finalizer(x::PyObjectArray) = GC.enqueue_all(x.ptrs) diff --git a/src/JlWrap/raw.jl b/src/JlWrap/raw.jl index a531df37..26456b21 100644 --- a/src/JlWrap/raw.jl +++ b/src/JlWrap/raw.jl @@ -79,55 +79,63 @@ function pyjlraw_delitem(self, k_::Py) end pyjlraw_bool(self::Bool) = Py(self) -pyjlraw_bool(self) = (errset(pybuiltins.TypeError, "Only Julia 'Bool' can be tested for truthyness"); PyNULL) +pyjlraw_bool(self) = + (errset(pybuiltins.TypeError, "Only Julia 'Bool' can be tested for truthyness"); PyNULL) function init_raw() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class RawValue(ValueBase): - __slots__ = () - def __repr__(self): - if self._jl_isnull(): - return "" - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlraw_repr))) - def __str__(self): - if self._jl_isnull(): - return "NULL" - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlraw_str))) - def __getattr__(self, k): + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class RawValue(ValueBase): + __slots__ = () + def __repr__(self): + if self._jl_isnull(): + return "" + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlraw_repr))) + def __str__(self): + if self._jl_isnull(): + return "NULL" + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlraw_str))) + def __getattr__(self, k): + if k.startswith("__") and k.endswith("__"): + raise AttributeError(k) + else: + return self._jl_callmethod($(pyjl_methodnum(pyjlraw_getattr)), k) + def __setattr__(self, k, v): + try: + ValueBase.__setattr__(self, k, v) + except AttributeError: if k.startswith("__") and k.endswith("__"): - raise AttributeError(k) - else: - return self._jl_callmethod($(pyjl_methodnum(pyjlraw_getattr)), k) - def __setattr__(self, k, v): - try: - ValueBase.__setattr__(self, k, v) - except AttributeError: - if k.startswith("__") and k.endswith("__"): - raise - else: - return - self._jl_callmethod($(pyjl_methodnum(pyjlraw_setattr)), k, v) - def __dir__(self): - return ValueBase.__dir__(self) + self._jl_callmethod($(pyjl_methodnum(pyjlraw_dir))) - def __call__(self, *args, **kwargs): - return self._jl_callmethod($(pyjl_methodnum(pyjlraw_call)), args, kwargs) - def __len__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlraw_len))) - def __getitem__(self, k): - return self._jl_callmethod($(pyjl_methodnum(pyjlraw_getitem)), k) - def __setitem__(self, k, v): - self._jl_callmethod($(pyjl_methodnum(pyjlraw_setitem)), k, v) - def __delitem__(self, k): - self._jl_callmethod($(pyjl_methodnum(pyjlraw_delitem)), k) - def __bool__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlraw_bool))) - def _jl_any(self): - return self._jl_callmethod($(pyjl_methodnum(pyjl))) - """, @__FILE__(), "exec"), jl.__dict__) + raise + else: + return + self._jl_callmethod($(pyjl_methodnum(pyjlraw_setattr)), k, v) + def __dir__(self): + return ValueBase.__dir__(self) + self._jl_callmethod($(pyjl_methodnum(pyjlraw_dir))) + def __call__(self, *args, **kwargs): + return self._jl_callmethod($(pyjl_methodnum(pyjlraw_call)), args, kwargs) + def __len__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlraw_len))) + def __getitem__(self, k): + return self._jl_callmethod($(pyjl_methodnum(pyjlraw_getitem)), k) + def __setitem__(self, k, v): + self._jl_callmethod($(pyjl_methodnum(pyjlraw_setitem)), k, v) + def __delitem__(self, k): + self._jl_callmethod($(pyjl_methodnum(pyjlraw_delitem)), k) + def __bool__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlraw_bool))) + def _jl_any(self): + return self._jl_callmethod($(pyjl_methodnum(pyjl))) +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjlrawtype, jl.RawValue) end diff --git a/src/JlWrap/set.jl b/src/JlWrap/set.jl index 38c9b82d..7b7b08e0 100644 --- a/src/JlWrap/set.jl +++ b/src/JlWrap/set.jl @@ -1,6 +1,7 @@ const pyjlsettype = pynew() -pyjlset_add(x::AbstractSet, v::Py) = (push!(x, pyconvertarg(eltype(x), v, "value")); Py(nothing)) +pyjlset_add(x::AbstractSet, v::Py) = + (push!(x, pyconvertarg(eltype(x), v, "value")); Py(nothing)) function pyjlset_discard(x::AbstractSet, v_::Py) v = @pyconvert(eltype(x), v_, return Py(nothing)) @@ -75,50 +76,57 @@ end function init_set() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class SetValue(AnyValue): - __slots__ = () - def __bool__(self): - return bool(len(self)) - def add(self, value): - return self._jl_callmethod($(pyjl_methodnum(pyjlset_add)), value) - def discard(self, value): - return self._jl_callmethod($(pyjl_methodnum(pyjlset_discard)), value) - def clear(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlset_clear))) - def copy(self): - return self._jl_callmethod($(pyjl_methodnum(Py ∘ copy))) - def pop(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlset_pop))) - def remove(self, value): - return self._jl_callmethod($(pyjl_methodnum(pyjlset_remove)), value) - def difference(self, other): - return set(self).difference(other) - def intersection(self, other): - return set(self).intersection(other) - def symmetric_difference(self, other): - return set(self).symmetric_difference(other) - def union(self, other): - return set(self).union(other) - def isdisjoint(self, other): - return set(self).isdisjoint(other) - def issubset(self, other): - return set(self).issubset(other) - def issuperset(self, other): - return set(self).issuperset(other) - def difference_update(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlset_difference_update)), other) - def intersection_update(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlset_intersection_update)), other) - def symmetric_difference_update(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlset_symmetric_difference_update)), other) - def update(self, other): - return self._jl_callmethod($(pyjl_methodnum(pyjlset_update)), other) - import collections.abc - collections.abc.MutableSet.register(SetValue) - del collections - """, @__FILE__(), "exec"), jl.__dict__) + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class SetValue(AnyValue): + __slots__ = () + def __bool__(self): + return bool(len(self)) + def add(self, value): + return self._jl_callmethod($(pyjl_methodnum(pyjlset_add)), value) + def discard(self, value): + return self._jl_callmethod($(pyjl_methodnum(pyjlset_discard)), value) + def clear(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlset_clear))) + def copy(self): + return self._jl_callmethod($(pyjl_methodnum(Py ∘ copy))) + def pop(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlset_pop))) + def remove(self, value): + return self._jl_callmethod($(pyjl_methodnum(pyjlset_remove)), value) + def difference(self, other): + return set(self).difference(other) + def intersection(self, other): + return set(self).intersection(other) + def symmetric_difference(self, other): + return set(self).symmetric_difference(other) + def union(self, other): + return set(self).union(other) + def isdisjoint(self, other): + return set(self).isdisjoint(other) + def issubset(self, other): + return set(self).issubset(other) + def issuperset(self, other): + return set(self).issuperset(other) + def difference_update(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlset_difference_update)), other) + def intersection_update(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlset_intersection_update)), other) + def symmetric_difference_update(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlset_symmetric_difference_update)), other) + def update(self, other): + return self._jl_callmethod($(pyjl_methodnum(pyjlset_update)), other) +import collections.abc +collections.abc.MutableSet.register(SetValue) +del collections +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjlsettype, jl.SetValue) end diff --git a/src/JlWrap/type.jl b/src/JlWrap/type.jl index ef079f5c..72a2f992 100644 --- a/src/JlWrap/type.jl +++ b/src/JlWrap/type.jl @@ -13,17 +13,24 @@ end function init_type() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class TypeValue(AnyValue): - __slots__ = () - def __getitem__(self, k): - return self._jl_callmethod($(pyjl_methodnum(pyjltype_getitem)), k) - def __setitem__(self, k, v): - raise TypeError("not supported") - def __delitem__(self, k): - raise TypeError("not supported") - """, @__FILE__(), "exec"), jl.__dict__) + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class TypeValue(AnyValue): + __slots__ = () + def __getitem__(self, k): + return self._jl_callmethod($(pyjl_methodnum(pyjltype_getitem)), k) + def __setitem__(self, k, v): + raise TypeError("not supported") + def __delitem__(self, k): + raise TypeError("not supported") +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjltypetype, jl.TypeValue) end diff --git a/src/JlWrap/vector.jl b/src/JlWrap/vector.jl index 9f728625..3c71e5b9 100644 --- a/src/JlWrap/vector.jl +++ b/src/JlWrap/vector.jl @@ -12,10 +12,10 @@ function pyjlvector_sort(x::AbstractVector, reverse_::Py, key_::Py) pydel!(reverse_) key = pyconvertarg(Any, key_, "size") if key === nothing - sort!(x, rev=reverse) + sort!(x, rev = reverse) pydel!(key_) else - sort!(x, rev=reverse, by=key) + sort!(x, rev = reverse, by = key) end Py(nothing) end @@ -39,12 +39,12 @@ function pyjlvector_insert(x::AbstractVector, k_::Py, v_::Py) pydel!(k_) a = axes(x, 1) k′ = k < 0 ? (last(a) + 1 + k) : (first(a) + k) - if checkbounds(Bool, x, k′) || k′ == last(a)+1 + if checkbounds(Bool, x, k′) || k′ == last(a) + 1 v = pyconvertarg(eltype(x), v_, "value") insert!(x, k′, v) return Py(nothing) else - errset(pybuiltins.IndexError, "array index out of bounds"); + errset(pybuiltins.IndexError, "array index out of bounds") return PyNULL end end @@ -119,38 +119,45 @@ end function init_vector() jl = pyjuliacallmodule - pybuiltins.exec(pybuiltins.compile(""" - $("\n"^(@__LINE__()-1)) - class VectorValue(ArrayValue): - __slots__ = () - def resize(self, size): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_resize)), size) - def sort(self, reverse=False, key=None): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_sort)), reverse, key) - def reverse(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_reverse))) - def clear(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_clear))) - def __reversed__(self): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_reversed))) - def insert(self, index, value): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_insert)), index, value) - def append(self, value): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_append)), value) - def extend(self, values): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_extend)), values) - def pop(self, index=-1): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_pop)), index) - def remove(self, value): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_remove)), value) - def index(self, value): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_index)), value) - def count(self, value): - return self._jl_callmethod($(pyjl_methodnum(pyjlvector_count)), value) - import collections.abc - collections.abc.MutableSequence.register(VectorValue) - del collections - """, @__FILE__(), "exec"), jl.__dict__) + pybuiltins.exec( + pybuiltins.compile( + """ +$("\n"^(@__LINE__()-1)) +class VectorValue(ArrayValue): + __slots__ = () + def resize(self, size): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_resize)), size) + def sort(self, reverse=False, key=None): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_sort)), reverse, key) + def reverse(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_reverse))) + def clear(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_clear))) + def __reversed__(self): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_reversed))) + def insert(self, index, value): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_insert)), index, value) + def append(self, value): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_append)), value) + def extend(self, values): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_extend)), values) + def pop(self, index=-1): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_pop)), index) + def remove(self, value): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_remove)), value) + def index(self, value): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_index)), value) + def count(self, value): + return self._jl_callmethod($(pyjl_methodnum(pyjlvector_count)), value) +import collections.abc +collections.abc.MutableSequence.register(VectorValue) +del collections +""", + @__FILE__(), + "exec", + ), + jl.__dict__, + ) pycopy!(pyjlvectortype, jl.VectorValue) end diff --git a/src/PyMacro/PyMacro.jl b/src/PyMacro/PyMacro.jl index 87087221..0e978eb6 100644 --- a/src/PyMacro/PyMacro.jl +++ b/src/PyMacro/PyMacro.jl @@ -19,7 +19,25 @@ Provides the `@py` macro. module PyMacro using ..Core -using ..Core: pyisnot, pynotin, BUILTINS, pynew, pycallargs, pydel!, pycopy!, pystr_intern!, pynulltuple, pytuple_setitem, pyset_add, pyisnull, unsafe_pynext, pydict_setitem, pylist_setitem, pynulllist, pybool_asbool, pythrow +using ..Core: + pyisnot, + pynotin, + BUILTINS, + pynew, + pycallargs, + pydel!, + pycopy!, + pystr_intern!, + pynulltuple, + pytuple_setitem, + pyset_add, + pyisnull, + unsafe_pynext, + pydict_setitem, + pylist_setitem, + pynulllist, + pybool_asbool, + pythrow using MacroTools: MacroTools, @capture, isexpr @@ -135,7 +153,7 @@ Base.@kwdef mutable struct PyMacroState inits::Vector{Any} = [] end -function py_macro_err(st, ex, msg=nothing) +function py_macro_err(st, ex, msg = nothing) ex2 = ex isa Expr ? Expr(ex.head, [arg isa Expr ? :__ : arg for arg in ex.args]...) : ex message = "@py syntax error: $ex2" if msg !== nothing @@ -152,12 +170,32 @@ py_macro_del(body, var, tmp) = push!(body, :($pydel!($var))) end -ismacroexpr(ex, name) = isexpr(ex, :macrocall) && (ex.args[1] === Symbol(name) || ex.args[1] === GlobalRef(Base.Core, Symbol(name))) +ismacroexpr(ex, name) = + isexpr(ex, :macrocall) && + (ex.args[1] === Symbol(name) || ex.args[1] === GlobalRef(Base.Core, Symbol(name))) -function py_macro_lower(st, body, ans, ex; flavour=:expr) +function py_macro_lower(st, body, ans, ex; flavour = :expr) # scalar literals - if ex isa Union{Nothing,String,Bool,Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt,Float16,Float32,Float64} + if ex isa Union{ + Nothing, + String, + Bool, + Int8, + Int16, + Int32, + Int64, + Int128, + UInt8, + UInt16, + UInt32, + UInt64, + UInt128, + BigInt, + Float16, + Float32, + Float64, + } x = get!(pynew, st.consts, ex) py_macro_assign(body, ans, x) return false @@ -224,11 +262,21 @@ function py_macro_lower(st, body, ans, ex; flavour=:expr) # x + y + z + ... elseif @capture(ex, +(ax_, ay_, az_, args__)) - return py_macro_lower(st, body, ans, foldl((x, y) -> :($x + $y), (ax, ay, az, args...))) + return py_macro_lower( + st, + body, + ans, + foldl((x, y) -> :($x + $y), (ax, ay, az, args...)), + ) # x * y * z * ... elseif @capture(ex, *(ax_, ay_, az_, args__)) - return py_macro_lower(st, body, ans, foldl((x, y) -> :($x * $y), (ax, ay, az, args...))) + return py_macro_lower( + st, + body, + ans, + foldl((x, y) -> :($x * $y), (ax, ay, az, args...)), + ) # f(args...; kwargs...) elseif isexpr(ex, :call) @@ -309,7 +357,12 @@ function py_macro_lower(st, body, ans, ex; flavour=:expr) @gensym f args kwargs tf = py_macro_lower(st, body, f, af) targs = py_macro_lower(st, body, args, Expr(:tuple, aargs...)) - tkwargs = py_macro_lower(st, body, kwargs, Expr(:braces, Expr(:parameters), akwargs...)) + tkwargs = py_macro_lower( + st, + body, + kwargs, + Expr(:braces, Expr(:parameters), akwargs...), + ) py_macro_assign(body, ans, :($pycallargs($f, $args, $kwargs))) py_macro_del(body, f, tf) py_macro_del(body, args, targs) @@ -344,7 +397,13 @@ function py_macro_lower(st, body, ans, ex; flavour=:expr) py_macro_assign(body, ans, :($pynulltuple($(length(ex.args))))) @gensym a for (i, aa) in enumerate(ex.args) - ta = py_macro_lower(st, body, a, aa, flavour=flavour == :index ? :index : :expr) + ta = py_macro_lower( + st, + body, + a, + aa, + flavour = flavour == :index ? :index : :expr, + ) push!(body, :($pytuple_setitem($ans, $(i - 1), $a))) py_macro_del(body, a, ta) end @@ -379,7 +438,9 @@ function py_macro_lower(st, body, ans, ex; flavour=:expr) # # e.g. these are sets: {x, y}, {x...} # e.g. these are dicts: {}, {x, y;}, {k=x}, {k=>x} - if isempty(ex.args) || any(isexpr(arg, :parameters, :(=), :kw) || @capture(arg, k_:v_) for arg in ex.args) + if isempty(ex.args) || any( + isexpr(arg, :parameters, :(=), :kw) || @capture(arg, k_:v_) for arg in ex.args + ) aargs = [] for a in ex.args if isexpr(a, :parameters) @@ -395,7 +456,11 @@ function py_macro_lower(st, body, ans, ex; flavour=:expr) py_macro_err(st, aa, "splatting into dicts not implemented") elseif isexpr(aa, :kw, :(=)) ak, av = aa.args - ak isa Symbol || py_macro_err(st, aa, "key of `key=value` must be a symbol - did you mean `key:value`?") + ak isa Symbol || py_macro_err( + st, + aa, + "key of `key=value` must be a symbol - did you mean `key:value`?", + ) tk = py_macro_lower(st, body, k, string(ak)) tv = py_macro_lower(st, body, v, av) push!(body, :($pydict_setitem($ans, $k, $v))) @@ -446,9 +511,9 @@ function py_macro_lower(st, body, ans, ex; flavour=:expr) @gensym x k tx = py_macro_lower(st, body, x, ax) if length(ak) == 1 - tk = py_macro_lower(st, body, k, ak[1]; flavour=:index) + tk = py_macro_lower(st, body, k, ak[1]; flavour = :index) else - tk = py_macro_lower(st, body, k, Expr(:tuple, ak...); flavour=:index) + tk = py_macro_lower(st, body, k, Expr(:tuple, ak...); flavour = :index) end py_macro_assign(body, ans, :($pygetitem($x, $k))) py_macro_del(body, x, tx) @@ -485,16 +550,20 @@ function py_macro_lower(st, body, ans, ex; flavour=:expr) @gensym x k tx = py_macro_lower(st, body, x, ax) if length(ak) == 1 - tk = py_macro_lower(st, body, k, ak[1], flavour=:index) + tk = py_macro_lower(st, body, k, ak[1], flavour = :index) else - tk = py_macro_lower(st, body, k, Expr(:tuple, ak...), flavour=:index) + tk = py_macro_lower(st, body, k, Expr(:tuple, ak...), flavour = :index) end push!(body, :($pydelitem($x, $k))) py_macro_del(body, x, tx) py_macro_del(body, k, tk) else - py_macro_err(st, ex, "@del argument must be an attribute or indexing expression") + py_macro_err( + st, + ex, + "@del argument must be an attribute or indexing expression", + ) end end py_macro_assign(body, ans, nothing) @@ -515,7 +584,13 @@ function py_macro_lower(st, body, ans, ex; flavour=:expr) x = pynew() args = [isexpr(arg, :(=)) ? Expr(:kw, arg.args...) : arg for arg in args] filename = "$(st.src.file):$(st.src.line)" - push!(st.inits, :($pycopy!($x, $pybuiltins.compile($code, filename=$filename, mode=$mode, $(args...))))) + push!( + st.inits, + :($pycopy!( + $x, + $pybuiltins.compile($code, filename = $filename, mode = $mode, $(args...)), + )), + ) py_macro_assign(body, ans, x) return false @@ -597,7 +672,10 @@ function py_macro_lower(st, body, ans, ex; flavour=:expr) tx || push!(body3, :($ans = $pynew($Py($ans)))) ty || push!(body2, :($ans = $pynew($Py($ans)))) end - push!(body, Expr(:if, :($pytruth($ans)), Expr(:block, body2...), Expr(:block, body3...))) + push!( + body, + Expr(:if, :($pytruth($ans)), Expr(:block, body2...), Expr(:block, body3...)), + ) return t # x || y @@ -613,7 +691,10 @@ function py_macro_lower(st, body, ans, ex; flavour=:expr) tx || push!(body2, :($ans = $pynew($Py($ans)))) ty || push!(body3, :($ans = $pynew($Py($ans)))) end - push!(body, Expr(:if, :($pytruth($ans)), Expr(:block, body2...), Expr(:block, body3...))) + push!( + body, + Expr(:if, :($pytruth($ans)), Expr(:block, body2...), Expr(:block, body3...)), + ) return t # while x; ...; end @@ -731,9 +812,9 @@ function py_macro_lower_assign(st, body, lhs, rhs::Symbol) @gensym x k tx = py_macro_lower(st, body, x, ax) if length(ak) == 1 - tk = py_macro_lower(st, body, k, ak[1], flavour=:index) + tk = py_macro_lower(st, body, k, ak[1], flavour = :index) else - tk = py_macro_lower(st, body, k, Expr(:tuple, ak...), flavour=:index) + tk = py_macro_lower(st, body, k, Expr(:tuple, ak...), flavour = :index) end push!(body, :($pysetitem($x, $k, $rhs))) py_macro_del(body, x, tx) @@ -773,7 +854,7 @@ end function py_macro(ex, mod, src) body = [] @gensym ans - st = PyMacroState(mod=mod, src=src) + st = PyMacroState(mod = mod, src = src) py_macro_lower(st, body, ans, ex) if !isempty(st.consts) || !isempty(st.inits) doinit = Ref(true) diff --git a/src/PythonCall.jl b/src/PythonCall.jl index fdd1774f..b773a1b4 100644 --- a/src/PythonCall.jl +++ b/src/PythonCall.jl @@ -24,13 +24,23 @@ for m in [:Core, :Convert, :PyMacro, :Wrap, :JlWrap, :Compat] end # non-exported API -for k in [:python_executable_path, :python_library_path, :python_library_handle, :python_version] +for k in + [:python_executable_path, :python_library_path, :python_library_handle, :python_version] @eval using .C: $k end for k in [:pynew, :pyisnull, :pycopy!, :getptr, :pydel!, :unsafe_pynext, :PyNULL, :CONFIG] @eval using .Core: $k end -for k in [:pyconvert_add_rule, :pyconvert_return, :pyconvert_unconverted, :PYCONVERT_PRIORITY_WRAP, :PYCONVERT_PRIORITY_ARRAY, :PYCONVERT_PRIORITY_CANONICAL, :PYCONVERT_PRIORITY_NORMAL, :PYCONVERT_PRIORITY_FALLBACK] +for k in [ + :pyconvert_add_rule, + :pyconvert_return, + :pyconvert_unconverted, + :PYCONVERT_PRIORITY_WRAP, + :PYCONVERT_PRIORITY_ARRAY, + :PYCONVERT_PRIORITY_CANONICAL, + :PYCONVERT_PRIORITY_NORMAL, + :PYCONVERT_PRIORITY_FALLBACK, +] @eval using .Convert: $k end for k in [:event_loop_on, :event_loop_off, :fix_qt_plugin_path] @@ -38,7 +48,21 @@ for k in [:event_loop_on, :event_loop_off, :fix_qt_plugin_path] end # not API but used in tests -for k in [:pyjlanytype, :pyjlarraytype, :pyjlvectortype, :pyjlbinaryiotype, :pyjltextiotype, :pyjldicttype, :pyjlmoduletype, :pyjlintegertype, :pyjlrationaltype, :pyjlrealtype, :pyjlcomplextype, :pyjlsettype, :pyjltypetype] +for k in [ + :pyjlanytype, + :pyjlarraytype, + :pyjlvectortype, + :pyjlbinaryiotype, + :pyjltextiotype, + :pyjldicttype, + :pyjlmoduletype, + :pyjlintegertype, + :pyjlrationaltype, + :pyjlrealtype, + :pyjlcomplextype, + :pyjlsettype, + :pyjltypetype, +] @eval using .JlWrap: $k end diff --git a/src/Utils/Utils.jl b/src/Utils/Utils.jl index 0b4a29f0..6e7b3f4d 100644 --- a/src/Utils/Utils.jl +++ b/src/Utils/Utils.jl @@ -1,273 +1,311 @@ module Utils - function explode_union(T) - @nospecialize T - - # unpack unionall - S = T - vars = [] - while S isa UnionAll - pushfirst!(vars, S.var) - S = S.body - end +function explode_union(T) + @nospecialize T + + # unpack unionall + S = T + vars = [] + while S isa UnionAll + pushfirst!(vars, S.var) + S = S.body + end - if S isa Union - Us = Any[explode_union(S.a)..., explode_union(S.b)...] - Any[foldl((body, var) -> UnionAll(var, body), vars, init=U) for U in Us] - elseif S == Union{} - Any[] - else - Any[T] - end + if S isa Union + Us = Any[explode_union(S.a)..., explode_union(S.b)...] + Any[foldl((body, var) -> UnionAll(var, body), vars, init = U) for U in Us] + elseif S == Union{} + Any[] + else + Any[T] end +end - """ - pointer_from_obj(x) +""" + pointer_from_obj(x) - Returns `(p, c)` where `Base.pointer_from_objref(p) === x`. +Returns `(p, c)` where `Base.pointer_from_objref(p) === x`. - The pointer remains valid provided the object `c` is not garbage collected. - """ - function pointer_from_obj(o::T) where {T} - if T.mutable - c = o - p = Base.pointer_from_objref(o) - else - c = Ref{Any}(o) - p = unsafe_load(Ptr{Ptr{Cvoid}}(Base.pointer_from_objref(c))) - end - p, c +The pointer remains valid provided the object `c` is not garbage collected. +""" +function pointer_from_obj(o::T) where {T} + if T.mutable + c = o + p = Base.pointer_from_objref(o) + else + c = Ref{Any}(o) + p = unsafe_load(Ptr{Ptr{Cvoid}}(Base.pointer_from_objref(c))) end + p, c +end - """ - ExtraNewline(x) +""" + ExtraNewline(x) - An object that displays the same as `x` but with an extra newline in text/plain. - """ - struct ExtraNewline{T} - value :: T - end - Base.show(io::IO, m::MIME, x::ExtraNewline) = show(io, m, x.value) - Base.show(io::IO, m::MIME"text/csv", x::ExtraNewline) = show(io, m, x.value) - Base.show(io::IO, m::MIME"text/tab-separated-values", x::ExtraNewline) = show(io, m, x.value) - Base.show(io::IO, m::MIME"text/plain", x::ExtraNewline) = (show(io, m, x.value); println(io)) - Base.showable(m::MIME, x::ExtraNewline) = showable(m, x.value) - - const ALL_MIMES = [ - "text/plain", - "text/html", - "text/markdown", - "text/json", - "text/latex", - "text/xml", - "text/csv", - "application/javascript", - "application/pdf", - "application/ogg", - "image/jpeg", - "image/png", - "image/svg+xml", - "image/gif", - "image/webp", - "image/tiff", - "image/bmp", - "audio/aac", - "audio/mpeg", - "audio/ogg", - "audio/opus", - "audio/webm", - "audio/wav", - "audio/midi", - "audio/x-midi", - "video/mpeg", - "video/ogg", - "video/webm", - ] - - function mimes_for(x) - @nospecialize x - # default mimes we always try - mimes = copy(ALL_MIMES) - # look for mimes on show methods for this type - for meth in methods(show, Tuple{IO, MIME, typeof(x)}).ms - mimetype = _unwrap_unionall(meth.sig).parameters[3] - mimetype isa DataType || continue - mimetype <: MIME || continue - mime = string(mimetype.parameters[1]) - push!(mimes, mime) - end - return mimes +An object that displays the same as `x` but with an extra newline in text/plain. +""" +struct ExtraNewline{T} + value::T +end +Base.show(io::IO, m::MIME, x::ExtraNewline) = show(io, m, x.value) +Base.show(io::IO, m::MIME"text/csv", x::ExtraNewline) = show(io, m, x.value) +Base.show(io::IO, m::MIME"text/tab-separated-values", x::ExtraNewline) = + show(io, m, x.value) +Base.show(io::IO, m::MIME"text/plain", x::ExtraNewline) = + (show(io, m, x.value); println(io)) +Base.showable(m::MIME, x::ExtraNewline) = showable(m, x.value) + +const ALL_MIMES = [ + "text/plain", + "text/html", + "text/markdown", + "text/json", + "text/latex", + "text/xml", + "text/csv", + "application/javascript", + "application/pdf", + "application/ogg", + "image/jpeg", + "image/png", + "image/svg+xml", + "image/gif", + "image/webp", + "image/tiff", + "image/bmp", + "audio/aac", + "audio/mpeg", + "audio/ogg", + "audio/opus", + "audio/webm", + "audio/wav", + "audio/midi", + "audio/x-midi", + "video/mpeg", + "video/ogg", + "video/webm", +] + +function mimes_for(x) + @nospecialize x + # default mimes we always try + mimes = copy(ALL_MIMES) + # look for mimes on show methods for this type + for meth in methods(show, Tuple{IO,MIME,typeof(x)}).ms + mimetype = _unwrap_unionall(meth.sig).parameters[3] + mimetype isa DataType || continue + mimetype <: MIME || continue + mime = string(mimetype.parameters[1]) + push!(mimes, mime) end + return mimes +end + +@generated _typeintersect(::Type{T1}, ::Type{T2}) where {T1,T2} = typeintersect(T1, T2) - @generated _typeintersect(::Type{T1}, ::Type{T2}) where {T1,T2} = typeintersect(T1, T2) +@generated _type_ub(::Type{T}) where {T} = begin + S = T + while S isa UnionAll + S = S{S.var.ub} + end + S +end - @generated _type_ub(::Type{T}) where {T} = begin +@generated _type_lb(::Type{T}) where {T} = begin + R = _unwrap_unionall(T) + if R isa DataType S = T while S isa UnionAll - S = S{S.var.ub} + S = S{S.var in R.parameters ? S.var.lb : S.var.ub} end S + else + _type_ub(T) end +end - @generated _type_lb(::Type{T}) where {T} = begin - R = _unwrap_unionall(T) - if R isa DataType - S = T - while S isa UnionAll - S = S{S.var in R.parameters ? S.var.lb : S.var.ub} - end - S - else - _type_ub(T) - end - end - - @generated function _unwrap_unionall(::Type{T}) where {T} - R = T - while R isa UnionAll - R = R.body - end - R +@generated function _unwrap_unionall(::Type{T}) where {T} + R = T + while R isa UnionAll + R = R.body end + R +end - @generated _promote_type_bounded(::Type{S}, ::Type{T}, ::Type{B}) where {S,T,B} = begin - S <: B || error("require S <: B") - T <: B || error("require T <: B") - if B isa Union - return Union{_promote_type_bounded(typeintersect(S, B.a), typeintersect(T, B.a), B.a), _promote_type_bounded(typeintersect(S, B.b), typeintersect(T, B.b), B.b)} +@generated _promote_type_bounded(::Type{S}, ::Type{T}, ::Type{B}) where {S,T,B} = begin + S <: B || error("require S <: B") + T <: B || error("require T <: B") + if B isa Union + return Union{ + _promote_type_bounded(typeintersect(S, B.a), typeintersect(T, B.a), B.a), + _promote_type_bounded(typeintersect(S, B.b), typeintersect(T, B.b), B.b), + } + else + R = promote_type(S, T) + if R <: B + return R else - R = promote_type(S, T) + R = typeintersect(typejoin(S, T), B) if R <: B return R else - R = typeintersect(typejoin(S, T), B) - if R <: B - return R - else - return B - end + return B end end end +end - @generated _promote_type_bounded(::Type{T1}, ::Type{T2}, ::Type{T3}, ::Type{B}) where {T1,T2,T3,B} = - _promote_type_bounded(_promote_type_bounded(T1, T2, B), T3, B) - - # TODO: what is the best way? - ismutablearray(x::Array) = true - ismutablearray(x::AbstractArray) = begin - p = parent(x) - p === x ? false : ismutablearray(p) - end +@generated _promote_type_bounded( + ::Type{T1}, + ::Type{T2}, + ::Type{T3}, + ::Type{B}, +) where {T1,T2,T3,B} = _promote_type_bounded(_promote_type_bounded(T1, T2, B), T3, B) + +# TODO: what is the best way? +ismutablearray(x::Array) = true +ismutablearray(x::AbstractArray) = begin + p = parent(x) + p === x ? false : ismutablearray(p) +end - islittleendian() = Base.ENDIAN_BOM == 0x04030201 ? true : Base.ENDIAN_BOM == 0x01020304 ? false : error() +islittleendian() = + Base.ENDIAN_BOM == 0x04030201 ? true : Base.ENDIAN_BOM == 0x01020304 ? false : error() - isflagset(flags, mask) = (flags & mask) == mask +isflagset(flags, mask) = (flags & mask) == mask - size_to_fstrides(elsz::Integer, sz::Tuple{Vararg{Integer}}) = - isempty(sz) ? () : (elsz, size_to_fstrides(elsz * sz[1], sz[2:end])...) +size_to_fstrides(elsz::Integer, sz::Tuple{Vararg{Integer}}) = + isempty(sz) ? () : (elsz, size_to_fstrides(elsz * sz[1], sz[2:end])...) - size_to_cstrides(elsz::Integer, sz::Tuple{Vararg{Integer}}) = - isempty(sz) ? () : (size_to_cstrides(elsz * sz[end], sz[1:end-1])..., elsz) +size_to_cstrides(elsz::Integer, sz::Tuple{Vararg{Integer}}) = + isempty(sz) ? () : (size_to_cstrides(elsz * sz[end], sz[1:end-1])..., elsz) - struct StaticString{T,N} <: AbstractString - codeunits :: NTuple{N,T} - StaticString{T,N}(codeunits::NTuple{N,T}) where {T,N} = new{T,N}(codeunits) - end +struct StaticString{T,N} <: AbstractString + codeunits::NTuple{N,T} + StaticString{T,N}(codeunits::NTuple{N,T}) where {T,N} = new{T,N}(codeunits) +end - function Base.String(x::StaticString{T,N}) where {T,N} - ts = x.codeunits - n = N - while n > 0 && iszero(ts[n]) - n -= 1 - end - cs = T[ts[i] for i in 1:n] - transcode(String, cs) +function Base.String(x::StaticString{T,N}) where {T,N} + ts = x.codeunits + n = N + while n > 0 && iszero(ts[n]) + n -= 1 end + cs = T[ts[i] for i = 1:n] + transcode(String, cs) +end - function Base.convert(::Type{StaticString{T,N}}, x::AbstractString) where {T,N} - ts = transcode(T, convert(String, x)) - n = length(ts) - n > N && throw(InexactError(:convert, StaticString{T,N}, x)) - n > 0 && iszero(ts[n]) && throw(InexactError(:convert, StaticString{T,N}, x)) - z = zero(T) - cs = ntuple(i -> i > n ? z : @inbounds(ts[i]), N) - StaticString{T,N}(cs) - end +function Base.convert(::Type{StaticString{T,N}}, x::AbstractString) where {T,N} + ts = transcode(T, convert(String, x)) + n = length(ts) + n > N && throw(InexactError(:convert, StaticString{T,N}, x)) + n > 0 && iszero(ts[n]) && throw(InexactError(:convert, StaticString{T,N}, x)) + z = zero(T) + cs = ntuple(i -> i > n ? z : @inbounds(ts[i]), N) + StaticString{T,N}(cs) +end - StaticString{T,N}(x::AbstractString) where {T,N} = convert(StaticString{T,N}, x) +StaticString{T,N}(x::AbstractString) where {T,N} = convert(StaticString{T,N}, x) - Base.ncodeunits(x::StaticString{T,N}) where {T,N} = N +Base.ncodeunits(x::StaticString{T,N}) where {T,N} = N - Base.codeunit(x::StaticString, i::Integer) = x.codeunits[i] +Base.codeunit(x::StaticString, i::Integer) = x.codeunits[i] - Base.codeunit(x::StaticString{T}) where {T} = T +Base.codeunit(x::StaticString{T}) where {T} = T - function Base.isvalid(x::StaticString{UInt8,N}, i::Int) where {N} - if i < 1 || i > N - return false - end - cs = x.codeunits - c = @inbounds cs[i] - if all(iszero, (cs[j] for j in i:N)) - return false - elseif (c & 0x80) == 0x00 - return true - elseif (c & 0x40) == 0x00 - return false - elseif (c & 0x20) == 0x00 - return @inbounds (i ≤ N-1) && ((cs[i+1] & 0xC0) == 0x80) - elseif (c & 0x10) == 0x00 - return @inbounds (i ≤ N-2) && ((cs[i+1] & 0xC0) == 0x80) && ((cs[i+2] & 0xC0) == 0x80) - elseif (c & 0x08) == 0x00 - return @inbounds (i ≤ N-3) && ((cs[i+1] & 0xC0) == 0x80) && ((cs[i+2] & 0xC0) == 0x80) && ((cs[i+3] & 0xC0) == 0x80) - else - return false - end +function Base.isvalid(x::StaticString{UInt8,N}, i::Int) where {N} + if i < 1 || i > N return false end + cs = x.codeunits + c = @inbounds cs[i] + if all(iszero, (cs[j] for j = i:N)) + return false + elseif (c & 0x80) == 0x00 + return true + elseif (c & 0x40) == 0x00 + return false + elseif (c & 0x20) == 0x00 + return @inbounds (i ≤ N - 1) && ((cs[i+1] & 0xC0) == 0x80) + elseif (c & 0x10) == 0x00 + return @inbounds (i ≤ N - 2) && + ((cs[i+1] & 0xC0) == 0x80) && + ((cs[i+2] & 0xC0) == 0x80) + elseif (c & 0x08) == 0x00 + return @inbounds (i ≤ N - 3) && + ((cs[i+1] & 0xC0) == 0x80) && + ((cs[i+2] & 0xC0) == 0x80) && + ((cs[i+3] & 0xC0) == 0x80) + else + return false + end + return false +end - function Base.iterate(x::StaticString{UInt8,N}, i::Int=1) where {N} - i > N && return - cs = x.codeunits - c = @inbounds cs[i] - if all(iszero, (cs[j] for j in i:N)) - return - elseif (c & 0x80) == 0x00 - return (reinterpret(Char, UInt32(c) << 24), i+1) - elseif (c & 0x40) == 0x00 - nothing - elseif (c & 0x20) == 0x00 - if @inbounds (i ≤ N-1) && ((cs[i+1] & 0xC0) == 0x80) - return (reinterpret(Char, (UInt32(cs[i]) << 24) | (UInt32(cs[i+1]) << 16)), i+2) - end - elseif (c & 0x10) == 0x00 - if @inbounds (i ≤ N-2) && ((cs[i+1] & 0xC0) == 0x80) && ((cs[i+2] & 0xC0) == 0x80) - return (reinterpret(Char, (UInt32(cs[i]) << 24) | (UInt32(cs[i+1]) << 16) | (UInt32(cs[i+2]) << 8)), i+3) - end - elseif (c & 0x08) == 0x00 - if @inbounds (i ≤ N-3) && ((cs[i+1] & 0xC0) == 0x80) && ((cs[i+2] & 0xC0) == 0x80) && ((cs[i+3] & 0xC0) == 0x80) - return (reinterpret(Char, (UInt32(cs[i]) << 24) | (UInt32(cs[i+1]) << 16) | (UInt32(cs[i+2]) << 8) | UInt32(cs[i+3])), i+4) - end +function Base.iterate(x::StaticString{UInt8,N}, i::Int = 1) where {N} + i > N && return + cs = x.codeunits + c = @inbounds cs[i] + if all(iszero, (cs[j] for j = i:N)) + return + elseif (c & 0x80) == 0x00 + return (reinterpret(Char, UInt32(c) << 24), i + 1) + elseif (c & 0x40) == 0x00 + nothing + elseif (c & 0x20) == 0x00 + if @inbounds (i ≤ N - 1) && ((cs[i+1] & 0xC0) == 0x80) + return ( + reinterpret(Char, (UInt32(cs[i]) << 24) | (UInt32(cs[i+1]) << 16)), + i + 2, + ) + end + elseif (c & 0x10) == 0x00 + if @inbounds (i ≤ N - 2) && ((cs[i+1] & 0xC0) == 0x80) && ((cs[i+2] & 0xC0) == 0x80) + return ( + reinterpret( + Char, + (UInt32(cs[i]) << 24) | + (UInt32(cs[i+1]) << 16) | + (UInt32(cs[i+2]) << 8), + ), + i + 3, + ) + end + elseif (c & 0x08) == 0x00 + if @inbounds (i ≤ N - 3) && + ((cs[i+1] & 0xC0) == 0x80) && + ((cs[i+2] & 0xC0) == 0x80) && + ((cs[i+3] & 0xC0) == 0x80) + return ( + reinterpret( + Char, + (UInt32(cs[i]) << 24) | + (UInt32(cs[i+1]) << 16) | + (UInt32(cs[i+2]) << 8) | + UInt32(cs[i+3]), + ), + i + 4, + ) end - throw(StringIndexError(x, i)) end + throw(StringIndexError(x, i)) +end - function Base.isvalid(x::StaticString{UInt32,N}, i::Int) where {N} - i < 1 && return false - cs = x.codeunits - return !all(iszero, (cs[j] for j in i:N)) - end +function Base.isvalid(x::StaticString{UInt32,N}, i::Int) where {N} + i < 1 && return false + cs = x.codeunits + return !all(iszero, (cs[j] for j = i:N)) +end - function Base.iterate(x::StaticString{UInt32,N}, i::Int=1) where {N} - i > N && return - cs = x.codeunits - c = @inbounds cs[i] - if all(iszero, (cs[j] for j in i:N)) - return - else - return (Char(c), i+1) - end +function Base.iterate(x::StaticString{UInt32,N}, i::Int = 1) where {N} + i > N && return + cs = x.codeunits + c = @inbounds cs[i] + if all(iszero, (cs[j] for j = i:N)) + return + else + return (Char(c), i + 1) end +end end diff --git a/src/Wrap/PyArray.jl b/src/Wrap/PyArray.jl index af7933cf..eb561bbc 100644 --- a/src/Wrap/PyArray.jl +++ b/src/Wrap/PyArray.jl @@ -1,5 +1,5 @@ struct UnsafePyObject - ptr :: C.PyPtr + ptr::C.PyPtr end """ @@ -25,7 +25,14 @@ struct PyArray{T,N,M,L,R} <: AbstractArray{T,N} strides::NTuple{N,Int} # strides (in bytes) between elements py::Py # underlying python object handle::Py # the data in this array is valid as long as this handle is alive - function PyArray{T,N,M,L,R}(::Val{:new}, ptr::Ptr{R}, size::NTuple{N,Int}, strides::NTuple{N,Int}, py::Py, handle::Py) where {T,N,M,L,R} + function PyArray{T,N,M,L,R}( + ::Val{:new}, + ptr::Ptr{R}, + size::NTuple{N,Int}, + strides::NTuple{N,Int}, + py::Py, + handle::Py, + ) where {T,N,M,L,R} T isa Type || error("T must be a Type") N isa Int || error("N must be an Int") M isa Bool || error("M must be a Bool") @@ -47,20 +54,31 @@ for N in (missing, 1, 2) "Py", M === missing ? "" : M ? "Mutable" : "Immutable", L === missing ? "" : L ? "Linear" : "Cartesian", - R ? "Raw" : "", + R ? "Raw" : "", N === missing ? "Array" : N == 1 ? "Vector" : "Matrix", ) name == :PyArray && continue - vars = Any[:T, N===missing ? :N : N, M===missing ? :M : M, L===missing ? :L : L, R ? :T : :R] - @eval const $name{$(unique([v for v in vars if v isa Symbol])...)} = PyArray{$(vars...)} + vars = Any[ + :T, + N === missing ? :N : N, + M === missing ? :M : M, + L === missing ? :L : L, + R ? :T : :R, + ] + @eval const $name{$(unique([v for v in vars if v isa Symbol])...)} = PyArray{$(vars...)} @eval export $name end end end end -(::Type{A})(x; array::Bool=true, buffer::Bool=true, copy::Bool=true) where {A<:PyArray} = @autopy x begin - r = pyarray_make(A, x_, array=array, buffer=buffer, copy=copy) +(::Type{A})( + x; + array::Bool = true, + buffer::Bool = true, + copy::Bool = true, +) where {A<:PyArray} = @autopy x begin + r = pyarray_make(A, x_, array = array, buffer = buffer, copy = copy) if pyconvert_isunconverted(r) error("cannot convert this Python '$(pytype(x_).__name__)' to a '$A'") else @@ -68,7 +86,8 @@ end end end -pyconvert_rule_array_nocopy(::Type{A}, x::Py) where {A<:PyArray} = pyarray_make(A, x, copy=false) +pyconvert_rule_array_nocopy(::Type{A}, x::Py) where {A<:PyArray} = + pyarray_make(A, x, copy = false) function pyconvert_rule_array(::Type{A}, x::Py) where {A<:AbstractArray} r = pyarray_make(PyArray, x) @@ -81,28 +100,34 @@ end abstract type PyArraySource end -function pyarray_make(::Type{A}, x::Py; array::Bool=true, buffer::Bool=true, copy::Bool=true) where {A<:PyArray} +function pyarray_make( + ::Type{A}, + x::Py; + array::Bool = true, + buffer::Bool = true, + copy::Bool = true, +) where {A<:PyArray} # TODO: try/catch is SLOW if an error is thrown, think about sending errors via return values instead A == Union{} && return pyconvert_unconverted() if array && (xa = pygetattr(x, "__array_struct__", PyNULL); !pyisnull(xa)) try return pyarray_make(A, x, PyArraySource_ArrayStruct(x, xa)) catch exc - @debug "failed to make PyArray from __array_struct__" exc=exc + @debug "failed to make PyArray from __array_struct__" exc = exc end end if array && (xi = pygetattr(x, "__array_interface__", PyNULL); !pyisnull(xi)) try return pyarray_make(A, x, PyArraySource_ArrayInterface(x, xi)) catch exc - @debug "failed to make PyArray from __array_interface__" exc=exc + @debug "failed to make PyArray from __array_interface__" exc = exc end end if buffer && C.PyObject_CheckBuffer(getptr(x)) try return pyarray_make(A, x, PyArraySource_Buffer(x)) catch exc - @debug "failed to make PyArray from buffer" exc=exc + @debug "failed to make PyArray from buffer" exc = exc end end if copy && array && pyhasattr(x, "__array__") @@ -111,31 +136,39 @@ function pyarray_make(::Type{A}, x::Py; array::Bool=true, buffer::Bool=true, cop try return pyarray_make(A, y, PyArraySource_ArrayStruct(y, ya)) catch exc - @debug "failed to make PyArray from __array__().__array_interface__" exc=exc + @debug "failed to make PyArray from __array__().__array_interface__" exc = + exc end end if (yi = pygetattr(y, "__array_interface__", PyNULL); !pyisnull(yi)) try return pyarray_make(A, y, PyArraySource_ArrayInterface(y, yi)) catch exc - @debug "failed to make PyArray from __array__().__array_interface__" exc=exc + @debug "failed to make PyArray from __array__().__array_interface__" exc = + exc end end end return pyconvert_unconverted() end -function pyarray_make(::Type{A}, x::Py, info::PyArraySource, ::Type{PyArray{T0,N0,M0,L0,R0}}=Utils._type_lb(A), ::Type{PyArray{T1,N1,M1,L1,R1}}=Utils._type_ub(A)) where {A<:PyArray,T0,N0,M0,L0,R0,T1,N1,M1,L1,R1} +function pyarray_make( + ::Type{A}, + x::Py, + info::PyArraySource, + ::Type{PyArray{T0,N0,M0,L0,R0}} = Utils._type_lb(A), + ::Type{PyArray{T1,N1,M1,L1,R1}} = Utils._type_ub(A), +) where {A<:PyArray,T0,N0,M0,L0,R0,T1,N1,M1,L1,R1} # R (buffer eltype) R′ = pyarray_get_R(info)::DataType if R0 == R1 R = R1 R == R′ || error("incorrect R, got $R, should be $R′") - # elseif T0 == T1 && T1 in (Bool, Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128, Float16, Float32, Float64, ComplexF16, ComplexF32, ComplexF64) - # R = T1 - # R == R′ || error("incorrect R, got $R, should be $R′") - # R <: R1 || error("R out of bounds, got $R, should be <: $R1") - # R >: R0 || error("R out of bounds, got $R, should be >: $R0") + # elseif T0 == T1 && T1 in (Bool, Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128, Float16, Float32, Float64, ComplexF16, ComplexF32, ComplexF64) + # R = T1 + # R == R′ || error("incorrect R, got $R, should be $R′") + # R <: R1 || error("R out of bounds, got $R, should be <: $R1") + # R >: R0 || error("R out of bounds, got $R, should be >: $R0") else R = R′ end @@ -190,13 +223,13 @@ end # array interface struct PyArraySource_ArrayInterface <: PyArraySource - obj :: Py - dict :: Py - ptr :: Ptr{Cvoid} - readonly :: Bool - handle :: Py + obj::Py + dict::Py + ptr::Ptr{Cvoid} + readonly::Bool + handle::Py end -function PyArraySource_ArrayInterface(x::Py, d::Py=x.__array_interface__) +function PyArraySource_ArrayInterface(x::Py, d::Py = x.__array_interface__) # offset # TODO: how is the offset measured? offset = pyconvert(Int, @py d.get("offset", 0)) @@ -272,7 +305,8 @@ pyarray_typestrdescr_to_type(ts::String, descr::Py) = begin pyisnull(descr) && error("not supported: void dtype with null descr") sz = parse(Int, ts[3:end]) T = pyarray_descr_to_type(descr) - sizeof(T) == sz || error("size mismatch: itemsize=$sz but sizeof(descr)=$(sizeof(T))") + sizeof(T) == sz || + error("size mismatch: itemsize=$sz but sizeof(descr)=$(sizeof(T))") return T else error("not supported: dtype of kind: $(repr(etc))") @@ -328,10 +362,10 @@ function pyarray_descr_to_type(descr::Py) end sizeof(T) == curoffset || error("not supported: dtype with end padding: $descr") # return the tuple type if the field names are f0, f1, ..., else return a named tuple - if fnames == [Symbol(:f, i-1) for i in 1:length(fnames)] + if fnames == [Symbol(:f, i - 1) for i = 1:length(fnames)] return T else - return NamedTuple{Tuple(fnames), T} + return NamedTuple{Tuple(fnames),T} end end @@ -347,9 +381,15 @@ pyarray_get_ptr(src::PyArraySource_ArrayInterface, ::Type{R}) where {R} = Ptr{R} pyarray_get_N(src::PyArraySource_ArrayInterface) = Int(@py jllen(@jl(src.dict)["shape"])) -pyarray_get_size(src::PyArraySource_ArrayInterface, ::Val{N}) where {N} = pyconvert(NTuple{N,Int}, src.dict["shape"]) +pyarray_get_size(src::PyArraySource_ArrayInterface, ::Val{N}) where {N} = + pyconvert(NTuple{N,Int}, src.dict["shape"]) -function pyarray_get_strides(src::PyArraySource_ArrayInterface, ::Val{N}, ::Type{R}, size::NTuple{N,Int}) where {R,N} +function pyarray_get_strides( + src::PyArraySource_ArrayInterface, + ::Val{N}, + ::Type{R}, + size::NTuple{N,Int}, +) where {R,N} @py strides = @jl(src.dict).get("strides") if pyisnone(strides) pydel!(strides) @@ -366,11 +406,11 @@ pyarray_get_handle(src::PyArraySource_ArrayInterface) = src.handle # array struct struct PyArraySource_ArrayStruct <: PyArraySource - obj :: Py - capsule :: Py - info :: C.PyArrayInterface + obj::Py + capsule::Py + info::C.PyArrayInterface end -function PyArraySource_ArrayStruct(x::Py, capsule::Py=x.__array_struct__) +function PyArraySource_ArrayStruct(x::Py, capsule::Py = x.__array_struct__) name = C.PyCapsule_GetName(getptr(capsule)) ptr = C.PyCapsule_GetPointer(getptr(capsule), name) info = unsafe_load(Ptr{C.PyArrayInterface}(ptr)) @@ -451,7 +491,8 @@ function pyarray_get_R(src::PyArraySource_ArrayStruct) hasdescr || error("not supported: void dtype with no descr") descr = pynew(incref(src.info.descr)) T = pyarray_descr_to_type(descr) - sizeof(T) == size || error("size mismatch: itemsize=$size but sizeof(descr)=$(sizeof(T))") + sizeof(T) == size || + error("size mismatch: itemsize=$size but sizeof(descr)=$(sizeof(T))") return T else error("not supported: dtype of kind: $(Char(kind))") @@ -469,12 +510,17 @@ end function pyarray_get_size(src::PyArraySource_ArrayStruct, ::Val{N}) where {N} ptr = src.info.shape - return ntuple(i->Int(unsafe_load(ptr, i)), Val(N)) + return ntuple(i -> Int(unsafe_load(ptr, i)), Val(N)) end -function pyarray_get_strides(src::PyArraySource_ArrayStruct, ::Val{N}, ::Type{R}, size::NTuple{N,Int}) where {N,R} +function pyarray_get_strides( + src::PyArraySource_ArrayStruct, + ::Val{N}, + ::Type{R}, + size::NTuple{N,Int}, +) where {N,R} ptr = src.info.strides - return ntuple(i->Int(unsafe_load(ptr, i)), Val(N)) + return ntuple(i -> Int(unsafe_load(ptr, i)), Val(N)) end function pyarray_get_M(src::PyArraySource_ArrayStruct) @@ -488,9 +534,9 @@ end # buffer protocol struct PyArraySource_Buffer <: PyArraySource - obj :: Py - memview :: Py - buf :: C.UnsafePtr{C.Py_buffer} + obj::Py + memview::Py + buf::C.UnsafePtr{C.Py_buffer} end function PyArraySource_Buffer(x::Py) memview = pybuiltins.memoryview(x) @@ -535,7 +581,11 @@ const PYARRAY_BUFFERFORMAT_TO_TYPE = let c = Utils.islittleendian() ? '<' : '>' ) end -pyarray_bufferformat_to_type(fmt::String) = get(()->error("not implemented: buffer format $(repr(fmt))"), PYARRAY_BUFFERFORMAT_TO_TYPE, fmt) +pyarray_bufferformat_to_type(fmt::String) = get( + () -> error("not implemented: buffer format $(repr(fmt))"), + PYARRAY_BUFFERFORMAT_TO_TYPE, + fmt, +) function pyarray_get_R(src::PyArraySource_Buffer) ptr = src.buf.format[] @@ -551,17 +601,22 @@ function pyarray_get_size(src::PyArraySource_Buffer, ::Val{N}) where {N} if size == C_NULL N == 0 ? () : N == 1 ? (Int(src.buf.len[]),) : @assert false else - ntuple(i->Int(size[i]), N) + ntuple(i -> Int(size[i]), N) end end -function pyarray_get_strides(src::PyArraySource_Buffer, ::Val{N}, ::Type{R}, size::NTuple{N,Int}) where {N,R} +function pyarray_get_strides( + src::PyArraySource_Buffer, + ::Val{N}, + ::Type{R}, + size::NTuple{N,Int}, +) where {N,R} strides = src.buf.strides[] if strides == C_NULL itemsize = src.buf.shape[] == C_NULL ? 1 : src.buf.itemsize[] Utils.size_to_cstrides(itemsize, size) else - ntuple(i->Int(strides[i]), N) + ntuple(i -> Int(strides[i]), N) end end @@ -577,7 +632,8 @@ Base.size(x::PyArray) = x.size Utils.ismutablearray(x::PyArray{T,N,M,L,R}) where {T,N,M,L,R} = M -Base.IndexStyle(::Type{PyArray{T,N,M,L,R}}) where {T,N,M,L,R} = L ? Base.IndexLinear() : Base.IndexCartesian() +Base.IndexStyle(::Type{PyArray{T,N,M,L,R}}) where {T,N,M,L,R} = + L ? Base.IndexLinear() : Base.IndexCartesian() Base.unsafe_convert(::Type{Ptr{T}}, x::PyArray{T,N,M,L,T}) where {T,N,M,L} = x.ptr @@ -588,7 +644,7 @@ Base.strides(x::PyArray{T,N,M,L,R}) where {T,N,M,L,R} = error("strides are not a multiple of element size") end -function Base.showarg(io::IO, x::PyArray{T,N}, toplevel::Bool) where {T, N} +function Base.showarg(io::IO, x::PyArray{T,N}, toplevel::Bool) where {T,N} toplevel || print(io, "::") print(io, "PyArray{") show(io, T) @@ -596,18 +652,24 @@ function Base.showarg(io::IO, x::PyArray{T,N}, toplevel::Bool) where {T, N} return end -@propagate_inbounds Base.getindex(x::PyArray{T,N}, i::Vararg{Int,N}) where {T,N} = pyarray_getindex(x, i...) -@propagate_inbounds Base.getindex(x::PyArray{T,N,M,true}, i::Int) where {T,N,M} = pyarray_getindex(x, i) -@propagate_inbounds Base.getindex(x::PyArray{T,1,M,true}, i::Int) where {T,M} = pyarray_getindex(x, i) +@propagate_inbounds Base.getindex(x::PyArray{T,N}, i::Vararg{Int,N}) where {T,N} = + pyarray_getindex(x, i...) +@propagate_inbounds Base.getindex(x::PyArray{T,N,M,true}, i::Int) where {T,N,M} = + pyarray_getindex(x, i) +@propagate_inbounds Base.getindex(x::PyArray{T,1,M,true}, i::Int) where {T,M} = + pyarray_getindex(x, i) @propagate_inbounds function pyarray_getindex(x::PyArray, i...) @boundscheck checkbounds(x, i...) pyarray_load(eltype(x), x.ptr + pyarray_offset(x, i...)) end -@propagate_inbounds Base.setindex!(x::PyArray{T,N,true}, v, i::Vararg{Int,N}) where {T,N} = pyarray_setindex!(x, v, i...) -@propagate_inbounds Base.setindex!(x::PyArray{T,N,true,true}, v, i::Int) where {T,N} = pyarray_setindex!(x, v, i) -@propagate_inbounds Base.setindex!(x::PyArray{T,1,true,true}, v, i::Int) where {T} = pyarray_setindex!(x, v, i) +@propagate_inbounds Base.setindex!(x::PyArray{T,N,true}, v, i::Vararg{Int,N}) where {T,N} = + pyarray_setindex!(x, v, i...) +@propagate_inbounds Base.setindex!(x::PyArray{T,N,true,true}, v, i::Int) where {T,N} = + pyarray_setindex!(x, v, i) +@propagate_inbounds Base.setindex!(x::PyArray{T,1,true,true}, v, i::Int) where {T} = + pyarray_setindex!(x, v, i) @propagate_inbounds function pyarray_setindex!(x::PyArray{T,N,true}, v, i...) where {T,N} @boundscheck checkbounds(x, i...) @@ -615,7 +677,8 @@ end x end -pyarray_offset(x::PyArray{T,N,M,true}, i::Int) where {T,N,M} = N == 0 ? 0 : (i - 1) * x.strides[1] +pyarray_offset(x::PyArray{T,N,M,true}, i::Int) where {T,N,M} = + N == 0 ? 0 : (i - 1) * x.strides[1] pyarray_offset(x::PyArray{T,1,M,true}, i::Int) where {T,M} = (i - 1) .* x.strides[1] pyarray_offset(x::PyArray{T,N}, i::Vararg{Int,N}) where {T,N} = sum((i .- 1) .* x.strides) pyarray_offset(x::PyArray{T,0}) where {T} = 0 @@ -671,4 +734,4 @@ function pyarray_check_T(::Type{T}, ::Type{R}) where {T,R} else error("invalid eltype T=$T for raw eltype R=$R") end -end +end diff --git a/src/Wrap/PyDict.jl b/src/Wrap/PyDict.jl index 494ec421..a9a9a405 100644 --- a/src/Wrap/PyDict.jl +++ b/src/Wrap/PyDict.jl @@ -6,24 +6,28 @@ Wraps the Python dict `x` (or anything satisfying the mapping interface) as an ` If `x` is not a Python object, it is converted to one using `pydict`. """ struct PyDict{K,V} <: AbstractDict{K,V} - py :: Py - PyDict{K,V}(x=pydict()) where {K,V} = new{K,V}(ispy(x) ? Py(x) : pydict(x)) + py::Py + PyDict{K,V}(x = pydict()) where {K,V} = new{K,V}(ispy(x) ? Py(x) : pydict(x)) end export PyDict -PyDict{K}(x=pydict()) where {K} = PyDict{K,Py}(x) -PyDict(x=pydict()) = PyDict{Py,Py}(x) +PyDict{K}(x = pydict()) where {K} = PyDict{K,Py}(x) +PyDict(x = pydict()) = PyDict{Py,Py}(x) ispy(::PyDict) = true Py(x::PyDict) = x.py -function pyconvert_rule_mapping(::Type{T}, x::Py, ::Type{T1}=Utils._type_ub(T)) where {T<:PyDict,T1} +function pyconvert_rule_mapping( + ::Type{T}, + x::Py, + ::Type{T1} = Utils._type_ub(T), +) where {T<:PyDict,T1} pyconvert_return(T1(x)) end Base.length(x::PyDict) = Int(pylen(x)) -function Base.iterate(x::PyDict{K,V}, it::Py=pyiter(x)) where {K,V} +function Base.iterate(x::PyDict{K,V}, it::Py = pyiter(x)) where {K,V} k_ = unsafe_pynext(it) pyisnull(k_) && return nothing v_ = pygetitem(x, k_) @@ -32,7 +36,7 @@ function Base.iterate(x::PyDict{K,V}, it::Py=pyiter(x)) where {K,V} return (k => v, it) end -function Base.iterate(x::Base.KeySet{K,PyDict{K,V}}, it::Py=pyiter(x.dict)) where {K,V} +function Base.iterate(x::Base.KeySet{K,PyDict{K,V}}, it::Py = pyiter(x.dict)) where {K,V} k_ = unsafe_pynext(it) pyisnull(k_) && return nothing k = pyconvert(K, k_) diff --git a/src/Wrap/PyIO.jl b/src/Wrap/PyIO.jl index ecc35895..232cef14 100644 --- a/src/Wrap/PyIO.jl +++ b/src/Wrap/PyIO.jl @@ -33,7 +33,15 @@ mutable struct PyIO <: IO obuflen::Int obuf::Vector{UInt8} - function PyIO(x; own::Bool = false, text::Union{Missing,Bool} = missing, buflen::Integer = 4096, ibuflen::Integer = buflen, obuflen::Integer = buflen, line_buffering::Bool=false) + function PyIO( + x; + own::Bool = false, + text::Union{Missing,Bool} = missing, + buflen::Integer = 4096, + ibuflen::Integer = buflen, + obuflen::Integer = buflen, + line_buffering::Bool = false, + ) if text === missing text = pyhasattr(x, "encoding") end @@ -151,7 +159,7 @@ function Base.unsafe_write(io::PyIO, ptr::Ptr{UInt8}, n::UInt) else append!(io.obuf, unsafe_wrap(Array, ptr, i)) putobuf(io) - append!(io.obuf, unsafe_wrap(Array, ptr+i, ntodo-i)) + append!(io.obuf, unsafe_wrap(Array, ptr + i, ntodo - i)) end else append!(io.obuf, buf) @@ -255,7 +263,9 @@ function Base.position(io::PyIO) if isempty(io.ibuf) return pyconvert(Int, @py io.tell()) else - error("`position(io)` text PyIO streams only implemented for empty input buffer (e.g. do `read(io, length(io.ibuf))` first)") + error( + "`position(io)` text PyIO streams only implemented for empty input buffer (e.g. do `read(io, length(io.ibuf))` first)", + ) end else return pyconvert(Int, @py io.tell()) - length(io.ibuf) diff --git a/src/Wrap/PyIterable.jl b/src/Wrap/PyIterable.jl index 807e306d..d8e6f137 100644 --- a/src/Wrap/PyIterable.jl +++ b/src/Wrap/PyIterable.jl @@ -4,7 +4,7 @@ This object iterates over iterable Python object `x`, yielding values of type `T`. """ struct PyIterable{T} - py :: Py + py::Py PyIterable{T}(x) where {T} = new{T}(Py(x)) end export PyIterable @@ -17,7 +17,7 @@ Py(x::PyIterable) = x.py Base.IteratorSize(::Type{PyIterable{T}}) where {T} = Base.SizeUnknown() Base.eltype(::Type{PyIterable{T}}) where {T} = T -function Base.iterate(x::PyIterable{T}, it::Py=pyiter(x)) where {T} +function Base.iterate(x::PyIterable{T}, it::Py = pyiter(x)) where {T} y = unsafe_pynext(it) if pyisnull(y) pydel!(it) @@ -27,6 +27,10 @@ function Base.iterate(x::PyIterable{T}, it::Py=pyiter(x)) where {T} end end -function pyconvert_rule_iterable(::Type{T}, x::Py, ::Type{T1}=Utils._type_ub(T)) where {T<:PyIterable,T1} +function pyconvert_rule_iterable( + ::Type{T}, + x::Py, + ::Type{T1} = Utils._type_ub(T), +) where {T<:PyIterable,T1} pyconvert_return(T1(x)) end diff --git a/src/Wrap/PyList.jl b/src/Wrap/PyList.jl index 1eac6479..69307c3a 100644 --- a/src/Wrap/PyList.jl +++ b/src/Wrap/PyList.jl @@ -6,17 +6,21 @@ Wraps the Python list `x` (or anything satisfying the sequence interface) as an If `x` is not a Python object, it is converted to one using `pylist`. """ struct PyList{T} <: AbstractVector{T} - py :: Py - PyList{T}(x=pylist()) where {T} = new{T}(ispy(x) ? Py(x) : pylist(x)) + py::Py + PyList{T}(x = pylist()) where {T} = new{T}(ispy(x) ? Py(x) : pylist(x)) end export PyList -PyList(x=pylist()) = PyList{Py}(x) +PyList(x = pylist()) = PyList{Py}(x) ispy(::PyList) = true Py(x::PyList) = x.py -function pyconvert_rule_sequence(::Type{T}, x::Py, ::Type{T1}=Utils._type_ub(T)) where {T<:PyList,T1} +function pyconvert_rule_sequence( + ::Type{T}, + x::Py, + ::Type{T1} = Utils._type_ub(T), +) where {T<:PyList,T1} pyconvert_return(T1(x)) end @@ -26,18 +30,18 @@ Base.size(x::PyList) = (length(x),) Base.@propagate_inbounds function Base.getindex(x::PyList{T}, i::Int) where {T} @boundscheck checkbounds(x, i) - return pyconvert(T, @py x[@jl(i-1)]) + return pyconvert(T, @py x[@jl(i - 1)]) end Base.@propagate_inbounds function Base.setindex!(x::PyList{T}, v, i::Int) where {T} @boundscheck checkbounds(x, i) - pysetitem(x, i-1, convert(T, v)) + pysetitem(x, i - 1, convert(T, v)) return x end Base.@propagate_inbounds function Base.insert!(x::PyList{T}, i::Integer, v) where {T} - @boundscheck (i==length(x)+1 || checkbounds(x, i)) - pydel!(@py x.insert(@jl(i-1), @jl(convert(T, v)))) + @boundscheck (i == length(x) + 1 || checkbounds(x, i)) + pydel!(@py x.insert(@jl(i - 1), @jl(convert(T, v)))) return x end @@ -69,7 +73,7 @@ end Base.@propagate_inbounds function Base.popat!(x::PyList{T}, i::Integer) where {T} @boundscheck checkbounds(x, i) - return pyconvert(T, @py x.pop(@jl(i-1))) + return pyconvert(T, @py x.pop(@jl(i - 1))) end Base.@propagate_inbounds function Base.popfirst!(x::PyList{T}) where {T} diff --git a/src/Wrap/PyPandasDataFrame.jl b/src/Wrap/PyPandasDataFrame.jl index 0c6ab85a..3c37bad9 100644 --- a/src/Wrap/PyPandasDataFrame.jl +++ b/src/Wrap/PyPandasDataFrame.jl @@ -15,7 +15,12 @@ struct PyPandasDataFrame <: PyTable indexname::Union{Symbol,Nothing} columnnames::Function # Py -> Symbol columntypes::Function # Symbol -> Union{Type,Nothing} - function PyPandasDataFrame(x; indexname::Union{Symbol,Nothing}=nothing, columnnames::Function=x->Symbol(x), columntypes::Function=x->nothing) + function PyPandasDataFrame( + x; + indexname::Union{Symbol,Nothing} = nothing, + columnnames::Function = x -> Symbol(x), + columntypes::Function = x -> nothing, + ) new(Py(x), indexname, columnnames, columntypes) end end @@ -24,7 +29,8 @@ export PyPandasDataFrame ispy(x::PyPandasDataFrame) = true Py(x::PyPandasDataFrame) = x.py -pyconvert_rule_pandasdataframe(::Type{PyPandasDataFrame}, x::Py) = pyconvert_return(PyPandasDataFrame(x)) +pyconvert_rule_pandasdataframe(::Type{PyPandasDataFrame}, x::Py) = + pyconvert_return(PyPandasDataFrame(x)) ### Show @@ -84,7 +90,7 @@ function _columns(df, columnnames, columntypes) # output a table # TODO: realising columns to vectors could be done lazily with a different table type schema = Tables.Schema(colnames, coltypes) - coldict = Tables.OrderedDict(k=>v for (k,v) in zip(colnames, columns)) + coldict = Tables.OrderedDict(k => v for (k, v) in zip(colnames, columns)) table = Tables.DictColumnTable(schema, coldict) Tables.columns(table) end diff --git a/src/Wrap/PySet.jl b/src/Wrap/PySet.jl index d2da19af..aaefd9b5 100644 --- a/src/Wrap/PySet.jl +++ b/src/Wrap/PySet.jl @@ -6,17 +6,21 @@ Wraps the Python set `x` (or anything satisfying the set interface) as an `Abstr If `x` is not a Python object, it is converted to one using `pyset`. """ struct PySet{T} <: AbstractSet{T} - py :: Py - PySet{T}(x=pyset()) where {T} = new{T}(ispy(x) ? Py(x) : pyset(x)) + py::Py + PySet{T}(x = pyset()) where {T} = new{T}(ispy(x) ? Py(x) : pyset(x)) end export PySet -PySet(x=pyset()) = PySet{Py}(x) +PySet(x = pyset()) = PySet{Py}(x) ispy(::PySet) = true Py(x::PySet) = x.py -function pyconvert_rule_set(::Type{T}, x::Py, ::Type{T1}=Utils._type_ub(T)) where {T<:PySet,T1} +function pyconvert_rule_set( + ::Type{T}, + x::Py, + ::Type{T1} = Utils._type_ub(T), +) where {T<:PySet,T1} pyconvert_return(T1(x)) end @@ -24,7 +28,7 @@ Base.length(x::PySet) = Int(pylen(x)) Base.isempty(x::PySet) = length(x) == 0 -function Base.iterate(x::PySet{T}, it::Py=pyiter(x)) where {T} +function Base.iterate(x::PySet{T}, it::Py = pyiter(x)) where {T} y = unsafe_pynext(it) if pyisnull(y) pydel!(it) diff --git a/src/Wrap/Wrap.jl b/src/Wrap/Wrap.jl index 4f934b28..0d19edd0 100644 --- a/src/Wrap/Wrap.jl +++ b/src/Wrap/Wrap.jl @@ -6,8 +6,31 @@ Defines Julia wrappers around Python objects, including `PyList`, `PyDict`, `PyA module Wrap using ..Core -using ..Core: C, Utils, @autopy, unsafe_pynext, pyisnull, PyNULL, getptr, pydel!, pybytes_asvector, pystr_asUTF8vector, pystr_fromUTF8, incref, decref, pynew, pyisnone, pyistuple, pyisstr -using ..Convert: pyconvert, pyconvert_tryconvert, pyconvert_unconverted, pyconvert_isunconverted, pyconvert_return, pyconvert_result +using ..Core: + C, + Utils, + @autopy, + unsafe_pynext, + pyisnull, + PyNULL, + getptr, + pydel!, + pybytes_asvector, + pystr_asUTF8vector, + pystr_fromUTF8, + incref, + decref, + pynew, + pyisnone, + pyistuple, + pyisstr +using ..Convert: + pyconvert, + pyconvert_tryconvert, + pyconvert_unconverted, + pyconvert_isunconverted, + pyconvert_return, + pyconvert_result using ..PyMacro using Base: @propagate_inbounds @@ -15,7 +38,11 @@ using Tables: Tables using UnsafePointers: UnsafePtr import ..Core: Py, ispy -import ..Convert: pyconvert_add_rule, PYCONVERT_PRIORITY_ARRAY, PYCONVERT_PRIORITY_CANONICAL, PYCONVERT_PRIORITY_NORMAL +import ..Convert: + pyconvert_add_rule, + PYCONVERT_PRIORITY_ARRAY, + PYCONVERT_PRIORITY_CANONICAL, + PYCONVERT_PRIORITY_NORMAL include("PyIterable.jl") include("PyDict.jl") @@ -34,14 +61,34 @@ function __init__() pyconvert_add_rule("", PyArray, pyconvert_rule_array_nocopy, priority) priority = PYCONVERT_PRIORITY_CANONICAL - pyconvert_add_rule("collections.abc:Iterable", PyIterable, pyconvert_rule_iterable, priority) - pyconvert_add_rule("collections.abc:Sequence", PyList, pyconvert_rule_sequence, priority) + pyconvert_add_rule( + "collections.abc:Iterable", + PyIterable, + pyconvert_rule_iterable, + priority, + ) + pyconvert_add_rule( + "collections.abc:Sequence", + PyList, + pyconvert_rule_sequence, + priority, + ) pyconvert_add_rule("collections.abc:Set", PySet, pyconvert_rule_set, priority) pyconvert_add_rule("collections.abc:Mapping", PyDict, pyconvert_rule_mapping, priority) pyconvert_add_rule("io:IOBase", PyIO, pyconvert_rule_io, priority) pyconvert_add_rule("_io:_IOBase", PyIO, pyconvert_rule_io, priority) - pyconvert_add_rule("pandas.core.frame:DataFrame", PyPandasDataFrame, pyconvert_rule_pandasdataframe, priority) - pyconvert_add_rule("pandas.core.arrays.base:ExtensionArray", PyList, pyconvert_rule_sequence, priority) + pyconvert_add_rule( + "pandas.core.frame:DataFrame", + PyPandasDataFrame, + pyconvert_rule_pandasdataframe, + priority, + ) + pyconvert_add_rule( + "pandas.core.arrays.base:ExtensionArray", + PyList, + pyconvert_rule_sequence, + priority, + ) priority = PYCONVERT_PRIORITY_NORMAL pyconvert_add_rule("", Array, pyconvert_rule_array, priority) diff --git a/src/Wrap/convert_rules.jl b/src/Wrap/convert_rules.jl index e69de29b..8b137891 100644 --- a/src/Wrap/convert_rules.jl +++ b/src/Wrap/convert_rules.jl @@ -0,0 +1 @@ + diff --git a/test/Aqua.jl b/test/Aqua.jl index 957c8682..47b932ee 100644 --- a/test/Aqua.jl +++ b/test/Aqua.jl @@ -2,5 +2,5 @@ # The unbound_args test fails on methods with signature like foo(::Type{Tuple{Vararg{V}}}) where V # Seems like a bug. import Aqua - Aqua.test_all(PythonCall, unbound_args=false) + Aqua.test_all(PythonCall, unbound_args = false) end diff --git a/test/Compat.jl b/test/Compat.jl index 77deb310..16b3e65a 100644 --- a/test/Compat.jl +++ b/test/Compat.jl @@ -45,7 +45,16 @@ end @testitem "Serialization.jl" begin using Serialization @testset "Py" begin - for x in Py[Py(123), Py(1.23), Py("hello"), pylist([1, 2, 3]), pytuple([1, 2, 3]), Py(nothing), Py([1, 2, 3]), Py(:hello)] + for x in Py[ + Py(123), + Py(1.23), + Py("hello"), + pylist([1, 2, 3]), + pytuple([1, 2, 3]), + Py(nothing), + Py([1, 2, 3]), + Py(:hello), + ] io = IOBuffer() serialize(io, x) seekstart(io) @@ -53,7 +62,7 @@ end @test y isa Py @test pyis(pytype(x), pytype(y)) @test pyeq(Bool, x, y) - end + end end @testset "PyException" begin for e in Py[pybuiltins.ValueError("hello")] @@ -71,13 +80,13 @@ end @testitem "Tables.jl" begin @testset "pytable" begin - x = (x = [1,2,3], y = ["a", "b", "c"]) + x = (x = [1, 2, 3], y = ["a", "b", "c"]) # pandas # TODO: install pandas and test properly @test_throws PyException pytable(x, :pandas) # columns y = pytable(x, :columns) - @test pyeq(Bool, y, pydict(x=[1,2,3], y=["a","b","c"])) + @test pyeq(Bool, y, pydict(x = [1, 2, 3], y = ["a", "b", "c"])) # rows y = pytable(x, :rows) @test pyeq(Bool, y, pylist([(1, "a"), (2, "b"), (3, "c")])) @@ -85,6 +94,14 @@ end @test all(pyisinstance(y.y, pybuiltins.str) for y in y) # rowdicts y = pytable(x, :rowdicts) - @test pyeq(Bool, y, pylist([pydict(x=1, y="a"), pydict(x=2, y="b"), pydict(x=3, y="c")])) + @test pyeq( + Bool, + y, + pylist([ + pydict(x = 1, y = "a"), + pydict(x = 2, y = "b"), + pydict(x = 3, y = "c"), + ]), + ) end end diff --git a/test/Convert.jl b/test/Convert.jl index 3d82c6af..4f137459 100644 --- a/test/Convert.jl +++ b/test/Convert.jl @@ -116,8 +116,8 @@ end t3 = pyconvert(Tuple{Int,Int}, (6, 7)) @test t3 === (6, 7) # generic case (>16 fields) - t4 = pyconvert(Tuple{ntuple(i->Int,20)...,Vararg{Int}}, ntuple(i->i, 30)) - @test t4 === ntuple(i->i, 30) + t4 = pyconvert(Tuple{ntuple(i -> Int, 20)...,Vararg{Int}}, ntuple(i -> i, 30)) + @test t4 === ntuple(i -> i, 30) end @testitem "iterable → Vector" begin @@ -157,34 +157,34 @@ end @testitem "named tuple → NamedTuple" begin NT = pyimport("collections" => "namedtuple") t1 = pyconvert(NamedTuple, NT("NT", "x y")(1, 2)) - @test t1 === (x=1, y=2) + @test t1 === (x = 1, y = 2) @test_throws Exception pyconvert(NamedTuple, (2, 3)) t2 = pyconvert(NamedTuple{(:x, :y)}, NT("NT", "x y")(3, 4)) - @test t2 === (x=3, y=4) + @test t2 === (x = 3, y = 4) @test_throws Exception pyconvert(NamedTuple{(:y, :x)}, NT("NT", "x y")(3, 4)) t3 = pyconvert(NamedTuple{names,Tuple{Int,Int}} where {names}, NT("NT", "x y")(4, 5)) - @test t3 === (x=4, y=5) + @test t3 === (x = 4, y = 5) @test_throws Exception pyconvert(NamedTuple{names,Tuple{Int,Int}} where {names}, (5, 6)) t4 = pyconvert(NamedTuple{(:x, :y),Tuple{Int,Int}}, NT("NT", "x y")(6, 7)) - @test t4 === (x=6, y=7) + @test t4 === (x = 6, y = 7) end @testitem "mapping → PyDict" begin - x1 = pyconvert(PyDict, pydict([1=>11, 2=>22, 3=>33])) + x1 = pyconvert(PyDict, pydict([1 => 11, 2 => 22, 3 => 33])) @test x1 isa PyDict{Any,Any} - @test isequal(x1, Dict([1=>11, 2=>22, 3=>33])) - x2 = pyconvert(PyDict{Int,Int}, pydict([1=>11, 2=>22, 3=>33])) + @test isequal(x1, Dict([1 => 11, 2 => 22, 3 => 33])) + x2 = pyconvert(PyDict{Int,Int}, pydict([1 => 11, 2 => 22, 3 => 33])) @test x2 isa PyDict{Int,Int} - @test x2 == Dict(1=>11, 2=>22, 3=>33) + @test x2 == Dict(1 => 11, 2 => 22, 3 => 33) end @testitem "mapping → Dict" begin - x1 = pyconvert(Dict, pydict(["a"=>1, "b"=>2])) - @test x1 isa Dict{String, Int} - @test x1 == Dict("a"=>1, "b"=>2) - x2 = pyconvert(Dict{Char,Float32}, pydict(["c"=>3, "d"=>4])) + x1 = pyconvert(Dict, pydict(["a" => 1, "b" => 2])) + @test x1 isa Dict{String,Int} + @test x1 == Dict("a" => 1, "b" => 2) + x2 = pyconvert(Dict{Char,Float32}, pydict(["c" => 3, "d" => 4])) @test x2 isa Dict{Char,Float32} - @test x2 == Dict('c'=>3.0, 'd'=>4.0) + @test x2 == Dict('c' => 3.0, 'd' => 4.0) end @testitem "sequence → PyList" begin @@ -226,57 +226,102 @@ end @testitem "timedelta → Nanosecond" begin using Dates td = pyimport("datetime").timedelta - @testset for x in [-1_000_000_000, -1_000_000, -1_000, -1, 0, 1, 1_000, 1_000_000, 1_000_000_000] - y = pyconvert(Nanosecond, td(microseconds=x)) + @testset for x in [ + -1_000_000_000, + -1_000_000, + -1_000, + -1, + 0, + 1, + 1_000, + 1_000_000, + 1_000_000_000, + ] + y = pyconvert(Nanosecond, td(microseconds = x)) @test y === Nanosecond(x * 1000) end - @test_throws Exception pyconvert(Nanosecond, td(days=200_000)) - @test_throws Exception pyconvert(Nanosecond, td(days=-200_000)) + @test_throws Exception pyconvert(Nanosecond, td(days = 200_000)) + @test_throws Exception pyconvert(Nanosecond, td(days = -200_000)) end @testitem "timedelta → Microsecond" begin using Dates td = pyimport("datetime").timedelta - @testset for x in [-1_000_000_000, -1_000_000, -1_000, -1, 0, 1, 1_000, 1_000_000, 1_000_000_000] - y = pyconvert(Microsecond, td(microseconds=x)) + @testset for x in [ + -1_000_000_000, + -1_000_000, + -1_000, + -1, + 0, + 1, + 1_000, + 1_000_000, + 1_000_000_000, + ] + y = pyconvert(Microsecond, td(microseconds = x)) @test y === Microsecond(x) end - @test_throws Exception pyconvert(Microsecond, td(days=200_000_000)) - @test_throws Exception pyconvert(Microsecond, td(days=-200_000_000)) + @test_throws Exception pyconvert(Microsecond, td(days = 200_000_000)) + @test_throws Exception pyconvert(Microsecond, td(days = -200_000_000)) end @testitem "timedelta → Millisecond" begin using Dates td = pyimport("datetime").timedelta - @testset for x in [-1_000_000_000, -1_000_000, -1_000, -1, 0, 1, 1_000, 1_000_000, 1_000_000_000] - y = pyconvert(Millisecond, td(microseconds=x*1000)) + @testset for x in [ + -1_000_000_000, + -1_000_000, + -1_000, + -1, + 0, + 1, + 1_000, + 1_000_000, + 1_000_000_000, + ] + y = pyconvert(Millisecond, td(microseconds = x * 1000)) @test y === Millisecond(x) end - @test_throws Exception pyconvert(Millisecond, td(microseconds=1)) + @test_throws Exception pyconvert(Millisecond, td(microseconds = 1)) end @testitem "timedelta → Second" begin using Dates td = pyimport("datetime").timedelta - @testset for x in [-1_000_000_000, -1_000_000, -1_000, -1, 0, 1, 1_000, 1_000_000, 1_000_000_000] - y = pyconvert(Second, td(seconds=x)) + @testset for x in [ + -1_000_000_000, + -1_000_000, + -1_000, + -1, + 0, + 1, + 1_000, + 1_000_000, + 1_000_000_000, + ] + y = pyconvert(Second, td(seconds = x)) @test y === Second(x) end - @test_throws Exception pyconvert(Second, td(microseconds=1000)) + @test_throws Exception pyconvert(Second, td(microseconds = 1000)) end @testitem "pyconvert_add_rule (#364)" begin - id = string(rand(UInt128), base=16) - pyexec(""" - class Hello_364_$id: - pass - """, @__MODULE__) + id = string(rand(UInt128), base = 16) + pyexec( + """ + class Hello_364_$id: + pass + """, + @__MODULE__ + ) x = pyeval("Hello_364_$id()", @__MODULE__) @test pyconvert(Any, x) === x # This test has a side effect of influencing the rules cache t = pytype(x) - PythonCall.pyconvert_add_rule("$(t.__module__):$(t.__qualname__)", String, (_, _) -> "Hello!!") + PythonCall.pyconvert_add_rule( + "$(t.__module__):$(t.__qualname__)", + String, + (_, _) -> "Hello!!", + ) @test pyconvert(String, x) == "Hello!!" @test pyconvert(Any, x) == "Hello!!" # Broken before PR #365 end - -end diff --git a/test/Core.jl b/test/Core.jl index 03ea6867..c5a9b48e 100644 --- a/test/Core.jl +++ b/test/Core.jl @@ -25,8 +25,14 @@ @testset "pygetattr" begin @test pyisinstance(pygetattr(pybuiltins.None, "__class__"), pybuiltins.type) @test_throws PyException pygetattr(pybuiltins.None, "not_an_attr") - @test pyisinstance(pygetattr(pybuiltins.None, "__class__", pybuiltins.None), pybuiltins.type) - @test pyis(pygetattr(pybuiltins.None, "not_an_attr", pybuiltins.None), pybuiltins.None) + @test pyisinstance( + pygetattr(pybuiltins.None, "__class__", pybuiltins.None), + pybuiltins.type, + ) + @test pyis( + pygetattr(pybuiltins.None, "not_an_attr", pybuiltins.None), + pybuiltins.None, + ) end @testset "pysetattr" begin x = pytype("Foo", (), ())() @@ -77,25 +83,25 @@ @testset "pytruth" begin @test !pytruth(pybuiltins.None) @test pytruth(pybuiltins.object) - for n in -2:2 + for n = -2:2 @test pytruth(pyint(n)) == (n != 0) end - for n in 0:3 + for n = 0:3 @test pytruth(pylist(zeros(n))) == (n != 0) end end @testset "pynot" begin @test pynot(pybuiltins.None) @test !pynot(pybuiltins.int) - for n in -2:2 + for n = -2:2 @test pynot(pyfloat(n)) == (n == 0) end - for n in 0:3 + for n = 0:3 @test pynot(pylist(zeros(n))) == (n == 0) end end @testset "pylen" begin - for n in 0:3 + for n = 0:3 @test pylen(pytuple(zeros(n))) == n @test pylen(pylist(zeros(n))) == n end @@ -142,9 +148,9 @@ @test_throws PyException pycall(pybuiltins.None) @test pyeq(Bool, pycall(pybuiltins.int, "10"), 10) @test_throws PyException pycall(pybuiltins.int, "10", "20") - @test pyeq(Bool, pycall(pybuiltins.int, "10", base=16), 16) - @test_throws PyException pycall(pybuiltins.int, "10", base="16") - @test_throws PyException pycall(pybuiltins.int, "10", bad_argument=0) + @test pyeq(Bool, pycall(pybuiltins.int, "10", base = 16), 16) + @test_throws PyException pycall(pybuiltins.int, "10", base = "16") + @test_throws PyException pycall(pybuiltins.int, "10", bad_argument = 0) end @testset "pyeq" begin @test pyis(pyeq(pybuiltins.None, pybuiltins.None), pybuiltins.True) @@ -159,32 +165,32 @@ @test pyne(Bool, pybuiltins.None, pybuiltins.int) end @testset "pylt" begin - for a in -1:1 - for b in -1:1 + for a = -1:1 + for b = -1:1 @test pyis(pylt(pyint(a), pyint(b)), pybool(a < b)) @test pylt(Bool, pyint(a), pyint(b)) == (a < b) end end end @testset "pyle" begin - for a in -1:1 - for b in -1:1 + for a = -1:1 + for b = -1:1 @test pyis(pyle(pyint(a), pyint(b)), pybool(a ≤ b)) @test pyle(Bool, pyint(a), pyint(b)) == (a ≤ b) end end end @testset "pygt" begin - for a in -1:1 - for b in -1:1 + for a = -1:1 + for b = -1:1 @test pyis(pygt(pyint(a), pyint(b)), pybool(a > b)) @test pygt(Bool, pyint(a), pyint(b)) == (a > b) end end end @testset "pyge" begin - for a in -1:1 - for b in -1:1 + for a = -1:1 + for b = -1:1 @test pyis(pyge(pyint(a), pyint(b)), pybool(a ≥ b)) @test pyge(Bool, pyint(a), pyint(b)) == (a ≥ b) end @@ -240,47 +246,47 @@ end @testitem "number" begin @testset "pyneg" begin - for n in -2:2 + for n = -2:2 @test pyeq(Bool, pyneg(pyint(n)), pyint(-n)) end end @testset "pypos" begin - for n in -2:2 + for n = -2:2 @test pyeq(Bool, pypos(pyint(n)), pyint(n)) end end @testset "pyabs" begin - for n in -2:2 + for n = -2:2 @test pyeq(Bool, pyabs(pyint(n)), pyint(abs(n))) end end @testset "pyinv" begin - for n in -2:2 + for n = -2:2 @test pyeq(Bool, pyinv(pyint(n)), pyint(-n - 1)) end end @testset "pyindex" begin - for n in -2:2 + for n = -2:2 @test pyeq(Bool, pyindex(pyint(n)), pyint(n)) end end @testset "pyadd" begin - for x in -2:2 - for y in -2:2 + for x = -2:2 + for y = -2:2 @test pyeq(Bool, pyadd(pyint(x), pyint(y)), pyint(x + y)) end end end @testset "pysub" begin - for x in -2:2 - for y in -2:2 + for x = -2:2 + for y = -2:2 @test pyeq(Bool, pysub(pyint(x), pyint(y)), pyint(x - y)) end end end @testset "pymul" begin - for x in -2:2 - for y in -2:2 + for x = -2:2 + for y = -2:2 @test pyeq(Bool, pymul(pyint(x), pyint(y)), pyint(x * y)) end end @@ -294,8 +300,8 @@ end # end # end @testset "pytruediv" begin - for x in -2:2 - for y in -2:2 + for x = -2:2 + for y = -2:2 if y == 0 @test_throws PyException pytruediv(pyint(x), pyint(y)) else @@ -305,8 +311,8 @@ end end end @testset "pyfloordiv" begin - for x in -2:2 - for y in -2:2 + for x = -2:2 + for y = -2:2 if y == 0 @test_throws PyException pyfloordiv(pyint(x), pyint(y)) else @@ -316,8 +322,8 @@ end end end @testset "pymod" begin - for x in -2:2 - for y in -2:2 + for x = -2:2 + for y = -2:2 if y == 0 @test_throws PyException pymod(pyint(x), pyint(y)) else @@ -327,8 +333,8 @@ end end end @testset "pydivmod" begin - for x in -2:2 - for y in -2:2 + for x = -2:2 + for y = -2:2 if y == 0 @test_throws PyException pydivmod(pyint(x), pyint(y)) else @@ -338,32 +344,32 @@ end end end @testset "pylshift" begin - for n in 0:3 + for n = 0:3 @test pyeq(Bool, pylshift(pyint(123), pyint(n)), pyint(123 << n)) end end @testset "pyrshift" begin - for n in 0:3 + for n = 0:3 @test pyeq(Bool, pyrshift(pyint(123), pyint(n)), pyint(123 >> n)) end end @testset "pyand" begin - for x in 0:3 - for y in 0:3 + for x = 0:3 + for y = 0:3 @test pyeq(Bool, pyand(pyint(x), pyint(y)), pyint(x & y)) end end end @testset "pyxor" begin - for x in 0:3 - for y in 0:3 + for x = 0:3 + for y = 0:3 @test pyeq(Bool, pyxor(pyint(x), pyint(y)), pyint(x ⊻ y)) end end end @testset "pyor" begin - for x in 0:3 - for y in 0:3 + for x = 0:3 + for y = 0:3 @test pyeq(Bool, pyor(pyint(x), pyint(y)), pyint(x | y)) end end @@ -374,7 +380,7 @@ end @testitem "builtins" begin @testset "pyprint" begin buf = pyimport("io").StringIO() - ans = pyprint("hello", 12, file=buf) + ans = pyprint("hello", 12, file = buf) @test ans === nothing buf.seek(0) @test pyeq(Bool, buf.read().strip(), "hello 12") @@ -441,7 +447,11 @@ end @test pyisinstance(pybytes(UInt8[1, 2, 3]), pybuiltins.bytes) @test pyeq(Bool, pybytes(pylist([1, 2, 3])), pybytes(UInt8[1, 2, 3])) @test pyeq(Bool, pybytes(b"foo"), pystr("foo").encode("ascii")) - @test pyeq(Bool, pybytes(codeunits(SubString("foobarbaz", 4:6))), pystr("bar").encode("ascii")) + @test pyeq( + Bool, + pybytes(codeunits(SubString("foobarbaz", 4:6))), + pystr("bar").encode("ascii"), + ) @test pybytes(Vector, pylist([1, 2, 3])) == UInt8[1, 2, 3] @test pybytes(Vector{UInt8}, pylist([1, 2, 3])) == UInt8[1, 2, 3] @test pybytes(Base.CodeUnits, pystr("foo").encode("ascii")) == b"foo" @@ -459,7 +469,7 @@ end @test pyeq(Bool, pygetitem(x, 1), 2) @test pyeq(Bool, pygetitem(x, 2), 3) @test pyeq(Bool, pytuple([1, 2, 3]), x) - @test pyeq(Bool, pytuple(i + 1 for i in 0:10 if i < 3), x) + @test pyeq(Bool, pytuple(i + 1 for i = 0:10 if i < 3), x) @test pyeq(Bool, pytuple(pytuple((1, 2, 3))), x) @test pyeq(Bool, pytuple(pylist([1, 2, 3])), x) end @@ -475,7 +485,7 @@ end @test pyeq(Bool, pygetitem(x, 1), 2) @test pyeq(Bool, pygetitem(x, 2), 3) @test pyeq(Bool, pylist([1, 2, 3]), x) - @test pyeq(Bool, pylist(i + 1 for i in 0:10 if i < 3), x) + @test pyeq(Bool, pylist(i + 1 for i = 0:10 if i < 3), x) @test pyeq(Bool, pylist(pylist((1, 2, 3))), x) @test pyeq(Bool, pylist(pytuple([1, 2, 3])), x) @test pyeq(Bool, pycollist([1, 2, 3]), pylist([1, 2, 3])) @@ -488,7 +498,7 @@ end z = pydict() @test pyisinstance(z, pybuiltins.dict) @test pylen(z) == 0 - x = pydict(foo=1, bar=2) + x = pydict(foo = 1, bar = 2) @test pyisinstance(x, pybuiltins.dict) @test pylen(x) == 2 @test pyeq(Bool, pygetitem(x, "foo"), 1) @@ -496,7 +506,7 @@ end @test pyeq(Bool, pydict(["foo" => 1, "bar" => 2]), x) @test pyeq(Bool, pydict([("foo" => 1), ("bar" => 2)]), x) @test pyeq(Bool, pydict(Dict("foo" => 1, "bar" => 2)), x) - @test pyeq(Bool, pydict((foo=1, bar=2)), x) + @test pyeq(Bool, pydict((foo = 1, bar = 2)), x) @test pyeq(Bool, pydict(x), x) end @@ -736,7 +746,7 @@ end @test pyeq(Bool, pyeval("x+1", g, l), 4) @test pyeq(Bool, pyeval("x+1", g, Dict()), 3) @test pyeq(Bool, pyeval("x+1", g, Dict("x" => 0)), 1) - @test pyeq(Bool, pyeval("x+1", g, (x=1,)), 2) + @test pyeq(Bool, pyeval("x+1", g, (x = 1,)), 2) # check pyexec runs in local scope pyexec("x=4", g, l) @test pyeq(Bool, g["x"], 2) @@ -751,13 +761,13 @@ end # @pyexec @test_throws PyException @pyexec(`raise ValueError`) @test @pyexec(`1 + 2`) === nothing - @test @pyexec(`ans = 1 + 2` => (ans::Int,)) === (ans=3,) - @test @pyexec((x=1, y=2) => `ans = x + y` => (ans::Int,)) === (ans=3,) + @test @pyexec(`ans = 1 + 2` => (ans::Int,)) === (ans = 3,) + @test @pyexec((x = 1, y = 2) => `ans = x + y` => (ans::Int,)) === (ans = 3,) # @pyeval @test_throws PyException @pyeval(`import sys`) # not an expression @test_throws PyException @pyeval(`None + None`) @test @pyeval(`1 + 2` => Int) === 3 - @test @pyeval((x=1, y=2) => `x + y` => Int) === 3 + @test @pyeval((x = 1, y = 2) => `x + y` => Int) === 3 end @testitem "@pyconst" begin diff --git a/test/JlWrap.jl b/test/JlWrap.jl index b6364ccd..f0a20be9 100644 --- a/test/JlWrap.jl +++ b/test/JlWrap.jl @@ -20,7 +20,7 @@ Base.powermod(x::Foo, y::Foo, z::Foo) = "powermod($(x.value), $(y.value), $(z.value))" (x::Foo)(args...; kw...) = "$(x.value)($args)$(length(kw))" Base.getindex(x::Foo, idx...) = "$(x.value)[$idx]" - Base.setindex!(x::Foo, v, idx...) = (x.value = v+sum(idx); x) + Base.setindex!(x::Foo, v, idx...) = (x.value = v + sum(idx); x) Base.delete!(x::Foo, idx...) = (x.value = -sum(idx); x) Base.in(v::Int, x::Foo) = x.value == v Base.nameof(x::Foo) = "nameof $(x.value)" @@ -56,7 +56,7 @@ @testset "call" begin z = pyjl(Foo(1))(4, 5) @test pyconvert(String, z) == "1((4, 5))0" - z = pyjl(Foo(1))(4, 5; foo=true, bar=true) + z = pyjl(Foo(1))(4, 5; foo = true, bar = true) @test pyconvert(String, z) == "1((4, 5))2" end @testset "getitem" begin @@ -149,11 +149,11 @@ @test pyconvert(String, z) == "1 % 2" end @testset "pow" begin - z = pyjl(Foo(1)) ^ pyjl(Foo(2)) + z = pyjl(Foo(1))^pyjl(Foo(2)) @test pyconvert(String, z) == "1 ^ 2" end @testset "rpow" begin - z = pyjlraw(Foo(1)) ^ pyjl(Foo(2)) + z = pyjlraw(Foo(1))^pyjl(Foo(2)) @test pyconvert(String, z) == "1 ^ 2" end @testset "lshift" begin @@ -207,11 +207,11 @@ end @testset "display" begin pyjl(Foo(1))._jl_display() - pyjl(Foo(1))._jl_display(mime="text/plain") + pyjl(Foo(1))._jl_display(mime = "text/plain") end @testset "help" begin pyjl(Foo(1))._jl_help() - pyjl(Foo(1))._jl_help(mime="text/plain") + pyjl(Foo(1))._jl_help(mime = "text/plain") end end @@ -247,16 +247,16 @@ end @test pyeq(Bool, x[-1], 5) @test pyeq(Bool, x[-2], 4) @test pyeq(Bool, x[-3], 3) - @test pyjlvalue(x[pyslice(3)]) == [1,2,3] - @test pyjlvalue(x[pyslice(2)]) == [1,2] - @test pyjlvalue(x[pyslice(1,2)]) == [2] - @test pyjlvalue(x[pyslice(2,2)]) == [] - @test pyjlvalue(x[pyslice(0,-1)]) == [1,2,3,4] - @test pyjlvalue(x[pyslice(-2,nothing)]) == [4,5] - @test pyjlvalue(x[pyslice(0, 3, 1)]) == [1,2,3] - @test pyjlvalue(x[pyslice(nothing,nothing,2)]) == [1,3,5] - @test pyjlvalue(x[pyslice(1,nothing,2)]) == [2,4] - @test pyjlvalue(x[pyslice(0,nothing,3)]) == [1,4] + @test pyjlvalue(x[pyslice(3)]) == [1, 2, 3] + @test pyjlvalue(x[pyslice(2)]) == [1, 2] + @test pyjlvalue(x[pyslice(1, 2)]) == [2] + @test pyjlvalue(x[pyslice(2, 2)]) == [] + @test pyjlvalue(x[pyslice(0, -1)]) == [1, 2, 3, 4] + @test pyjlvalue(x[pyslice(-2, nothing)]) == [4, 5] + @test pyjlvalue(x[pyslice(0, 3, 1)]) == [1, 2, 3] + @test pyjlvalue(x[pyslice(nothing, nothing, 2)]) == [1, 3, 5] + @test pyjlvalue(x[pyslice(1, nothing, 2)]) == [2, 4] + @test pyjlvalue(x[pyslice(0, nothing, 3)]) == [1, 4] x = pyjl([1 2; 3 4]) @test pyeq(Bool, x[0, 0], 1) @test pyeq(Bool, x[0, 1], 2) @@ -268,19 +268,19 @@ end @testset "setitem" begin x = [0 0; 0 0] y = pyjl(x) - y[0,0] = 1 + y[0, 0] = 1 @test x == [1 0; 0 0] - y[0,1] = 2 + y[0, 1] = 2 @test x == [1 2; 0 0] - y[1,0] = 3 + y[1, 0] = 3 @test x == [1 2; 3 0] - y[-1,0] = 4 + y[-1, 0] = 4 @test x == [1 2; 4 0] - y[-2,pyslice(nothing)] = 5 + y[-2, pyslice(nothing)] = 5 @test x == [5 5; 4 0] - y[pyslice(nothing),-1] = 6 + y[pyslice(nothing), -1] = 6 @test x == [5 6; 4 6] - y[pyslice(nothing),pyslice(nothing)] = 7 + y[pyslice(nothing), pyslice(nothing)] = 7 @test x == [7 7; 7 7] end @testset "delitem" begin @@ -292,7 +292,7 @@ end @test x == [2, 3, 5, 6, 7, 8] pydelitem(y, -3) @test x == [2, 3, 5, 7, 8] - pydelitem(y, pyslice(1,nothing,2)) + pydelitem(y, pyslice(1, nothing, 2)) @test x == [2, 5, 8] end @testset "reshape" begin @@ -309,7 +309,7 @@ end @test pyjlvalue(x) == pyjlvalue(y) @test typeof(pyjlvalue(x)) == typeof(pyjlvalue(y)) @test pyjlvalue(x) !== pyjlvalue(y) - x[0,0] = 0 + x[0, 0] = 0 @test pyjlvalue(x) == [0 2; 3 4] @test pyjlvalue(y) == [1 2; 3 4] end @@ -334,7 +334,7 @@ end @test pytruth(m.f_contiguous) @test pyeq(Bool, m.format, "f") @test pyeq(Bool, m.itemsize, 4) - @test pyeq(Bool, m.nbytes, 4*6) + @test pyeq(Bool, m.nbytes, 4 * 6) @test pyeq(Bool, m.ndim, 2) @test !pytruth(m.readonly) @test pyeq(Bool, m.shape, (2, 3)) @@ -358,7 +358,7 @@ end end @testset "bool" begin @test !pytruth(pyjl(Dict())) - @test pytruth(pyjl(Dict("one"=>1, "two"=>2))) + @test pytruth(pyjl(Dict("one" => 1, "two" => 2))) end end @@ -375,7 +375,7 @@ end end @testitem "iter" begin - x1 = [1,2,3,4,5] + x1 = [1, 2, 3, 4, 5] x2 = pyjl(x1) x3 = pylist(x2) x4 = pyconvert(Vector{Int}, x3) @@ -400,19 +400,19 @@ end @testset "type" begin @test pyis(pytype(pyjl(false)), PythonCall.pyjlintegertype) @test pyis(pytype(pyjl(0)), PythonCall.pyjlintegertype) - @test pyis(pytype(pyjl(0//1)), PythonCall.pyjlrationaltype) + @test pyis(pytype(pyjl(0 // 1)), PythonCall.pyjlrationaltype) @test pyis(pytype(pyjl(0.0)), PythonCall.pyjlrealtype) @test pyis(pytype(pyjl(Complex(0.0))), PythonCall.pyjlcomplextype) end @testset "bool" begin @test !pytruth(pyjl(false)) @test !pytruth(pyjl(0)) - @test !pytruth(pyjl(0//1)) + @test !pytruth(pyjl(0 // 1)) @test !pytruth(pyjl(0.0)) @test !pytruth(pyjl(Complex(0.0))) @test pytruth(pyjl(true)) @test pytruth(pyjl(3)) - @test pytruth(pyjl(5//2)) + @test pytruth(pyjl(5 // 2)) @test pytruth(pyjl(2.3)) @test pytruth(pyjl(Complex(1.2, 3.4))) end @@ -432,7 +432,7 @@ end end @testset "bool" begin @test !pytruth(pyjl(Set())) - @test pytruth(pyjl(Set([1,2,3]))) + @test pytruth(pyjl(Set([1, 2, 3]))) end end @@ -452,7 +452,7 @@ end @testset "bool" begin @test !pytruth(pyjl([])) @test pytruth(pyjl([1])) - @test pytruth(pyjl([1,2])) + @test pytruth(pyjl([1, 2])) end @testset "resize" begin x = pyjl([1, 2, 3, 4, 5]) @@ -469,91 +469,91 @@ end @test pyjlvalue(x) == [5, 6] end @testset "sort" begin - x = pyjl([4,6,2,3,7,6,1]) + x = pyjl([4, 6, 2, 3, 7, 6, 1]) x.sort() - @test pyjlvalue(x) == [1,2,3,4,6,6,7] - x = pyjl([4,6,2,3,7,6,1]) - x.sort(reverse=true) - @test pyjlvalue(x) == [7,6,6,4,3,2,1] - x = pyjl([4,-6,2,-3,7,-6,1]) - x.sort(key=abs) - @test pyjlvalue(x) == [1,2,-3,4,-6,-6,7] - x = pyjl([4,-6,2,-3,7,-6,1]) - x.sort(key=abs, reverse=true) - @test pyjlvalue(x) == [7,-6,-6,4,-3,2,1] + @test pyjlvalue(x) == [1, 2, 3, 4, 6, 6, 7] + x = pyjl([4, 6, 2, 3, 7, 6, 1]) + x.sort(reverse = true) + @test pyjlvalue(x) == [7, 6, 6, 4, 3, 2, 1] + x = pyjl([4, -6, 2, -3, 7, -6, 1]) + x.sort(key = abs) + @test pyjlvalue(x) == [1, 2, -3, 4, -6, -6, 7] + x = pyjl([4, -6, 2, -3, 7, -6, 1]) + x.sort(key = abs, reverse = true) + @test pyjlvalue(x) == [7, -6, -6, 4, -3, 2, 1] end @testset "reverse" begin - x = pyjl([1,2,3,4,5]) + x = pyjl([1, 2, 3, 4, 5]) x.reverse() - @test pyjlvalue(x) == [5,4,3,2,1] + @test pyjlvalue(x) == [5, 4, 3, 2, 1] end @testset "clear" begin - x = pyjl([1,2,3,4,5]) - @test pyjlvalue(x) == [1,2,3,4,5] + x = pyjl([1, 2, 3, 4, 5]) + @test pyjlvalue(x) == [1, 2, 3, 4, 5] x.clear() @test pyjlvalue(x) == [] end @testset "reversed" begin - x = pyjl([1,2,3,4,5]) + x = pyjl([1, 2, 3, 4, 5]) y = pybuiltins.reversed(x) - @test pyjlvalue(x) == [1,2,3,4,5] - @test pyjlvalue(y) == [5,4,3,2,1] + @test pyjlvalue(x) == [1, 2, 3, 4, 5] + @test pyjlvalue(y) == [5, 4, 3, 2, 1] end @testset "insert" begin - x = pyjl([1,2,3]) + x = pyjl([1, 2, 3]) x.insert(0, 4) - @test pyjlvalue(x) == [4,1,2,3] + @test pyjlvalue(x) == [4, 1, 2, 3] x.insert(2, 5) - @test pyjlvalue(x) == [4,1,5,2,3] + @test pyjlvalue(x) == [4, 1, 5, 2, 3] x.insert(5, 6) - @test pyjlvalue(x) == [4,1,5,2,3,6] + @test pyjlvalue(x) == [4, 1, 5, 2, 3, 6] x.insert(-3, 7) - @test pyjlvalue(x) == [4,1,5,7,2,3,6] + @test pyjlvalue(x) == [4, 1, 5, 7, 2, 3, 6] @test_throws PyException x.insert(10, 10) end @testset "append" begin - x = pyjl([1,2,3]) + x = pyjl([1, 2, 3]) x.append(4) - @test pyjlvalue(x) == [1,2,3,4] + @test pyjlvalue(x) == [1, 2, 3, 4] x.append(5.0) - @test pyjlvalue(x) == [1,2,3,4,5] + @test pyjlvalue(x) == [1, 2, 3, 4, 5] @test_throws PyException x.append(nothing) @test_throws PyException x.append(1.2) @test_throws PyException x.append("2") end @testset "extend" begin - x = pyjl([1,2,3]) + x = pyjl([1, 2, 3]) x.extend(pylist()) - @test pyjlvalue(x) == [1,2,3] - x.extend(pylist([4,5])) - @test pyjlvalue(x) == [1,2,3,4,5] + @test pyjlvalue(x) == [1, 2, 3] + x.extend(pylist([4, 5])) + @test pyjlvalue(x) == [1, 2, 3, 4, 5] x.extend(pylist([6.0])) - @test pyjlvalue(x) == [1,2,3,4,5,6] + @test pyjlvalue(x) == [1, 2, 3, 4, 5, 6] end @testset "pop" begin - x = pyjl([1,2,3,4,5]) + x = pyjl([1, 2, 3, 4, 5]) @test pyeq(Bool, x.pop(), 5) - @test pyjlvalue(x) == [1,2,3,4] + @test pyjlvalue(x) == [1, 2, 3, 4] @test pyeq(Bool, x.pop(0), 1) - @test pyjlvalue(x) == [2,3,4] + @test pyjlvalue(x) == [2, 3, 4] @test pyeq(Bool, x.pop(1), 3) - @test pyjlvalue(x) == [2,4] + @test pyjlvalue(x) == [2, 4] @test pyeq(Bool, x.pop(-2), 2) @test pyjlvalue(x) == [4] @test_throws PyException x.pop(10) end @testset "remove" begin - x = pyjl([1,3,2,4,5,3,1]) - @test pyjlvalue(x) == [1,3,2,4,5,3,1] + x = pyjl([1, 3, 2, 4, 5, 3, 1]) + @test pyjlvalue(x) == [1, 3, 2, 4, 5, 3, 1] x.remove(3) - @test pyjlvalue(x) == [1,2,4,5,3,1] + @test pyjlvalue(x) == [1, 2, 4, 5, 3, 1] @test_throws PyException x.remove(0) @test_throws PyException x.remove(nothing) @test_throws PyException x.remove("2") - @test pyjlvalue(x) == [1,2,4,5,3,1] + @test pyjlvalue(x) == [1, 2, 4, 5, 3, 1] end @testset "index" begin - x = pyjl([1,3,2,4,5,2,1]) + x = pyjl([1, 3, 2, 4, 5, 2, 1]) @test pyeq(Bool, x.index(1), 0) @test pyeq(Bool, x.index(2), 2) @test pyeq(Bool, x.index(3), 1) @@ -566,7 +566,7 @@ end @test_throws PyException x.index("2") end @testset "count" begin - x = pyjl([1,2,3,4,5,1,2,3,1]) + x = pyjl([1, 2, 3, 4, 5, 1, 2, 3, 1]) @test pyeq(Bool, x.count(0), 0) @test pyeq(Bool, x.count(1), 3) @test pyeq(Bool, x.count(2), 2) diff --git a/test/PyMacro.jl b/test/PyMacro.jl index d3a1b1b0..2b5bd4cf 100644 --- a/test/PyMacro.jl +++ b/test/PyMacro.jl @@ -84,14 +84,14 @@ @test x isa Py @test pyis(pytype(x), pybuiltins.dict) @test pyeq(Bool, x, pydict()) - x = @py {x=1, y=2} + x = @py {x = 1, y = 2} @test x isa Py @test pyis(pytype(x), pybuiltins.dict) - @test pyeq(Bool, x, pydict(x=1, y=2)) - x = @py {"x": 1, "y": 2} + @test pyeq(Bool, x, pydict(x = 1, y = 2)) + x = @py {"x":1, "y":2} @test x isa Py @test pyis(pytype(x), pybuiltins.dict) - @test pyeq(Bool, x, pydict(x=1, y=2)) + @test pyeq(Bool, x, pydict(x = 1, y = 2)) # set x = @py set() @test x isa Py @@ -197,7 +197,7 @@ @test pyis(_ver, sys.version_info) end @testset "short-circuit" begin - x = @py 3 && pylist([1,2]) + x = @py 3 && pylist([1, 2]) @test pyeq(Bool, x, pylist([1, 2])) x = @py None && True @test pyis(x, pybuiltins.None) @@ -207,30 +207,54 @@ @test pyeq(Bool, x, 8) end @testset "if" begin - x = @py if 1 == 2; "a"; end + x = @py if 1 == 2 + "a" + end @test x isa Py @test pyis(x, pybuiltins.None) - x = @py if 1 < 2; "a"; end + x = @py if 1 < 2 + "a" + end @test x isa Py @test pyeq(Bool, x, "a") - x = @py if 1 == 2; "a"; else; "b"; end + x = @py if 1 == 2 + "a" + else + "b" + end @test x isa Py @test pyeq(Bool, x, "b") - x = @py if 1 < 2; "a"; else; "b"; end + x = @py if 1 < 2 + "a" + else + "b" + end @test x isa Py @test pyeq(Bool, x, "a") - x = @py if 1 == 2; "a"; elseif 1 < 2; "b"; end + x = @py if 1 == 2 + "a" + elseif 1 < 2 + "b" + end @test x isa Py @test pyeq(Bool, x, "b") - x = @py if 1 < 2; "a"; elseif 2 < 3; "b"; end + x = @py if 1 < 2 + "a" + elseif 2 < 3 + "b" + end @test x isa Py @test pyeq(Bool, x, "a") - x = @py if 1 == 2; "a"; elseif 2 == 3; "b"; end + x = @py if 1 == 2 + "a" + elseif 2 == 3 + "b" + end @test x isa Py @test pyis(x, pybuiltins.None) end @testset "for" begin - x = pydict(x=1, y=2) + x = pydict(x = 1, y = 2) y = pylist() @py for k in x y.append(k) diff --git a/test/Utils.jl b/test/Utils.jl index 0898cfea..33c82bd9 100644 --- a/test/Utils.jl +++ b/test/Utils.jl @@ -3,7 +3,7 @@ struct Test{T<:Number} x::T end - Base.show(io::IO, ::MIME"text/plain", x::Test{T}) where T = show(io, x.t) + Base.show(io::IO, ::MIME"text/plain", x::Test{T}) where {T} = show(io, x.t) Base.show(io::IO, ::MIME"text/x-test", x::Test) = show(io, x.t) @testset for x in Any[1, "foo", [], 'z', Test(5)] @@ -16,7 +16,7 @@ end @testitem "StaticString length and indexing" begin - s = PythonCall.Utils.StaticString{UInt32, 44}("ababababb") + s = PythonCall.Utils.StaticString{UInt32,44}("ababababb") @test length(s) == 9 @test s[1] == 'a' @test s[1:2] == "ab" diff --git a/test/Wrap.jl b/test/Wrap.jl index 56e5d371..fe8659e3 100644 --- a/test/Wrap.jl +++ b/test/Wrap.jl @@ -1,5 +1,5 @@ @testitem "PyArray" begin - x = pyimport("array").array("i", pylist([1,2,3])) + x = pyimport("array").array("i", pylist([1, 2, 3])) y = PyArray(x) z = PyArray{Cint,1,false,false,Cint}(x) @testset "construct" begin @@ -85,7 +85,7 @@ end @testitem "PyDict" begin - x = pydict(["foo"=>12]) + x = pydict(["foo" => 12]) y = PyDict(x) z = PyDict{String,Int}(x) @testset "construct" begin @@ -106,8 +106,8 @@ end @test t isa PyDict{String,Int} @test !pyis(t, z) t["bar"] = 34 - @test z == Dict("foo"=>12) - @test t == Dict("foo"=>12, "bar"=>34) + @test z == Dict("foo" => 12) + @test t == Dict("foo" => 12, "bar" => 34) end @testset "iterate" begin @test collect(z) == ["foo" => 12] @@ -122,19 +122,19 @@ end @testset "setindex!" begin t = copy(z) @test setindex!(t, 34, "bar") === t - @test t == Dict("foo"=>12, "bar"=>34) + @test t == Dict("foo" => 12, "bar" => 34) @test setindex!(t, 56, "foo") === t - @test t == Dict("foo"=>56, "bar"=>34) + @test t == Dict("foo" => 56, "bar" => 34) @test_throws Exception setindex!(t, 0, nothing) @test_throws Exception setindex!(t, nothing, "foo") - @test t == Dict("foo"=>56, "bar"=>34) + @test t == Dict("foo" => 56, "bar" => 34) end @testset "delete!" begin t = copy(z) @test delete!(t, "bar") === t - @test t == Dict("foo"=>12) + @test t == Dict("foo" => 12) @test delete!(t, 0) === t - @test t == Dict("foo"=>12) + @test t == Dict("foo" => 12) @test delete!(t, "foo") === t @test isempty(t) @test delete!(t, "foo") === t @@ -160,23 +160,23 @@ end @test get(t, 0, 1) === 1 @test get(Vector, t, "foo") === 12 @test get(Vector, t, "bar") == [] - @test t == Dict("foo"=>12) + @test t == Dict("foo" => 12) end @testset "get!" begin t = copy(z) @test get!(t, "foo", 0) === 12 - @test t == Dict("foo"=>12) + @test t == Dict("foo" => 12) @test get!(t, "bar", 0) === 0 - @test t == Dict("foo"=>12, "bar"=>0) - @test get!(()->99, t, "foo") === 12 - @test t == Dict("foo"=>12, "bar"=>0) - @test get!(()->99, t, "baz") === 99 - @test t == Dict("foo"=>12, "bar"=>0, "baz"=>99) + @test t == Dict("foo" => 12, "bar" => 0) + @test get!(() -> 99, t, "foo") === 12 + @test t == Dict("foo" => 12, "bar" => 0) + @test get!(() -> 99, t, "baz") === 99 + @test t == Dict("foo" => 12, "bar" => 0, "baz" => 99) @test_throws Exception get!(t, 0, 0) @test_throws Exception get!(t, "", "") - @test_throws Exception get!(()->99, t, 0) + @test_throws Exception get!(() -> 99, t, 0) @test_throws Exception get!(Vector, t, "") - @test t == Dict("foo"=>12, "bar"=>0, "baz"=>99) + @test t == Dict("foo" => 12, "bar" => 0, "baz" => 99) end @testset "construct empty" begin @test PyDict() isa PyDict{Py,Py} @@ -332,7 +332,7 @@ end t = copy(z) @test setindex!(t, 11, 1) === t @test setindex!(t, 22.0, 2) === t - @test setindex!(t, 66//2, 3) == t + @test setindex!(t, 66 // 2, 3) == t @test t == [11, 22, 33] @test_throws BoundsError t[-1] = 0 @test_throws BoundsError t[0] = 0 @@ -440,7 +440,7 @@ end def __init__(self, **kw): self.__dict__.update(kw) """ => DataFrame - df = DataFrame(shape=(4, 3), columns=pylist(["foo", "bar", "baz"])) + df = DataFrame(shape = (4, 3), columns = pylist(["foo", "bar", "baz"])) x = PyPandasDataFrame(df) @test ispy(x) @test Py(x) === df