Skip to content

Commit

Permalink
Do not include undefined Elixir variables in the expanded ~PY sigil (#12
Browse files Browse the repository at this point in the history
)
  • Loading branch information
jonatanklosko authored Feb 27, 2025
1 parent d646e69 commit b07752f
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 3 deletions.
12 changes: 10 additions & 2 deletions lib/pythonx.ex
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,17 @@ defmodule Pythonx do
defmacro sigil_PY({:<<>>, _meta, [code]}, []) when is_binary(code) do
%{referenced: referenced, defined: defined} = Pythonx.AST.scan_globals(code)

caller = __CALLER__

globals_entries =
for name <- referenced do
{name, {String.to_atom(name), [], nil}}
for name <- referenced,
name_atom = String.to_atom(name),
# We only reference variables that are actually defined.
# This way, if an undefined variable is referenced in the
# Python code, it results in an informative Python error,
# rather than Elixir compile error.
Macro.Env.has_var?(caller, {name_atom, nil}) do
{name, {name_atom, [], nil}}
end

assignments =
Expand Down
17 changes: 16 additions & 1 deletion test/pythonx_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,21 @@ defmodule PythonxTest do
assert Keyword.keys(binding) == [:x]
end

test "results in a Python error when a variable is undefined" do
assert_raise Pythonx.Error, ~r/NameError: name 'x' is not defined/, fn ->
Code.eval_string(
~S'''
import Pythonx
~PY"""
x + 1
"""
''',
[]
)
end
end

test "global redefinition" do
{_result, binding} =
Code.eval_string(
Expand Down Expand Up @@ -414,7 +429,7 @@ defmodule PythonxTest do
assert repr(result) == "43"
end

test "does not result in unused variables" do
test "does not result in unused variables diagnostics" do
{_result, diagnostics} =
Code.with_diagnostics(fn ->
Code.eval_string(~s'''
Expand Down

0 comments on commit b07752f

Please sign in to comment.