@@ -26,3 +26,200 @@ mutable struct PyException <: Exception
2626 _b:: Py
2727 _isnormalized:: Bool
2828end
29+
30+ """
31+ PyArray{T,N,M,L,R}(x; copy=true, array=true, buffer=true)
32+
33+ Wrap the Python array `x` as a Julia `AbstractArray{T,N}`.
34+
35+ The input `x` can be `bytes`, `bytearray`, `array.array`, `numpy.ndarray` or anything satisfying the buffer protocol (if `buffer=true`) or the numpy array interface (if `array=true`).
36+
37+ If `copy=false` then the resulting array is guaranteed to directly wrap the data in `x`. If `copy=true` then a copy is taken if necessary to produce an array.
38+
39+ The type parameters are all optional, and are:
40+ - `T`: The element type.
41+ - `N`: The number of dimensions.
42+ - `M`: True if the array is mutable.
43+ - `L`: True if the array supports fast linear indexing.
44+ - `R`: The element type of the underlying buffer. Often equal to `T`.
45+ """
46+ struct PyArray{T,N,M,L,R} <: AbstractArray{T,N}
47+ ptr:: Ptr{R} # pointer to the data
48+ length:: Int # length of the array
49+ size:: NTuple{N,Int} # size of the array
50+ strides:: NTuple{N,Int} # strides (in bytes) between elements
51+ py:: Py # underlying python object
52+ handle:: Py # the data in this array is valid as long as this handle is alive
53+ function PyArray {T,N,M,L,R} (
54+ :: Val{:new} ,
55+ ptr:: Ptr{R} ,
56+ size:: NTuple{N,Int} ,
57+ strides:: NTuple{N,Int} ,
58+ py:: Py ,
59+ handle:: Py ,
60+ ) where {T,N,M,L,R}
61+ T isa Type || error (" T must be a Type" )
62+ N isa Int || error (" N must be an Int" )
63+ M isa Bool || error (" M must be a Bool" )
64+ L isa Bool || error (" L must be a Bool" )
65+ R isa DataType || error (" R must be a DataType" )
66+ new {T,N,M,L,R} (ptr, prod (size), size, strides, py, handle)
67+ end
68+ end
69+
70+ """
71+ PyDict{K=Py,V=Py}([x])
72+
73+ Wraps the Python dict `x` (or anything satisfying the mapping interface) as an `AbstractDict{K,V}`.
74+
75+ If `x` is not a Python object, it is converted to one using `pydict`.
76+ """
77+ struct PyDict{K,V} <: AbstractDict{K,V}
78+ py:: Py
79+ PyDict {K,V} (x = pydict ()) where {K,V} = new {K,V} (ispy (x) ? Py (x) : pydict (x))
80+ end
81+
82+ """
83+ PyIO(x; own=false, text=missing, line_buffering=false, buflen=4096)
84+
85+ Wrap the Python IO stream `x` as a Julia IO stream.
86+
87+ When this goes out of scope and is finalized, it is automatically flushed. If `own=true` then it is also closed.
88+
89+ If `text=false` then `x` must be a binary stream and arbitrary binary I/O is possible.
90+ If `text=true` then `x` must be a text stream and only UTF-8 must be written (i.e. use `print` not `write`).
91+ If `text` is not specified then it is chosen automatically.
92+ If `x` is a text stream and you really need a binary stream, then often `PyIO(x.buffer)` will work.
93+
94+ If `line_buffering=true` then output is flushed at each line.
95+
96+ For efficiency, reads and writes are buffered before being sent to `x`.
97+ The size of the buffers is `buflen`.
98+ The buffers are cleared using `flush`.
99+ """
100+ mutable struct PyIO <: IO
101+ py:: Py
102+ # true to close the file automatically
103+ own:: Bool
104+ # true if `o` is text, false if binary
105+ text:: Bool
106+ # true to flush whenever '\n' or '\r' is encountered
107+ line_buffering:: Bool
108+ # true if we are definitely at the end of the file; false if we are not or don't know
109+ eof:: Bool
110+ # input buffer
111+ ibuflen:: Int
112+ ibuf:: Vector{UInt8}
113+ # output buffer
114+ obuflen:: Int
115+ obuf:: Vector{UInt8}
116+
117+ function PyIO (
118+ x;
119+ own:: Bool = false ,
120+ text:: Union{Missing,Bool} = missing ,
121+ buflen:: Integer = 4096 ,
122+ ibuflen:: Integer = buflen,
123+ obuflen:: Integer = buflen,
124+ line_buffering:: Bool = false ,
125+ )
126+ if text === missing
127+ text = pyhasattr (x, " encoding" )
128+ end
129+ buflen = convert (Int, buflen)
130+ buflen > 0 || error (" buflen must be positive" )
131+ ibuflen = convert (Int, ibuflen)
132+ ibuflen > 0 || error (" ibuflen must be positive" )
133+ obuflen = convert (Int, obuflen)
134+ obuflen > 0 || error (" obuflen must be positive" )
135+ new (Py (x), own, text, line_buffering, false , ibuflen, UInt8[], obuflen, UInt8[])
136+ end
137+ end
138+
139+ """
140+ PyIterable{T=Py}(x)
141+
142+ This object iterates over iterable Python object `x`, yielding values of type `T`.
143+ """
144+ struct PyIterable{T}
145+ py:: Py
146+ PyIterable {T} (x) where {T} = new {T} (Py (x))
147+ end
148+
149+ """
150+ PyList{T=Py}([x])
151+
152+ Wraps the Python list `x` (or anything satisfying the sequence interface) as an `AbstractVector{T}`.
153+
154+ If `x` is not a Python object, it is converted to one using `pylist`.
155+ """
156+ struct PyList{T} <: AbstractVector{T}
157+ py:: Py
158+ PyList {T} (x = pylist ()) where {T} = new {T} (ispy (x) ? Py (x) : pylist (x))
159+ end
160+
161+ """
162+ PySet{T=Py}([x])
163+
164+ Wraps the Python set `x` (or anything satisfying the set interface) as an `AbstractSet{T}`.
165+
166+ If `x` is not a Python object, it is converted to one using `pyset`.
167+ """
168+ struct PySet{T} <: AbstractSet{T}
169+ py:: Py
170+ PySet {T} (x = pyset ()) where {T} = new {T} (ispy (x) ? Py (x) : pyset (x))
171+ end
172+
173+ """
174+ PyTable(x)
175+
176+ Wrap `x` as a Tables.jl-compatible table.
177+
178+ `PyTable` is an abstract type. See [`PyPandasDataFrame`](@ref) for a concrete example.
179+ """
180+ abstract type PyTable end
181+
182+ """
183+ PyPandasDataFrame(x; [indexname::Union{Nothing,Symbol}], [columnnames::Function], [columntypes::Function])
184+
185+ Wraps the pandas DataFrame `x` as a Tables.jl-compatible table.
186+
187+ - `indexname`: The name of the column including the index. The default is `nothing`, meaning
188+ to exclude the index.
189+ - `columnnames`: A function mapping the Python column name (a `Py`) to the Julia one (a
190+ `Symbol`). The default is `x -> Symbol(x)`.
191+ - `columntypes`: A function taking the column name (a `Symbol`) and returning either the
192+ desired element type of the column, or `nothing` to indicate automatic inference.
193+ """
194+ struct PyPandasDataFrame <: PyTable
195+ py:: Py
196+ indexname:: Union{Symbol,Nothing}
197+ columnnames:: Function # Py -> Symbol
198+ columntypes:: Function # Symbol -> Union{Type,Nothing}
199+ function PyPandasDataFrame (
200+ x;
201+ indexname:: Union{Symbol,Nothing} = nothing ,
202+ columnnames:: Function = x -> Symbol (x),
203+ columntypes:: Function = x -> nothing ,
204+ )
205+ new (Py (x), indexname, columnnames, columntypes)
206+ end
207+ end
208+
209+ """
210+ PyObjectArray(undef, dims...)
211+ PyObjectArray(array)
212+
213+ An array of `Py`s which supports the Python buffer protocol.
214+
215+ Internally, the objects are stored as an array of pointers.
216+ """
217+ mutable struct PyObjectArray{N} <: AbstractArray{Py,N}
218+ ptrs:: Array{Ptr{Cvoid},N}
219+ function PyObjectArray {N} (:: UndefInitializer , dims:: NTuple{N,Integer} ) where {N}
220+ x = new {N} (fill (C_NULL , dims))
221+ finalizer (Internals. JlWrap. pyobjectarray_finalizer, x)
222+ end
223+ end
224+ const PyObjectVector = PyObjectArray{1 }
225+ const PyObjectMatrix = PyObjectArray{2 }
0 commit comments