Set proper file in env when the notebook is persisted (#95)

* Set proper file in env when the notebook is persisted

* Fix typo
This commit is contained in:
Jonatan Kłosko 2021-03-21 16:53:00 +01:00 committed by GitHub
parent e2cd992b78
commit 5e20541774
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 104 additions and 23 deletions

View file

@ -64,10 +64,16 @@ defmodule Livebook.Evaluator do
Evaluation response is sent to the process identified by `send_to` as `{:evaluation_response, ref, response}`. Evaluation response is sent to the process identified by `send_to` as `{:evaluation_response, ref, response}`.
Note that response is transformed with the configured formatter (identity by default). Note that response is transformed with the configured formatter (identity by default).
## Options
* `:file` - file to which the evaluated code belongs. Most importantly,
this has an impact on the value of `__DIR__`.
""" """
@spec evaluate_code(t(), pid(), String.t(), ref(), ref()) :: :ok @spec evaluate_code(t(), pid(), String.t(), ref(), ref(), keyword()) :: :ok
def evaluate_code(evaluator, send_to, code, ref, prev_ref \\ :initial) when ref != :initial do def evaluate_code(evaluator, send_to, code, ref, prev_ref \\ :initial, opts \\ [])
GenServer.cast(evaluator, {:evaluate_code, send_to, code, ref, prev_ref}) when ref != :initial do
GenServer.cast(evaluator, {:evaluate_code, send_to, code, ref, prev_ref, opts})
end end
@doc """ @doc """
@ -107,11 +113,14 @@ defmodule Livebook.Evaluator do
end end
@impl true @impl true
def handle_cast({:evaluate_code, send_to, code, ref, prev_ref}, state) do def handle_cast({:evaluate_code, send_to, code, ref, prev_ref, opts}, state) do
Evaluator.IOProxy.configure(state.io_proxy, send_to, ref) Evaluator.IOProxy.configure(state.io_proxy, send_to, ref)
context = Map.get(state.contexts, prev_ref, state.contexts.initial) context = Map.get(state.contexts, prev_ref, state.contexts.initial)
file = Keyword.get(opts, :file, "nofile")
context = put_in(context.env.file, file)
case eval(code, context.binding, context.env) do case eval(code, context.binding, context.env) do
{:ok, result, binding, env} -> {:ok, result, binding, env} ->
result_context = %{binding: binding, env: env} result_context = %{binding: binding, env: env}

View file

@ -41,9 +41,21 @@ defprotocol Livebook.Runtime do
* `{:evaluation_stdout, ref, string}` - output captured during evaluation * `{:evaluation_stdout, ref, string}` - output captured during evaluation
* `{:evaluation_response, ref, response}` - final result of the evaluation * `{:evaluation_response, ref, response}` - final result of the evaluation
## Options
* `:file` - file to which the evaluated code belongs. Most importantly,
this has an impact on the value of `__DIR__`.
""" """
@spec evaluate_code(t(), String.t(), ref(), ref(), ref()) :: :ok @spec evaluate_code(t(), String.t(), ref(), ref(), ref(), keyword()) :: :ok
def evaluate_code(runtime, code, container_ref, evaluation_ref, prev_evaluation_ref \\ :initial) def evaluate_code(
runtime,
code,
container_ref,
evaluation_ref,
prev_evaluation_ref \\ :initial,
opts \\ []
)
@doc """ @doc """
Disposes of evaluation identified by the given ref. Disposes of evaluation identified by the given ref.

View file

@ -49,13 +49,21 @@ defimpl Livebook.Runtime, for: Livebook.Runtime.Attached do
ErlDist.Manager.stop(runtime.node) ErlDist.Manager.stop(runtime.node)
end end
def evaluate_code(runtime, code, container_ref, evaluation_ref, prev_evaluation_ref \\ :initial) do def evaluate_code(
runtime,
code,
container_ref,
evaluation_ref,
prev_evaluation_ref \\ :initial,
opts \\ []
) do
ErlDist.Manager.evaluate_code( ErlDist.Manager.evaluate_code(
runtime.node, runtime.node,
code, code,
container_ref, container_ref,
evaluation_ref, evaluation_ref,
prev_evaluation_ref prev_evaluation_ref,
opts
) )
end end

View file

@ -73,13 +73,21 @@ defimpl Livebook.Runtime, for: Livebook.Runtime.ElixirStandalone do
ErlDist.Manager.stop(runtime.node) ErlDist.Manager.stop(runtime.node)
end end
def evaluate_code(runtime, code, container_ref, evaluation_ref, prev_evaluation_ref \\ :initial) do def evaluate_code(
runtime,
code,
container_ref,
evaluation_ref,
prev_evaluation_ref \\ :initial,
opts \\ []
) do
ErlDist.Manager.evaluate_code( ErlDist.Manager.evaluate_code(
runtime.node, runtime.node,
code, code,
container_ref, container_ref,
evaluation_ref, evaluation_ref,
prev_evaluation_ref prev_evaluation_ref,
opts
) )
end end

View file

@ -49,12 +49,25 @@ defmodule Livebook.Runtime.ErlDist.Manager do
See `Evaluator` for more details. See `Evaluator` for more details.
""" """
@spec evaluate_code(node(), String.t(), Evaluator.ref(), Evaluator.ref(), Evaluator.ref()) :: @spec evaluate_code(
:ok node(),
def evaluate_code(node, code, container_ref, evaluation_ref, prev_evaluation_ref \\ :initial) do String.t(),
Evaluator.ref(),
Evaluator.ref(),
Evaluator.ref(),
keyword()
) :: :ok
def evaluate_code(
node,
code,
container_ref,
evaluation_ref,
prev_evaluation_ref \\ :initial,
opts \\ []
) do
GenServer.cast( GenServer.cast(
{@name, node}, {@name, node},
{:evaluate_code, code, container_ref, evaluation_ref, prev_evaluation_ref} {:evaluate_code, code, container_ref, evaluation_ref, prev_evaluation_ref, opts}
) )
end end
@ -153,7 +166,7 @@ defmodule Livebook.Runtime.ErlDist.Manager do
end end
def handle_cast( def handle_cast(
{:evaluate_code, code, container_ref, evaluation_ref, prev_evaluation_ref}, {:evaluate_code, code, container_ref, evaluation_ref, prev_evaluation_ref, opts},
state state
) do ) do
state = ensure_evaluator(state, container_ref) state = ensure_evaluator(state, container_ref)
@ -163,7 +176,8 @@ defmodule Livebook.Runtime.ErlDist.Manager do
state.owner, state.owner,
code, code,
evaluation_ref, evaluation_ref,
prev_evaluation_ref prev_evaluation_ref,
opts
) )
{:noreply, state} {:noreply, state}

