Skip to content

Commit a71a7db

Browse files
committed
Change eval to return nil when code does not end with an expression
1 parent 79a3dea commit a71a7db

File tree

3 files changed

+13
-16
lines changed

3 files changed

+13
-16
lines changed

c_src/pythonx/pythonx.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,7 +1105,7 @@ std::tuple<PyObjectPtr, PyObjectPtr> compile(ErlNifEnv *env,
11051105
return std::make_tuple(py_body_code, py_last_expr_code);
11061106
}
11071107

1108-
std::tuple<ExObject, fine::Term>
1108+
std::tuple<std::optional<ExObject>, fine::Term>
11091109
eval(ErlNifEnv *env, ErlNifBinary code, std::string code_md5,
11101110
std::vector<std::tuple<ErlNifBinary, ExObject>> globals,
11111111
ErlNifPid stdout_device, ErlNifPid stderr_device) {
@@ -1276,14 +1276,12 @@ eval(ErlNifEnv *env, ErlNifBinary code, std::string code_md5,
12761276
Py_DecRef(py_body_result);
12771277
}
12781278

1279-
PyObjectPtr py_result;
1279+
auto result = std::optional<ExObject>();
12801280

1281-
if (py_last_expr_code == nullptr) {
1282-
py_result = Py_BuildValue("");
1283-
raise_if_failed(env, py_result);
1284-
} else {
1285-
py_result = PyEval_EvalCode(py_last_expr_code, py_globals, py_globals);
1281+
if (py_last_expr_code != nullptr) {
1282+
auto py_result = PyEval_EvalCode(py_last_expr_code, py_globals, py_globals);
12861283
raise_if_failed(env, py_result);
1284+
result = ExObject(fine::make_resource<ExObjectResource>(py_result));
12871285
}
12881286

12891287
// Step 4: flat-decode globals
@@ -1326,8 +1324,7 @@ eval(ErlNifEnv *env, ErlNifBinary code, std::string code_md5,
13261324
throw std::runtime_error("failed to make a map");
13271325
}
13281326

1329-
return std::make_tuple(
1330-
ExObject(fine::make_resource<ExObjectResource>(py_result)), map);
1327+
return std::make_tuple(result, map);
13311328
}
13321329

13331330
FINE_NIF(eval, ERL_NIF_DIRTY_JOB_CPU_BOUND);

lib/pythonx.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ defmodule Pythonx do
108108
by calling `encode!/1`.
109109
110110
The function returns the evaluation result and a map with the updated
111-
global variables. Note that, unless `code` ends with an expression,
112-
the result will be a `None` object.
111+
global variables. Note that the result is an object only if `code`
112+
ends with an expression, otherwise it is `nil`.
113113
114114
If the Python code raises an exception, `Pythonx.Error` is raised and
115115
the message includes the usual Python error message with traceback.
@@ -196,7 +196,7 @@ defmodule Pythonx do
196196
197197
'''
198198
@spec eval(String.t(), %{optional(String.t()) => term()}) ::
199-
{Object.t(), %{optional(String.t()) => Object.t()}}
199+
{Object.t() | nil, %{optional(String.t()) => Object.t()}}
200200
def eval(code, globals) do
201201
globals =
202202
for {key, value} <- globals do

test/pythonx_test.exs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ defmodule PythonxTest do
155155
%{}
156156
)
157157

158-
assert repr(result) == "None"
158+
assert result == nil
159159
assert repr(nums) == "[1, 2, 3]"
160160
assert repr(sum) == "6"
161161
end
@@ -174,12 +174,12 @@ defmodule PythonxTest do
174174
assert repr(result) == "2"
175175
end
176176

177-
test "returns none for empty code" do
177+
test "returns nil for empty code" do
178178
assert {result, %{}} = Pythonx.eval("", %{})
179-
assert repr(result) == "None"
179+
assert result == nil
180180

181181
assert {result, %{}} = Pythonx.eval("# Comment", %{})
182-
assert repr(result) == "None"
182+
assert result == nil
183183
end
184184

185185
test "encodes terms given as globals" do

0 commit comments

Comments
 (0)