From ee4888ba2b0a71c69a57bbc76feada92b44bd539 Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sat, 29 Jun 2024 20:40:19 +0200 Subject: [PATCH 01/11] try fixing dev stuff --- src/frompackage/helpers.jl | 20 +++++++++++--------- src/frompackage/types.jl | 10 +++------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/frompackage/helpers.jl b/src/frompackage/helpers.jl index c8e8875..561e073 100644 --- a/src/frompackage/helpers.jl +++ b/src/frompackage/helpers.jl @@ -326,15 +326,17 @@ function populate_loaded_modules() end callbacks = Base.package_callbacks if mirror_package_callback ∉ callbacks - # # We just make sure to delete previous instances of the package callbacks when reloading this package itself - # for i in reverse(eachindex(callbacks)) - # f = callbacks[i] - # nameof(f) === :mirror_package_callback || continue - # nameof(parentmodule(f)) === nameof(@__MODULE__) || continue - # # We delete this as it's a previous version of the mirror_package_callback function - # @warn "Deleting previous version of package_callback function" - # deleteat!(callbacks, i) - # end + for i in reverse(eachindex(callbacks)) + # This part is only useful when developing this package itself + f = callbacks[i] + nameof(f) === :mirror_package_callback || continue + owner = parentmodule(f) + nameof(owner) === nameof(@__MODULE__) || continue + isdefined(owner, :IS_DEV) && owner.IS_DEV || continue + # We delete this as it's a previous version of the mirror_package_callback function + @warn "Deleting previous version of package_callback function" + deleteat!(callbacks, i) + end # Add the package callback if not already present push!(callbacks, mirror_package_callback) end diff --git a/src/frompackage/types.jl b/src/frompackage/types.jl index ff701b5..b547512 100644 --- a/src/frompackage/types.jl +++ b/src/frompackage/types.jl @@ -1,18 +1,14 @@ const default_pkg_io = Ref{IO}(devnull) -const TEMP_MODULE_NAME = if first(fullname(@__MODULE__)) === :Main - # We are loading this module from PlutoDevMacros, so we use a dev name - :_FromPackage_TempModule_DEV_ -else - :_FromPackage_TempModule_ -end +const IS_DEV = first(fullname(@__MODULE__)) === :Main +const TEMP_MODULE_NAME = Symbol(:_FrompPackage_TempModule_, IS_DEV ? "DEV_" : "") const EMPTY_PIPE = Pipe() const STDLIBS_DATA = Dict{String,Base.UUID}() for (uuid, (name, _)) in Pkg.Types.stdlibs() STDLIBS_DATA[name] = uuid end -const PREV_CONTROLLER_NAME = :_Previous_Controller_ +const PREV_CONTROLLER_NAME = Symbol(:_Previous_Controller_, IS_DEV ? "DEV_" : "") # This structure is just a placeholder that is put in place of expressions that are to be removed when parsing a file struct RemoveThisExpr end From 2981ed757722b17c2ef7e65653e3367dd3628031 Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sat, 29 Jun 2024 23:47:58 +0200 Subject: [PATCH 02/11] move consts in separate file --- src/frompackage/FromPackage.jl | 1 + src/frompackage/consts.jl | 10 ++++++++++ src/frompackage/types.jl | 22 ++++++++++------------ 3 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 src/frompackage/consts.jl diff --git a/src/frompackage/FromPackage.jl b/src/frompackage/FromPackage.jl index 029452d..88bc1dd 100644 --- a/src/frompackage/FromPackage.jl +++ b/src/frompackage/FromPackage.jl @@ -10,6 +10,7 @@ module FromPackage export @fromparent, @addmethod, @frompackage include("types.jl") + include("consts.jl") include("imports_helpers.jl") include("helpers.jl") include("code_parsing.jl") diff --git a/src/frompackage/consts.jl b/src/frompackage/consts.jl new file mode 100644 index 0000000..4dc2d16 --- /dev/null +++ b/src/frompackage/consts.jl @@ -0,0 +1,10 @@ +const IS_DEV = first(fullname(@__MODULE__)) === :Main +const TEMP_MODULE_NAME = Symbol(:_FrompPackage_TempModule_, IS_DEV ? "DEV_" : "") +const EMPTY_PIPE = Pipe() +const STDLIBS_DATA = Dict{String,Base.UUID}() +for (uuid, (name, _)) in Pkg.Types.stdlibs() + STDLIBS_DATA[name] = uuid +end +const PREV_CONTROLLER_NAME = Symbol(:_Previous_Controller_, IS_DEV ? "DEV_" : "") + +const CURRENT_FROMPACKAGE_CONTROLLER = Ref{FromPackageController}() \ No newline at end of file diff --git a/src/frompackage/types.jl b/src/frompackage/types.jl index b547512..9c0c633 100644 --- a/src/frompackage/types.jl +++ b/src/frompackage/types.jl @@ -1,18 +1,15 @@ -const default_pkg_io = Ref{IO}(devnull) - -const IS_DEV = first(fullname(@__MODULE__)) === :Main -const TEMP_MODULE_NAME = Symbol(:_FrompPackage_TempModule_, IS_DEV ? "DEV_" : "") -const EMPTY_PIPE = Pipe() -const STDLIBS_DATA = Dict{String,Base.UUID}() -for (uuid, (name, _)) in Pkg.Types.stdlibs() - STDLIBS_DATA[name] = uuid -end -const PREV_CONTROLLER_NAME = Symbol(:_Previous_Controller_, IS_DEV ? "DEV_" : "") - # This structure is just a placeholder that is put in place of expressions that are to be removed when parsing a file struct RemoveThisExpr end +@kwdef mutable struct FromPackageOptions + "Specifies whether the target package shall be registered as root module while loading" + rootmodule::Bool = false + "Flag to specify whether the project should be resolved before loading" + resolve::Bool = false + "Flag to enable verbose logging of FromPackage functions" + verbose::Bool = false +end struct ProjectData file::String deps::Dict{String, Base.UUID} @@ -79,8 +76,9 @@ abstract type AbstractEvalController end imported_names::Set{Symbol} = Set{Symbol}() "ID of the cell where the macro was called, nothing if not called from Pluto" cell_id::Union{Nothing, Base.UUID} = nothing + "Options to customize loading" + options::FromPackageOptions = FromPackageOptions() end -const CURRENT_FROMPACKAGE_CONTROLLER = Ref{FromPackageController}() # Default constructor function FromPackageController(target_path::AbstractString, caller_module::Module; cell_id = nothing) From ec621d905e98f8b87a8c8ebcd6a904da72aefd94 Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sat, 29 Jun 2024 23:48:37 +0200 Subject: [PATCH 03/11] improve inception development --- src/frompackage/helpers.jl | 154 +++++++++++++++++++++++-------------- src/frompackage/loading.jl | 22 +++++- src/frompackage/macro.jl | 7 +- 3 files changed, 121 insertions(+), 62 deletions(-) diff --git a/src/frompackage/helpers.jl b/src/frompackage/helpers.jl index 561e073..13ae310 100644 --- a/src/frompackage/helpers.jl +++ b/src/frompackage/helpers.jl @@ -51,71 +51,101 @@ end ## HTML Popup -_popup_style(id) = """ - fromparent-container { - height: 20px; - position: fixed; - top: 40px; - right: 10px; - margin-top: 5px; - padding-right: 5px; - z-index: 200; - background: var(--overlay-button-bg); - padding: 5px 8px; - border: 3px solid var(--overlay-button-border); - border-radius: 12px; - height: 35px; - font-family: "Segoe UI Emoji", "Roboto Mono", monospace; - font-size: 0.75rem; - } - fromparent-container.errored { - border-color: var(--error-cell-color) - } - fromparent-container:hover { - font-weight: 800; - cursor: pointer; - } - body.disable_ui fromparent-container { - display: none; - } - pluto-log-dot-positioner[hidden] { - display: none; - } +function _popup_style() +#! format: off """ +fromparent-container { + height: 20px; + position: fixed; + top: 40px; + right: 10px; + margin-top: 5px; + padding-right: 5px; + z-index: 200; + background: var(--overlay-button-bg); + padding: 5px 8px; + border: 3px solid var(--overlay-button-border); + border-radius: 12px; + height: 35px; + font-family: "Segoe UI Emoji", "Roboto Mono", monospace; + font-size: 0.75rem; +} -function html_reload_button(p::FromPackageController; text) +fromparent-container.PlutoDevMacros { + right: auto; + left: 10px; +} +fromparent-container.PlutoDevMacros:before { + content: "Reload PlutoDevMacros" +} + +fromparent-container.errored { + border-color: var(--error-cell-color); +} +fromparent-container:hover { + font-weight: 800; + cursor: pointer; +} +body.disable_ui fromparent-container { + display: none; +} +pluto-log-dot-positioner[hidden] { + display: none; +} +""" +#! format: on +end + +function is_plutodevmacros(p::FromPackageController) @nospecialize + (; name, uuid) = p.project + return name === "PlutoDevMacros" && uuid === Base.UUID("a0499f29-c39b-4c5c-807c-88074221b949") +end + +function html_reload_button(p::FromPackageController; kwargs...) + @nospecialize + (; name) = p.project simple_html_cat( beautify_package_path(p), - html_reload_button(p.cell_id; text) + html_reload_button(p.cell_id; name, kwargs...), ) end -function html_reload_button(cell_id; text="Reload @frompackage", err=false) +function html_reload_button(cell_id; name="@frompackage", err=false) id = string(cell_id) - style_content = _popup_style(id) + text_content = "Reload $name" + style_content = _popup_style() + #! format: off + # We add the text content based on the package name + style_content *= """ +fromparent-container:before { + content: '$text_content'; +} + """ html_content = """ - + """ + #! format: on # We make an HTML object combining this content and the hide_this_log functionality return hide_this_log(html_content) end @@ -266,8 +296,18 @@ end function update_loadpath(p::FromPackageController) @nospecialize + (; verbose) = p.options proj_file = p.project.file + if isassigned(CURRENT_FROMPACKAGE_CONTROLLER) + prev_proj = CURRENT_FROMPACKAGE_CONTROLLER[].project.file + prev_idx = findfirst(==(prev_proj), LOAD_PATH) + if !isnothing(prev_idx) && prev_proj !== proj_file + verbose && @info "Deleting $prev_proj from LOAD_PATH" + deleteat!(LOAD_PATH, prev_idx) + end + end if proj_file ∉ LOAD_PATH + verbose && @info "Adding $proj_file to end of LOAD_PATH" push!(LOAD_PATH, proj_file) end end @@ -315,7 +355,7 @@ end get_loaded_modules_mod() = get_temp_module(:_LoadedModules_)::Module get_direct_deps_mod() = get_temp_module(:_DirectDeps_)::Module -function populate_loaded_modules() +function populate_loaded_modules(; verbose=false) loaded_modules = get_loaded_modules_mod() @lock Base.require_lock begin for (id, m) in Base.loaded_modules @@ -334,7 +374,7 @@ function populate_loaded_modules() nameof(owner) === nameof(@__MODULE__) || continue isdefined(owner, :IS_DEV) && owner.IS_DEV || continue # We delete this as it's a previous version of the mirror_package_callback function - @warn "Deleting previous version of package_callback function" + verbose && @warn "Deleting previous version of package_callback function" deleteat!(callbacks, i) end # Add the package callback if not already present diff --git a/src/frompackage/loading.jl b/src/frompackage/loading.jl index 500ed24..b83a08b 100644 --- a/src/frompackage/loading.jl +++ b/src/frompackage/loading.jl @@ -130,7 +130,8 @@ function load_module!(p::FromPackageController{name}; reset=true) where {name} # Maybe call init maybe_call_init(get_temp_module(p)) # We populate the loaded modules - populate_loaded_modules() + (; verbose) = p.options + populate_loaded_modules(;verbose) # Try loading extensions try_load_extensions!(p) return p @@ -172,3 +173,22 @@ function process_include_expr!(p::FromPackageController, mapexpr::Function, path split_and_execute!(p, ast, f) return nothing end + +# This function will register the target module for `dict` as a root module. +# This relies on Base internals (and even the C API) but will allow make the loaded module behave more like if we simply did `using TargetPackage` in the REPL +function register_target_as_root(p::FromPackageController) + @nospecialize + (;name, uuid) = p.project + m = get_temp_module(p) + id = Base.PkgId(uuid, name) + @lock Base.require_lock begin + # Set the uuid of this module with the C API. This is required to get the correct UUID just from the module within `register_root_module` + ccall(:jl_set_module_uuid, Cvoid, (Any, NTuple{2, UInt64}), m, uuid) + # Register this module as root + Base.with_logger(EMPTY_PIPE) do + Base.register_root_module(m) + end + # Set the path of the module to the actual package + Base.set_pkgorigin_version_path(id, entry_point) + end +end \ No newline at end of file diff --git a/src/frompackage/macro.jl b/src/frompackage/macro.jl index d1d1cc2..eed7262 100644 --- a/src/frompackage/macro.jl +++ b/src/frompackage/macro.jl @@ -29,10 +29,10 @@ function frompackage(ex, target_file, caller_module; macroname, cell_id) try $(args...) # We add the reload button as last expression so it's sent to the cell output - $html_reload_button($p; text=$text) + $html_reload_button($p) catch e # We also send the reload button as an @info log, so that we can use the cell output to format the error nicely - @info $html_reload_button($p; text=$text, err = true) + @info $html_reload_button($p; err = true) rethrow() end end |> flatten @@ -53,9 +53,8 @@ function _combined(ex, target, calling_file, caller_module; macroname) notebook_local || rethrow() out = Expr(:block) if !(e isa ErrorException && startswith(e.msg, "Multiple Calls: The")) - text = "Reload $macroname" # We send a log to maintain the reload button - @info html_reload_button(cell_id; text, err=true) + @info html_reload_button(cell_id; name = macroname, err=true) end # Wrap ParseError in LoadError (see https://github.com/disberd/PlutoDevMacros.jl/issues/30) we = wrap_parse_error(e) From a792209247e8d864df3bf93a4b639769a9354e38 Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sun, 30 Jun 2024 09:57:24 +0200 Subject: [PATCH 04/11] improve logs_hider --- src/frompackage/helpers.jl | 4 +-- src/frompackage/macro.jl | 6 ++-- src/html_helpers.jl | 64 ++++++++++++++++++++++++-------------- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/src/frompackage/helpers.jl b/src/frompackage/helpers.jl index 13ae310..bf7a89d 100644 --- a/src/frompackage/helpers.jl +++ b/src/frompackage/helpers.jl @@ -69,6 +69,7 @@ fromparent-container { height: 35px; font-family: "Segoe UI Emoji", "Roboto Mono", monospace; font-size: 0.75rem; + visibility: visible; } fromparent-container.PlutoDevMacros { @@ -89,9 +90,6 @@ fromparent-container:hover { body.disable_ui fromparent-container { display: none; } -pluto-log-dot-positioner[hidden] { - display: none; -} """ #! format: on end diff --git a/src/frompackage/macro.jl b/src/frompackage/macro.jl index eed7262..a6ca84a 100644 --- a/src/frompackage/macro.jl +++ b/src/frompackage/macro.jl @@ -52,10 +52,8 @@ function _combined(ex, target, calling_file, caller_module; macroname) # If we are outside of pluto we simply rethrow notebook_local || rethrow() out = Expr(:block) - if !(e isa ErrorException && startswith(e.msg, "Multiple Calls: The")) - # We send a log to maintain the reload button - @info html_reload_button(cell_id; name = macroname, err=true) - end + # We send a log to maintain the reload button + @info html_reload_button(cell_id; name = macroname, err=true) # Wrap ParseError in LoadError (see https://github.com/disberd/PlutoDevMacros.jl/issues/30) we = wrap_parse_error(e) bt = stacktrace(catch_backtrace()) diff --git a/src/html_helpers.jl b/src/html_helpers.jl index 6b56d6a..8e9d62c 100644 --- a/src/html_helpers.jl +++ b/src/html_helpers.jl @@ -32,33 +32,49 @@ Which will correctly send the message to the console even if the cell output is ![hide_this_log example gif](https://github.com/disberd/PlutoDevMacros.jl/assets/12846528/8208243b-62ce-437a-ae87-97e63ca94e12) """ function hide_this_log(content = ""; id = randid()) - this_contents = "" + #! format: on simple_html_cat(content, this_contents) end From 73b3c28b94361888a35e22f6456ae950964e69ff Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sun, 30 Jun 2024 10:27:28 +0200 Subject: [PATCH 05/11] delete non-used function --- src/frompackage/helpers.jl | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/frompackage/helpers.jl b/src/frompackage/helpers.jl index bf7a89d..39b51e9 100644 --- a/src/frompackage/helpers.jl +++ b/src/frompackage/helpers.jl @@ -94,12 +94,6 @@ body.disable_ui fromparent-container { #! format: on end -function is_plutodevmacros(p::FromPackageController) - @nospecialize - (; name, uuid) = p.project - return name === "PlutoDevMacros" && uuid === Base.UUID("a0499f29-c39b-4c5c-807c-88074221b949") -end - function html_reload_button(p::FromPackageController; kwargs...) @nospecialize (; name) = p.project From 8268edd595979fca9828e486e64b078ac137de48 Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sun, 30 Jun 2024 10:27:44 +0200 Subject: [PATCH 06/11] add option to register as rootmodule --- Project.toml | 2 ++ src/frompackage/FromPackage.jl | 1 + src/frompackage/loading.jl | 6 ++++-- src/frompackage/types.jl | 6 +++--- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Project.toml b/Project.toml index cea21e6..32ccfe5 100644 --- a/Project.toml +++ b/Project.toml @@ -5,12 +5,14 @@ version = "0.9.0-DEV" [deps] JuliaInterpreter = "aa1ae85d-cabe-5617-a682-6adf51b2e16a" +Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" [compat] JuliaInterpreter = "0.9" +Logging = "1" MacroTools = "0.5" Pkg = "1" TOML = "1" diff --git a/src/frompackage/FromPackage.jl b/src/frompackage/FromPackage.jl index 88bc1dd..6243dd6 100644 --- a/src/frompackage/FromPackage.jl +++ b/src/frompackage/FromPackage.jl @@ -5,6 +5,7 @@ module FromPackage import TOML using MacroTools: postwalk, flatten, MacroTools, isdef, longdef using JuliaInterpreter: ExprSplitter + using Logging export @fromparent, @addmethod, @frompackage diff --git a/src/frompackage/loading.jl b/src/frompackage/loading.jl index b83a08b..8189f6b 100644 --- a/src/frompackage/loading.jl +++ b/src/frompackage/loading.jl @@ -115,6 +115,7 @@ function load_module!(p::FromPackageController{name}; reset=true) where {name} m = Core.eval(temp_mod, :(module $name end)) # We mirror the generated module inside the temp_module module, so we can alwyas access it without having to know the current workspace Core.eval(get_temp_module(), :($name = $m)) + p.options.rootmodule && register_target_as_root(p) # We put the controller inside the module Core.eval(m, :($(variable_name(p)) = $p)) end @@ -185,10 +186,11 @@ function register_target_as_root(p::FromPackageController) # Set the uuid of this module with the C API. This is required to get the correct UUID just from the module within `register_root_module` ccall(:jl_set_module_uuid, Cvoid, (Any, NTuple{2, UInt64}), m, uuid) # Register this module as root - Base.with_logger(EMPTY_PIPE) do + logger = Logging.current_logger() + Logging.with_logger(logger) do Base.register_root_module(m) end # Set the path of the module to the actual package - Base.set_pkgorigin_version_path(id, entry_point) + Base.set_pkgorigin_version_path(id, p.entry_point) end end \ No newline at end of file diff --git a/src/frompackage/types.jl b/src/frompackage/types.jl index 9c0c633..02ddef9 100644 --- a/src/frompackage/types.jl +++ b/src/frompackage/types.jl @@ -4,9 +4,9 @@ struct RemoveThisExpr end @kwdef mutable struct FromPackageOptions "Specifies whether the target package shall be registered as root module while loading" - rootmodule::Bool = false - "Flag to specify whether the project should be resolved before loading" - resolve::Bool = false + rootmodule::Bool = true + "Symbol to select whether the target environment should be instantiated or resolved before loading the package" + manifest::Symbol = :none "Flag to enable verbose logging of FromPackage functions" verbose::Bool = false end From c576940ff6776e7717e8909694582e4726a480e9 Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sun, 30 Jun 2024 11:59:13 +0200 Subject: [PATCH 07/11] fix extension handling as root module --- src/frompackage/code_parsing.jl | 3 ++- src/frompackage/loading.jl | 18 +++++++++--------- test/TestIndirectExtension/test_extension.jl | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/frompackage/code_parsing.jl b/src/frompackage/code_parsing.jl index 753bbdf..6d91616 100644 --- a/src/frompackage/code_parsing.jl +++ b/src/frompackage/code_parsing.jl @@ -92,5 +92,6 @@ end function handle_extensions_imports(p::FromPackageController, ex::Expr) @nospecialize @assert Meta.isexpr(ex, (:using, :import)) "You can only call this function with using or import expressions as second argument" - return inside_extension(p) ? process_import_statement(p, ex; inside_extension = true) : ex + inside_extension(p) || return ex + return process_import_statement(p, ex; inside_extension = true) end \ No newline at end of file diff --git a/src/frompackage/loading.jl b/src/frompackage/loading.jl index 8189f6b..181c4bf 100644 --- a/src/frompackage/loading.jl +++ b/src/frompackage/loading.jl @@ -40,10 +40,6 @@ function process_exprsplitter_item!(p::AbstractEvalController, ex, process_func: new_ex = process_func(ex) # @info "Change" new_ex if !isa(new_ex, RemoveThisExpr) && !p.target_reached - # if process_func !== p.custom_walk - # subtype = process_func isa ComposedFunction{typeof(p.custom_walk),<:Any} - # @info "inside mapexpr" new_ex ex process_func p.custom_walk subtype typeof(process_func) - # end Core.eval(p.current_module, new_ex) end return @@ -81,11 +77,15 @@ function try_load_extensions!(p::FromPackageController) end if nactive === length(triggers) entry_path = find_ext_path(p.project, name) - # Set the module to the package module - p.current_module = get_temp_module(p) - # Load the extension module inside the package module - process_include_expr!(p, entry_path) - push!(p.loaded_extensions, name) + # Set the module to the package module parent, which is a temp module in the Pluto workspace + p.current_module = get_temp_module(p) |> parentmodule + try + # Load the extension module inside the package module + process_include_expr!(p, entry_path) + push!(p.loaded_extensions, name) + finally + p.current_module = get_temp_module(p) + end end end end diff --git a/test/TestIndirectExtension/test_extension.jl b/test/TestIndirectExtension/test_extension.jl index 22c2fcf..d1b2445 100644 --- a/test/TestIndirectExtension/test_extension.jl +++ b/test/TestIndirectExtension/test_extension.jl @@ -1,5 +1,5 @@ ### A Pluto.jl notebook ### -# v0.19.42 +# v0.19.43 using Markdown using InteractiveUtils @@ -54,7 +54,7 @@ PlotlyKaleido = "~2.1.0" PLUTO_MANIFEST_TOML_CONTENTS = """ # This file is machine-generated - editing it directly is not advised -julia_version = "1.10.3" +julia_version = "1.10.4" manifest_format = "2.0" project_hash = "a306e345b2ba616e53c5188b7eca690040bebb51" From dfef2788c1854fa6028d474d44e28b1b5e59c333 Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sun, 30 Jun 2024 12:01:01 +0200 Subject: [PATCH 08/11] add options parsing in input --- src/frompackage/input_parsing.jl | 23 ++++++++++++++++++++++- src/frompackage/loading.jl | 10 +++++++--- src/frompackage/macro.jl | 15 ++++++++------- src/frompackage/types.jl | 2 +- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/frompackage/input_parsing.jl b/src/frompackage/input_parsing.jl index 26d4495..eb3e6ae 100644 --- a/src/frompackage/input_parsing.jl +++ b/src/frompackage/input_parsing.jl @@ -1,4 +1,25 @@ -# New stuff +function parse_options!(p::FromPackageController, ex::Expr, extra_args) + @nospecialize + (; options) = p + #! format: off + error_msg = "The provided extra arguments at the end of the macro call are not in a supported format. +Each argument should be in the form `option_name = value`, with the following supported option names and types: +- `rootmodule::Bool` +- `manifest::Symbol` +- `verbose::Bool` +Check the documentations for more details on the options." + #! format: on + for arg in extra_args + Meta.isexpr(arg, :(=)) || error(error_msg) + name, val = arg.args + typeof(name) in (Symbol, QuoteNode) || error(error_msg) + hasfield(FromPackageOptions, name) || error(error_msg) + name isa QuoteNode && (name = name.value) + val isa fieldtype(FromPackageOptions, name) || error(error_msg) + setproperty!(options, name, val) + end + return nothing +end function should_exclude_using_names!(ex::Expr) Meta.isexpr(ex, :macrocall) || return false diff --git a/src/frompackage/loading.jl b/src/frompackage/loading.jl index 181c4bf..7a44429 100644 --- a/src/frompackage/loading.jl +++ b/src/frompackage/loading.jl @@ -66,6 +66,8 @@ function try_load_extensions!(p::FromPackageController) @nospecialize loaded_modules = get_loaded_modules_mod() (; extensions, deps, weakdeps) = p.project + package_name = p.project.name + (; options) = p for (name, triggers) in extensions name in p.loaded_extensions && continue nactive = 0 @@ -76,6 +78,7 @@ function try_load_extensions!(p::FromPackageController) nactive += is_loaded end if nactive === length(triggers) + options.verbose && @info "Loading code of extension $name for package $package_name" entry_path = find_ext_path(p.project, name) # Set the module to the package module parent, which is a temp module in the Pluto workspace p.current_module = get_temp_module(p) |> parentmodule @@ -175,18 +178,19 @@ function process_include_expr!(p::FromPackageController, mapexpr::Function, path return nothing end -# This function will register the target module for `dict` as a root module. -# This relies on Base internals (and even the C API) but will allow make the loaded module behave more like if we simply did `using TargetPackage` in the REPL +# This function will register the module of the target package as a root module. +# This relies on Base internals (and even the C API) so it's disable by default but will allow make the loaded module behave more like if we simply did `using TargetPackage` without the macro function register_target_as_root(p::FromPackageController) @nospecialize (;name, uuid) = p.project m = get_temp_module(p) id = Base.PkgId(uuid, name) + (; verbose) = p.options @lock Base.require_lock begin # Set the uuid of this module with the C API. This is required to get the correct UUID just from the module within `register_root_module` ccall(:jl_set_module_uuid, Cvoid, (Any, NTuple{2, UInt64}), m, uuid) # Register this module as root - logger = Logging.current_logger() + logger = verbose ? Logging.current_logger() : Logging.NullLogger() Logging.with_logger(logger) do Base.register_root_module(m) end diff --git a/src/frompackage/macro.jl b/src/frompackage/macro.jl index a6ca84a..43cb940 100644 --- a/src/frompackage/macro.jl +++ b/src/frompackage/macro.jl @@ -13,9 +13,10 @@ function wrap_parse_error(e) end ## @frompackage -function frompackage(ex, target_file, caller_module; macroname, cell_id) +function frompackage(ex, target_file, caller_module; macroname, cell_id, extra_args) p = FromPackageController(target_file, caller_module; cell_id) p.cell_id !== nothing || return process_outside_pluto(p, ex) + parse_options!(p, ex, extra_args) load_module!(p) args = extract_input_args(ex) for (i, arg) in enumerate(args) @@ -39,7 +40,7 @@ function frompackage(ex, target_file, caller_module; macroname, cell_id) return out end -function _combined(ex, target, calling_file, caller_module; macroname) +function _combined(ex, target, calling_file, caller_module; macroname, extra_args) # Enforce absolute path to handle different OSs calling_file = abspath(calling_file) _, cell_id = _cell_data(calling_file) @@ -47,7 +48,7 @@ function _combined(ex, target, calling_file, caller_module; macroname) # Get the target file target_file = extract_target_path(target, caller_module; calling_file, notebook_local) out = try - frompackage(ex, target_file, caller_module; macroname, cell_id) + frompackage(ex, target_file, caller_module; macroname, cell_id, extra_args) catch e # If we are outside of pluto we simply rethrow notebook_local || rethrow() @@ -96,9 +97,9 @@ See the package [documentation](https://disberd.github.io/PlutoDevMacros.jl/dev/ See also: [`@fromparent`](@ref) """ -macro frompackage(target::Union{AbstractString,Expr,Symbol}, ex) +macro frompackage(target::Union{AbstractString,Expr,Symbol}, ex, extra_args...) calling_file = String(__source__.file) - out = _combined(ex, target, calling_file, __module__; macroname="@frompackage") + out = _combined(ex, target, calling_file, __module__; macroname="@frompackage", extra_args) esc(out) end @@ -117,8 +118,8 @@ Refer to the [`@frompackage`](@ref) docstring and the package for understanding its use. See also: [`@addmethod`](@ref) """ -macro fromparent(ex) +macro fromparent(ex, extra_args...) calling_file = String(__source__.file) - out = _combined(ex, calling_file, calling_file, __module__; macroname="@fromparent") + out = _combined(ex, calling_file, calling_file, __module__; macroname="@fromparent", extra_args) esc(out) end diff --git a/src/frompackage/types.jl b/src/frompackage/types.jl index 02ddef9..7b7e5a3 100644 --- a/src/frompackage/types.jl +++ b/src/frompackage/types.jl @@ -4,7 +4,7 @@ struct RemoveThisExpr end @kwdef mutable struct FromPackageOptions "Specifies whether the target package shall be registered as root module while loading" - rootmodule::Bool = true + rootmodule::Bool = false "Symbol to select whether the target environment should be instantiated or resolved before loading the package" manifest::Symbol = :none "Flag to enable verbose logging of FromPackage functions" From 01400db40fb1af38febb3807dfac7abf02c18bc1 Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sun, 30 Jun 2024 12:23:22 +0200 Subject: [PATCH 09/11] add support for instantiating manifest of target via option --- src/frompackage/FromPackage.jl | 1 + src/frompackage/consts.jl | 1 - src/frompackage/helpers.jl | 59 +++++++++++++++++++++++++--------- src/frompackage/macro.jl | 1 + src/frompackage/types.jl | 2 +- 5 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/frompackage/FromPackage.jl b/src/frompackage/FromPackage.jl index 6243dd6..e13ec3c 100644 --- a/src/frompackage/FromPackage.jl +++ b/src/frompackage/FromPackage.jl @@ -2,6 +2,7 @@ module FromPackage import ..PlutoDevMacros: @addmethod, _cell_data, is_notebook_local import ..PlutoDevMacros: hide_this_log, simple_html_cat import Pkg + import Pkg.Types: Context, EnvCache import TOML using MacroTools: postwalk, flatten, MacroTools, isdef, longdef using JuliaInterpreter: ExprSplitter diff --git a/src/frompackage/consts.jl b/src/frompackage/consts.jl index 4dc2d16..81b49e1 100644 --- a/src/frompackage/consts.jl +++ b/src/frompackage/consts.jl @@ -1,6 +1,5 @@ const IS_DEV = first(fullname(@__MODULE__)) === :Main const TEMP_MODULE_NAME = Symbol(:_FrompPackage_TempModule_, IS_DEV ? "DEV_" : "") -const EMPTY_PIPE = Pipe() const STDLIBS_DATA = Dict{String,Base.UUID}() for (uuid, (name, _)) in Pkg.Types.stdlibs() STDLIBS_DATA[name] = uuid diff --git a/src/frompackage/helpers.jl b/src/frompackage/helpers.jl index 39b51e9..8a42adc 100644 --- a/src/frompackage/helpers.jl +++ b/src/frompackage/helpers.jl @@ -265,25 +265,52 @@ function beautify_package_path(p::FromPackageController) ) end -function generate_manifest_deps(proj_file::String) - envdir = dirname(abspath(proj_file)) - manifest_file = "" - for name in ("Manifest.toml", "JuliaManifest.toml") - path = joinpath(envdir, name) - if isfile(path) - manifest_file = path - break - end - end - @assert !isempty(manifest_file) "A manifest could not be found at the project's location.\nYou have to provide an instantiated environment.\nEnvDir: $envdir" - d = TOML.parsefile(manifest_file) - out = Dict{Base.UUID,String}() +function populate_manifest_deps!(p::FromPackageController) + @nospecialize + (;manifest_deps) = p + d = TOML.parsefile(get_manifest_file(p)) for (name, data) in d["deps"] - # We use only here because I believe the entry will always contain a single dict wrapped in an array. If we encounter a case where this is not true the only will throw instead of silently taking just the first + # We use `only` here because I believe the entry will always contain a single dict wrapped in an array. If we encounter a case where this is not true the only will throw instead of silently taking just the first uuid = only(data)["uuid"] |> Base.UUID - out[uuid] = name + manifest_deps[uuid] = name end - return out + return manifest_deps +end + +# This will extract the path of the manifest file. By default it will error if the manifest can not be found in the env directory, but it can be forced to instantiate/resolve using options +function get_manifest_file(p::FromPackageController) + @nospecialize + (; project, options) = p + mode = options.manifest + proj_file = project.file + envdir = dirname(abspath(proj_file)) + manifest_file = if mode in (:instantiate, :resolve) + context_kwargs = options.verbose ? (;) : (; io = devnull) + c = Context(;env = EnvCache(proj_file), context_kwargs...) + resolve = mode === :resolve + if resolve + Pkg.resolve(c) + else + Pkg.instantiate(c; update_registry = false, allow_build = false, allow_autoprecomp = false) + end + joinpath(envdir, "Manifest.toml") + else + manifest_file = "" + for name in ("Manifest.toml", "JuliaManifest.toml") + path = joinpath(envdir, name) + if isfile(path) + manifest_file = path + break + end + end + #! format: off + @assert !isempty(manifest_file) "A manifest could not be found at the project's location. +You have to provide an instantiated environment or set the `manifest` option to `:resolve` or `:instantiate`. +EnvDir: $envdir" + #! format: on + manifest_file + end + return manifest_file end function update_loadpath(p::FromPackageController) diff --git a/src/frompackage/macro.jl b/src/frompackage/macro.jl index 43cb940..ad9a2a5 100644 --- a/src/frompackage/macro.jl +++ b/src/frompackage/macro.jl @@ -17,6 +17,7 @@ function frompackage(ex, target_file, caller_module; macroname, cell_id, extra_a p = FromPackageController(target_file, caller_module; cell_id) p.cell_id !== nothing || return process_outside_pluto(p, ex) parse_options!(p, ex, extra_args) + populate_manifest_deps!(p) load_module!(p) args = extract_input_args(ex) for (i, arg) in enumerate(args) diff --git a/src/frompackage/types.jl b/src/frompackage/types.jl index 7b7e5a3..b865649 100644 --- a/src/frompackage/types.jl +++ b/src/frompackage/types.jl @@ -92,7 +92,7 @@ function FromPackageController(target_path::AbstractString, caller_module::Modul @assert project.name !== nothing "@frompackage can only be called with a Package as target.\nThe pointed project does not have `name` and `uuid` fields" entry_point = joinpath(dirname(project_file), "src", project.name * ".jl") name = project.name - manifest_deps = generate_manifest_deps(project_file) + manifest_deps = Dict{Base.UUID, String}() # We parse the cell_id if string cell_id = cell_id isa AbstractString ? (isempty(cell_id) ? nothing : Base.UUID(cell_id)) : cell_id p = FromPackageController{Symbol(name)}(;entry_point, manifest_deps, target_path, project, caller_module, cell_id) From 3bde431114612e63337780609ca3e8163500719f Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sun, 30 Jun 2024 16:55:08 +0200 Subject: [PATCH 10/11] remove target_reached field --- src/frompackage/code_parsing.jl | 2 +- src/frompackage/helpers.jl | 5 ++++- src/frompackage/loading.jl | 12 +++--------- src/frompackage/types.jl | 5 +---- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/frompackage/code_parsing.jl b/src/frompackage/code_parsing.jl index 6d91616..0cd4fd1 100644 --- a/src/frompackage/code_parsing.jl +++ b/src/frompackage/code_parsing.jl @@ -18,7 +18,7 @@ function custom_walk!(p::AbstractEvalController) end function custom_walk!(p::AbstractEvalController, ex) @nospecialize - if p.target_reached + if target_reached(p) return RemoveThisExpr() else ex isa Expr || return ex diff --git a/src/frompackage/helpers.jl b/src/frompackage/helpers.jl index 8a42adc..8709e54 100644 --- a/src/frompackage/helpers.jl +++ b/src/frompackage/helpers.jl @@ -449,4 +449,7 @@ function _names(m::Module; only_exported=false, all=!only_exported, imported=!on only_exported && return Base.isexported(m, nm) return true end -end \ No newline at end of file +end + +# Check whether the FromPackageController has reached the target file while loading the module +target_reached(p::FromPackageController) = (@nospecialize; p.target_location !== nothing) \ No newline at end of file diff --git a/src/frompackage/loading.jl b/src/frompackage/loading.jl index 7a44429..ac77506 100644 --- a/src/frompackage/loading.jl +++ b/src/frompackage/loading.jl @@ -39,7 +39,7 @@ function process_exprsplitter_item!(p::AbstractEvalController, ex, process_func: # @info "Original" ex new_ex = process_func(ex) # @info "Change" new_ex - if !isa(new_ex, RemoveThisExpr) && !p.target_reached + if !isa(new_ex, RemoveThisExpr) && !target_reached(p) Core.eval(p.current_module, new_ex) end return @@ -124,13 +124,8 @@ function load_module!(p::FromPackageController{name}; reset=true) where {name} end # We put the controller in the Ref CURRENT_FROMPACKAGE_CONTROLLER[] = p - try - load_direct_deps(p) # We load the direct dependencies - Core.eval(p.current_module, process_include_expr!(p, p.entry_point)) - finally - # We set the target reached to false to avoid skipping expression when loading extensions - p.target_reached = false - end + load_direct_deps(p) # We load the direct dependencies + Core.eval(p.current_module, process_include_expr!(p, p.entry_point)) # Maybe call init maybe_call_init(get_temp_module(p)) # We populate the loaded modules @@ -161,7 +156,6 @@ function process_include_expr!(p::FromPackageController, mapexpr::Function, path filepath = get_filepath(path, caller_path) # @info "Custom Including $(basename(filepath))" if issamepath(p.target_path, filepath) - p.target_reached = true p.target_location = p.current_line p.target_module = p.current_module return nothing diff --git a/src/frompackage/types.jl b/src/frompackage/types.jl index b865649..3157934 100644 --- a/src/frompackage/types.jl +++ b/src/frompackage/types.jl @@ -66,8 +66,6 @@ abstract type AbstractEvalController end target_location::Union{Nothing,LineNumberNode} = nothing "Module of where the target is included if the target is found. Nothing otherwise" target_module::Union{Nothing, Module} = nothing - "Flag that is set to true when the macro target is found in the code, to skip all the remaining expressions. It is set back to false after loading to allow extension handling." - target_reached::Bool = false "Custom walk function" custom_walk::Function = identity "Loaded Extensions" @@ -92,10 +90,9 @@ function FromPackageController(target_path::AbstractString, caller_module::Modul @assert project.name !== nothing "@frompackage can only be called with a Package as target.\nThe pointed project does not have `name` and `uuid` fields" entry_point = joinpath(dirname(project_file), "src", project.name * ".jl") name = project.name - manifest_deps = Dict{Base.UUID, String}() # We parse the cell_id if string cell_id = cell_id isa AbstractString ? (isempty(cell_id) ? nothing : Base.UUID(cell_id)) : cell_id - p = FromPackageController{Symbol(name)}(;entry_point, manifest_deps, target_path, project, caller_module, cell_id) + p = FromPackageController{Symbol(name)}(;entry_point, target_path, project, caller_module, cell_id) p.custom_walk = custom_walk!(p) return p end \ No newline at end of file From c19873c2c6e8eadc9ead4c5ddb297016cbd456cc Mon Sep 17 00:00:00 2001 From: Alberto Mengali Date: Sun, 30 Jun 2024 19:09:22 +0200 Subject: [PATCH 11/11] add more tests --- src/frompackage/input_parsing.jl | 13 +- test/TestInception/Project.toml | 15 + test/TestInception/ext/DualExtension.jl | 10 + test/TestInception/ext/SingleExtension.jl | 7 + test/TestInception/inception_notebook.jl | 419 ++++++++++++++++++++++ test/TestInception/src/TestInception.jl | 9 + test/TestUsingNames/Project.toml | 1 + test/frompackage/basics.jl | 132 +++---- test/frompackage/basics_helpers.jl | 3 +- test/frompackage/helpers.jl | 7 + test/frompackage/with_pluto_session.jl | 48 +++ 11 files changed, 582 insertions(+), 82 deletions(-) create mode 100644 test/TestInception/Project.toml create mode 100644 test/TestInception/ext/DualExtension.jl create mode 100644 test/TestInception/ext/SingleExtension.jl create mode 100644 test/TestInception/inception_notebook.jl create mode 100644 test/TestInception/src/TestInception.jl diff --git a/src/frompackage/input_parsing.jl b/src/frompackage/input_parsing.jl index eb3e6ae..bb87737 100644 --- a/src/frompackage/input_parsing.jl +++ b/src/frompackage/input_parsing.jl @@ -2,7 +2,8 @@ function parse_options!(p::FromPackageController, ex::Expr, extra_args) @nospecialize (; options) = p #! format: off - error_msg = "The provided extra arguments at the end of the macro call are not in a supported format. + error_msg(arg) = "The provided extra arguments at the end of the macro call are not in a supported format. +$(arg) Each argument should be in the form `option_name = value`, with the following supported option names and types: - `rootmodule::Bool` - `manifest::Symbol` @@ -10,12 +11,12 @@ Each argument should be in the form `option_name = value`, with the following su Check the documentations for more details on the options." #! format: on for arg in extra_args - Meta.isexpr(arg, :(=)) || error(error_msg) + Meta.isexpr(arg, :(=)) || error(error_msg(arg)) name, val = arg.args - typeof(name) in (Symbol, QuoteNode) || error(error_msg) - hasfield(FromPackageOptions, name) || error(error_msg) - name isa QuoteNode && (name = name.value) - val isa fieldtype(FromPackageOptions, name) || error(error_msg) + typeof(name) in (Symbol, QuoteNode) || error(error_msg(arg)) + hasfield(FromPackageOptions, name) || error(error_msg(arg)) + val isa QuoteNode && (val = val.value) + val isa fieldtype(FromPackageOptions, name) || error(error_msg(arg)) setproperty!(options, name, val) end return nothing diff --git a/test/TestInception/Project.toml b/test/TestInception/Project.toml new file mode 100644 index 0000000..f40b153 --- /dev/null +++ b/test/TestInception/Project.toml @@ -0,0 +1,15 @@ +name = "TestInception" +uuid = "fc02ac8e-9cfc-4b2b-ab03-e2c2c1b89471" +authors = ["Alberto Mengali "] +version = "0.1.0" + +[deps] +PlotlyExtensionsHelper = "a7e57fc7-3548-4021-90c3-ac0e175068b1" + +[weakdeps] +SimplePlutoInclude = "6f00a2c5-ea4a-46bf-9183-91b7b57a087f" +Example = "7876af07-990d-54b4-ab0e-23690620f79a" + +[extensions] +"DualExtension" = ["Example", "SimplePlutoInclude"] +"SingleExtension" = "SimplePlutoInclude" diff --git a/test/TestInception/ext/DualExtension.jl b/test/TestInception/ext/DualExtension.jl new file mode 100644 index 0000000..ed089f5 --- /dev/null +++ b/test/TestInception/ext/DualExtension.jl @@ -0,0 +1,10 @@ +module DualExtension +using Example +using SimplePlutoInclude +using TestInception + +@info "Loading DualExtension" Example SimplePlutoInclude + +TestInception.dual_extension_loaded[] = true + +end diff --git a/test/TestInception/ext/SingleExtension.jl b/test/TestInception/ext/SingleExtension.jl new file mode 100644 index 0000000..74458f9 --- /dev/null +++ b/test/TestInception/ext/SingleExtension.jl @@ -0,0 +1,7 @@ +module SingleExtension +using SimplePlutoInclude +using TestInception + +@info "Loading SingleExtension" SimplePlutoInclude + +end diff --git a/test/TestInception/inception_notebook.jl b/test/TestInception/inception_notebook.jl new file mode 100644 index 0000000..748d730 --- /dev/null +++ b/test/TestInception/inception_notebook.jl @@ -0,0 +1,419 @@ +### A Pluto.jl notebook ### +# v0.19.43 + +using Markdown +using InteractiveUtils + +# ╔═╡ abcc4604-aa6c-4830-8909-5811aa6eab8d +# Here we import PlutoDevMacros itself with @frompackage so we can reload it +PDM.@frompackage "../.." begin + import PackageModule.FromPackage: * +end verbose = true # Verbose here makes deletion of package callback logs below (only after first run) + +# ╔═╡ 12d02710-36fa-11ef-1430-512f552ee8e1 +begin + # We do a hack to import PlutoDevMacros + plutodevmacros_proj = Base.current_project("../..") |> abspath + push!(LOAD_PATH, plutodevmacros_proj) + try + Core.eval(Main, :(import PlutoDevMacros as PDM)) + finally + pop!(LOAD_PATH) + end + PDM = Main.PDM +end + +# ╔═╡ f120af18-d655-4221-b53c-028f0c396e2f +# This should trigger the extension in the direct dependency PlotlyExtensionHelper +using PlotlyBase + +# ╔═╡ 308cbcf0-2a0b-4e97-b5f1-30f8d06020c6 +# Here we instead import the TestPackage module +@fromparent import * verbose = true rootmodule = true manifest = :instantiate + +# ╔═╡ edac1ff6-d264-4268-8063-0b4f4e0d8dca +md""" +## Rootmodule +""" + +# ╔═╡ 5762c453-fc45-49e2-b71a-f15036c81d30 +pkgdir(TestInception) === (@__DIR__) || error("The registration as root module did not seem to work, pkgdir returns the wrong path") + +# ╔═╡ bdac8541-fca9-4650-a9bb-485519fa02b8 +md""" +## Indirect Extension +""" + +# ╔═╡ 6ae6e908-d78e-4e23-9565-a0a44c9d509e +hasmethod(PlotlyExtensionsHelper._plot_func, Tuple{Val{:PlotlyBase}}) || error("The indirect extension was not loaded correctly") + +# ╔═╡ 340e3c74-6504-45d9-b23f-d60b71ffe527 +md""" +## Direct Extension (Single) +""" + +# ╔═╡ d189a27d-5612-41a7-937c-756644c669b3 +import SimplePlutoInclude # This triggers a direct extension + +# ╔═╡ d11a039c-32fc-451f-af42-e4abcdf8e8b4 +isdefined(parentmodule(TestInception), :SingleExtension) || error("The single dependency extension did not seem to load correctly") + +# ╔═╡ bbc3bdc3-249f-4b56-8ba2-c2694932372f +md""" +## Direct Extension (Dual) +""" + +# ╔═╡ 3e2621f4-bd00-4e6a-b44b-dd62091228c4 +import Example # This triggers the other direct extension depending on both SimplePlutoInclude and Example + +# ╔═╡ 0be0fe0b-a40c-4575-934d-26b289f06e98 +isdefined(parentmodule(TestInception), :DualExtension) || error("The single dependency extension did not seem to load correctly") + +# ╔═╡ b81acc6d-df12-48af-9f12-5f79b6ab59bc +dual_extension_loaded[] || error("The single dependency extension did not seem to load correctly") + +# ╔═╡ 16528b1e-e59b-426d-9ba5-37c2f83ab775 +md""" +## Test Reload +""" + +# ╔═╡ 4244baf8-bd30-4d81-9236-f4291b364c44 +random_variable + +# ╔═╡ 00000000-0000-0000-0000-000000000001 +PLUTO_PROJECT_TOML_CONTENTS = """ +[deps] +Example = "7876af07-990d-54b4-ab0e-23690620f79a" +PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5" +SimplePlutoInclude = "6f00a2c5-ea4a-46bf-9183-91b7b57a087f" + +[compat] +Example = "~0.5.3" +PlotlyBase = "~0.8.19" +SimplePlutoInclude = "~0.1.0" +""" + +# ╔═╡ 00000000-0000-0000-0000-000000000002 +PLUTO_MANIFEST_TOML_CONTENTS = """ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.4" +manifest_format = "2.0" +project_hash = "e006c989728577e863f2417116df37ca484b4a62" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.ColorSchemes]] +deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"] +git-tree-sha1 = "4b270d6465eb21ae89b732182c20dc165f8bf9f2" +uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +version = "3.25.0" + +[[deps.ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "b10d0b65641d57b8b4d5e234446582de5047050d" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.11.5" + +[[deps.ColorVectorSpace]] +deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "Requires", "Statistics", "TensorCore"] +git-tree-sha1 = "a1f44953f2382ebb937d60dafbe2deea4bd23249" +uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" +version = "0.10.0" + + [deps.ColorVectorSpace.extensions] + SpecialFunctionsExt = "SpecialFunctions" + + [deps.ColorVectorSpace.weakdeps] + SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" + +[[deps.Colors]] +deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] +git-tree-sha1 = "362a287c3aa50601b0bc359053d5c2468f0e7ce0" +uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" +version = "0.12.11" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "1.1.1+0" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.DelimitedFiles]] +deps = ["Mmap"] +git-tree-sha1 = "9e2f36d3c96a820c678f2f1f1782582fcf685bae" +uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" +version = "1.9.1" + +[[deps.DocStringExtensions]] +deps = ["LibGit2"] +git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.9.3" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.Example]] +git-tree-sha1 = "46e44e869b4d90b96bd8ed1fdcf32244fddfb6cc" +uuid = "7876af07-990d-54b4-ab0e-23690620f79a" +version = "0.5.3" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "05882d6995ae5c12bb5f36dd2ed3f61c98cbb172" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.5" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.4" + +[[deps.LaTeXStrings]] +git-tree-sha1 = "50901ebc375ed41dbf8058da26f9de442febbbec" +uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +version = "1.3.1" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.4" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "8.4.0+0" + +[[deps.LibGit2]] +deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[deps.LibGit2_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" +version = "1.6.4+0" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.11.0+1" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.2+1" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2023.1.10" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.23+4" + +[[deps.OrderedCollections]] +git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.6.3" + +[[deps.Parameters]] +deps = ["OrderedCollections", "UnPack"] +git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe" +uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a" +version = "0.12.3" + +[[deps.Parsers]] +deps = ["Dates", "PrecompileTools", "UUIDs"] +git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.8.1" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.10.0" + +[[deps.PlotlyBase]] +deps = ["ColorSchemes", "Dates", "DelimitedFiles", "DocStringExtensions", "JSON", "LaTeXStrings", "Logging", "Parameters", "Pkg", "REPL", "Requires", "Statistics", "UUIDs"] +git-tree-sha1 = "56baf69781fc5e61607c3e46227ab17f7040ffa2" +uuid = "a03496cd-edff-5a9b-9e67-9cda94a718b5" +version = "0.8.19" + +[[deps.PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.2.1" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.4.3" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[deps.Random]] +deps = ["SHA"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.0" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.SimplePlutoInclude]] +git-tree-sha1 = "db4e715674a7ad0fcc00bf1dc55f40a3bfc6ab15" +uuid = "6f00a2c5-ea4a-46bf-9183-91b7b57a087f" +version = "0.1.0" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.SparseArrays]] +deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +version = "1.10.0" + +[[deps.Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +version = "1.10.0" + +[[deps.SuiteSparse_jll]] +deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] +uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" +version = "7.2.1+1" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.0" + +[[deps.TensorCore]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" +uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" +version = "0.1.1" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.UnPack]] +git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" +uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" +version = "1.0.2" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.8.0+1" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.52.0+1" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+2" +""" + +# ╔═╡ Cell order: +# ╠═12d02710-36fa-11ef-1430-512f552ee8e1 +# ╠═abcc4604-aa6c-4830-8909-5811aa6eab8d +# ╠═308cbcf0-2a0b-4e97-b5f1-30f8d06020c6 +# ╟─edac1ff6-d264-4268-8063-0b4f4e0d8dca +# ╠═5762c453-fc45-49e2-b71a-f15036c81d30 +# ╟─bdac8541-fca9-4650-a9bb-485519fa02b8 +# ╠═f120af18-d655-4221-b53c-028f0c396e2f +# ╠═6ae6e908-d78e-4e23-9565-a0a44c9d509e +# ╠═340e3c74-6504-45d9-b23f-d60b71ffe527 +# ╠═d189a27d-5612-41a7-937c-756644c669b3 +# ╠═d11a039c-32fc-451f-af42-e4abcdf8e8b4 +# ╠═bbc3bdc3-249f-4b56-8ba2-c2694932372f +# ╠═3e2621f4-bd00-4e6a-b44b-dd62091228c4 +# ╠═0be0fe0b-a40c-4575-934d-26b289f06e98 +# ╠═b81acc6d-df12-48af-9f12-5f79b6ab59bc +# ╟─16528b1e-e59b-426d-9ba5-37c2f83ab775 +# ╠═4244baf8-bd30-4d81-9236-f4291b364c44 +# ╟─00000000-0000-0000-0000-000000000001 +# ╟─00000000-0000-0000-0000-000000000002 diff --git a/test/TestInception/src/TestInception.jl b/test/TestInception/src/TestInception.jl new file mode 100644 index 0000000..72f985a --- /dev/null +++ b/test/TestInception/src/TestInception.jl @@ -0,0 +1,9 @@ +module TestInception + +using PlotlyExtensionsHelper + +random_variable = rand() + +dual_extension_loaded = Ref{Bool}(false) + +end # module TestInception diff --git a/test/TestUsingNames/Project.toml b/test/TestUsingNames/Project.toml index ec4af6b..0bf602d 100644 --- a/test/TestUsingNames/Project.toml +++ b/test/TestUsingNames/Project.toml @@ -8,3 +8,4 @@ Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" Example = "7876af07-990d-54b4-ab0e-23690620f79a" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" +Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" diff --git a/test/frompackage/basics.jl b/test/frompackage/basics.jl index 1f1c8f3..051b42f 100644 --- a/test/frompackage/basics.jl +++ b/test/frompackage/basics.jl @@ -1,34 +1,39 @@ @testitem "Project/Manifest" begin include(joinpath(@__DIR__, "basics_helpers.jl")) - tmpdir = mktempdir() - # We test parsing the project of the test folder - test_proj = Base.current_project(@__DIR__) - pd = ProjectData(test_proj) - @test pd.uuid |> isnothing - @test pd.name |> isnothing - @test pd.version |> isnothing - + # We test parsing the project of the TestUsingNames folder + target_dir = abspath(@__DIR__, "../TestUsingNames/") + # We delete the manifest if it exists + delete_manifest(target_dir) + # We test that by default it throws since there is no manifest + controller = FromPackageController(target_dir, @__MODULE__; cell_id = Base.UUID(0)) + @test controller.options.manifest ∉ (:instantiate, :resolve) + pd = controller.project + @test pd.uuid === Base.UUID("ad5af708-d1e5-4d28-9e91-6798178ddbab") + @test pd.name === "TestUsingNames" + @test pd.version === v"0.1.0" + + @test "Example" in keys(pd.deps) @test "Revise" in keys(pd.deps) - @test "TestItemRunner" in keys(pd.deps) # We test parsing of the Manifest - md = generate_manifest_deps(test_proj) - - @test "Revise" in values(md) - @test "TestItemRunner" in values(md) + @test_throws "A manifest could not be found" populate_manifest_deps!(controller) + controller.options.verbose = true + controller.options.manifest = :resolve + populate_manifest_deps!(controller) + @test isfile(joinpath(target_dir, "Manifest.toml")) + delete_manifest(target_dir) + @test !isfile(joinpath(target_dir, "Manifest.toml")) + controller.options.manifest = :instantiate + populate_manifest_deps!(controller) + @test isfile(joinpath(target_dir, "Manifest.toml")) + + md = controller.manifest_deps + + @test "Example" in values(md) + @test "InteractiveUtils" in values(md) # Indirect Dependencies + @test "TOML" in values(md) @test "CodeTracking" in values(md) - @test "p7zip_jll" in values(md) - - # We try to copy the proj to a temp dir - copied_proj = joinpath(tmpdir, basename(test_proj)) - cp(test_proj, copied_proj) - # Without a manifest it will throw - @test_throws "A manifest could not be found" generate_manifest_deps(copied_proj) - instantiate_from_path(copied_proj) - # After instantiating, the manifest is correctly parsed and equivalent to the original one - md2 = generate_manifest_deps(copied_proj) - @test md2 == md # We test that pointing to a folder without a project throws @test_throws "No project was found" FromPackageController(homedir(), @__MODULE__) @@ -194,6 +199,7 @@ end cell_id = Base.UUID(0) caller_module = Core.eval(@__MODULE__, :(module $(gensym(:InPackage)) end)) controller = FromPackageController(inpackage_target, caller_module; cell_id) + populate_manifest_deps!(controller) load_module!(controller) f(ex; alias=false) = MacroTools.prettify(process_input_expr(controller, ex); alias) @@ -316,54 +322,30 @@ end @test_throws "or a begin-end block of import statements" extract_input_args(:(1+1)) end -# # This tests macroexpand and the multiple calls error -# @testset "Macroexpand" begin -# id1 = "4dc0e7fa-6ddc-48ba-867d-8e74d7e6e373" -# id2 = "5288e998-6b66-4d46-ab8d-4aa3159c0982" -# file_path = joinpath(TestPackage_path, "test_macroexpand.jl") -# inpluto_path(id) = join([file_path, "#==#", id]) -# # Create the fake module -# m = Core.eval(Main, :(module $(gensym(:MacroExpand)) end)) -# # Load the macro in the module -# m.var"@fromparent" = var"@fromparent" -# # We simulate a call from cell 1 with the normal macro -# fromparent_call_ex = Expr(:macrocall, Symbol("@fromparent"), LineNumberNode(36, Symbol(inpluto_path(id1))), :(import *)) -# # Run the macro -# Core.eval(m, fromparent_call_ex); -# # Check that the dummy variable generated by the macro is defined in the module -# @test isdefined(m, FromPackage._id_name(id1)) -# # We try calling the macro from another cell and test that it throws -# error_ex = Expr(:macrocall, Symbol("@fromparent"), LineNumberNode(41, Symbol(inpluto_path(id2))), :(import *)) -# macroexpand_ex = Expr(:macrocall, Symbol("@macroexpand"), LineNumberNode(41, Symbol(inpluto_path(id2))), error_ex) -# # We test that this thorws a CapturedException -# out = Core.eval(m, error_ex) -# @test out isa CapturedException -# # We test that Multiple Calls is in the error exception message -# @test contains(out.ex.msg, "Multiple Calls") -# if VERSION >= v"1.10" # This seems to not work in 1.9, not sure why now -# # We try macroexpand, which should directly rethrow without the CaptureException -# @test_throws "Multiple Calls" Core.eval(m, macroexpand_ex) -# end -# end - -# # This test is just for 100% coverage by checking that absolute path includes are respected -# mktempdir() do tmpdir -# cd(tmpdir) do -# included_file = joinpath(tmpdir, "random_include.jl") |> abspath -# open(included_file, "w") do io -# write(io, "a = 15") -# end -# # We generate a dummy package folder -# Pkg.generate("RandomPackage") -# pkgdir = joinpath(tmpdir, "RandomPackage") -# open(joinpath(pkgdir, "src", "RandomPackage.jl"), "w") do io -# println(io, "module RandomPackage") -# println(io, "include(raw\"$included_file\")") -# println(io, "end") -# end -# dict = get_package_data(pkgdir) -# load_module_in_caller(dict, Main) -# m = get_target_module(dict) -# @test isdefined(m, :a) -# end -# end \ No newline at end of file +@testitem "Options Parsing" begin + include(joinpath(@__DIR__, "basics_helpers.jl")) + # Parse options + macro dummy(args...) + caller_module = __module__ + calling_file = @__FILE__ + target = outpackage_target + target_file = extract_target_path(target, caller_module; calling_file, notebook_local=false) + p = FromPackageController(target_file, caller_module; cell_id = Base.UUID(0)) + ex = :(import *) + parse_options!(p, ex, args) + :($p) + end + # Test correct handling + default = FromPackageOptions() + p = @dummy verbose = true rootmodule = true manifest = :instantiate + @test p.options.verbose === true !== default.verbose + @test p.options.rootmodule === true !== default.rootmodule + @test p.options.manifest === :instantiate !== default.manifest + # Manifest with name directly + p = @dummy manifest = resolve + @test p.options.manifest === :resolve !== default.manifest + # + @test_throws "are not in a supported format" eval(:(@dummy verboses = true)) + @test_throws "are not in a supported format" eval(:(@dummy verbose = 3)) + @test_throws "are not in a supported format" eval(:(@dummy manifest = true)) +end \ No newline at end of file diff --git a/test/frompackage/basics_helpers.jl b/test/frompackage/basics_helpers.jl index 25c5abb..6a66928 100644 --- a/test/frompackage/basics_helpers.jl +++ b/test/frompackage/basics_helpers.jl @@ -1,5 +1,6 @@ -import PlutoDevMacros.FromPackage: FromPackage, @fromparent, load_module!, FromPackageController, generate_manifest_deps, ProjectData, @frompackage, extract_target_path, is_notebook_local, process_outside_pluto, process_input_expr, iterate_imports, ImportAs, get_temp_module, PREV_CONTROLLER_NAME, filterednames, ModuleWithNames, JustModules, get_loaded_modules_mod, unique_module_name, extract_nested_module, get_dep_from_loaded_modules, extract_input_args, custom_walk! +import PlutoDevMacros.FromPackage: FromPackage, @fromparent, load_module!, FromPackageController, populate_manifest_deps!, ProjectData, @frompackage, extract_target_path, is_notebook_local, process_outside_pluto, process_input_expr, iterate_imports, ImportAs, get_temp_module, PREV_CONTROLLER_NAME, filterednames, ModuleWithNames, JustModules, get_loaded_modules_mod, unique_module_name, extract_nested_module, get_dep_from_loaded_modules, extract_input_args, custom_walk!, parse_options!, FromPackageOptions import MacroTools +using Test function compare_exprs(ex1, ex2) ex1 = MacroTools.prettify(ex1) diff --git a/test/frompackage/helpers.jl b/test/frompackage/helpers.jl index 48037ab..f731b0c 100644 --- a/test/frompackage/helpers.jl +++ b/test/frompackage/helpers.jl @@ -34,4 +34,11 @@ function instantiate_from_path(path::AbstractString; resolve = true) c = Context(;env = EnvCache(Base.current_project(path))) resolve && Pkg.resolve(c) Pkg.instantiate(c; update_registry = false, allow_build = false, allow_autoprecomp = false) +end + +function delete_manifest(path::AbstractString) + envdir = dirname(Base.current_project(path)) + manifest_file = joinpath(envdir, "Manifest.toml") + isfile(manifest_file) && rm(manifest_file) + return nothing end \ No newline at end of file diff --git a/test/frompackage/with_pluto_session.jl b/test/frompackage/with_pluto_session.jl index 30279bb..a81bf70 100644 --- a/test/frompackage/with_pluto_session.jl +++ b/test/frompackage/with_pluto_session.jl @@ -174,4 +174,52 @@ end @test first_value != second_value SessionActions.shutdown(ss, nb) end +end + +@testitem "TestInception" begin + # Include the setup + include(joinpath(@__DIR__, "with_pluto_helpers.jl")) + # We test @exclude_using (issue 11) + target_dir = joinpath(@__DIR__, "../TestInception") + # We delete the manifest if it exists as we are testing the instantiation happens correctly + delete_manifest(target_dir) + # Do the tests + ss = ServerSession(; options) + path = abspath(target_dir, "inception_notebook.jl") + nb = SessionActions.open(ss, path; run_async=false) + # We test that no errors are present + for cell in nb.cells + @test noerror(cell) + end + function has_log_msg(cell, needle) + any(cell.logs) do dict + msg = dict["msg"] |> first + contains(msg, needle) + end + end + # We check that the manifest has been created from the cell, and the messages has been logged in the 3rd cell (which is the one calling @fromparent) + @test has_log_msg(nb.cells[3], r"Updating .*Manifest.toml") + # We check that the cell importing SimplePlutoInclude has logs for loading the SingleExtension + @test has_log_msg(nb.cells[10], "Loading code of extension SingleExtension") + # We check that the cell importing Example has logs for loading the DualExtension + @test has_log_msg(nb.cells[13], "Loading code of extension DualExtension") + # We extract the rand_variable value + first_value = eval_in_nb((ss, nb), :random_variable) + # We rerun the second cell, containing the `PDM.@frompackage` call, which reload PlutoDevMacros itself + update_run!(ss, nb, nb.cells[2]) + # We check again that no errors arose + for cell in nb.cells + @test noerror(cell) + end + # We check that warning of replacing rootmodule and deleting mirror_package_callback from previous workspace are present in cell 3 + @test has_log_msg(nb.cells[3], "Replacing module") + @test has_log_msg(nb.cells[3], "Deleting previous version of package_callback function") + # We also have the messages for reloading the extension in this cell now + @test has_log_msg(nb.cells[3], "Loading code of extension SingleExtension") + @test has_log_msg(nb.cells[3], "Loading code of extension DualExtension") + # We check that the rand_variable value changed + second_value = eval_in_nb((ss, nb), :random_variable) + @test first_value != second_value + # We now try to + SessionActions.shutdown(ss, nb) end \ No newline at end of file