@@ -23,7 +23,7 @@ pyisnull(x) = getptr(x) == C.PyNULL
2323
2424Get the underlying pointer from the Python object `x`.
2525"""
26- getptr (x) = getptr (getpy (x):: Py )
26+ getptr (x) = ispy (x) ? getptr (Py (x):: Py ) : throw ( MethodError (getptr, (x,)) )
2727
2828"""
2929 Py(x)
@@ -36,10 +36,6 @@ Such an object supports attribute access (`obj.attr`), indexing (`obj[idx]`), ca
3636(`obj(arg1, arg2)`), iteration (`for x in obj`), arithmetic (`obj + obj2`) and comparison
3737(`obj > obj2`), among other things. These operations convert all their arguments to `Py` and
3838return `Py`.
39-
40- !!! warning
41-
42- Do not overload this function. To define a new conversion, overload [`getpy`](@ref).
4339"""
4440mutable struct Py
4541 ptr :: C.PyPtr
@@ -56,7 +52,6 @@ function py_finalizer(x::Py)
5652end
5753
5854ispy (:: Py ) = true
59- getpy (x:: Py ) = x
6055getptr (x:: Py ) = getfield (x, :ptr )
6156
6257setptr! (x:: Py , ptr:: C.PyPtr ) = (setfield! (x, :ptr , ptr); x)
@@ -85,6 +80,8 @@ const PyNULL = pynew()
8580
8681pynew (ptr:: C.PyPtr ) = setptr! (pynew (), ptr)
8782
83+ pynew (x:: Py ) = pynew (incref (getptr (x)))
84+
8885"""
8986 pycopy!(dst::Py, src)
9087
@@ -97,7 +94,7 @@ the top level then `pycopy!(x, pything())` inside `__init__()`.
9794
9895Assumes `dst` is NULL, otherwise a memory leak will occur.
9996"""
100- pycopy! (dst, src) = GC. @preserve src setptr! (dst, incref (getptr (src)))
97+ pycopy! (dst:: Py , src) = GC. @preserve src setptr! (dst, incref (getptr (src)))
10198
10299"""
103100 pydel!(x::Py)
@@ -120,76 +117,44 @@ function pydel!(x::Py)
120117 ptr = getptr (x)
121118 if ptr != C. PyNULL
122119 C. Py_DecRef (ptr)
120+ setptr! (x, C. PyNULL)
123121 end
124- pystolen! (x)
125- end
126-
127- function pystolen! (x:: Py )
128- setptr! (x, C. PyNULL)
129122 push! (PYNULL_CACHE, x)
130- nothing
123+ return
131124end
132125
133126macro autopy (args... )
134127 vs = args[1 : end - 1 ]
135128 ts = [Symbol (v, " _" ) for v in vs]
136129 body = args[end ]
137- ans = gensym (" ans" )
130+ # ans = gensym("ans")
138131 esc (quote
139- $ ([:($ t = $ ispy ($ v) ? $ v : $ Py ($ v)) for (t, v) in zip (ts, vs)]. .. )
140- $ ans = $ body
141- $ ([:($ ispy ($ v) || $ pydel! ($ t)) for (t, v) in zip (ts, vs)]. .. )
142- $ ans
132+ # $([:($t = $ispy($v) ? $v : $Py($v)) for (t, v) in zip(ts, vs)]...)
133+ # $ans = $body
134+ # $([:($ispy($v) || $pydel!($t)) for (t, v) in zip(ts, vs)]...)
135+ # $ans
136+ $ ([:($ t = $ Py ($ v)) for (t, v) in zip (ts, vs)]. .. )
137+ $ body
143138 end )
144139end
145140
146- struct NewPy
147- py:: Py
148- NewPy (py:: Py ) = new (py)
149- end
150-
151- Py (x:: Py ) = GC. @preserve x pynew (incref (getptr (x))) # copy, because Py must always return a new object
152- Py (x:: NewPy ) = x. py
153- Py (x) = Py (getpy (x):: Union{Py,NewPy} )
154-
155- """
156- getpy(x)
157-
158- Convert `x` to a `Py`.
159-
160- Overload this function (not [`Py`](@ref)) to define a new conversion to Python.
161-
162- If `x` is a simple wrapper around a Python object (such as [`PyList`](@ref) or
163- [`PyDict`](@ref)) then `getpy(x)` should return the Python object. You should also define
164- `ispy(x) = true`. This means that when `x` is passed back to Python, the underlying object
165- is used directly.
166-
167- ### Optional optimization (for experts)
168-
169- If [`ispy(x)`](@ref) is false and the returned Julia object `ans` is not referenced anywhere
170- else, in the sense that [`pydel!(ans)`](@ref) would be safe, you may instead return
171- `NewPy(ans)`.
172-
173- This can avoid the Julia garbage collector in performance-critical code.
174-
175- If [`ispy(x)`](@ref) is true, you **must** return a [`Py`](@ref).
176- """
177- getpy (x) = ispy (x) ? throw (MethodError (getpy, (x,))) : NewPy (pyjl (x))
178- getpy (x:: Nothing ) = pybuiltins. None
179- getpy (x:: Bool ) = NewPy (pybool (x))
180- getpy (x:: Union{String, SubString{String}, Char} ) = NewPy (pystr (x))
181- getpy (x:: Base.CodeUnits{UInt8, String} ) = NewPy (pybytes (x))
182- getpy (x:: Base.CodeUnits{UInt8, SubString{String}} ) = NewPy (pybytes (x))
183- getpy (x:: Tuple ) = NewPy (pytuple_fromiter (x))
184- getpy (x:: Pair ) = NewPy (pytuple_fromiter (x))
185- getpy (x:: Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt} ) = NewPy (pyint (x))
186- getpy (x:: Rational{<:Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}} ) = NewPy (pyfraction (x))
187- getpy (x:: Union{Float16,Float32,Float64} ) = NewPy (pyfloat (x))
188- getpy (x:: Complex{<:Union{Float16,Float32,Float64}} ) = NewPy (pycomplex (x))
189- getpy (x:: AbstractRange{<:Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}} ) = NewPy (pyrange_fromrange (x))
190- getpy (x:: Date ) = NewPy (pydate (x))
191- getpy (x:: Time ) = NewPy (pytime (x))
192- getpy (x:: DateTime ) = NewPy (pydatetime (x))
141+ Py (x:: Py ) = x
142+ Py (x:: Nothing ) = pybuiltins. None
143+ Py (x:: Bool ) = x ? pybuiltins. True : pybuiltins. False
144+ Py (x:: Union{String, SubString{String}, Char} ) = pystr (x)
145+ Py (x:: Base.CodeUnits{UInt8, String} ) = pybytes (x)
146+ Py (x:: Base.CodeUnits{UInt8, SubString{String}} ) = pybytes (x)
147+ Py (x:: Tuple ) = pytuple_fromiter (x)
148+ Py (x:: Pair ) = pytuple_fromiter (x)
149+ Py (x:: Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt} ) = pyint (x)
150+ Py (x:: Rational{<:Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}} ) = pyfraction (x)
151+ Py (x:: Union{Float16,Float32,Float64} ) = pyfloat (x)
152+ Py (x:: Complex{<:Union{Float16,Float32,Float64}} ) = pycomplex (x)
153+ Py (x:: AbstractRange{<:Union{Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128,BigInt}} ) = pyrange_fromrange (x)
154+ Py (x:: Date ) = pydate (x)
155+ Py (x:: Time ) = pytime (x)
156+ Py (x:: DateTime ) = pydatetime (x)
157+ Py (x) = ispy (x) ? throw (MethodError (Py, (x,))) : pyjl (x)
193158
194159Base. string (x:: Py ) = pyisnull (x) ? " <py NULL>" : pystr (String, x)
195160Base. print (io:: IO , x:: Py ) = print (io, string (x))
0 commit comments