Skip to content

Instantly share code, notes, and snippets.

@reclosedev
Last active May 13, 2016 13:39
Show Gist options
  • Save reclosedev/894d563eec69a3c74d2dd969735c72d9 to your computer and use it in GitHub Desktop.
Save reclosedev/894d563eec69a3c74d2dd969735c72d9 to your computer and use it in GitHub Desktop.

Revisions

  1. reclosedev revised this gist May 13, 2016. No changes.
  2. reclosedev created this gist May 13, 2016.
    84 changes: 84 additions & 0 deletions new_order.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,84 @@
    """
    Module contains ``order_dicts`` decorator. When used, all dicts declarations are converted to OrderedDict. Example::
    from new_order import order_dicts
    @order_dicts
    def func():
    d1 = {1: 2, 3: 4, 5: 6}
    d2 = {"test": 2 ** 42, "foo": "bar", "baz": d1}
    print("What do we have here? %s" % d1)
    print(d2)
    func()
    Output::
    What do we have here? OrderedDict([(1, 2), (3, 4), (5, 6)])
    OrderedDict([('test', 4398046511104), ('foo', 'bar'), ('baz', OrderedDict([(1, 2), (3, 4), (5, 6)]))])
    """
    import ast
    import inspect
    import textwrap


    class order_dicts(object):
    """ Decorator to convert all dict literals to OrderedDict.
    """

    def __init__(self, func):
    self.original_function = func
    self.updated_function = None

    def __call__(self, *args, **kwargs):
    if self.updated_function is None:
    source = inspect.getsourcelines(self.original_function)
    source = "".join(source[0])
    source = textwrap.dedent(source)
    code = _convert_dicts_to_ordered(source)
    exec(code, self.original_function.__globals__)

    result = self.original_function.__globals__[self.original_function.__name__]
    while isinstance(result, order_dicts):
    result = result.original_function
    self.updated_function = result
    return self.updated_function(*args, **kwargs)


    def _convert_dicts_to_ordered(source):
    root = ast.parse(source)
    import_odict = ast.parse("from collections import OrderedDict")
    root.body.insert(0, import_odict.body[0])
    root = ChangeDictToOrderedTransformer().visit(root)
    root = ast.fix_missing_locations(root)
    return compile(root, "<string>", "exec")


    class ChangeDictToOrderedTransformer(ast.NodeTransformer):
    def visit_Dict(self, node):
    self.generic_visit(node)
    tuples = [ast.Tuple(elts=[key, value], ctx=ast.Load())
    for key, value in zip(node.keys, node.values)]

    od_node = ast.Call(
    func=ast.Name(id="OrderedDict", ctx=ast.Load()),
    args=[ast.Tuple(elts=tuples, ctx=ast.Load())],
    ctx=ast.Load(),
    keywords=[], starargs=None, kwargs=None
    )
    return od_node


    # Demo
    if __name__ == "__main__":

    @order_dicts
    def func():
    d1 = {1: 2, 3: 4, 5: 6}
    d2 = {"test": 2 ** 42, "foo": "bar", "baz": d1}
    print("What do we have here? %s" % d1)
    print(d2)


    func()