Skip to content

Commit 3a17ba7

Browse files
committed
fix: route PyDict REPL completion through Python thread
1 parent beec1ec commit 3a17ba7

5 files changed

Lines changed: 42 additions & 8 deletions

File tree

src/Core/Py.jl

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,25 @@ Py(x::Date) = pydate(x)
125125
Py(x::Time) = pytime(x)
126126
Py(x::DateTime) = pydatetime(x)
127127

128+
function _py_on_main_thread_if_needed(f)
129+
if C.PyGILState_Check() == 1
130+
f()
131+
else
132+
C.on_main_thread(f)
133+
end
134+
end
135+
128136
Base.string(x::Py) = pyisnull(x) ? "<py NULL>" : pystr(String, x)
129137
Base.print(io::IO, x::Py) = print(io, string(x))
130138

131139
function Base.show(io::IO, x::Py)
140+
_py_on_main_thread_if_needed() do
141+
_show(io, x)
142+
nothing
143+
end
144+
end
145+
146+
function _show(io::IO, x::Py)
132147
if get(io, :typeinfo, Any) == Py
133148
if pyisnull(x)
134149
print(io, "NULL")
@@ -292,13 +307,9 @@ function _propertynames(x::Py, private::Bool)
292307
end
293308

294309
function Base.propertynames(x::Py, private::Bool = false)
295-
if C.PyGILState_Check() == 1
310+
_py_on_main_thread_if_needed() do
296311
_propertynames(x, private)
297-
else
298-
C.on_main_thread() do
299-
_propertynames(x, private)
300-
end::Vector{Symbol}
301-
end
312+
end::Vector{Symbol}
302313
end
303314

304315
Base.Bool(x::Py) = pytruth(x)

src/Wrap/PyDict.jl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,19 @@ function Base.iterate(x::PyDict{K,V}, it::Py = pyiter(x)) where {K,V}
2424
return (k => v, it)
2525
end
2626

27-
function Base.iterate(x::Base.KeySet{K,PyDict{K,V}}, it::Py = pyiter(x.dict)) where {K,V}
27+
function Base.iterate(x::Base.KeySet{K,<:PyDict{K}})::Union{Nothing,Tuple{K,Py}} where {K}
28+
_py_on_main_thread_if_needed() do
29+
_iterate(x, pyiter(x.dict))
30+
end
31+
end
32+
33+
function Base.iterate(x::Base.KeySet{K,<:PyDict{K}}, it::Py)::Union{Nothing,Tuple{K,Py}} where {K}
34+
_py_on_main_thread_if_needed() do
35+
_iterate(x, it)
36+
end
37+
end
38+
39+
function _iterate(x::Base.KeySet{K,<:PyDict{K}}, it::Py) where {K}
2840
k_ = unsafe_pynext(it)
2941
pyisnull(k_) && return nothing
3042
k = pyconvert(K, k_)

src/Wrap/Wrap.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ using Base: @propagate_inbounds
2020
using Tables: Tables
2121
using UnsafePointers: UnsafePtr
2222

23-
import ..Core: Py, ispy
23+
import ..Core: Py, ispy, _py_on_main_thread_if_needed
2424

2525
include("PyIterable.jl")
2626
include("PyDict.jl")

test/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
55
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
66
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
77
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
8+
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
89
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
910
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
1011
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

test/Wrap.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,16 @@ end
122122
@testset "iterate keys" begin
123123
@test collect(keys(z)) == ["foo"]
124124
end
125+
@testset "complete keys from another thread" begin
126+
using REPL
127+
task = Threads.@spawn begin
128+
completions, _, _ = REPL.REPLCompletions.completions("y[", 2, @__MODULE__)
129+
length(completions)
130+
end
131+
wait(task)
132+
completion_count = fetch(task)
133+
@test completion_count == 1
134+
end
125135
@testset "getindex" begin
126136
@test z["foo"] === 12
127137
@test_throws KeyError z["bar"]

0 commit comments

Comments
 (0)