Open wonkodv opened 3 years ago
Hey, thanks for the PR. It's an interesting idea.
I think it would be nicer to make the Rust globals an object with read-only properties. One downside for that is that it gives a runtime error when trying to assign, rather than syntax errors. But it's python, so I think people will forgive that. The advantage is that the error message will make more sense, and there's no need to intercept and adjust error messages then.
My first Idea was to use a new type as locals
argument to exec
, it does not have to be a dict
. Globals have to be a dict
. This is how it could look in python:
class ReadOnlyRustVariables:
def __init__(self, dict):
self.dict = dict
def __getitem__(self, key):
return self.dict[key]
def __setitem__(self, key, val):
if key.startswith("__rust_var_"):
k = key[len("__rust_var_"):]
raise TypeError(f"You can not modify the rust-variable '{k} use Context::get_global()")
self.dict[key] = val
locals_ = ReadOnlyRustVariables({"__rust_var_x":42})
globals_ = vars(__import__("builtins"))
exec("y = __rust_var_x * 2", globals_, locals_)
assert locals_["y"] == 84, locals_
exec("__rust_var_x = __rust_var_x * 2", globals_, locals_)
# TypeError: You can not modify the rust-variable 'x use Context::get_global()
I didn't try this one.
another Idea was to replace 'var
with _RUST_IMMUT_VARS['var']
(and maybe #var
with _RUST_MUT_VARS['var']
).
The two objects could be created in Context::try_new()
using inline_python::python!
to initialize the python environment like so:
class RustVars:
__slots__ = ("_dict", "_mutable")
def __init__(self, mutable:bool):
self._dict = dict()
self._mutable = mutable
def __setitem__(self, key, value):
if self._mutable:
self._dict[key] = value
else:
raise TypeError("You are trying to write to "+'\''+key+" which is read-only. Try #"+key)
def __getitem__(self, key):
return self._dict[key]
_RUST_MUT_VARS = RustVars(True)
_RUST_IMMUT_VARS = RustVars(False)
del RustVars
from builtins import *
I tried implementing the second in rust and failed to run python code when initializing the context. It's a mess: https://github.com/wonkodv/inline-python/commit/1a6a51f28a4324dae417eee65e265ffb38ca90fb
When I thought of the lambda trick and found it easy to implement I liked the compile time errors better than runtime errors, even if the Error Message is not perfect.
You can cause a Syntaxerror for assignments to rust variables by expanding them to
((lambda:_RUST_var)())
Since the SyntaxError has a very confusing message, the likely cause is appended:
The Error message could be improved by inspecting the code it is raised for, but I don't know how to do it reliably.