Repository: joshtemple/lkml

Issue:
lkml.dump deletes "name" key from dict
[dump](https://github.com/joshtemple/lkml/blob/3d629172bbc97a93f1d5f5af0cf4f219752a1ca8/lkml/__init__.py#L56) function mutates input dict by removing all "name" fields in the dict.
Looks like it is caused by a `.pop` call on [this line](https://github.com/joshtemple/lkml/blob/3d629172bbc97a93f1d5f5af0cf4f219752a1ca8/lkml/simple.py#L312).


Discussion:

Patch:
diff --git a/lkml/simple.py b/lkml/simple.py
index 096a966..0d3b651 100644
--- a/lkml/simple.py
+++ b/lkml/simple.py
@@ -6,6 +6,7 @@ to interact with the parse tree.
 
 """
 
+import copy
 import logging
 from typing import Any, Dict, List, Optional, Sequence, Type, Union, cast
 
@@ -306,6 +307,7 @@ class DictParser:
             A generator of serialized string chunks
 
         """
+
         if isinstance(value, str):
             return self.parse_pair(key, value)
         elif isinstance(value, (list, tuple)):
@@ -314,11 +316,12 @@ class DictParser:
             else:
                 return self.parse_list(key, value)
         elif isinstance(value, dict):
+            to_parse = copy.copy(value)
             if key in KEYS_WITH_NAME_FIELDS or "name" not in value.keys():
                 name = None
             else:
-                name = value.pop("name")
-            return self.parse_block(key, value, name)
+                name = to_parse.pop("name")
+            return self.parse_block(key, to_parse, name)
         else:
             raise TypeError("Value must be a string, list, tuple, or dict.")
 
diff --git a/setup.py b/setup.py
index 015da82..018177b 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@ from pathlib import Path
 
 from setuptools import find_packages, setup
 
-__version__ = "1.3.0"
+__version__ = "1.3.1"
 
 here = Path(__file__).parent.resolve()
 


Test patch:
diff --git a/tests/test_functional.py b/tests/test_functional.py
index e53416e..07e6171 100644
--- a/tests/test_functional.py
+++ b/tests/test_functional.py
@@ -102,3 +102,21 @@ def test_lists_with_comma_configurations():
 def test_reserved_dimension_names():
     parsed = load("block_with_reserved_dimension_names.view.lkml")
     assert parsed is not None
+
+
+def test_repeated_dump_does_not_mutate_input():
+    text = """view: albums {
+        dimension: id {
+            primary_key: yes
+            type: number
+            sql: ${TABLE}.album_id ;;
+        }
+    }
+    """
+
+    tree = lkml.parse(text)
+    visitor = lkml.DictVisitor()
+    parsed: dict = visitor.visit(tree)
+    first = lkml.dump(parsed)
+    second = lkml.dump(parsed)
+    assert first == second