Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some code comments #3108

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Pluto.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import Pkg
import Scratch

include_dependency("../Project.toml")
const PLUTO_VERSION = VersionNumber(Pkg.TOML.parsefile(joinpath(ROOT_DIR, "Project.toml"))["version"])
const PLUTO_VERSION = pkgversion(@__MODULE__)
const PLUTO_VERSION_STR = "v$(string(PLUTO_VERSION))"
const JULIA_VERSION_STR = "v$(string(VERSION))"

Expand Down
2 changes: 2 additions & 0 deletions src/analysis/DependencyCache.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import UUIDs: UUID

"""
Gets a dictionary of all symbols and the respective cells which are dependent on the given cell.

Expand Down
26 changes: 22 additions & 4 deletions src/analysis/MoreAnalysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,22 @@ function _find_bound_variables!(found::Set{Symbol}, expr::Any) end


"Return the given cells, and all cells that depend on them (recursively)."
function downstream_recursive(notebook::Notebook, topology::NotebookTopology, from::Union{Vector{Cell},Set{Cell}})::Set{Cell}
function downstream_recursive(
notebook::Notebook,
topology::NotebookTopology,
from::Union{Vector{Cell},Set{Cell}},
)::Set{Cell}
found = Set{Cell}(copy(from))
_downstream_recursive!(found, notebook, topology, from)
found
end

function _downstream_recursive!(found::Set{Cell}, notebook::Notebook, topology::NotebookTopology, from::Vector{Cell})::Nothing
function _downstream_recursive!(
found::Set{Cell},
notebook::Notebook,
topology::NotebookTopology,
from::Vector{Cell},
)::Nothing
for cell in from
one_down = PlutoDependencyExplorer.where_referenced(topology, cell)
for next in one_down
Expand All @@ -68,13 +77,22 @@ end


"Return all cells that are depended upon by any of the given cells."
function upstream_recursive(notebook::Notebook, topology::NotebookTopology, from::Union{Vector{Cell},Set{Cell}})::Set{Cell}
function upstream_recursive(
notebook::Notebook,
topology::NotebookTopology,
from::Union{Vector{Cell},Set{Cell}},
)::Set{Cell}
found = Set{Cell}(copy(from))
_upstream_recursive!(found, notebook, topology, from)
found
end

function _upstream_recursive!(found::Set{Cell}, notebook::Notebook, topology::NotebookTopology, from::Vector{Cell})::Nothing
function _upstream_recursive!(
found::Set{Cell},
notebook::Notebook,
topology::NotebookTopology,
from::Vector{Cell},
)::Nothing
for cell in from
references = topology.nodes[cell].references
for upstream in PlutoDependencyExplorer.where_assigned(topology, references)
Expand Down
2 changes: 2 additions & 0 deletions src/analysis/Parse.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# This is how we go from a String of cell code to a Julia `Expr` that can be executed.

import ExpressionExplorer
import Markdown

Expand Down
4 changes: 1 addition & 3 deletions src/evaluation/Run.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import REPL: ends_with_semicolon
import .Configuration
import .Throttled
import ExpressionExplorer: is_joined_funcname
import UUIDs: UUID

"""
Run given cells and all the cells that depend on them, based on the topology information before and after the changes.
Expand Down Expand Up @@ -507,9 +508,6 @@ function cells_to_disable_to_resolve_multiple_defs(old::NotebookTopology, new::N

if length(fellow_assigners_new) > length(fellow_assigners_old)
other_definers = setdiff(fellow_assigners_new, (cell,))

@debug "Solving multiple defs" cell.cell_id cell_id.(other_definers) disjoint(cells, other_definers)

# we want cell to be the only element of cells that defines this varialbe, i.e. all other definers must have been created previously
if disjoint(cells, other_definers)
# all fellow cells (including the current cell) should meet some criteria:
Expand Down
3 changes: 3 additions & 0 deletions src/notebook/Cell.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import UUIDs: UUID, uuid1

# Hello! 👋 Check out the `Cell` struct.


const METADATA_DISABLED_KEY = "disabled"
const METADATA_SHOW_LOGS_KEY = "show_logs"
const METADATA_SKIP_AS_SCRIPT_KEY = "skip_as_script"
Expand Down
2 changes: 2 additions & 0 deletions src/notebook/Export.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ function prefetch_statefile_html(statefile_js::AbstractString)
end

"""
This function takes the `editor.html` file from Pluto's source code, and uses string replacements to insert custom data. By inserting a statefile (and more), you can create an HTML file that will display a notebook when opened: this is how the Static HTML export works.

See [PlutoSliderServer.jl](https://github.com/JuliaPluto/PlutoSliderServer.jl) if you are interested in exporting notebooks programatically.
"""
function generate_html(;
Expand Down
12 changes: 10 additions & 2 deletions src/notebook/Notebook.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# The `Notebook` struct!

import UUIDs: UUID, uuid1
import .Configuration
import .PkgCompat: PkgCompat, PkgContext
import Pkg
import TOML
import .Status

const DEFAULT_NOTEBOOK_METADATA = Dict{String, Any}()
Expand All @@ -22,7 +23,11 @@ const ProcessStatus = (
waiting_for_permission="waiting_for_permission",
)

"Like a [`Diary`](@ref) but more serious. 📓"
"""
A Pluto notebook, yay! 📓

This mutable struct is a notebook session. It contains the information loaded from the `.jl` file, the cell outputs, package information, execution metadata and more.
"""
Base.@kwdef mutable struct Notebook
"Cells are ordered in a `Notebook`, and this order can be changed by the user. Cells will always have a constant UUID."
cells_dict::Dict{UUID,Cell}
Expand Down Expand Up @@ -111,15 +116,18 @@ end
Notebook(cells::Vector{Cell}, path::AbstractString=numbered_until_new(joinpath(new_notebooks_directory(), cutename()))) = Notebook(cells, path, uuid1())

function Base.getproperty(notebook::Notebook, property::Symbol)
# This is so that you can do notebook.cells to get all cells as a vector.
if property == :cells
_collect_cells(notebook.cells_dict, notebook.cell_order)
# This is for Firebasey I think
elseif property == :cell_inputs
notebook.cells_dict
else
getfield(notebook, property)
end
end

# New method for this function with a `Notebook` as input.
function PlutoDependencyExplorer.topological_order(notebook::Notebook)
cached = notebook._cached_topological_order
if cached === nothing || cached.input_topology !== notebook.topology
Expand Down
2 changes: 1 addition & 1 deletion src/notebook/path helpers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ end
const tamepath = abspath ∘ tryexpanduser

"Block until reading the file two times in a row gave the same result."
function wait_until_file_unchanged(filename::String, timeout::Real, last_contents::String="")::Nothing
function wait_until_file_unchanged(filename::String, timeout::Real, last_contents::String="-=-=-=-")::Nothing
new_contents = try
read(filename, String)
catch
Expand Down
39 changes: 21 additions & 18 deletions src/notebook/saving and loading.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

import TOML
import UUIDs: UUID

const _notebook_header = "### A Pluto.jl notebook ###"
const _notebook_metadata_prefix = "#> "
Expand Down Expand Up @@ -43,7 +44,8 @@ function save_notebook(io::IO, notebook::Notebook)
end
end

# Anything between the version string and the first UUID delimiter will be ignored by the notebook loader.
# (Anything between the version string and the first UUID delimiter will be ignored by the notebook loader.)
# We insert these two imports because they are also imported by default in the Pluto session. You might use these packages in your code, so we add the imports to the file, so the file can run as a script.
println(io, "")
println(io, "using Markdown")
println(io, "using InteractiveUtils")
Expand Down Expand Up @@ -78,15 +80,18 @@ function save_notebook(io::IO, notebook::Notebook)
end
end
end

# Do one little string replacement to make it impossible to use the Pluto cell delimiter inside of actual cell code. If this would happen, then the notebook file cannot load correctly. So we just remove it from your code (sorry!)
current_code = replace(c.code, _cell_id_delimiter => "# ")

if must_be_commented_in_file(c)
print(io, _disabled_prefix)
print(io, replace(c.code, _cell_id_delimiter => "# "))
print(io, current_code)
print(io, _disabled_suffix)
print(io, _cell_suffix)
else
# write the cell code and prevent collisions with the cell delimiter
print(io, replace(c.code, _cell_id_delimiter => "# "))
print(io, current_code)
print(io, _cell_suffix)
end
end
Expand Down Expand Up @@ -155,7 +160,7 @@ save_notebook(notebook::Notebook) = save_notebook(notebook, notebook.path)
# LOADING
###

function _notebook_metadata!(@nospecialize(io::IO))
function _read_notebook_metadata!(@nospecialize(io::IO))
firstline = String(readline(io))::String

if firstline != _notebook_header
Expand Down Expand Up @@ -192,7 +197,7 @@ function _notebook_metadata!(@nospecialize(io::IO))
return notebook_metadata
end

function _notebook_collected_cells!(@nospecialize(io::IO))
function _read_notebook_collected_cells!(@nospecialize(io::IO))
collected_cells = Dict{UUID,Cell}()
while !eof(io)
cell_id_str = String(readline(io))
Expand Down Expand Up @@ -239,7 +244,7 @@ function _notebook_collected_cells!(@nospecialize(io::IO))
return collected_cells
end

function _notebook_cell_order!(@nospecialize(io::IO), collected_cells)
function _read_notebook_cell_order!(@nospecialize(io::IO), collected_cells)
cell_order = UUID[]
while !eof(io)
cell_id_str = String(readline(io))
Expand All @@ -259,7 +264,7 @@ function _notebook_cell_order!(@nospecialize(io::IO), collected_cells)
return cell_order
end

function _notebook_nbpkg_ctx(cell_order::Vector{UUID}, collected_cells::Dict{Base.UUID, Cell})
function _read_notebook_nbpkg_ctx(cell_order::Vector{UUID}, collected_cells::Dict{Base.UUID, Cell})
read_package =
_ptoml_cell_id ∈ cell_order &&
_mtoml_cell_id ∈ cell_order &&
Expand Down Expand Up @@ -295,7 +300,7 @@ function _notebook_nbpkg_ctx(cell_order::Vector{UUID}, collected_cells::Dict{Bas
return nbpkg_ctx
end

function _notebook_appeared_order!(cell_order::Vector{UUID}, collected_cells::Dict{Base.UUID, Cell})
function _read_notebook_appeared_order!(cell_order::Vector{UUID}, collected_cells::Dict{Base.UUID, Cell})
setdiff!(
union!(
# don't include cells that only appear in the order, but no code was given
Expand All @@ -310,12 +315,12 @@ end

"Load a notebook without saving it or creating a backup; returns a `Notebook`. REMEMBER TO CHANGE THE NOTEBOOK PATH after loading it to prevent it from autosaving and overwriting the original file."
function load_notebook_nobackup(@nospecialize(io::IO), @nospecialize(path::AbstractString))::Notebook
notebook_metadata = _notebook_metadata!(io)
notebook_metadata = _read_notebook_metadata!(io)
collected_cells = _read_notebook_collected_cells!(io)
cell_order = _read_notebook_cell_order!(io, collected_cells)
nbpkg_ctx = _read_notebook_nbpkg_ctx(cell_order, collected_cells)
appeared_order = _read_notebook_appeared_order!(cell_order, collected_cells)

collected_cells = _notebook_collected_cells!(io)
cell_order = _notebook_cell_order!(io, collected_cells)
nbpkg_ctx = _notebook_nbpkg_ctx(cell_order, collected_cells)
appeared_order = _notebook_appeared_order!(cell_order, collected_cells)
appeared_cells_dict = filter(collected_cells) do (k, v)
k ∈ appeared_order
end
Expand All @@ -336,16 +341,14 @@ end
# UTILS

function load_notebook_nobackup(path::String)::Notebook
local loaded
open(path, "r") do io
loaded = load_notebook_nobackup(io, path)
load_notebook_nobackup(io, path)
end
loaded
end

# BACKUPS

"Create a backup of the given file, load the file as a .jl Pluto notebook, save the loaded notebook, compare the two files, and delete the backup of the newly saved file is equal to the backup."
"Create a backup of the given file, load the file as a .jl Pluto notebook, save the loaded notebook, compare the two files, and delete the backup of the newly saved file is mostly equal to the backup."
function load_notebook(path::String; disable_writing_notebook_files::Bool=false)::Notebook
backup_path = backup_filename(path)
# local backup_num = 1
Expand Down
7 changes: 7 additions & 0 deletions src/packages/Packages.jl
Original file line number Diff line number Diff line change
Expand Up @@ -485,9 +485,16 @@ function with_auto_fixes(f::Function, notebook::Notebook)
@info "Operation failed. Updating registries and trying again..." exception=e

PkgCompat.update_registries(; force=true)

# TODO: check for resolver errors around stdlibs and fix them by doing `up Statistics`




try
f()
catch e
# this is identical to Pkg.update, right?
@warn "Operation failed. Removing Manifest and trying again..." exception=e

reset_nbpkg!(notebook; keep_project=true, save=false, backup=false)
Expand Down
2 changes: 1 addition & 1 deletion src/packages/PkgCompat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ end
###


_project_key_order = ["name", "uuid", "keywords", "license", "desc", "deps", "weakdeps", "sources", "extensions", "compat"]
const _project_key_order = ["name", "uuid", "keywords", "license", "desc", "deps", "weakdeps", "sources", "extensions", "compat"]
project_key_order(key::String) =
something(findfirst(x -> x == key, _project_key_order), length(_project_key_order) + 1)

Expand Down
2 changes: 1 addition & 1 deletion src/runner/Loader.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# The goal of this file is to import PlutoRunner into Main.
# The goal of this file is to import PlutoRunner into Main, on the process of the notebook (created by Malt.jl).
#
# This is difficult because PlutoRunner uses standard libraries and packages that are not necessarily available in the standard environment.
#
Expand Down
2 changes: 1 addition & 1 deletion src/runner/PlutoRunner/src/bonds.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Base64

import UUIDs: UUID

const registered_bond_elements = Dict{Symbol, Any}()

Expand Down
1 change: 0 additions & 1 deletion src/webserver/Dynamic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,6 @@ function _set_cells_to_queued_in_local_state(client, notebook, cells)
if haskey(results, cell.cell_id)
old = results[cell.cell_id]["queued"]
results[cell.cell_id]["queued"] = true
@debug "Setting val!" cell.cell_id old
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion src/webserver/Router.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

function http_router_for(session::ServerSession)
router = HTTP.Router(default_404)
router = HTTP.Router(default_404_response)
security = session.options.security

function create_serve_onefile(path)
Expand Down
29 changes: 19 additions & 10 deletions src/webserver/Static.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import HTTP
import Markdown: htmlesc
import UUIDs: UUID
import Pkg
import MIMEs

Expand All @@ -24,7 +23,7 @@ const day = let
day = 24hour
end

function default_404(req = nothing)
function default_404_response(req = nothing)
HTTP.Response(404, "Not found!")
end

Expand All @@ -41,7 +40,7 @@ function asset_response(path; cacheable::Bool=false)
cacheable && HTTP.setheader(response, "Cache-Control" => "public, max-age=$(30day), immutable")
response
else
default_404()
default_404_response()
end
end

Expand Down Expand Up @@ -73,19 +72,29 @@ function notebook_response(notebook; home_url="./", as_redirect=true)
end
end

const found_is_pluto_dev = Ref{Union{Nothing,Bool}}(nothing)
const found_is_pluto_dev = Ref{Bool}()
"""
Is the Pluto package `dev`ed? Returns `false` for normal Pluto installation from the registry.
"""
function is_pluto_dev()
if found_is_pluto_dev[] !== nothing
if isassigned(found_is_pluto_dev)
return found_is_pluto_dev[]
end

found_is_pluto_dev[] = try
deps = Pkg.dependencies()
# is the package located in .julia/packages ?
if startswith(pkgdir(@__MODULE__), joinpath(get(DEPOT_PATH, 1, "zzz"), "packages"))
false
else
deps = Pkg.dependencies()

p_index = findfirst(p -> p.name == "Pluto", deps)
p = deps[p_index]
p_index = findfirst(p -> p.name == "Pluto", deps)
p = deps[p_index]

p.is_tracking_path
catch
p.is_tracking_path
end
catch e
@debug "is_pluto_dev failed" e
false
end
end
Expand Down
Loading
Loading