eval-less implementation, preliminary to browser support
On some browser-python runtimes, eval() is either catastrophically slow (brython, skulpt) or completely unavailable (pyj(ama)s, batavia). Since attrs is The Library You Should Absolutely Use No Matter What™, it would be nice if it had an affordance to support those runtimes.
We don’t use eval! ✨ 😜
I guess exec is evil too?
Oh. It probably should use eval :).
But yes, exec has exactly the same limitations.
See #87.
This might be an interesting technical challenge. But how do we go about it operationally?
- how to separate the eval code from the fallbacks?
- how to test the fallbacks?
Guarding sections of code with a flag from _compat would get messy quickly I think.
@Tinche First - we don't need to do all of those in the same PR :).
how to separate the eval code from the fallbacks?
They should just be in totally separate functions. Not supporting eval efficiently is a reasonable thing for a Python runtime to do given certain constraints; but everybody can support returning a higher-order function, so we just have two ways to construct the __init__.
how to test the fallbacks?
This doesn't seem hard to me; just set a flag and run all the same unit tests to ensure the behavior is the same.
This doesn't seem hard to me; just set a flag and run all the same unit tests to ensure the behavior is the same.
Ideally we could test using one of the runtimes you enumerated. Or monkeypatch eval to blow up when called, but that might break other libs like pytest?
Ideally we could test using one of the runtimes you enumerated. Or monkeypatch eval to blow up when called, but that might break other libs like pytest?
For testing purposes, we can have a private API that explicitly selects the init-creation mode; @attr._s_but_with_no_eval, as a strawman example.
What's the alternative to using eval/exec? For CPython and pypy, we could emit bytecode directly, but that also doesn't support every python implementation out there (pyston).
What's the alternative to using eval/exec?
Calling setattr.
Here's another use case for eval-less class creation: building classes from configuration such as swagger/openapi. Because the spec might come from an untrusted source, eval is ill-advised.
Because the spec might come from an untrusted source
If this is the case, then the swagger loader ought to be properly parsing and sanitizing everything (transforming everything into valid identifiers, for example). If the inputs are in the appropriate format, then eval should be just as safe as any other construction mechanism.
Just bumped into this issue - our environment doesn't allow either eval or compile. Is there any way we can use this package without either of those functions being required?
Not at this time. That should be possible once we have pluggable method builders but there’s sadly no timeline.
@tyteen4a03 I am super curious—what environment is this?
Not at liberty to say unfortunately, but we do have good reasons for this.
@tyteen4a03 Understandable — independent of any reason, any interest in submitting a PR? :)