forked from JuliaPy/PyCall.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathio.jl
139 lines (123 loc) · 4.47 KB
/
io.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# Julia IO subclasses are converted into Python objects implementing
# the IOBase + RawIOBase interface.
#
# (A useful model here is the Python FileIO class, which is implemented
# in Modules/_io/fileio.c in the Python source code.)
##########################################################################
# IOBase methods:
# IO objects should raise IOError for unsupported operations or failed IO
function ioraise(e, bt = nothing)
if isa(e, MethodError) || isa(e, ErrorException)
ccall((@pysym :PyErr_SetString), Cvoid, (PyPtr, Cstring),
pyexc[PyIOError],
showerror_string(e, bt))
else
pyraise(e, bt)
end
end
macro with_ioraise(expr)
:(try
$(esc(expr))
catch e
ioraise(e, catch_backtrace())
end)
end
function jl_io_readline(io::IO, nb)
d = readline(io, keep=true)
if sizeof(d) > nb ≥ 0
error("byte-limited readline is not yet supported by PyCall")
end
return d
end
function jl_io_readlines(io::IO, nb)
ret = PyObject[]
nread = 0
while (nb < 0 || nread ≤ nb) && !eof(io)
d = readline(io, keep=true)
nread += sizeof(d)
push!(ret, PyObject(d))
end
return ret
end
isseekable(io) = hasmethod(seek, Tuple{typeof(io), Int64})
isseekable(io::IOBuffer) = io.seekable
function jl_io_seek(io::IO, offset, whence)
if whence == 0
seek(io, offset)
elseif whence == 1
skip(io, offset)
elseif whence == 2
seekend(io)
skip(io, offset)
else
throw(ArgumentError("unrecognized whence=$n argument to seek"))
end
return position(io)
end
##########################################################################
pyio_jl(self::PyObject) = unsafe_pyjlwrap_to_objref(self."io")::IO
const PyIO = PyNULL()
pyio_initialized = false
function pyio_initialize()
global pyio_initialized
if !pyio_initialized::Bool
copy!(PyIO, @pydef_object mutable struct PyIO
function __init__(self, io::IO; istextio=false)
self.io = pyjlwrap_new(io) # avoid recursion
self.istextio = istextio
end
close(self) = @with_ioraise(close(pyio_jl(self)))
closed.get(self) = @with_ioraise(!isopen(pyio_jl(self)))
encoding.get(self) = "UTF-8"
fileno(self) = @with_ioraise(fd(pyio_jl(self)))
function flush(self)
@with_ioraise begin
io = pyio_jl(self)
if hasmethod(flush, Tuple{typeof(io)})
flush(io)
end
end
end
isatty(self) = isa(pyio_jl(self), Base.TTY)
readable(self) = isreadable(pyio_jl(self))
writable(self) = iswritable(pyio_jl(self))
readline(self, size=typemax(Int)) =
@with_ioraise(jl_io_readline(pyio_jl(self), size))
readlines(self, size=typemax(Int)) =
@with_ioraise(array2py(jl_io_readlines(pyio_jl(self), size)))
seek(self, offset, whence=1) =
@with_ioraise(jl_io_seek(pyio_jl(self), offset, whence))
seekable(self) = isseekable(pyio_jl(self))
tell(self) = @with_ioraise(position(pyio_jl(self)))
writelines(self, seq) =
@with_ioraise(for s in seq write(pyio_jl(self), s) end)
read(self, nb=typemax(Int)) =
@with_ioraise(self.istextio ?
String(read(pyio_jl(self), nb < 0 ? typemax(Int) : nb)) :
pybytes(read(pyio_jl(self), nb < 0 ? typemax(Int) : nb)))
readall(self) =
@with_ioraise(self.istextio ? read(pyio_jl(self), String) :
pybytes(read(pyio_jl(self))))
readinto(self, b) = @with_ioraise(pybytes(readbytes!(pyio_jl(self), b)))
write(self, b) = @with_ioraise(write(pyio_jl(self), b))
end)
pyio_initialized = true
end
return
end
##########################################################################
function PyObject(io::IO)
pyio_initialize()
# pyjlwrap_new is necessary to avoid PyIO(io) calling PyObject(::IO)
PyIO(pyjlwrap_new(io))
end
"""
PyTextIO(io::IO)
PyObject(io::IO)
Julia IO streams are converted into Python objects implementing the RawIOBase interface,
so they can be used for binary I/O in Python
"""
function PyTextIO(io::IO)
pyio_initialize()
PyIO(pyjlwrap_new(io); istextio=true)
end