Skip to content

Commit d1e80d6

Browse files
author
Christopher Doris
committed
rename ispynull to pyisnull
1 parent a05f640 commit d1e80d6

File tree

12 files changed

+84
-28
lines changed

12 files changed

+84
-28
lines changed

src/Py.jl

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,29 @@
11
incref(x::C.PyPtr) = (C.Py_IncRef(x); x)
22
decref(x::C.PyPtr) = (C.Py_DecRef(x); x)
33

4+
"""
5+
ispy(x)
6+
7+
True if `x` is a Python object.
8+
9+
This includes `Py` and Python wrapper types such as `PyList`.
10+
"""
411
ispy(x) = false
5-
ispynull(x) = getptr(x) == C.PyNULL
12+
export ispy
13+
14+
"""
15+
pyisnull(x)
16+
17+
True if the Python object `x` is NULL.
18+
"""
19+
pyisnull(x) = getptr(x) == C.PyNULL
20+
21+
"""
22+
getptr(x)
23+
24+
Get the underlying pointer from the Python object `x`.
25+
"""
626
getptr(x) = getptr(getpy(x)::Py)
7-
export ispy, ispynull
827

928
"""
1029
Py(x)
@@ -33,6 +52,17 @@ setptr!(x::Py, ptr::C.PyPtr) = (setfield!(x, :ptr, ptr); x)
3352

3453
const PYNULL_CACHE = Py[]
3554

55+
"""
56+
pynew([ptr])
57+
58+
A new `Py` representing the Python object at `ptr` (NULL by default).
59+
60+
If `ptr` is given and non-NULL, this function steals a reference to the Python object it
61+
points at, i.e. the new `Py` object owns a reference.
62+
63+
Note that NULL Python objects are not safe in the sense that most API functions will probably
64+
crash your Julia session if you pass a NULL argument.
65+
"""
3666
pynew() =
3767
if isempty(PYNULL_CACHE)
3868
Py(Val(:new), C.PyNULL)
@@ -44,9 +74,37 @@ const PyNULL = pynew()
4474

4575
pynew(ptr::C.PyPtr) = setptr!(pynew(), ptr)
4676

47-
# assumes dst is NULL
77+
"""
78+
pycopy!(dst::Py, src)
79+
80+
Copy the Python object `src` into `dst`, so that they both represent the same object.
81+
82+
This function exists to support module-level constant Python objects. It is illegal to call
83+
most PythonCall API functions at the top level of a module (i.e. before `__init__()` has run)
84+
so you cannot do `const x = pything()` at the top level. Instead do `const x = pynew()` at
85+
the top level then `pycopy!(x, pything())` inside `__init__()`.
86+
87+
Assumes `dst` is NULL, otherwise a memory leak will occur.
88+
"""
4889
pycopy!(dst, src) = setptr!(dst, incref(getptr(src)))
4990

91+
"""
92+
pydel!(x::Py)
93+
94+
Delete the Python object `x`.
95+
96+
DANGER! Use this function ONLY IF the Julia object `x` could have been garbage-collected
97+
anyway, i.e. was about to become unreachable. This means you MUST KNOW that no other part of
98+
the program has the Julia object `x`.
99+
100+
This decrements the reference count, sets the pointer to NULL and appends `x` to a cache
101+
of unused objects (`PYNULL_CACHE`).
102+
103+
This is an optimization to avoid excessive allocation and deallocation in Julia, which can
104+
be a significant source of slow-down in code which uses a lot of Python objects. It allows
105+
`pynew()` to pop an item from `PYNULL_CACHE` instead of allocating one, and avoids calling
106+
the relatively slow finalizer on `x`.
107+
"""
50108
function pydel!(x::Py)
51109
ptr = getptr(x)
52110
if ptr != C.PyNULL
@@ -61,8 +119,6 @@ function pystolen!(x::Py)
61119
nothing
62120
end
63121

64-
export pynull, pynew, pydel!, pystolen!
65-
66122
macro autopy(args...)
67123
vs = args[1:end-1]
68124
ts = [Symbol(v, "_") for v in vs]
@@ -94,7 +150,7 @@ Py(x::Time) = pytime(x)
94150
Py(x::DateTime) = pydatetime(x)
95151
Py(x) = ispy(x) ? Py(getpy(x)) : pyjl(x)
96152

97-
Base.string(x::Py) = ispynull(x) ? "<py NULL>" : pystr(String, x)
153+
Base.string(x::Py) = pyisnull(x) ? "<py NULL>" : pystr(String, x)
98154
Base.print(io::IO, x::Py) = print(io, string(x))
99155

100156
function Base.repr(x::Py)
@@ -124,7 +180,7 @@ end
124180

125181
function Base.show(io::IO, mime::MIME"text/plain", o::Py)
126182
hasprefix = get(io, :typeinfo, Any) != Py
127-
if ispynull(o)
183+
if pyisnull(o)
128184
if hasprefix
129185
printstyled(io, "Python NULL", bold=true)
130186
else
@@ -261,7 +317,7 @@ Base.IteratorSize(::Type{Py}) = Base.SizeUnknown()
261317

262318
function Base.iterate(x::Py, it::Py=pyiter(x))
263319
v = unsafe_pynext(it)
264-
if ispynull(v)
320+
if pyisnull(v)
265321
pydel!(it)
266322
nothing
267323
else

src/abstract/collection.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
function _pyconvert_rule_iterable(ans::Vector{T0}, it::Py, ::Type{T1}) where {T0,T1}
44
@label again
55
x_ = unsafe_pynext(it)
6-
if ispynull(x_)
6+
if pyisnull(x_)
77
pydel!(it)
88
return pyconvert_return(ans)
99
end
@@ -29,7 +29,7 @@ end
2929
function _pyconvert_rule_iterable(ans::Set{T0}, it::Py, ::Type{T1}) where {T0,T1}
3030
@label again
3131
x_ = unsafe_pynext(it)
32-
if ispynull(x_)
32+
if pyisnull(x_)
3333
pydel!(it)
3434
return pyconvert_return(ans)
3535
end
@@ -55,7 +55,7 @@ end
5555
function _pyconvert_rule_mapping(ans::Dict{K0,V0}, x::Py, it::Py, ::Type{K1}, ::Type{V1}) where {K0,V0,K1,V1}
5656
@label again
5757
k_ = unsafe_pynext(it)
58-
if ispynull(k_)
58+
if pyisnull(k_)
5959
pydel!(it)
6060
return pyconvert_return(ans)
6161
end
@@ -128,22 +128,22 @@ end
128128
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}
129129
it = pyiter(x)
130130
k_ = unsafe_pynext(it)
131-
if ispynull(k_)
131+
if pyisnull(k_)
132132
pydel!(it)
133133
pydel!(k_)
134134
return pyconvert_unconverted()
135135
end
136136
k = @pyconvert_and_del(K1, k_)
137137
v_ = unsafe_pynext(it)
138-
if ispynull(v_)
138+
if pyisnull(v_)
139139
pydel!(it)
140140
pydel!(v_)
141141
return pyconvert_unconverted()
142142
end
143143
v = @pyconvert_and_del(V1, v_)
144144
z_ = unsafe_pynext(it)
145145
pydel!(it)
146-
if ispynull(z_)
146+
if pyisnull(z_)
147147
pydel!(z_)
148148
else
149149
pydel!(z_)

src/compat/serialization.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# We use pickle to serialise Python objects to bytes.
44

55
function serialize_py(s, x::Py)
6-
if ispynull(x)
6+
if pyisnull(x)
77
serialize(s, nothing)
88
else
99
b = pyimport("pickle").dumps(x)

src/convert.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ function pyconvert_get_rules(type::Type, pytype::Py)
105105
xbase = base
106106
end
107107
end
108-
if !ispynull(xbase)
108+
if !pyisnull(xbase)
109109
push!(basetypes, xtype)
110110
xmro = collect(xtype.__mro__)
111111
pyisin(xbase, xmro) || pushfirst!(xmro, xbase)

src/err.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ end
8080
function Base.getproperty(exc::PyException, k::Symbol)
8181
if k in (:t, :v, :b) && !exc._isnormalized
8282
errnormalize!(exc._t, exc._v, exc._b)
83-
ispynull(exc._t) && setptr!(exc._t, incref(getptr(pybuiltins.None)))
84-
ispynull(exc._v) && setptr!(exc._v, incref(getptr(pybuiltins.None)))
85-
ispynull(exc._b) && setptr!(exc._b, incref(getptr(pybuiltins.None)))
83+
pyisnull(exc._t) && setptr!(exc._t, incref(getptr(pybuiltins.None)))
84+
pyisnull(exc._v) && setptr!(exc._v, incref(getptr(pybuiltins.None)))
85+
pyisnull(exc._b) && setptr!(exc._b, incref(getptr(pybuiltins.None)))
8686
pyisnone(exc._v) || (exc._v.__traceback__ = exc._b)
8787
exc._isnormalized = true
8888
end
@@ -124,7 +124,7 @@ function Base.showerror(io::IO, e::PyException)
124124
end
125125

126126
# if this is a Julia exception then recursively print it and its stacktrace
127-
if !ispynull(pyJuliaError) && pyissubclass(e.t, pyJuliaError)
127+
if !pyisnull(pyJuliaError) && pyissubclass(e.t, pyJuliaError)
128128
try
129129
# Extract error value
130130
je, jb = pyconvert(Tuple{Any,Any}, e.v.args)

src/jlwrap/array.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ function pyjlarray_array_interface(x::AbstractArray{T,N}) where {T,N}
276276
d["data"] = data
277277
d["strides"] = strides(x) .* Base.aligned_sizeof(T)
278278
d["version"] = 3
279-
if !ispynull(descr)
279+
if !pyisnull(descr)
280280
d["descr"] = descr
281281
end
282282
return d

src/jlwrap/base.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ end
110110
function pyjl_handle_error(f, self, exc)
111111
@nospecialize f self exc
112112
t = pyjl_handle_error_type(f, self, exc)::Py
113-
if ispynull(t)
113+
if pyisnull(t)
114114
# NULL => raise JuliaError
115115
errset(pyJuliaError, pytuple((pyjlraw(exc), pyjlraw(catch_backtrace()))))
116116
return C.PyNULL

src/py_macro.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ function py_macro_lower(st, body, ans, ex; flavour=:expr)
596596
py_macro_del(body, y, ty)
597597
body2 = []
598598
push!(body2, :($v = $unsafe_pynext($i)))
599-
push!(body2, Expr(:if, :($ispynull($v)), Expr(:block, :($pydel!($v)), :(break))))
599+
push!(body2, Expr(:if, :($pyisnull($v)), Expr(:block, :($pydel!($v)), :(break))))
600600
py_macro_lower_assign(st, body2, ax, v)
601601
py_macro_del(body2, v, true)
602602
tz = py_macro_lower(st, body2, z, az)

src/pyconst_macro.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@ macro pyconst(ex)
1919
else
2020
val = :($Py($val))
2121
end
22-
:(ispynull($x) ? pycopy!($x, $val) : $x)
22+
:(pyisnull($x) ? pycopy!($x, $val) : $x)
2323
end
2424
export @pyconst

src/pywrap/PyDict.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Base.length(x::PyDict) = Int(pylen(x))
3434

3535
function Base.iterate(x::PyDict{K,V}, it::Py=pyiter(x)) where {K,V}
3636
k_ = unsafe_pynext(it)
37-
ispynull(k_) && return nothing
37+
pyisnull(k_) && return nothing
3838
v_ = pygetitem(x, k_)
3939
k = pyconvert_and_del(K, k_)
4040
v = pyconvert_and_del(V, v_)
@@ -43,7 +43,7 @@ end
4343

4444
function Base.iterate(x::Base.KeySet{K,PyDict{K,V}}, it::Py=pyiter(x.dict)) where {K,V}
4545
k_ = unsafe_pynext(it)
46-
ispynull(k_) && return nothing
46+
pyisnull(k_) && return nothing
4747
k = pyconvert_and_del(K, k_)
4848
return (k, it)
4949
end

0 commit comments

Comments
 (0)