Source code for armi.utils.parsing

# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""

This file contains tools for common tasks in parsing in python strings into non-string values

"""

import ast
import copy
from dateutil import parser


[docs]def tryLiteralEval(source): try: source = ast.literal_eval(source) except (ValueError, SyntaxError): pass return source
# the following dict helps avoid the need for an eval() statement # Is there no better way to go 'bool' -> bool !? _str_types = { tp.__name__: tp for tp in (type(None), bool, int, complex, float, str, bytes, list, tuple, dict) } _type_strs = {v: k for k, v in _str_types.items()} # python's matching truth evaluations of Nones in different primitive types # str's and unicodes omitted because parseValue denies their use. _none_types = { type(None): None, bool: False, int: 0, complex: 0j, float: 0.0, list: [], tuple: (), dict: {}, }
[docs]def _numericSpecialBehavior(source, rt): try: return rt(source), True # convert, report success except (ValueError, TypeError): return source, False # fail, report failure
[docs]def parseValue(source, requestedType, allowNone=False, matchingNonetype=True): """Tries parse a python value, expecting input to be the right type or a string""" # misuse prevention if requestedType == str: raise TypeError( "Unreliable and unnecessary to use parseValue for strs and unicodes. " "Given parameters are {}, {}, {}.".format(source, requestedType, allowNone) ) # evaluation and special evaluation for numbers evaluated_source, skip_instance_check = tryLiteralEval(source), False if requestedType in [int, float, complex]: evaluated_source, skip_instance_check = _numericSpecialBehavior( evaluated_source, requestedType ) # none logic if allowNone and not evaluated_source: if matchingNonetype: return copy.deepcopy(_none_types[requestedType]) else: return evaluated_source # assert everything went well if not skip_instance_check and not isinstance(evaluated_source, requestedType): msg = "Could not parse {} from source {}." if allowNone: msg += " Nor could None be parsed from source." raise ValueError(msg.format(requestedType, evaluated_source)) return evaluated_source
# -----------------------------------
[docs]def datetimeFromStr(string): """Converts an arbitrary string to a datetime object""" return parser.parse(string)