From 05864aa29fdf98441a9b8b81ae8317d27ef12250 Mon Sep 17 00:00:00 2001
From: Florian Spreckelsen <florian.spreckelsen@gmx.net>
Date: Tue, 25 Aug 2020 14:34:08 +0000
Subject: [PATCH] Fix deep copy of messages

---
 CHANGELOG.md                |  2 ++
 src/caosdb/common/models.py |  6 ++++
 unittests/test_message.py   | 61 +++++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+)
 create mode 100644 unittests/test_message.py

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ff8555cd..b6d7d84f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Fixed ###
 
+* deepcopy of `_Messages` objects
+
 ### Security ###
 
 ## [0.4.0] - 2020-07-17##
diff --git a/src/caosdb/common/models.py b/src/caosdb/common/models.py
index 7ef5df66..4523b1f8 100644
--- a/src/caosdb/common/models.py
+++ b/src/caosdb/common/models.py
@@ -2049,6 +2049,9 @@ class _Messages(dict):
             else:
                 raise TypeError(
                     "('type', 'code'), ('type'), or 'type' expected.")
+        if isinstance(key, _Messages._msg_key):
+            type = key._type  # @ReservedAssignment
+            code = key._code
         else:
             type = key  # @ReservedAssignment
             code = None
@@ -2063,6 +2066,9 @@ class _Messages(dict):
             else:
                 raise TypeError(
                     "('description', 'body'), ('body'), or 'body' expected.")
+        if isinstance(value, Message):
+            body = value.body
+            description = value.description
         else:
             body = value
             description = None
diff --git a/unittests/test_message.py b/unittests/test_message.py
new file mode 100644
index 00000000..b209b0f5
--- /dev/null
+++ b/unittests/test_message.py
@@ -0,0 +1,61 @@
+# encoding: utf-8
+#
+# ** header v3.0
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2020 Florian Spreckelsen <f.spreckelsen@indiscale.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# ** end header
+#
+import caosdb as db
+from copy import deepcopy
+
+
+def test_deepcopy():
+    """Test whether deepcopy of _Messages objects doesn't mess up
+    contained Messages objects.
+
+    """
+    msgs = db.common.models._Messages()
+    msg = db.Message(type="bla", code=1234, description="desc", body="blabla")
+    msgs.append(msg)
+    msg_copy = deepcopy(msgs)[0]
+
+    # make sure type is string-like (formerly caused problems)
+    assert hasattr(msg_copy.type, "lower")
+    assert msg_copy.type == msg.type
+    assert msg_copy.code == msg.code
+    assert msg_copy.description == msg.description
+    assert msg_copy.body == msg.body
+
+
+def test_deepcopy_clear_server():
+
+    msgs = db.common.models._Messages()
+    msg = db.Message(type="bla", code=1234, description="desc", body="blabla")
+    err_msg = db.Message(type="Error", code=1357, description="error")
+    msgs.extend([msg, err_msg])
+    copied_msgs = deepcopy(msgs)
+
+    assert len(copied_msgs) == 2
+    assert copied_msgs.get("Error", err_msg.code).code == err_msg.code
+    assert copied_msgs.get("bla", msg.code).code == msg.code
+
+    # Only the error should be removed
+    copied_msgs.clear_server_messages()
+    assert len(copied_msgs) == 1
+    assert copied_msgs[0].code == msg.code
-- 
GitLab