Skip to content

Commit 5e41917

Browse files
committed
fix: guard PyDict REPL completion with GIL
1 parent beec1ec commit 5e41917

6 files changed

Lines changed: 29 additions & 4 deletions

File tree

src/Core/Core.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const ROOT_DIR = dirname(dirname(@__DIR__))
1111
using ..PythonCall
1212
using ..C
1313
using ..GC: GC
14+
using ..GIL
1415
using ..Utils
1516

1617
using Base: @propagate_inbounds, @kwdef

src/Core/Py.jl

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

128-
Base.string(x::Py) = pyisnull(x) ? "<py NULL>" : pystr(String, x)
128+
Base.string(x::Py) = GIL.@lock (pyisnull(x) ? "<py NULL>" : pystr(String, x))
129129
Base.print(io::IO, x::Py) = print(io, string(x))
130130

131-
function Base.show(io::IO, x::Py)
131+
Base.show(io::IO, x::Py) = GIL.@lock _show(io, x)
132+
133+
function _show(io::IO, x::Py)
132134
if get(io, :typeinfo, Any) == Py
133135
if pyisnull(x)
134136
print(io, "NULL")
@@ -149,7 +151,9 @@ function Base.show(io::IO, x::Py)
149151
end
150152
end
151153

152-
function Base.show(io::IO, ::MIME"text/plain", o::Py)
154+
Base.show(io::IO, mime::MIME"text/plain", o::Py) = GIL.@lock _show(io, mime, o)
155+
156+
function _show(io::IO, ::MIME"text/plain", o::Py)
153157
if pyisnull(o)
154158
str = "NULL"
155159
else

src/Wrap/PyDict.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ 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+
Base.iterate(x::Base.KeySet{K,<:PyDict{K}}) where {K} = GIL.@lock _iterate(x, pyiter(x.dict))
28+
29+
function Base.iterate(x::Base.KeySet{K,<:PyDict{K}}, it::Py) where {K}
30+
GIL.@lock _iterate(x, it)
31+
end
32+
33+
function _iterate(x::Base.KeySet{K,<:PyDict{K}}, it::Py) where {K}
2834
k_ = unsafe_pynext(it)
2935
pyisnull(k_) && return nothing
3036
k = pyconvert(K, k_)

src/Wrap/Wrap.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ using ..NumpyDates
1111
using ..C
1212
using ..Core
1313
using ..Convert
14+
using ..GIL
1415
using ..PyMacro
1516

1617
import ..PythonCall:

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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,18 @@ end
122122
@testset "iterate keys" begin
123123
@test collect(keys(z)) == ["foo"]
124124
end
125+
@testset "complete keys without GIL" begin
126+
using REPL
127+
completion_count = PythonCall.GIL.@unlock begin
128+
task = @async begin
129+
completions, _, _ = REPL.REPLCompletions.completions("y[", 2, @__MODULE__)
130+
length(completions)
131+
end
132+
wait(task)
133+
fetch(task)
134+
end
135+
@test completion_count == 1
136+
end
125137
@testset "getindex" begin
126138
@test z["foo"] === 12
127139
@test_throws KeyError z["bar"]

0 commit comments

Comments
 (0)