Handling more literals via the eval() variants

A configuration file may have values of types that don't have simple string representations. For example, a collection might be provided as a tuple or a list literal; a mapping might be provided as a dict literal. We have several choices to handle these more complex values.

The choices resolve the issue of how much Python syntax the conversion is able to tolerate. For some types (int, float, bool, complex, decimal.Decimal, and fractions.Fraction), we can safely convert the string to a literal value because the __init__() object for these types can handle string values.

For other types, however, we can't simply do the string conversion. We have several choices on how to proceed:

  • Forbid these data types and rely on the configuration file syntax plus processing rules to assemble complex Python values from very simple parts; this is tedious but it can be made to work. In the case of the table payout, we need to break the payout into two separate configuration items for the numerator and denominator. This is a lot of configuration file complexity for a simple two-tuple.
  • Use ast.literal_eval() as it handles many cases of Python literal values. This is often the ideal solution.
  • Use eval() to simply evaluate the string and create the expected Python object. This will parse more kinds of objects than ast.literal_eval(). But, do consider whether this level of generality is really needed.
  • Use the ast module to compile and then vet the resulting code object. This vetting process can check for the import statements as well as use some small set of permitted modules. This is quite complex; if we're effectively allowing code, perhaps we should be designing a framework and simply including Python code.

If we are performing RESTful transfers of Python objects through the network, eval() of the resulting text cannot be trusted. You can refer to Chapter 10Serializing and Saving – JSON, YAML, Pickle, CSV, and XML.

In the case of reading a local configuration file, however, eval() is certainly usable. In some cases, the Python application code is as easily modified as the configuration file. Worrying about eval() may not be helpful when the base code can be tweaked.

Here's how we use ast.literal_eval() instead of eval():

>>> import ast 
>>> ast.literal_eval('(3,2)') 
(3, 2) 

This broadens the domain of possible values in a configuration file. It doesn't allow arbitrary Python objects, but it allows a broad spectrum of literal values including tuples.

Let's take a look at how to store the configuration in PY files.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset