Repository: sdispater/tomlkit

Issue:
table.copy should return an instance of table
`table.copy` appears to return an instance of `dict`, not `table`:

```
⊙  rm -rf venv; python3.7 -m venv venv; venv/bin/python -m pip install --quiet tomlkit; venv/bin/python -m pip list | grep tomlkit; venv/bin/python -c '                julian@Air
import tomlkit
table = tomlkit.table()
print(type(table.copy()))'
/Users/julian/Desktop/venv/lib/python3.7/site-packages/pip/_vendor/msgpack/fallback.py:133: DeprecationWarning: encoding is deprecated, Use raw=False instead.
  unpacker = Unpacker(None, max_buffer_size=len(packed), **kwargs)
tomlkit    0.5.8
<class 'dict'>
```

Besides having the type change during copying, this makes doing immutable changes to tables more difficult (copying a table and mutating the copy).

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 91ab737..aaf12c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
 
 ### Fixed
 
+- Support copy protocols for table items. ([#65](https://github.com/sdispater/tomlkit/issues/#65))
 - Escape characters in double quoted key string. ([#136](https://github.com/sdispater/tomlkit/issues/#136))
 - Fix the invalid dumping output of multiline array when it is empty. ([#139](https://github.com/sdispater/tomlkit/issues/#139))
 - Fix a bug that tomlkit accepts an invalid table with missing `=`. ([#141](https://github.com/sdispater/tomlkit/issues/141))
diff --git a/tomlkit/items.py b/tomlkit/items.py
index 50ebfa3..f325029 100644
--- a/tomlkit/items.py
+++ b/tomlkit/items.py
@@ -1,4 +1,5 @@
 import abc
+import copy
 import re
 import string
 
@@ -216,6 +217,9 @@ class Trivia:
 
         self.trail = trail
 
+    def copy(self) -> "Trivia":
+        return type(self)(self.indent, self.comment_ws, self.comment, self.trail)
+
 
 class KeyType(Enum):
     """
@@ -1144,6 +1148,9 @@ class AbstractTable(Item, _CustomDict):
     def __str__(self):
         return str(self.value)
 
+    def copy(self: AT) -> AT:
+        return copy.copy(self)
+
     def __repr__(self) -> str:
         return repr(self.value)
 
@@ -1210,6 +1217,16 @@ class Table(AbstractTable):
     def discriminant(self) -> int:
         return 9
 
+    def __copy__(self) -> "Table":
+        return type(self)(
+            self._value.copy(),
+            self._trivia.copy(),
+            self._is_aot_element,
+            self._is_super_table,
+            self.name,
+            self.display_name,
+        )
+
     def append(self, key, _item):
         """
         Appends a (key, item) to the table.
@@ -1374,6 +1391,9 @@ class InlineTable(AbstractTable):
             value.trivia.comment = ""
         super().__setitem__(key, value)
 
+    def __copy__(self) -> "InlineTable":
+        return type(self)(self._value.copy(), self._trivia.copy(), self._new)
+
     def _getstate(self, protocol: int = 3) -> tuple:
         return (self._value, self._trivia)
 


Test patch:
diff --git a/tests/test_items.py b/tests/test_items.py
index 34e1786..9c73a94 100644
--- a/tests/test_items.py
+++ b/tests/test_items.py
@@ -654,3 +654,12 @@ value = false
 
     assert {"foo": {"value": False}} == content
     assert {"value": False} == content["foo"]
+
+
+def test_table_copy():
+    table = item({"foo": "bar"})
+    table_copy = table.copy()
+    assert isinstance(table_copy, Table)
+    table["foo"] = "baz"
+    assert table_copy["foo"] == "bar"
+    assert table_copy.as_string() == 'foo = "bar"\n'