-
Notifications
You must be signed in to change notification settings - Fork 85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Don't misuse KeyError for the custom names
function.
#126
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -277,9 +277,34 @@ You can also hand the handling of names over to a function, if you prefer: | |||||
3 | ||||||
|
||||||
That was a bit of a silly example, but you could use this for pulling values | ||||||
from a database or file, say, or doing some kind of caching system. | ||||||
from a database or file, looking up spreadsheet cells, say, or doing some kind of caching system. | ||||||
|
||||||
The two default names that are provided are ``True`` and ``False``. So if you want to provide your own names, but want ``True`` and ``False`` to keep working, either provide them yourself, or ``.copy()`` and ``.update`` the ``DEFAULT_NAMES``. (See functions example above). | ||||||
In general, when it attempts to find a variable by name, if it cannot find one, | ||||||
then it will look in the ``functions`` for a function of that name. If you want your name handler | ||||||
function to return a "I can't find that name!", then it should raise a ``simpleeval.NameNotDefined`` | ||||||
exception. Eg: | ||||||
|
||||||
.. code-block:: python | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. REPL sessions like this should use
Suggested change
|
||||||
|
||||||
>>> def name_handler(node): | ||||||
... if node.id[0] == 'a': | ||||||
... return 21 | ||||||
... raise NameNotDefined(node.id[0], "Not found") | ||||||
... | ||||||
... simple_eval('a + a', names=name_handler, functions={"b": 100}) | ||||||
|
||||||
42 | ||||||
|
||||||
>>> simple_eval('a + b', names=name_handler, functions={'b': 100}) | ||||||
121 | ||||||
|
||||||
(Note: in that example, putting a number directly into the functions dict was done just to | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
show the fall-back to functions. Normally only put actual callables in there.) | ||||||
|
||||||
|
||||||
The two default names that are provided are ``True`` and ``False``. So if you want to provide | ||||||
your own names, but want ``True`` and ``False`` to keep working, either provide them yourself, | ||||||
or ``.copy()`` and ``.update`` the ``DEFAULT_NAMES``. (See functions example above). | ||||||
|
||||||
Creating an Evaluator Class | ||||||
--------------------------- | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -526,24 +526,30 @@ def _eval_name(self, node): | |
try: | ||
# This happens at least for slicing | ||
# This is a safe thing to do because it is impossible | ||
# that there is a true exression assigning to none | ||
# that there is a true expression assigning to none | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
# (the compiler rejects it, so you can't even | ||
# pass that to ast.parse) | ||
if hasattr(self.names, "__getitem__"): | ||
return self.names[node.id] | ||
if callable(self.names): | ||
return self.names[node.id] | ||
|
||
except (TypeError, KeyError): | ||
pass | ||
|
||
if callable(self.names): | ||
try: | ||
return self.names(node) | ||
except NameNotDefined: | ||
pass | ||
elif not hasattr(self.names, "__getitem__"): | ||
raise InvalidExpression( | ||
'Trying to use name (variable) "{0}"' | ||
' when no "names" defined for' | ||
" evaluator".format(node.id) | ||
) | ||
|
||
except KeyError: | ||
if node.id in self.functions: | ||
return self.functions[node.id] | ||
if node.id in self.functions: | ||
return self.functions[node.id] | ||
|
||
raise NameNotDefined(node.id, self.expr) | ||
raise NameNotDefined(node.id, self.expr) | ||
|
||
def _eval_subscript(self, node): | ||
container = self._eval(node.value) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.