Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions simpleeval.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,9 @@
########################################
# Tiny helpers:


def is_hashable(value):
try:
return hash(value)
except TypeError:
return False
# Primitive types that are always safe: can't be modules, can't be in DISALLOW_FUNCTIONS,
# and don't need recursive container checks. Used as a fast path in _check_disallowed_items.
_PRIMITIVE_TYPES = frozenset({int, float, str, bool, type(None), bytes, complex})


# Disallow functions:
Expand Down Expand Up @@ -628,21 +625,25 @@ def _check_disallowed_items(self, item):
Raises FeatureNotAvailable if forbidden content found.
ModuleWrapper instances are allowed (explicit opt-in to module access).
"""
# Fast path: primitive scalars are always safe (most common case)
if type(item) in _PRIMITIVE_TYPES:
return

# Allow ModuleWrapper (explicit opt-in to module access)
if isinstance(item, ModuleWrapper):
return

if isinstance(item, types.ModuleType):
raise FeatureNotAvailable("Sorry, modules are not allowed")
if is_hashable(item) and item in DISALLOW_FUNCTIONS:
raise FeatureNotAvailable("This function is forbidden")

if isinstance(item, (list, tuple)):
for element in item:
self._check_disallowed_items(element)
elif isinstance(item, dict):
for value in item.values():
self._check_disallowed_items(value)
elif callable(item) and item in DISALLOW_FUNCTIONS:
raise FeatureNotAvailable("This function is forbidden")

@staticmethod
def parse(expr):
Expand Down Expand Up @@ -875,7 +876,7 @@ def _eval_attribute(self, node):
if item is not _ATTR_NOT_FOUND:
if isinstance(item, types.ModuleType):
raise FeatureNotAvailable("Sorry, modules are not allowed in attribute access")
if is_hashable(item) and item in DISALLOW_FUNCTIONS:
if callable(item) and item in DISALLOW_FUNCTIONS:
raise FeatureNotAvailable("This function is forbidden")
return item

Expand Down