We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
stream deepcopy issue
taken from http://lists.obspy.org/pipermail/obspy-users/2013-April/000451.html
## 

hello all,

i have some issues with deep copies of stream objects.

it looks like format-specific dicts are "linked" in deep copy operations instead of being duplicated.

this happened after some obspy upgrades, since i'm pretty sure my code using deep copy functions worked correctly (and was not changed) until some months ago.

here's a sample session.

``` python
$ ipython
Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48)
Type "copyright", "credits" or "license" for more information.

IPython 0.10 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object'. ?object also works, ?? prints more.

In [1]: from obspy import read
In [2]: from obspy.arclink.client import Client
In [3]: from obspy.core import UTCDateTime
In [4]: client = Client(user="test@obspy.de")
In [5]: t = UTCDateTime("2009-08-24 00:20:03")

# let's grab some data first:
In [6]: st = client.getWaveform('BW', 'RJOB', '', 'EHZ', t, t + 30,
route=False)
In [7]: st[0].stats
Out[7]: Stats({'network': 'BW', '_format': 'MSEED', 'mseed': AttribDict({'dataquality': 'D', 'record_length': 512, 'byteorder': '>', 'encoding': 'STEIM1'}), 'sampling_rate': 200.0, 'station': 'RJOB', 'location': '', 'starttime': UTCDateTime(2009, 8, 24, 0, 20, 3), 'delta': 0.0050000000000000001, 'calib': 1.0, 'npts': 6001, 'endtime': UTCDateTime(2009, 8, 24, 0, 20, 33), 'channel': 'EHZ'})

# here comes the weird stuff:
In [8]: from copy import deepcopy as copy_deepcopy
In [9]: ct = copy_deepcopy(st)
In [10]: st[0].stats.mseed.dataquality = 'X'
In [11]: st[0].stats.mseed.dataquality
Out[11]: 'X'
In [12]: ct[0].stats.mseed.dataquality
Out[12]: 'X'

# BUT, dict data in common header is deep-copied as expected:
In [13]: st[0].stats.network = 'XX'
In [14]: st[0].stats.network
Out[14]: 'XX'
In [15]: ct[0].stats.network
Out[15]: 'BW'
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `obspy/core/util/attribdict.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 """
3 AttribDict class for ObsPy.
4 
5 :copyright:
6     The ObsPy Development Team (devs@obspy.org)
7 :license:
8     GNU Lesser General Public License, Version 3
9     (http://www.gnu.org/copyleft/lesser.html)
10 """
11 
12 import collections
13 
14 
15 class AttribDict(collections.MutableMapping):
16     """
17     A class which behaves like a dictionary.
18 
19     :type data: dict, optional
20     :param data: Dictionary with initial keywords.
21 
22     .. rubric:: Basic Usage
23 
24     You may use the following syntax to change or access data in this class.
25 
26     >>> stats = AttribDict()
27     >>> stats.network = 'BW'
28     >>> stats['station'] = 'ROTZ'
29     >>> stats.get('network')
30     'BW'
31     >>> stats['network']
32     'BW'
33     >>> stats.station
34     'ROTZ'
35     >>> x = stats.keys()
36     >>> x = sorted(x)
37     >>> x[0:3]
38     ['network', 'station']
39     """
40     defaults = {}
41     readonly = []
42 
43     def __init__(self, *args, **kwargs):
44         """
45         An AttribDict can be initialized in two ways. It can be given an
46         existing dictionary as a simple argument or alternatively all keyword
47         arguments will become (key, value) pairs.
48 
49         >>> attrib_dict_1 = AttribDict({"a":1, "b":2})
50         >>> attrib_dict_2 = AttribDict(a=1, b=2)
51         >>> print attrib_dict_1
52         AttribDict({'a': 1, 'b': 2})
53         >>> assert(attrib_dict_1 == attrib_dict_2)
54         """
55         # set default values directly
56         self.__dict__.update(self.defaults)
57         # use overwritable update method to set arguments
58         self.update(dict(*args, **kwargs))
59 
60     def __repr__(self):
61         return "%s(%s)" % (self.__class__.__name__, self.__dict__)
62 
63     def __getitem__(self, name, default=None):
64         try:
65             return self.__dict__[name]
66         except KeyError:
67             # check if we got any default value given at class level
68             if name in self.defaults:
69                 return self.defaults[name]
70             # if both are missing check for a given default value
71             if default is None:
72                 raise
73             return default
74 
75     def __setitem__(self, key, value):
76         if key in self.readonly:
77             msg = 'Attribute "%s" in %s object is read only!'
78             raise AttributeError(msg % (key, self.__class__.__name__))
79         self.__dict__[key] = value
80 
81     def __delitem__(self, name):
82         del self.__dict__[name]
83 
84     def __getstate__(self):
85         return self.__dict__
86 
87     def __setstate__(self, adict):
88         # set default values
89         self.__dict__.update(self.defaults)
90         # update with pickle dictionary
91         self.update(adict)
92 
93     __getattr__ = __getitem__
94     __setattr__ = __setitem__
95     __delattr__ = __delitem__
96 
97     def copy(self):
98         return self.__class__(self.__dict__.copy())
99 
100     def __deepcopy__(self, *args, **kwargs):  # @UnusedVariable
101         ad = self.__class__()
102         ad.update(self.__dict__)
103         return ad
104 
105     def update(self, adict={}):
106         for (key, value) in adict.iteritems():
107             if key in self.readonly:
108                 continue
109             self.__setitem__(key, value)
110 
111     def _pretty_str(self, priorized_keys=[], min_label_length=16):
112         """
113         Return better readable string representation of AttribDict object.
114 
115         :type priorized_keys: List of str, optional
116         :param priorized_keys: Keywords of current AttribtDict which will be
117             shown before all other keywords. Those keywords must exists
118             otherwise an exception will be raised. Defaults to empty list.
119         :type min_label_length: int, optional
120         :param min_label_length: Minimum label length for keywords. Defaults
121             to ``16``.
122         :return: String representation of current AttribDict object.
123         """
124         keys = self.keys()
125         # determine longest key name for alignment of all items
126         try:
127             i = max(max([len(k) for k in keys]), min_label_length)
128         except ValueError:
129             # no keys
130             return ""
131         pattern = "%%%ds: %%s" % (i)
132         # check if keys exist
133         other_keys = [k for k in keys if k not in priorized_keys]
134         # priorized keys first + all other keys
135         keys = priorized_keys + sorted(other_keys)
136         head = [pattern % (k, self.__dict__[k]) for k in keys]
137         return "\n".join(head)
138 
139     def __iter__(self):
140         return iter(self.__dict__)
141 
142     def __len__(self):
143         return len(self.__dict__)
144 
145 
146 if __name__ == '__main__':
147     import doctest
148     doctest.testmod(exclude_empty=True)
149
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/obspy/core/util/attribdict.py b/obspy/core/util/attribdict.py
--- a/obspy/core/util/attribdict.py
+++ b/obspy/core/util/attribdict.py
@@ -10,6 +10,7 @@
 """
 
 import collections
+import copy
 
 
 class AttribDict(collections.MutableMapping):
@@ -95,11 +96,11 @@
     __delattr__ = __delitem__
 
     def copy(self):
-        return self.__class__(self.__dict__.copy())
+        return copy.deepcopy(self)
 
     def __deepcopy__(self, *args, **kwargs):  # @UnusedVariable
         ad = self.__class__()
-        ad.update(self.__dict__)
+        ad.update(copy.deepcopy(self.__dict__))
         return ad
 
     def update(self, adict={}):

{"golden_diff": "diff --git a/obspy/core/util/attribdict.py b/obspy/core/util/attribdict.py\n--- a/obspy/core/util/attribdict.py\n+++ b/obspy/core/util/attribdict.py\n@@ -10,6 +10,7 @@\n \"\"\"\n \n import collections\n+import copy\n \n \n class AttribDict(collections.MutableMapping):\n@@ -95,11 +96,11 @@\n     __delattr__ = __delitem__\n \n     def copy(self):\n-        return self.__class__(self.__dict__.copy())\n+        return copy.deepcopy(self)\n \n     def __deepcopy__(self, *args, **kwargs):  # @UnusedVariable\n         ad = self.__class__()\n-        ad.update(self.__dict__)\n+        ad.update(copy.deepcopy(self.__dict__))\n         return ad\n \n     def update(self, adict={}):\n", "issue": "stream deepcopy issue\ntaken from http://lists.obspy.org/pipermail/obspy-users/2013-April/000451.html\n## \n\nhello all,\n\ni have some issues with deep copies of stream objects.\n\nit looks like format-specific dicts are \"linked\" in deep copy operations instead of being duplicated.\n\nthis happened after some obspy upgrades, since i'm pretty sure my code using deep copy functions worked correctly (and was not changed) until some months ago.\n\nhere's a sample session.\n\n``` python\n$ ipython\nPython 2.6.6 (r266:84292, Dec 26 2010, 22:31:48)\nType \"copyright\", \"credits\" or \"license\" for more information.\n\nIPython 0.10 -- An enhanced Interactive Python.\n?         -> Introduction and overview of IPython's features.\n%quickref -> Quick reference.\nhelp      -> Python's own help system.\nobject?   -> Details about 'object'. ?object also works, ?? prints more.\n\nIn [1]: from obspy import read\nIn [2]: from obspy.arclink.client import Client\nIn [3]: from obspy.core import UTCDateTime\nIn [4]: client = Client(user=\"test@obspy.de\")\nIn [5]: t = UTCDateTime(\"2009-08-24 00:20:03\")\n\n# let's grab some data first:\nIn [6]: st = client.getWaveform('BW', 'RJOB', '', 'EHZ', t, t + 30,\nroute=False)\nIn [7]: st[0].stats\nOut[7]: Stats({'network': 'BW', '_format': 'MSEED', 'mseed': AttribDict({'dataquality': 'D', 'record_length': 512, 'byteorder': '>', 'encoding': 'STEIM1'}), 'sampling_rate': 200.0, 'station': 'RJOB', 'location': '', 'starttime': UTCDateTime(2009, 8, 24, 0, 20, 3), 'delta': 0.0050000000000000001, 'calib': 1.0, 'npts': 6001, 'endtime': UTCDateTime(2009, 8, 24, 0, 20, 33), 'channel': 'EHZ'})\n\n# here comes the weird stuff:\nIn [8]: from copy import deepcopy as copy_deepcopy\nIn [9]: ct = copy_deepcopy(st)\nIn [10]: st[0].stats.mseed.dataquality = 'X'\nIn [11]: st[0].stats.mseed.dataquality\nOut[11]: 'X'\nIn [12]: ct[0].stats.mseed.dataquality\nOut[12]: 'X'\n\n# BUT, dict data in common header is deep-copied as expected:\nIn [13]: st[0].stats.network = 'XX'\nIn [14]: st[0].stats.network\nOut[14]: 'XX'\nIn [15]: ct[0].stats.network\nOut[15]: 'BW'\n```\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nAttribDict class for ObsPy.\n\n:copyright:\n    The ObsPy Development Team (devs@obspy.org)\n:license:\n    GNU Lesser General Public License, Version 3\n    (http://www.gnu.org/copyleft/lesser.html)\n\"\"\"\n\nimport collections\n\n\nclass AttribDict(collections.MutableMapping):\n    \"\"\"\n    A class which behaves like a dictionary.\n\n    :type data: dict, optional\n    :param data: Dictionary with initial keywords.\n\n    .. rubric:: Basic Usage\n\n    You may use the following syntax to change or access data in this class.\n\n    >>> stats = AttribDict()\n    >>> stats.network = 'BW'\n    >>> stats['station'] = 'ROTZ'\n    >>> stats.get('network')\n    'BW'\n    >>> stats['network']\n    'BW'\n    >>> stats.station\n    'ROTZ'\n    >>> x = stats.keys()\n    >>> x = sorted(x)\n    >>> x[0:3]\n    ['network', 'station']\n    \"\"\"\n    defaults = {}\n    readonly = []\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"\n        An AttribDict can be initialized in two ways. It can be given an\n        existing dictionary as a simple argument or alternatively all keyword\n        arguments will become (key, value) pairs.\n\n        >>> attrib_dict_1 = AttribDict({\"a\":1, \"b\":2})\n        >>> attrib_dict_2 = AttribDict(a=1, b=2)\n        >>> print attrib_dict_1\n        AttribDict({'a': 1, 'b': 2})\n        >>> assert(attrib_dict_1 == attrib_dict_2)\n        \"\"\"\n        # set default values directly\n        self.__dict__.update(self.defaults)\n        # use overwritable update method to set arguments\n        self.update(dict(*args, **kwargs))\n\n    def __repr__(self):\n        return \"%s(%s)\" % (self.__class__.__name__, self.__dict__)\n\n    def __getitem__(self, name, default=None):\n        try:\n            return self.__dict__[name]\n        except KeyError:\n            # check if we got any default value given at class level\n            if name in self.defaults:\n                return self.defaults[name]\n            # if both are missing check for a given default value\n            if default is None:\n                raise\n            return default\n\n    def __setitem__(self, key, value):\n        if key in self.readonly:\n            msg = 'Attribute \"%s\" in %s object is read only!'\n            raise AttributeError(msg % (key, self.__class__.__name__))\n        self.__dict__[key] = value\n\n    def __delitem__(self, name):\n        del self.__dict__[name]\n\n    def __getstate__(self):\n        return self.__dict__\n\n    def __setstate__(self, adict):\n        # set default values\n        self.__dict__.update(self.defaults)\n        # update with pickle dictionary\n        self.update(adict)\n\n    __getattr__ = __getitem__\n    __setattr__ = __setitem__\n    __delattr__ = __delitem__\n\n    def copy(self):\n        return self.__class__(self.__dict__.copy())\n\n    def __deepcopy__(self, *args, **kwargs):  # @UnusedVariable\n        ad = self.__class__()\n        ad.update(self.__dict__)\n        return ad\n\n    def update(self, adict={}):\n        for (key, value) in adict.iteritems():\n            if key in self.readonly:\n                continue\n            self.__setitem__(key, value)\n\n    def _pretty_str(self, priorized_keys=[], min_label_length=16):\n        \"\"\"\n        Return better readable string representation of AttribDict object.\n\n        :type priorized_keys: List of str, optional\n        :param priorized_keys: Keywords of current AttribtDict which will be\n            shown before all other keywords. Those keywords must exists\n            otherwise an exception will be raised. Defaults to empty list.\n        :type min_label_length: int, optional\n        :param min_label_length: Minimum label length for keywords. Defaults\n            to ``16``.\n        :return: String representation of current AttribDict object.\n        \"\"\"\n        keys = self.keys()\n        # determine longest key name for alignment of all items\n        try:\n            i = max(max([len(k) for k in keys]), min_label_length)\n        except ValueError:\n            # no keys\n            return \"\"\n        pattern = \"%%%ds: %%s\" % (i)\n        # check if keys exist\n        other_keys = [k for k in keys if k not in priorized_keys]\n        # priorized keys first + all other keys\n        keys = priorized_keys + sorted(other_keys)\n        head = [pattern % (k, self.__dict__[k]) for k in keys]\n        return \"\\n\".join(head)\n\n    def __iter__(self):\n        return iter(self.__dict__)\n\n    def __len__(self):\n        return len(self.__dict__)\n\n\nif __name__ == '__main__':\n    import doctest\n    doctest.testmod(exclude_empty=True)\n", "path": "obspy/core/util/attribdict.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nAttribDict class for ObsPy.\n\n:copyright:\n    The ObsPy Development Team (devs@obspy.org)\n:license:\n    GNU Lesser General Public License, Version 3\n    (http://www.gnu.org/copyleft/lesser.html)\n\"\"\"\n\nimport collections\nimport copy\n\n\nclass AttribDict(collections.MutableMapping):\n    \"\"\"\n    A class which behaves like a dictionary.\n\n    :type data: dict, optional\n    :param data: Dictionary with initial keywords.\n\n    .. rubric:: Basic Usage\n\n    You may use the following syntax to change or access data in this class.\n\n    >>> stats = AttribDict()\n    >>> stats.network = 'BW'\n    >>> stats['station'] = 'ROTZ'\n    >>> stats.get('network')\n    'BW'\n    >>> stats['network']\n    'BW'\n    >>> stats.station\n    'ROTZ'\n    >>> x = stats.keys()\n    >>> x = sorted(x)\n    >>> x[0:3]\n    ['network', 'station']\n    \"\"\"\n    defaults = {}\n    readonly = []\n\n    def __init__(self, *args, **kwargs):\n        \"\"\"\n        An AttribDict can be initialized in two ways. It can be given an\n        existing dictionary as a simple argument or alternatively all keyword\n        arguments will become (key, value) pairs.\n\n        >>> attrib_dict_1 = AttribDict({\"a\":1, \"b\":2})\n        >>> attrib_dict_2 = AttribDict(a=1, b=2)\n        >>> print attrib_dict_1\n        AttribDict({'a': 1, 'b': 2})\n        >>> assert(attrib_dict_1 == attrib_dict_2)\n        \"\"\"\n        # set default values directly\n        self.__dict__.update(self.defaults)\n        # use overwritable update method to set arguments\n        self.update(dict(*args, **kwargs))\n\n    def __repr__(self):\n        return \"%s(%s)\" % (self.__class__.__name__, self.__dict__)\n\n    def __getitem__(self, name, default=None):\n        try:\n            return self.__dict__[name]\n        except KeyError:\n            # check if we got any default value given at class level\n            if name in self.defaults:\n                return self.defaults[name]\n            # if both are missing check for a given default value\n            if default is None:\n                raise\n            return default\n\n    def __setitem__(self, key, value):\n        if key in self.readonly:\n            msg = 'Attribute \"%s\" in %s object is read only!'\n            raise AttributeError(msg % (key, self.__class__.__name__))\n        self.__dict__[key] = value\n\n    def __delitem__(self, name):\n        del self.__dict__[name]\n\n    def __getstate__(self):\n        return self.__dict__\n\n    def __setstate__(self, adict):\n        # set default values\n        self.__dict__.update(self.defaults)\n        # update with pickle dictionary\n        self.update(adict)\n\n    __getattr__ = __getitem__\n    __setattr__ = __setitem__\n    __delattr__ = __delitem__\n\n    def copy(self):\n        return copy.deepcopy(self)\n\n    def __deepcopy__(self, *args, **kwargs):  # @UnusedVariable\n        ad = self.__class__()\n        ad.update(copy.deepcopy(self.__dict__))\n        return ad\n\n    def update(self, adict={}):\n        for (key, value) in adict.iteritems():\n            if key in self.readonly:\n                continue\n            self.__setitem__(key, value)\n\n    def _pretty_str(self, priorized_keys=[], min_label_length=16):\n        \"\"\"\n        Return better readable string representation of AttribDict object.\n\n        :type priorized_keys: List of str, optional\n        :param priorized_keys: Keywords of current AttribtDict which will be\n            shown before all other keywords. Those keywords must exists\n            otherwise an exception will be raised. Defaults to empty list.\n        :type min_label_length: int, optional\n        :param min_label_length: Minimum label length for keywords. Defaults\n            to ``16``.\n        :return: String representation of current AttribDict object.\n        \"\"\"\n        keys = self.keys()\n        # determine longest key name for alignment of all items\n        try:\n            i = max(max([len(k) for k in keys]), min_label_length)\n        except ValueError:\n            # no keys\n            return \"\"\n        pattern = \"%%%ds: %%s\" % (i)\n        # check if keys exist\n        other_keys = [k for k in keys if k not in priorized_keys]\n        # priorized keys first + all other keys\n        keys = priorized_keys + sorted(other_keys)\n        head = [pattern % (k, self.__dict__[k]) for k in keys]\n        return \"\\n\".join(head)\n\n    def __iter__(self):\n        return iter(self.__dict__)\n\n    def __len__(self):\n        return len(self.__dict__)\n\n\nif __name__ == '__main__':\n    import doctest\n    doctest.testmod(exclude_empty=True)\n", "path": "obspy/core/util/attribdict.py"}]}