-
-
Notifications
You must be signed in to change notification settings - Fork 409
/
IJulia.jl
321 lines (269 loc) · 10.7 KB
/
IJulia.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
"""
**IJulia** is a [Julia-language](http://julialang.org/) backend
combined with the [Jupyter](http://jupyter.org/) interactive
environment (also used by [IPython](http://ipython.org/)). This
combination allows you to interact with the Julia language using
Jupyter/IPython's powerful [graphical
notebook](http://ipython.org/notebook.html), which combines code,
formatted text, math, and multimedia in a single document.
The `IJulia` module is used in three ways
* Typing `using IJulia; notebook()` will launch the Jupyter notebook
interface in your web browser. This is an alternative to launching
`jupyter notebook` directly from your operating-system command line.
* In a running notebook, the `IJulia` module is loaded and `IJulia.somefunctions`
can be used to interact with the running IJulia kernel:
- `IJulia.load(filename)` and `IJulia.load_string(s)` load the contents
of a file or a string, respectively, into a notebook cell.
- `IJulia.clear_output()` to clear the output from the notebook cell,
useful for simple animations.
- `IJulia.clear_history()` to clear the history variables `In` and `Out`.
- `push_X_hook(f)` and `pop_X_hook(f)`, where `X` is either
`preexecute`, `postexecute`, or `posterror`. This allows you to
insert a "hook" function into a list of functions to execute
when notebook cells are evaluated.
- `IJulia.set_verbose()` enables verbose output about what IJulia
is doing internally; this is mainly used for debugging.
* It is used internally by the IJulia kernel when talking
to the Jupyter server.
"""
module IJulia
export notebook, jupyterlab, installkernel
using ZMQ, JSON, SoftGlobalScope
import Base.invokelatest
import Dates
using Dates: now
import Random
using Base64: Base64EncodePipe
import REPL
# InteractiveUtils is not used inside IJulia, but loaded in src/kernel.jl
# and this import makes it possible to load InteractiveUtils from the IJulia namespace
import InteractiveUtils
const depfile = joinpath(dirname(@__FILE__), "..", "deps", "deps.jl")
isfile(depfile) || error("IJulia not properly installed. Please run Pkg.build(\"IJulia\")")
include(depfile) # generated by Pkg.build("IJulia")
#######################################################################
# Debugging IJulia
# in the Jupyter front-end, enable verbose output via IJulia.set_verbose()
verbose = IJULIA_DEBUG
"""
set_verbose(v=true)
This function enables (or disables, for `set_verbose(false)`) verbose
output from the IJulia kernel, when called within a running notebook.
This consists of log messages printed to the terminal window where
`jupyter` was launched, displaying information about every message sent
or received by the kernel. Used for debugging IJulia.
"""
function set_verbose(v::Bool=true)
global verbose = v
end
"""
`inited` is a global variable that is set to `true` if the IJulia
kernel is running, i.e. in a running IJulia notebook. To test
whether you are in an IJulia notebook, therefore, you can check
`isdefined(Main, :IJulia) && IJulia.inited`.
"""
inited = false
# set this to false for debugging, to disable stderr redirection
"""
The IJulia kernel captures all [stdout and stderr](https://en.wikipedia.org/wiki/Standard_streams)
output and redirects it to the notebook. When debugging IJulia problems,
however, it can be more convenient to *not* capture stdout and stderr output
(since the notebook may not be functioning). This can be done by editing
`IJulia.jl` to set `capture_stderr` and/or `capture_stdout` to `false`.
"""
const capture_stdout = true
const capture_stderr = !IJULIA_DEBUG
set_current_module(m::Module) = current_module[] = m
const current_module = Ref{Module}(Main)
#######################################################################
include("jupyter.jl")
#######################################################################
"""
load_string(s, replace=false)
Load the string `s` into a new input code cell in the running IJulia notebook,
somewhat analogous to the `%load` magics in IPython. If the optional argument
`replace` is `true`, then `s` replaces the *current* cell rather than creating
a new cell.
"""
function load_string(s::AbstractString, replace::Bool=false)
push!(execute_payloads, Dict(
"source"=>"set_next_input",
"text"=>s,
"replace"=>replace
))
return nothing
end
"""
load(filename, replace=false)
Load the file given by `filename` into a new input code cell in the running
IJulia notebook, analogous to the `%load` magics in IPython.
If the optional argument `replace` is `true`, then the file contents
replace the *current* cell rather than creating a new cell.
"""
load(filename::AbstractString, replace::Bool=false) =
load_string(read(filename, String), replace)
#######################################################################
# History: global In/Out and other exported history variables
"""
`In` is a global dictionary of input strings, where `In[n]`
returns the string for input cell `n` of the notebook (as it was
when it was *last evaluated*).
"""
const In = Dict{Int,String}()
"""
`Out` is a global dictionary of output values, where `Out[n]`
returns the output from the last evaluation of cell `n` in the
notebook.
"""
const Out = Dict{Int,Any}()
"""
`ans` is a global variable giving the value returned by the last
notebook cell evaluated.
"""
ans = nothing
# execution counter
"""
`IJulia.n` is the (integer) index of the last-evaluated notebook cell.
"""
n = 0
#######################################################################
# methods to clear history or any subset thereof
function clear_history(indices)
for n in indices
delete!(In, n)
if haskey(Out, n)
delete!(Out, n)
end
end
end
# since a range could be huge, intersect it with 1:n first
clear_history(r::AbstractRange{<:Integer}) =
invoke(clear_history, Tuple{Any}, intersect(r, 1:n))
function clear_history()
empty!(In)
empty!(Out)
global ans = nothing
end
"""
clear_history([indices])
The `clear_history()` function clears all of the input and output
history stored in the running IJulia notebook. This is sometimes
useful because all cell outputs are remember in the `Out` global variable,
which prevents them from being freed, so potentially this could
waste a lot of memory in a notebook with many large outputs.
The optional `indices` argument is a collection of indices indicating
a subset of cell inputs/outputs to clear.
"""
clear_history
#######################################################################
# methods to print history or any subset thereof
function history(io::IO, indices::AbstractVector{<:Integer})
for n in intersect(indices, 1:IJulia.n)
if haskey(In, n)
print(io, In[n])
end
end
end
history(io::IO, x::Union{Integer,AbstractVector{<:Integer}}...) = history(io, vcat(x...))
history(x...) = history(stdout, x...)
history(io::IO, x...) = throw(MethodError(history, (io, x...,)))
history() = history(1:n)
"""
history([io], [indices...])
The `history()` function prints all of the input history stored in
the running IJulia notebook in a format convenient for copying.
The optional `indices` argument is one or more indices or collections
of indices indicating a subset input cells to print.
The optional `io` argument is for specifying an output stream. The default
is `stdout`.
"""
history
#######################################################################
# Similar to the ipython kernel, we provide a mechanism by
# which modules can register thunk functions to be called after
# executing an input cell, e.g. to "close" the current plot in Pylab.
# Modules should only use these if isdefined(Main, IJulia) is true.
const postexecute_hooks = Function[]
"""
push_postexecute_hook(f::Function)
Push a function `f()` onto the end of a list of functions to
execute after executing any notebook cell.
"""
push_postexecute_hook(f::Function) = push!(postexecute_hooks, f)
"""
pop_postexecute_hook(f::Function)
Remove a function `f()` from the list of functions to
execute after executing any notebook cell.
"""
pop_postexecute_hook(f::Function) =
splice!(postexecute_hooks, findlast(isequal(f), postexecute_hooks))
const preexecute_hooks = Function[]
"""
push_preexecute_hook(f::Function)
Push a function `f()` onto the end of a list of functions to
execute before executing any notebook cell.
"""
push_preexecute_hook(f::Function) = push!(preexecute_hooks, f)
"""
pop_preexecute_hook(f::Function)
Remove a function `f()` from the list of functions to
execute before executing any notebook cell.
"""
pop_preexecute_hook(f::Function) =
splice!(preexecute_hooks, findlast(isequal(f), preexecute_hooks))
# similar, but called after an error (e.g. to reset plotting state)
const posterror_hooks = Function[]
"""
pop_posterror_hook(f::Function)
Remove a function `f()` from the list of functions to
execute after an error occurs when a notebook cell is evaluated.
"""
push_posterror_hook(f::Function) = push!(posterror_hooks, f)
"""
pop_posterror_hook(f::Function)
Remove a function `f()` from the list of functions to
execute after an error occurs when a notebook cell is evaluated.
"""
pop_posterror_hook(f::Function) =
splice!(posterror_hooks, findlast(isequal(f), posterror_hooks))
#######################################################################
# The user can call IJulia.clear_output() to clear visible output from the
# front end, useful for simple animations. Using wait=true clears the
# output only when new output is available, for minimal flickering.
"""
clear_output(wait=false)
Call `clear_output()` to clear visible output from the current notebook
cell. Using `wait=true` clears the output only when new output is
available, which reduces flickering and is useful for simple animations.
"""
function clear_output(wait=false)
# flush pending stdio
flush_all()
empty!(displayqueue) # discard pending display requests
send_ipython(publish[], msg_reply(execute_msg::Msg, "clear_output",
Dict("wait" => wait)))
stdio_bytes[] = 0 # reset output throttling
end
"""
set_max_stdio(max_output::Integer)
Sets the maximum number of bytes, `max_output`, that can be written to stdout and
stderr before getting truncated. A large value here allows a lot of output to be
displayed in the notebook, potentially bogging down the browser.
"""
function set_max_stdio(max_output::Integer)
max_output_per_request[] = max_output
end
#######################################################################
include("init.jl")
include("hmac.jl")
include("eventloop.jl")
include("stdio.jl")
include("msg.jl")
include("display.jl")
include("magics.jl")
include("comm_manager.jl")
include("execute_request.jl")
include("handlers.jl")
include("heartbeat.jl")
include("inline.jl")
end # IJulia