1

I have a string of a list that I am trying to convert to list, however ast.literal_eval returns an error:

y = "[
        {
           'ake_ii': 88888, 
           'azefmlkh_amrlgba_dd': datetime.datetime(2022, 1, 31, 16, 52), 
           'sklmfs_qujdf_': datetime.datetime(2022, 1, 31, 23, 4)
        }
     ]"
ast.literal_eval(y)

error returned

ValueError: malformed node or string: <ast.Call object at 0x7fbaec22da60>

I want a list returned without it being a string.

martineau
  • 119,623
  • 25
  • 170
  • 301
Amin Selim
  • 71
  • 4
  • 1
    A call to a function isn’t a *literal*, and AST refuses to evaluate it. You’d need just `eval`, with all its problems. – deceze Mar 12 '22 at 11:23
  • 2
    @deceze Not quite. You can implement this with an extension of literal_eval to also parse calls to datetime.datetime - I've done that in a prior answer I can't find right now. – AKX Mar 12 '22 at 11:24
  • 3
    Ah, there we go. Not marking as duplicate since this doesn't directly do what op wants but could be adapted to. https://stackoverflow.com/a/71137896/51685 (cc @deceze) – AKX Mar 12 '22 at 11:28

1 Answers1

3

Here's an answer adapted from my other related answer:

import ast
import datetime

data = """
[
        {
           'ake_ii': 88888, 
           'azefmlkh_amrlgba_dd': datetime.datetime(2022, 1, 31, 16, 52), 
           'sklmfs_qujdf_': datetime.datetime(2022, 1, 31, 23, 4)
        }
]
""".strip()


def literal_eval_with_datetime(source):
    # Adapted from `ast.literal_eval`
    def _convert(node):
        if isinstance(node, list):
            return [_convert(arg) for arg in node]
        if isinstance(node, ast.Constant):
            return node.value
        if isinstance(node, ast.Tuple):
            return tuple(map(_convert, node.elts))
        if isinstance(node, ast.List):
            return list(map(_convert, node.elts))
        if isinstance(node, ast.Set):
            return set(map(_convert, node.elts))
        if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id == 'set' and node.args == node.keywords == []:
            return set()
        if isinstance(node, ast.Dict):
            return dict(zip(map(_convert, node.keys), map(_convert, node.values)))
        if isinstance(node, ast.Expression):
            return _convert(node.body)
        if isinstance(node, ast.Call) and ast.get_source_segment(source, node.func) == 'datetime.datetime':
            return datetime.datetime(*_convert(node.args))
        return {
            f'${node.__class__.__name__}': ast.get_source_segment(source, node),
        }

    return _convert(ast.parse(source, mode='eval'))


print(literal_eval_with_datetime(data))

The output is (a real list, of course):

[
    {
        "ake_ii": 88888,
        "azefmlkh_amrlgba_dd": datetime.datetime(2022, 1, 31, 16, 52),
        "sklmfs_qujdf_": datetime.datetime(2022, 1, 31, 23, 4),
    }
]
AKX
  • 152,115
  • 15
  • 115
  • 172