Repository: googleapis/google-cloud-python

Issue:
Resource Manager Labels Update is broke
The resource manager `update` fails when setting a label, in the style according to the docs.

```python
>>> client = resource_manager.Client()
>>> project = client.fetch_project('purple-spaceship-124')
>>> project.labels['color'] = 'purple'
>>> project
<Project: None ('purple-spaceship-124')>
>>> project.update()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/waprin/.virtualenvs/resourcemanager/lib/python2.7/site-packages/google/cloud/resource_manager/project.py", line 207, in update
    method='PUT', path=self.path, data=data)
  File "/Users/waprin/.virtualenvs/resourcemanager/lib/python2.7/site-packages/google/cloud/_http.py", line 336, in api_request
    error_info=method + ' ' + url)
google.cloud.exceptions.BadRequest: 400 Request contains an invalid argument. (PUT https://cloudresourcemanager.googleapis.com/v1beta1/projects/purple-spaceship-124)
```

Will likely submit a PR to fix this myself, digging into it, making issue in case I'm doing something silly.


Discussion:
Thanks @waprin 

Resolving patch:
diff --git a/resource_manager/google/cloud/resource_manager/project.py b/resource_manager/google/cloud/resource_manager/project.py
--- a/resource_manager/google/cloud/resource_manager/project.py
+++ b/resource_manager/google/cloud/resource_manager/project.py
@@ -58,6 +58,7 @@ def __init__(self, project_id, client, name=None, labels=None):
         self.number = None
         self.labels = labels or {}
         self.status = None
+        self.parent = None
 
     def __repr__(self):
         return '<Project: %r (%r)>' % (self.name, self.project_id)
@@ -85,6 +86,8 @@ def set_properties_from_api_repr(self, resource):
         self.number = resource['projectNumber']
         self.labels = resource.get('labels', {})
         self.status = resource['lifecycleState']
+        if 'parent' in resource:
+            self.parent = resource['parent']
 
     @property
     def full_name(self):
@@ -202,7 +205,12 @@ def update(self, client=None):
         """
         client = self._require_client(client)
 
-        data = {'name': self.name, 'labels': self.labels}
+        data = {
+            'name': self.name,
+            'labels': self.labels,
+            'parent': self.parent,
+        }
+
         resp = client._connection.api_request(
             method='PUT', path=self.path, data=data)
         self.set_properties_from_api_repr(resp)


Test patch:
diff --git a/resource_manager/unit_tests/test_project.py b/resource_manager/unit_tests/test_project.py
--- a/resource_manager/unit_tests/test_project.py
+++ b/resource_manager/unit_tests/test_project.py
@@ -35,6 +35,7 @@ def test_constructor_defaults(self):
         self.assertIsNone(project.number)
         self.assertEqual(project.labels, {})
         self.assertIsNone(project.status)
+        self.assertIsNone(project.parent)
 
     def test_constructor_explicit(self):
         client = object()
@@ -49,6 +50,7 @@ def test_constructor_explicit(self):
         self.assertIsNone(project.number)
         self.assertEqual(project.labels, LABELS)
         self.assertIsNone(project.status)
+        self.assertIsNone(project.parent)
 
     def test_from_api_repr(self):
         client = object()
@@ -57,11 +59,14 @@ def test_from_api_repr(self):
         PROJECT_NUMBER = 12345678
         PROJECT_LABELS = {'env': 'prod'}
         PROJECT_LIFECYCLE_STATE = 'ACTIVE'
+        PARENT = {'type': 'organization', 'id': '433637338579'}
+
         resource = {'projectId': PROJECT_ID,
                     'name': PROJECT_NAME,
                     'projectNumber': PROJECT_NUMBER,
                     'labels': PROJECT_LABELS,
-                    'lifecycleState': PROJECT_LIFECYCLE_STATE}
+                    'lifecycleState': PROJECT_LIFECYCLE_STATE,
+                    'parent': PARENT}
         project = self._get_target_class().from_api_repr(resource, client)
         self.assertEqual(project.project_id, PROJECT_ID)
         self.assertEqual(project._client, client)
@@ -69,6 +74,7 @@ def test_from_api_repr(self):
         self.assertEqual(project.number, PROJECT_NUMBER)
         self.assertEqual(project.labels, PROJECT_LABELS)
         self.assertEqual(project.status, PROJECT_LIFECYCLE_STATE)
+        self.assertEqual(project.parent, PARENT)
 
     def test_full_name(self):
         PROJECT_ID = 'project-id'
@@ -94,6 +100,10 @@ def test_create(self):
             'name': 'Project Name',
             'labels': {},
             'lifecycleState': 'ACTIVE',
+            'parent': {
+                'type': 'organization',
+                'id': '433637338589',
+            },
         }
         connection = _Connection(PROJECT_RESOURCE)
         client = _Client(connection=connection)
@@ -123,6 +133,10 @@ def test_reload(self):
             'name': 'Project Name',
             'labels': {'env': 'prod'},
             'lifecycleState': 'ACTIVE',
+            'parent': {
+                'type': 'organization',
+                'id': '433637338579',
+            },
         }
         connection = _Connection(PROJECT_RESOURCE)
         client = _Client(connection=connection)
@@ -197,6 +211,7 @@ def test_update(self):
             'data': {
                 'name': PROJECT_NAME,
                 'labels': LABELS,
+                'parent': None,
             },
             'path': project.path,
         }
@@ -211,6 +226,10 @@ def test_delete_without_reload_data(self):
             'name': 'Project Name',
             'labels': {'env': 'prod'},
             'lifecycleState': 'ACTIVE',
+            'parent': {
+                'type': 'organization',
+                'id': '433637338579',
+            },
         }
         connection = _Connection(PROJECT_RESOURCE)
         client = _Client(connection=connection)
@@ -234,6 +253,10 @@ def test_delete_with_reload_data(self):
             'name': 'Project Name',
             'labels': {'env': 'prod'},
             'lifecycleState': 'ACTIVE',
+            'parent': {
+                'type': 'organization',
+                'id': '433637338579',
+            },
         }
         DELETING_PROJECT = PROJECT_RESOURCE.copy()
         DELETING_PROJECT['lifecycleState'] = NEW_STATE = 'DELETE_REQUESTED'
@@ -268,6 +291,10 @@ def test_undelete_without_reload_data(self):
             'name': 'Project Name',
             'labels': {'env': 'prod'},
             'lifecycleState': 'DELETE_REQUESTED',
+            'parent': {
+                'type': 'organization',
+                'id': '433637338579',
+            },
         }
         connection = _Connection(PROJECT_RESOURCE)
         client = _Client(connection=connection)
@@ -291,6 +318,10 @@ def test_undelete_with_reload_data(self):
             'name': 'Project Name',
             'labels': {'env': 'prod'},
             'lifecycleState': 'DELETE_REQUESTED',
+            'parent': {
+                'type': 'organization',
+                'id': '433637338579',
+            },
         }
         UNDELETED_PROJECT = PROJECT_RESOURCE.copy()
         UNDELETED_PROJECT['lifecycleState'] = NEW_STATE = 'ACTIVE'