1717from __future__ import absolute_import
1818
1919import copy
20+ from typing import Dict , Any
2021
2122import google .cloud ._helpers # type: ignore
2223
@@ -77,28 +78,29 @@ def _get_routine_reference(self, routine_id):
7778class AccessEntry (object ):
7879 """Represents grant of an access role to an entity.
7980
80- An entry must have exactly one of the allowed :attr:`ENTITY_TYPES`. If
81- anything but ``view`` or ``routine`` are set, a ``role`` is also required.
82- ``role `` is omitted for ``view `` and ``routine``, because they are always
83- read-only.
81+ An entry must have exactly one of the allowed
82+ :class:`google.cloud.bigquery.enums.EntityTypes`. If anything but ``view``, ``routine``,
83+ or ``dataset `` are set, a ``role `` is also required. ``role`` is omitted for ``view``,
84+ ``routine``, ``dataset``, because they are always read-only.
8485
8586 See https://cloud.google.com/bigquery/docs/reference/rest/v2/datasets.
8687
8788 Args:
8889 role (str):
8990 Role granted to the entity. The following string values are
9091 supported: `'READER'`, `'WRITER'`, `'OWNER'`. It may also be
91- :data:`None` if the ``entity_type`` is ``view`` or ``routine ``.
92+ :data:`None` if the ``entity_type`` is ``view``, ``routine``, or ``dataset ``.
9293
9394 entity_type (str):
94- Type of entity being granted the role. One of :attr:`ENTITY_TYPES`.
95+ Type of entity being granted the role. See
96+ :class:`google.cloud.bigquery.enums.EntityTypes` for supported types.
9597
9698 entity_id (Union[str, Dict[str, str]]):
97- If the ``entity_type`` is not 'view' or 'routine ', the ``entity_id``
98- is the ``str`` ID of the entity being granted the role. If the
99- ``entity_type`` is 'view' or 'routine', the ``entity_id`` is a ``dict``
100- representing the view or routine from a different dataset to grant
101- access to in the following format for views::
99+ If the ``entity_type`` is not 'view', 'routine', or 'dataset ', the
100+ ``entity_id`` is the ``str`` ID of the entity being granted the role. If
101+ the ``entity_type`` is 'view' or 'routine', the ``entity_id`` is a ``dict``
102+ representing the view or routine from a different dataset to grant access
103+ to in the following format for views::
102104
103105 {
104106 'projectId': string,
@@ -114,11 +116,22 @@ class AccessEntry(object):
114116 'routineId': string
115117 }
116118
119+ If the ``entity_type`` is 'dataset', the ``entity_id`` is a ``dict`` that includes
120+ a 'dataset' field with a ``dict`` representing the dataset and a 'target_types'
121+ field with a ``str`` value of the dataset's resource type::
122+
123+ {
124+ 'dataset': {
125+ 'projectId': string,
126+ 'datasetId': string,
127+ },
128+ 'target_types: 'VIEWS'
129+ }
130+
117131 Raises:
118132 ValueError:
119- If the ``entity_type`` is not among :attr:`ENTITY_TYPES`, or if a
120- ``view`` or a ``routine`` has ``role`` set, or a non ``view`` and
121- non ``routine`` **does not** have a ``role`` set.
133+ If a ``view``, ``routine``, or ``dataset`` has ``role`` set, or a non ``view``,
134+ non ``routine``, and non ``dataset`` **does not** have a ``role`` set.
122135
123136 Examples:
124137 >>> entry = AccessEntry('OWNER', 'userByEmail', 'user@example.com')
@@ -131,27 +144,9 @@ class AccessEntry(object):
131144 >>> entry = AccessEntry(None, 'view', view)
132145 """
133146
134- ENTITY_TYPES = frozenset (
135- [
136- "userByEmail" ,
137- "groupByEmail" ,
138- "domain" ,
139- "specialGroup" ,
140- "view" ,
141- "iamMember" ,
142- "routine" ,
143- ]
144- )
145- """Allowed entity types."""
146-
147- def __init__ (self , role , entity_type , entity_id ) -> None :
148- if entity_type not in self .ENTITY_TYPES :
149- message = "Entity type %r not among: %s" % (
150- entity_type ,
151- ", " .join (self .ENTITY_TYPES ),
152- )
153- raise ValueError (message )
154- if entity_type in ("view" , "routine" ):
147+ def __init__ (self , role = None , entity_type = None , entity_id = None ) -> None :
148+ self ._properties : Dict [str , Any ] = {}
149+ if entity_type in ("view" , "routine" , "dataset" ):
155150 if role is not None :
156151 raise ValueError (
157152 "Role must be None for a %r. Received "
@@ -162,7 +157,6 @@ def __init__(self, role, entity_type, entity_id) -> None:
162157 raise ValueError (
163158 "Role must be set for entity " "type %r" % (entity_type ,)
164159 )
165-
166160 self ._role = role
167161 self ._entity_type = entity_type
168162 self ._entity_id = entity_id
@@ -214,7 +208,8 @@ def to_api_repr(self):
214208 Returns:
215209 Dict[str, object]: Access entry represented as an API resource
216210 """
217- resource = {self ._entity_type : self ._entity_id }
211+ resource = copy .deepcopy (self ._properties )
212+ resource [self ._entity_type ] = self ._entity_id
218213 if self ._role is not None :
219214 resource ["role" ] = self ._role
220215 return resource
@@ -241,7 +236,10 @@ def from_api_repr(cls, resource: dict) -> "AccessEntry":
241236 entity_type , entity_id = entry .popitem ()
242237 if len (entry ) != 0 :
243238 raise ValueError ("Entry has unexpected keys remaining." , entry )
244- return cls (role , entity_type , entity_id )
239+
240+ config = cls (role , entity_type , entity_id )
241+ config ._properties = copy .deepcopy (resource )
242+ return config
245243
246244
247245class DatasetReference (object ):
0 commit comments