Skip to content

Commit

Permalink
Backport fix for #895
Browse files Browse the repository at this point in the history
  • Loading branch information
fonsp committed Feb 20, 2021
1 parent 8cf1689 commit 532168a
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 63 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Expand Up @@ -2,7 +2,7 @@ name = "Pluto"
uuid = "c3e4b0f8-55cb-11ea-2926-15256bba5781"
license = "MIT"
authors = ["Fons van der Plas <fonsvdplas@gmail.com>"]
version = "0.12.20"
version = "0.12.21"

[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
Expand Down
148 changes: 87 additions & 61 deletions src/runner/PlutoRunner.jl
Expand Up @@ -15,7 +15,6 @@ using Markdown
import Markdown: html, htmlinline, LaTeX, withtag, htmlesc
import Distributed
import Base64
import Tables
import FuzzyCompletions: Completion, ModuleCompletion, completions, completion_text, score
import Base: show, istextmime
import UUIDs: UUID
Expand Down Expand Up @@ -403,6 +402,8 @@ const table_column_display_limit_increase = 30
const tree_display_extra_items = Dict{UUID,Dict{ObjectDimPair,Int64}}()

function formatted_result_of(id::UUID, ends_with_semicolon::Bool, showmore::Union{ObjectDimPair,Nothing}=nothing)::NamedTuple{(:output_formatted, :errored, :interrupted, :runtime),Tuple{MimedOutput,Bool,Bool,Union{UInt64,Missing}}}
load_Tables_support_if_needed()

extra_items = if showmore === nothing
tree_display_extra_items[id] = Dict{ObjectDimPair,Int64}()
else
Expand Down Expand Up @@ -616,7 +617,7 @@ end
# we write our own function instead of extending Base.showable with our new MIME because:
# we need the method Base.showable(::MIME"asdfasdf", ::Any) = Tables.rowaccess(x)
# but overload ::MIME{"asdf"}, ::Any will cause ambiguity errors in other packages that write a method like:
# Baee.showable(m::MIME, x::Plots.Plot)
# Base.showable(m::MIME, x::Plots.Plot)
# because MIME is less specific than MIME"asdff", but Plots.PLot is more specific than Any.
pluto_showable(m::MIME, @nospecialize(x))::Bool = Base.invokelatest(showable, m, x)

Expand All @@ -637,11 +638,6 @@ pluto_showable(::MIME"application/vnd.pluto.tree+object", ::AbstractRange) = fal
pluto_showable(::MIME"application/vnd.pluto.tree+object", ::Any) = false


pluto_showable(::MIME"application/vnd.pluto.table+object", x::Any) = try Tables.rowaccess(x)::Bool catch; false end
pluto_showable(::MIME"application/vnd.pluto.table+object", t::Type) = false
pluto_showable(::MIME"application/vnd.pluto.table+object", t::AbstractVector{<:NamedTuple}) = false


# in the next functions you see a `context` argument
# this is really only used for the circular reference tracking

Expand Down Expand Up @@ -800,78 +796,108 @@ trynameof(x::Any) = Symbol()
# TABLE VIEWER
##

function maptruncated(f::Function, xs, filler, limit; truncate=true)
if truncate
result = Any[
# not xs[1:limit] because of https://github.com/JuliaLang/julia/issues/38364
f(xs[i]) for i in 1:limit
]
push!(result, filler)
result
else
Any[f(x) for x in xs]
const tables_pkgid = Base.PkgId(UUID("bd369af6-aec1-5ad0-b16a-f7cc5008161c"), "Tables")

# We have a super cool viewer for objects that are a Tables.jl table. To avoid version conflicts, we only load this code after the user (indirectly) loaded the package Tables.jl.
# This is similar to how Requires.jl works, except we don't use a callback, we just check every time.
const _load_tables_code = quote

const Tables = Base.loaded_modules[tables_pkgid]

function maptruncated(f::Function, xs, filler, limit; truncate=true)
if truncate
result = Any[
# not xs[1:limit] because of https://github.com/JuliaLang/julia/issues/38364
f(xs[i]) for i in 1:limit
]
push!(result, filler)
result
else
Any[f(x) for x in xs]
end
end
end

function table_data(x::Any, io::IOContext)
rows = Tables.rows(x)
function table_data(x::Any, io::IOContext)
rows = Tables.rows(x)

my_row_limit = get_my_display_limit(x, 1, io, table_row_display_limit, table_row_display_limit_increase)
my_row_limit = get_my_display_limit(x, 1, io, table_row_display_limit, table_row_display_limit_increase)

# TODO: the commented line adds support for lazy loading columns, but it uses the same extra_items counter as the rows. So clicking More Rows will also give more columns, and vice versa, which isn't ideal. To fix, maybe use (objectid,dimension) as index instead of (objectid)?
# TODO: the commented line adds support for lazy loading columns, but it uses the same extra_items counter as the rows. So clicking More Rows will also give more columns, and vice versa, which isn't ideal. To fix, maybe use (objectid,dimension) as index instead of (objectid)?

my_column_limit = get_my_display_limit(x, 2, io, table_column_display_limit, table_column_display_limit_increase)
# my_column_limit = table_column_display_limit
my_column_limit = get_my_display_limit(x, 2, io, table_column_display_limit, table_column_display_limit_increase)
# my_column_limit = table_column_display_limit

# additional 5 so that we don't cut off 1 or 2 itmes - that's silly
truncate_rows = my_row_limit + 5 < length(rows)
truncate_columns = if isempty(rows)
false
else
my_column_limit + 5 < length(first(rows))
end
# additional 5 so that we don't cut off 1 or 2 itmes - that's silly
truncate_rows = my_row_limit + 5 < length(rows)
truncate_columns = if isempty(rows)
false
else
my_column_limit + 5 < length(first(rows))
end

row_data_for(row) = maptruncated(row, "more", my_column_limit; truncate=truncate_columns) do el
format_output_default(el, io)
end
row_data_for(row) = maptruncated(row, "more", my_column_limit; truncate=truncate_columns) do el
format_output_default(el, io)
end

# ugliest code in Pluto:
# ugliest code in Pluto:

# not a map(row) because it needs to be a Vector
# not enumerate(rows) because of some silliness
# not rows[i] because `getindex` is not guaranteed to exist
L = truncate_rows ? my_row_limit : length(rows)
row_data = Array{Any,1}(undef, L)
for (i, row) in zip(1:L,rows)
row_data[i] = (i, row_data_for(row))
end
# not a map(row) because it needs to be a Vector
# not enumerate(rows) because of some silliness
# not rows[i] because `getindex` is not guaranteed to exist
L = truncate_rows ? my_row_limit : length(rows)
row_data = Array{Any,1}(undef, L)
for (i, row) in zip(1:L,rows)
row_data[i] = (i, row_data_for(row))
end

if truncate_rows
push!(row_data, "more")
if applicable(lastindex, rows)
push!(row_data, (length(rows), row_data_for(last(rows))))
if truncate_rows
push!(row_data, "more")
if applicable(lastindex, rows)
push!(row_data, (length(rows), row_data_for(last(rows))))
end
end
end

# TODO: render entire schema by default?

# TODO: render entire schema by default?

schema = Tables.schema(rows)
schema_data = schema === nothing ? nothing : Dict{Symbol,Any}(
:names => maptruncated(string, schema.names, "more", my_column_limit; truncate=truncate_columns),
:types => String.(maptruncated(trynameof, schema.types, "more", my_column_limit; truncate=truncate_columns)),
)
schema = Tables.schema(rows)
schema_data = schema === nothing ? nothing : Dict{Symbol,Any}(
:names => maptruncated(string, schema.names, "more", my_column_limit; truncate=truncate_columns),
:types => String.(maptruncated(trynameof, schema.types, "more", my_column_limit; truncate=truncate_columns)),
)

Dict{Symbol,Any}(
:objectid => string(objectid(x), base=16),
:schema => schema_data,
:rows => row_data,
)
end

Dict{Symbol,Any}(
:objectid => string(objectid(x), base=16),
:schema => schema_data,
:rows => row_data,
)
end

pluto_showable(::MIME"application/vnd.pluto.table+object", x::Any) = try Tables.rowaccess(x)::Bool catch; false end
pluto_showable(::MIME"application/vnd.pluto.table+object", t::Type) = false
pluto_showable(::MIME"application/vnd.pluto.table+object", t::AbstractVector{<:NamedTuple}) = false

end

const _Tables_support_loaded = Ref(false)

function load_Tables_support_if_needed()
if !_Tables_support_loaded[] && haskey(Base.loaded_modules, tables_pkgid)
load_Tables_support()
end
end


function load_Tables_support()
_Tables_support_loaded[] = true
try
eval(_load_tables_code)
true
catch e
@error "Failed to load display support for Tables.jl" exception=(e, catch_backtrace())
false
end
end



Expand Down
8 changes: 7 additions & 1 deletion test/RichOutput.jl
Expand Up @@ -112,7 +112,9 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb
WorkspaceManager.unmake_workspace((🍭, notebook))
end


@testset "Special arrays" begin
🍭.options.evaluation.workspace_use_distributed = true

notebook = Notebook([
Cell("using OffsetArrays"),
Expand All @@ -132,10 +134,13 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb
end

WorkspaceManager.unmake_workspace((🍭, notebook))
🍭.options.evaluation.workspace_use_distributed = false
end
end


@testset "Table viewer" begin
🍭.options.evaluation.workspace_use_distributed = true
notebook = Notebook([
Cell("using DataFrames, Tables"),
Cell("DataFrame()"),
Expand Down Expand Up @@ -191,8 +196,9 @@ import Pluto: update_run!, WorkspaceManager, ClientSession, ServerSession, Noteb
# TODO: test lazy loading more rows/cols

WorkspaceManager.unmake_workspace((🍭, notebook))
🍭.options.evaluation.workspace_use_distributed = false
end

begin
escape_me = "16 \\ \" ' / \b \f \n \r \t πŸ’© \x10 \$"
notebook = Notebook([
Expand Down

0 comments on commit 532168a

Please sign in to comment.