View file

@ -109,13 +109,21 @@ defimpl Livebook.Runtime, for: Livebook.Runtime.MixStandalone do
ErlDist.Manager.stop(runtime.node) ErlDist.Manager.stop(runtime.node)
end end
def evaluate_code(runtime, code, container_ref, evaluation_ref, prev_evaluation_ref \\ :initial) do def evaluate_code(
runtime,
code,
container_ref,
evaluation_ref,
prev_evaluation_ref \\ :initial,
opts \\ []
) do
ErlDist.Manager.evaluate_code( ErlDist.Manager.evaluate_code(
runtime.node, runtime.node,
code, code,
container_ref, container_ref,
evaluation_ref, evaluation_ref,
prev_evaluation_ref prev_evaluation_ref,
opts
) )
end end

View file

@ -546,7 +546,10 @@ defmodule Livebook.Session do
[] -> :initial [] -> :initial
end end
Runtime.evaluate_code(state.data.runtime, cell.source, :main, cell.id, prev_ref) file = (state.data.path || "") <> "#cell"
opts = [file: file]
Runtime.evaluate_code(state.data.runtime, cell.source, :main, cell.id, prev_ref, opts)
state state
end end

View file

@ -8,7 +8,7 @@ defmodule Livebook.EvaluatorTest do
%{evaluator: evaluator} %{evaluator: evaluator}
end end
describe "evaluate_code/4" do describe "evaluate_code/6" do
test "given a valid code returns evaluation result", %{evaluator: evaluator} do test "given a valid code returns evaluation result", %{evaluator: evaluator} do
code = """ code = """
x = 1 x = 1
@ -107,6 +107,17 @@ defmodule Livebook.EvaluatorTest do
1000 1000
end) end)
end end
test "given file option sets it in evaluation environment", %{evaluator: evaluator} do
code = """
__DIR__
"""
opts = [file: "/path/dir/file"]
Evaluator.evaluate_code(evaluator, self(), code, :code_1, :initial, opts)
assert_receive {:evaluation_response, :code_1, {:ok, "/path/dir"}}
end
end end
describe "forget_evaluation/2" do describe "forget_evaluation/2" do

View file

@ -28,7 +28,7 @@ defmodule Livebook.Runtime.ErlDist.ManagerTest do
end end
end end
describe "evaluate_code/2" do describe "evaluate_code/6" do
test "spawns a new evaluator when necessary" do test "spawns a new evaluator when necessary" do
Manager.start() Manager.start()
Manager.set_owner(node(), self()) Manager.set_owner(node(), self())

View file

@ -30,9 +30,17 @@ defimpl Livebook.Runtime, for: LivebookTest.Runtime.SingleEvaluator do
code, code,
_container_ref, _container_ref,
evaluation_ref, evaluation_ref,
prev_evaluation_ref \\ :initial prev_evaluation_ref \\ :initial,
opts \\ []
) do ) do
Evaluator.evaluate_code(runtime.evaluator, self(), code, evaluation_ref, prev_evaluation_ref) Evaluator.evaluate_code(
runtime.evaluator,
self(),
code,
evaluation_ref,
prev_evaluation_ref,
opts
)
:ok :ok
end end