Repository: googleapis/google-cloud-python

Issue:
Storage: bucket.labels surprisingly returns a deepcopy
I expected this to work:

```python
    bucket = storage_client.get_bucket(bucket_name)
    bucket.labels['example'] = 'label'
    bucket.patch()
```

Turns out `bucket.labels` returns a deepcopy, so I have to do this instead:

```python
    bucket = storage_client.get_bucket(bucket_name)
    labels = bucket.labels
    labels['example'] = 'label'
    bucket.labels = labels
    bucket.patch()
```


Discussion:
I'm not sure what the right move is. There are definitely pros and cons here, i.e. I can imagine a user surprised they mutated the `Bucket` when they didn't intend to.
Yeah I agree. Could we at least document it better? The docstring for labels is actually totally wrong: https://google-cloud-python.readthedocs.io/en/latest/storage/buckets.html#google.cloud.storage.bucket.Bucket.labels
Copy-pasta strikes again!
The other properties which contain non-scalar values (`cors`, `lifecycle_rules`) also return copies.  I'm working on a PR which adds the following note (modified to use values appropriate to each one):

```rst
        .. note::

           The getter for this property returns a list which contains 
           *copies* of the bucket's CORS policy mappings.  Mutating the list
           or one of its dicts has no effect unless you then re-assign the
           dict via the setter.  E.g.:

           >>> cors = bucket.cors
           >>> cors.append({'origin': '/foo', ...})
           >>> del policies[0]
           >>> bucket.cors = cors
``` 

Resolving patch:
diff --git a/storage/google/cloud/storage/bucket.py b/storage/google/cloud/storage/bucket.py
--- a/storage/google/cloud/storage/bucket.py
+++ b/storage/google/cloud/storage/bucket.py
@@ -544,6 +544,19 @@ def cors(self):
         See http://www.w3.org/TR/cors/ and
              https://cloud.google.com/storage/docs/json_api/v1/buckets
 
+        .. note::
+
+           The getter for this property returns a list which contains
+           *copies* of the bucket's CORS policy mappings.  Mutating the list
+           or one of its dicts has no effect unless you then re-assign the
+           dict via the setter.  E.g.:
+
+           >>> policies = bucket.cors
+           >>> policies.append({'origin': '/foo', ...})
+           >>> policies[1]['maxAgeSeconds'] = 3600
+           >>> del policies[0]
+           >>> bucket.cors = policies
+
         :setter: Set CORS policies for this bucket.
         :getter: Gets the CORS policies for this bucket.
 
@@ -567,11 +580,22 @@ def cors(self, entries):
 
     @property
     def labels(self):
-        """Retrieve or set CORS policies configured for this bucket.
+        """Retrieve or set labels assigned to this bucket.
 
         See
         https://cloud.google.com/storage/docs/json_api/v1/buckets#labels
 
+        .. note::
+
+           The getter for this property returns a dict which is a *copy*
+           of the bucket's labels.  Mutating that dict has no effect unless
+           you then re-assign the dict via the setter.  E.g.:
+
+           >>> labels = bucket.labels
+           >>> labels['new_key'] = 'some-label'
+           >>> del labels['old_key']
+           >>> bucket.labels = labels
+
         :setter: Set labels for this bucket.
         :getter: Gets the labels for this bucket.
 
@@ -585,7 +609,7 @@ def labels(self):
 
     @labels.setter
     def labels(self, mapping):
-        """Set CORS policies configured for this bucket.
+        """Set labels assigned to this bucket.
 
         See
         https://cloud.google.com/storage/docs/json_api/v1/buckets#labels
@@ -627,6 +651,19 @@ def lifecycle_rules(self):
         See https://cloud.google.com/storage/docs/lifecycle and
              https://cloud.google.com/storage/docs/json_api/v1/buckets
 
+        .. note::
+
+           The getter for this property returns a list which contains
+           *copies* of the bucket's lifecycle rules mappings.  Mutating the
+           list or one of its dicts has no effect unless you then re-assign
+           the dict via the setter.  E.g.:
+
+           >>> rules = bucket.lifecycle_rules
+           >>> rules.append({'origin': '/foo', ...})
+           >>> rules[1]['rule']['action']['type'] = 'Delete'
+           >>> del rules[0]
+           >>> bucket.lifecycle_rules = rules
+
         :setter: Set lifestyle rules for this bucket.
         :getter: Gets the lifestyle rules for this bucket.
 


Test patch: