Skip to content
Merged
Show file tree
Hide file tree
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
6 changes: 4 additions & 2 deletions apptools/preferences/preference_binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
# Thanks for using Enthought open source!
""" A binding between a trait on an object and a preference value. """

from ast import literal_eval

# Enthought library imports.
from traits.api import Any, HasTraits, Instance, Str, Undefined
Expand Down Expand Up @@ -101,10 +102,11 @@ def _get_value(self, trait_name, value):
if type(handler) is Str:
pass

# Otherwise, we eval it!
# Otherwise, we literal_eval it! This is safe against arbitrary code
# execution, but it does limit values to core Python data types.
else:
try:
value = eval(value)
value = literal_eval(value)

# If the eval fails then there is probably a syntax error, but
# we will let the handler validation throw the exception.
Expand Down
6 changes: 4 additions & 2 deletions apptools/preferences/preferences_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@


# Standard library imports.
from ast import literal_eval
import logging

# Enthought library imports.
Expand Down Expand Up @@ -154,10 +155,11 @@ def _get_value(self, trait_name, value):
if isinstance(handler, Str) or trait.is_str:
pass

# Otherwise, we eval it!
# Otherwise, we literal_eval it! This is safe against arbitrary code
# execution, but it does limit values to core Python data types.
else:
try:
value = eval(value)
value = literal_eval(value)

# If the eval fails then there is probably a syntax error, but
# we will let the handler validation throw the exception.
Expand Down
1 change: 1 addition & 0 deletions apptools/preferences/tests/example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ visible = True
description = 'acme ui'
offsets = "[1, 2, 3, 4]"
names = "['joe', 'fred', 'jane']"
invalid = "sum(range(100))"

[acme.ui.splash_screen]
image = splash
Expand Down
19 changes: 18 additions & 1 deletion apptools/preferences/tests/test_preference_binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from apptools.preferences.api import Preferences
from apptools.preferences.api import bind_preference
from apptools.preferences.api import set_default_preferences
from traits.api import Bool, HasTraits, Int, Float, Str
from traits.api import Bool, HasTraits, Int, Float, Str, TraitError
from traits.observation.api import match


Expand Down Expand Up @@ -321,3 +321,20 @@ class AcmeUI(HasTraits):
self.assertEqual("color", listener.trait_name)
self.assertEqual("blue", listener.old)
self.assertEqual("red", listener.new)

def test_invalid_preference(self):

p = self.preferences
p.load(self.example)

class AcmeUI(HasTraits):
""" The Acme UI class! """

# The traits that we want to initialize from preferences.
invalid = Int

acme_ui = AcmeUI()

# Make a binding with an invalid value.
with self.assertRaises(TraitError):
bind_preference(acme_ui, "invalid", "acme.ui.invalid")
17 changes: 16 additions & 1 deletion apptools/preferences/tests/test_preferences_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from apptools.preferences.api import ScopedPreferences
from apptools.preferences.api import set_default_preferences
from traits.api import (
Any, Bool, HasTraits, Int, Float, List, Str,
Any, Bool, HasTraits, Int, Float, List, Str, TraitError,
push_exception_handler, pop_exception_handler,
)
from traits.observation.api import match
Expand Down Expand Up @@ -587,3 +587,18 @@ class AcmeUIPreferencesHelper(PreferencesHelper):
helper = AcmeUIPreferencesHelper(preferences_path="acme.ui")

self.assertEqual("50", helper.width)

def test_invalid_preference(self):

p = self.preferences
p.load(self.example)

class AcmeUIPreferencesHelper(PreferencesHelper):
""" The Acme UI class! """

# The traits that we want to initialize from preferences.
invalid = Int

# attempt to create instance from invalid value
with self.assertRaises(TraitError):
AcmeUIPreferencesHelper(preferences_path="acme.ui")
1 change: 1 addition & 0 deletions docs/releases/upcoming/299.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Replace eval with ast.literal_eval in apptools.preferences (#299)