Skip to content

Commit

Permalink
Merge pull request #1142 from JuliaLang/changelog
Browse files Browse the repository at this point in the history
Documentation fixes and a changelog
  • Loading branch information
JamesWrigley authored Feb 4, 2025
2 parents 855eba2 + 0db2726 commit 4390ef4
Show file tree
Hide file tree
Showing 19 changed files with 214 additions and 33 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/Docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@v2
with:
version: '1'
- uses: julia-actions/cache@v2
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-docdeploy@v1
env:
Expand Down
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,4 @@
/deps/JUPYTER
/deps/julia-*
*.jl.*.cov
/docs/src/assets/logo.svg
/docs/src/assets/favicon.ico
Manifest*.toml
1 change: 1 addition & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
build/
src/changelog.md
4 changes: 4 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
[deps]
Changelog = "5217a498-cd5d-4ec6-b8c2-9b85a09b6e3e"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a"

[compat]
Documenter = "1"

[sources]
IJulia = {path = ".."}
21 changes: 12 additions & 9 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import Changelog
using Documenter, IJulia

# Copy assets from `deps` directory
path_assets = joinpath(@__DIR__, "src/assets")
path_deps = joinpath(@__DIR__, "../deps")
mkpath(path_assets)
cp(joinpath(path_deps, "ijuliafavicon.ico"), joinpath(path_assets, "favicon.ico"), force=true)
cp(joinpath(path_deps, "ijulialogo.svg"), joinpath(path_assets, "logo.svg"), force=true)
# Build the changelog
Changelog.generate(
Changelog.Documenter(),
joinpath(@__DIR__, "src/_changelog.md"),
joinpath(@__DIR__, "src/changelog.md"),
repo="JuliaLang/IJulia.jl"
)

# Make docs to `docs/build` directory
makedocs(
makedocs(;
repo=Remotes.GitHub("JuliaLang", "IJulia.jl"),
modules=[IJulia],
sitename="IJulia",
format=Documenter.HTML(;
Expand All @@ -27,8 +30,8 @@ makedocs(
"library/public.md",
"library/internals.md",
],
],
warnonly=true,
"changelog.md"
]
)

# Deploy docs
Expand Down
19 changes: 19 additions & 0 deletions docs/src/_changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
```@meta
CurrentModule = IJulia
```

# Changelog

This documents notable changes in IJulia.jl. The format is based on [Keep a
Changelog](https://keepachangelog.com).

## Unreleased

### Added
- [`installkernel()`](@ref) now supports a `displayname` argument to customize
the kernel display name ([#1137]).

### Fixed
- The internal heartbeat thread will now shut down cleanly ([#1135],
[#1144]). This should prevent segfaults upon exit.
- Various fixes to the messaging code to be compliant with Jupyter ([#1138]).
File renamed without changes.
File renamed without changes
1 change: 0 additions & 1 deletion docs/src/library/internals.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ IJulia.send_status
## Request handlers

```@docs
IJulia.handlers
IJulia.connect_request
IJulia.execute_request
IJulia.shutdown_request
Expand Down
8 changes: 6 additions & 2 deletions src/IJulia.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,19 @@ whether you are in an IJulia notebook, therefore, you can check
"""
inited = false

# set this to false for debugging, to disable stderr redirection
"""
const _capture_docstring = """
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`.
"""

@doc _capture_docstring
const capture_stdout = true

# set this to false for debugging, to disable stderr redirection
@doc _capture_docstring
const capture_stderr = !IJULIA_DEBUG

set_current_module(m::Module) = current_module[] = m
Expand Down
19 changes: 16 additions & 3 deletions src/display.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,21 @@ const ijulia_jsonmime_types = Vector{Union{MIME, Vector{MIME}}}([
MIME("application/vnd.dataresource+json"), MIME("application/vnd.plotly.v1+json")
])

register_mime(x::Union{MIME, Vector{MIME}})= push!(ijulia_mime_types, x)
"""
register_mime(x::Union{MIME, Vector{MIME}})
register_mime(x::AbstractVector{<:MIME})
Register a new MIME type.
"""
register_mime(x::Union{MIME, Vector{MIME}}) = push!(ijulia_mime_types, x)
register_mime(x::AbstractVector{<:MIME}) = push!(ijulia_mime_types, Vector{Mime}(x))

"""
register_jsonmime(x::Union{MIME, Vector{MIME}})
register_jsonmime(x::AbstractVector{<:MIME})
Register a new JSON MIME type.
"""
register_jsonmime(x::Union{MIME, Vector{MIME}}) = push!(ijulia_jsonmime_types, x)
register_jsonmime(x::AbstractVector{<:MIME}) = push!(ijulia_jsonmime_types, Vector{Mime}(x))

Expand Down Expand Up @@ -92,8 +105,8 @@ display_mimejson(m::MIME, x) = (m, JSON.JSONText(limitstringmime(m, x, true)))

"""
Generate a dictionary of `mime_type => data` pairs for all registered MIME
types. This is the format that Jupyter expects in display_data and
execute_result messages.
types. This is the format that Jupyter expects in `display_data` and
`execute_result` messages.
"""
function display_dict(x)
data = Dict{String, Union{String, JSONText}}()
Expand Down
13 changes: 13 additions & 0 deletions src/eventloop.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
"""
eventloop(socket)
Generic event loop for one of the [kernel
sockets](https://jupyter-client.readthedocs.io/en/latest/messaging.html#introduction).
"""
function eventloop(socket)
task_local_storage(:IJulia_task, "write task")
try
Expand Down Expand Up @@ -33,6 +39,13 @@ function eventloop(socket)
end

const requests_task = Ref{Task}()

"""
waitloop()
Main loop of a kernel. Runs the event loops for the control and shell sockets
(note: in IJulia the shell socket is called `requests`).
"""
function waitloop()
@async eventloop(control[])
requests_task[] = @async eventloop(requests[])
Expand Down
7 changes: 7 additions & 0 deletions src/execute_request.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ import REPL: helpmode
# use a global array to accumulate "payloads" for the execute_reply message
const execute_payloads = Dict[]

"""
execute_request(socket, msg)
Handle a [execute
request](https://jupyter-client.readthedocs.io/en/latest/messaging.html#execute).
This will execute Julia code, along with Pkg and shell commands.
"""
function execute_request(socket, msg)
code = msg.content["code"]
@vprintln("EXECUTING ", code)
Expand Down
59 changes: 55 additions & 4 deletions src/handlers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ function complete_types(comps)
return typeMap
end

"""
complete_request(socket, msg)
Handle a [completion
request](https://jupyter-client.readthedocs.io/en/latest/messaging.html#completion).
"""
function complete_request(socket, msg)
code = msg.content["code"]
cursor_chr = msg.content["cursor_pos"]
Expand Down Expand Up @@ -153,6 +159,12 @@ function complete_request(socket, msg)
"cursor_end" => cursor_end)))
end

"""
kernel_info_request(socket, msg)
Handle a [kernel info
request](https://jupyter-client.readthedocs.io/en/latest/messaging.html#kernel-info).
"""
function kernel_info_request(socket, msg)
send_ipython(socket,
msg_reply(msg, "kernel_info_reply",
Expand All @@ -179,21 +191,34 @@ function kernel_info_request(socket, msg)
"status" => "ok")))
end

"""
connect_request(socket, msg)
Handle a [connect
request](https://jupyter-client.readthedocs.io/en/latest/messaging.html#connect).
"""
function connect_request(socket, msg)
send_ipython(requests[],
msg_reply(msg, "connect_reply",
Dict("shell_port" => profile["shell_port"],
"iopub_port" => profile["iopub_port"],
"stdin_port" => profile["stdin_port"],
"hb_port" => profile["hb_port"])))
"iopub_port" => profile["iopub_port"],
"stdin_port" => profile["stdin_port"],
"hb_port" => profile["hb_port"])))
end

"""
shutdown_request(socket, msg)
Handle a [shutdown
request](https://jupyter-client.readthedocs.io/en/latest/messaging.html#kernel-shutdown). After
sending the reply this will exit the process.
"""
function shutdown_request(socket, msg)
# stop heartbeat thread by closing the context
close(heartbeat_context[])

send_ipython(requests[], msg_reply(msg, "shutdown_reply",
msg.content))
msg.content))
sleep(0.1) # short delay (like in ipykernel), to hopefully ensure shutdown_reply is sent
exit()
end
Expand Down Expand Up @@ -235,6 +260,12 @@ function get_token(code, pos)
return code[startpos:endpos]
end

"""
inspect_request(socket, msg)
Handle a [introspection
request](https://jupyter-client.readthedocs.io/en/latest/messaging.html#introspection).
"""
function inspect_request(socket, msg)
try
code = msg.content["code"]
Expand All @@ -256,6 +287,13 @@ function inspect_request(socket, msg)
end
end

"""
history_request(socket, msg)
Handle a [history
request](https://jupyter-client.readthedocs.io/en/latest/messaging.html#history). This
is currently only a dummy implementation that doesn't actually do anything.
"""
function history_request(socket, msg)
# we will just send back empty history for now, pending clarification
# as requested in ipython/ipython#3806
Expand All @@ -264,6 +302,12 @@ function history_request(socket, msg)
Dict("history" => [])))
end

"""
is_complete_request(socket, msg)
Handle a [completeness
request](https://jupyter-client.readthedocs.io/en/latest/messaging.html#code-completeness).
"""
function is_complete_request(socket, msg)
ex = Meta.parse(msg.content["code"], raise=false)
status = Meta.isexpr(ex, :incomplete) ? "incomplete" : Meta.isexpr(ex, :error) ? "invalid" : "complete"
Expand All @@ -272,6 +316,13 @@ function is_complete_request(socket, msg)
Dict("status"=>status, "indent"=>"")))
end

"""
interrupt_request(socket, msg)
Handle a [interrupt
request](https://jupyter-client.readthedocs.io/en/latest/messaging.html#kernel-interrupt). This
will throw an `InterruptException` to the currently executing request handler.
"""
function interrupt_request(socket, msg)
@async Base.throwto(requests_task[], InterruptException())
send_ipython(socket, msg_reply(msg, "interrupt_reply", Dict()))
Expand Down
7 changes: 7 additions & 0 deletions src/init.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ const socket_locks = Dict{Socket,ReentrantLock}()
const minirepl = Ref{MiniREPL}()
end

"""
init(args)
Initialize a kernel. `args` may either be empty or have one element containing
the path to an existing connection file. If `args` is empty a connection file
will be generated.
"""
function init(args)
inited && error("IJulia is already running")
if length(args) > 0
Expand Down
29 changes: 22 additions & 7 deletions src/inline.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import Base: display, redisplay

"""
Struct to dispatch on for inline display.
"""
struct InlineDisplay <: AbstractDisplay end

# supported MIME types for inline display in IPython, in descending order
# of preference (descending "richness")
"""
Supported MIME types for inline display in IPython, in descending order
of preference (descending "richness").
"""
const ipy_mime = [
"application/vnd.dataresource+json",
["application/vnd.vegalite.v$n+json" for n in 4:-1:2]...,
Expand All @@ -19,21 +24,31 @@ const ipy_mime = [
"application/javascript"
]

# need special handling for showing a string as a textmime
# type, since in that case the string is assumed to be
# raw data unless it is text/plain
"""
Need special handling for showing a string as a textmime type, since in that
case the string is assumed to be raw data unless it is text/plain.
"""
israwtext(m::MIME, x::AbstractString) = !showable(m, x)
israwtext(::MIME"text/plain", x::AbstractString) = false
israwtext(::MIME, x) = false

"""
InlineIOContext(io, KVs::Pair...)
Create an `IOContext` for inline display.
"""
InlineIOContext(io, KVs::Pair...) = IOContext(
io,
:limit=>true, :color=>true, :jupyter=>true,
KVs...
)

# convert x to a string of type mime, making sure to use an
# IOContext that tells the underlying show function to limit output
"""
limitstringmime(mime::MIME, x, forcetext=false)
Convert x to a string of type mime, making sure to use an IOContext that tells
the underlying show function to limit output.
"""
function limitstringmime(mime::MIME, x, forcetext=false)
buf = IOBuffer()
if forcetext || istextmime(mime)
Expand Down
Loading

0 comments on commit 4390ef4

Please sign in to comment.