Skip to content

Drive object

DriveObject

Base class for a Google Drive Object

Includes common, core functionality including creation, manipulation, deletion, and more. Other GSuite objects are derived from this class, including:

  • File
  • Folder
  • Spreadsheet
  • Presentation
  • Document
Source code in pygsuite/drive/drive_object.py
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
class DriveObject:
    """Base class for a Google Drive Object

    Includes common, core functionality including creation, manipulation, deletion, and more.
    Other GSuite objects are derived from this class, including:

    - File
    - Folder
    - Spreadsheet
    - Presentation
    - Document
    """

    _mimetype = MimeType.UNKNOWN
    _base_url = "https://drive.google.com/file/d/{}/view"

    def __init__(self, id: str = None, client: Optional[Resource] = None):

        self.id = parse_id(id) if id else None
        # object-specific client
        self.client = client

        # metadata cache
        self._metadata = None

    @lazy_property
    def _drive_client(self):
        """Google Drive API client used for file manipulations"""
        return Clients.drive_client_v3

    @classmethod
    def _create(
        cls,
        name: Optional[str] = None,
        parent_folder_ids: Optional[List[str]] = None,
        mimetype: Optional[Union[str, MimeType]] = None,
        media_body: Optional[Union[BytesIO, MediaFileUpload, MediaIoBaseUpload]] = None,
        starred: bool = False,
        extra_body: Optional[dict] = None,
        drive_client: Optional[Resource] = None,
        object_client: Optional[Resource] = None,
        **kwargs,
    ):
        """Base create method.

        Args:
            name (str): Name of the file.
            parent_folder_ids (List[str]): The IDs of the parent folders which contain the folder.
                If not specified as part of a create request, the file will be placed directly in the user's My Drive folder.
            mimetype (Union[str, MimeType]): Specified type of the file to create.
            media_body (BytesIO, MediaFileUpload, MediaIoBaseUpload): Content for the file.
            starred (bool): Whether the user has starred the file.
            extra_body (dict): Extra parameters for the request body.
            drive_client (Resource): client connection to the Drive API used to create file.
            object_client (Resource): optional domain client (e.g. SHEETS client) used by the created object.
        """

        # establish a client
        drive_client = drive_client or Clients.drive_client_v3

        # handle Google mimetypes
        mimetype = str(mimetype) if mimetype is not None else None

        # create request body
        body = {
            "name": name,
            "mimeType": mimetype,
            "parents": parent_folder_ids,
            "starred": starred,
        }

        if extra_body:
            body.update(extra_body)

        # handle media conversion for bytes-like objects
        if isinstance(media_body, BytesIO):
            # if a mimetype is not provided, find best match
            if not mimetype:
                logging.warning("No mimetype specified, attempting to determine one.")
                mimetype = filetype.guess_mime(media_body.read(2048))
                logging.info(f"MimeType found for file: {mimetype}")

            media_body = MediaIoBaseUpload(fd=media_body, mimetype=mimetype)

        # execute files.create request and return File object
        file = (
            drive_client.files()
            .create(body=body, media_body=media_body, fields="id", **kwargs)
            .execute()
        )

        return DriveObject(id=file.get("id"), client=object_client)

    @classmethod
    def create(
        cls,
        name: Optional[str] = None,
        parent_folder_ids: Optional[List[str]] = None,
        mimetype: Optional[Union[str, MimeType]] = None,
        media_body: Optional[Union[BytesIO, MediaFileUpload, MediaIoBaseUpload]] = None,
        starred: bool = False,
        extra_body: Optional[dict] = None,
        drive_client: Optional[Resource] = None,
        object_client: Optional[Resource] = None,
        **kwargs,
    ):
        """Create a new Google Drive object (e.g. File, Folder, Spreadsheet, Presentation, Document)

        Args:
            name (str): Name of the file.
            parent_folder_ids (List[str]): The IDs of the parent folders which contain the file.
                If not specified as part of a create request, the file will be placed directly in the user's My Drive folder.
            mimetype (Union[str, MimeType]): Specified type of the file to create.
            media_body (BytesIO, MediaFileUpload, MediaIoBaseUpload): Content for the file.
            starred (bool): Whether the user has starred the file.
            extra_body (dict): Extra parameters for the request body.
            drive_client (Resource): client connection to the Drive API used to create file.
            object_client (Resource): optional domain client (e.g. SHEETS client) used by the created object.

        Returns the newly created pygsuite object.
        """
        drive_client = drive_client or Clients.drive_client_v3
        mimetype = mimetype or cls._mimetype

        new_file = cls._create(
            name=name,
            parent_folder_ids=parent_folder_ids,
            mimetype=str(mimetype),
            media_body=media_body,
            starred=starred,
            extra_body=extra_body,
            drive_client=drive_client,
            **kwargs,
        )
        return cls(id=new_file.id, client=object_client)

    @classmethod
    def upload(
        cls,
        filepath: str,
        name: Optional[str] = None,
        parent_folder_ids: Optional[List[str]] = None,
        mimetype: Optional[Union[str, MimeType]] = None,
        convert_to: Optional[Union[str, GoogleDocFormat]] = None,
        starred: bool = False,
        drive_client: Optional[Resource] = None,
        object_client: Optional[Resource] = None,
        **kwargs,
    ):
        """Method to upload a local file to Google Drive.

        Args:
            filepath (str): Filepath of the file to upload.
            name (str): Name of the file in Google Drive once uploaded.
            parent_folder_ids (List[str]): The IDs of the parent folders which contain the file.
                If not specified as part of a create request, the file will be placed directly in the user's My Drive folder.
            mimetype (Union[str, MimeType]): Specified type of the file to create. mimetype is automatically determined if not specified.
            convert_to (str, GoogleDocFormat): Convert the upload file into a Google App file (e.g. CSV -> Google Sheet)
            starred (bool): Whether the user has starred the file.
            drive_client (Resource): client connection to the Drive API used to create file.
            object_client (Resource): optional domain client (e.g. SHEETS client) used by the created object.
        """
        # establish a client
        drive_client = drive_client or Clients.drive_client_v3

        # get upload file size
        filesize = os.path.getsize(filepath)

        # establish if the upload should be resumable
        # TODO: expand upon this and determine how this should work for users
        resumable = filesize > DRIVE_FILE_MAX_SINGLE_UPLOAD_SIZE

        # get filename and extension
        _, extension = os.path.splitext(filepath)

        # name of the file in Drive
        name = name if name else os.path.basename(filepath)

        # handle MimeType enums
        mimetype = str(mimetype) if mimetype is not None else None

        # first use the given mimetype (which can be None) to specify the upload file's mimetype
        media_body = MediaFileUpload(
            filename=filepath, mimetype=mimetype, chunksize=-1, resumable=resumable
        )

        # next, if converting, determine the mimetype of the Google app to convert to
        if convert_to:
            # try to coerce str into a GoogleDocFormat
            if isinstance(convert_to, str):
                try:
                    convert_to = GoogleDocFormat[convert_to.upper()]
                except Exception as e:
                    raise ValueError(
                        f"For converting to a Google Document, please use one of the following inputs:\n{[item.name for item in GoogleDocFormat]}"
                    ) from e

            # find the corresponding mime type of the extension of the upload file
            try:
                mimetype = FILE_MIME_TYPE_MAP[convert_to][extension.lower()]
            except Exception as e:
                raise ValueError(
                    f"File extension {extension.lower()} is not supported with the Google Document type {convert_to.value}"
                ) from e

        file = cls.create(
            name=name,
            parent_folder_ids=parent_folder_ids,
            mimetype=mimetype,
            media_body=media_body,
            starred=starred,
            drive_client=drive_client,
            object_client=object_client,
            **kwargs,
        )

        return file

    @classmethod
    def get_safe(
        cls,
        name: str,
        exact_match: bool = True,
        parent_folder_ids: Optional[List[str]] = None,
        mimetype: Optional[Union[MimeType, str]] = None,
        support_all_drives: bool = True,
        extra_conditions: Optional[Union[QueryString, QueryStringGroup]] = None,
        drive_client: Optional[Resource] = None,
        object_client: Optional[Resource] = None,
    ):
        """Get a file or create one if not found

        Args:
            name (str): The case-sensitive name of the file to search for.
            exact_match (bool): Whether to only match the given name exactly, or return any name containing the string.
            parent_folder_ids (List[str]): The IDs of the parent folders which contain the file.
            mimetype (Union[GoogleMimeType, str]): A specific Google Docs type to match.
            support_all_drives (bool): Whether or not to search both My Drives and shared drives.
            extra_conditions (Union[QueryString, QueryStringGroup]): Any additional queries to pass to the files search.
            drive_client (Resource): client connection to the Drive API used to create file.
            object_client (Resource): optional domain client (e.g. SHEETS client) used by the created object.

        Returns:
            An instantiated File object, or specific Google Docs type object, such as Spreadsheet, Presentation, or Document.
        """
        # establish a client
        drive_client = drive_client or Clients.drive_client_v3
        # always restrict to the mimetype if set
        if not mimetype and cls._mimetype != MimeType.UNKNOWN:
            mimetype = cls._mimetype
        # name match query
        operator = Operator.EQUAL if exact_match else Operator.CONTAINS
        name_query = QueryString(QueryTerm.NAME, operator, name)
        base_query = name_query
        query_components: List[Union[QueryString, QueryStringGroup]] = [base_query]
        # optional folder query
        if parent_folder_ids:
            folder_query: Union[QueryString, QueryStringGroup]
            folder_queries = []
            for id in parent_folder_ids:
                folder_query = QueryString(QueryTerm.PARENTS, Operator.IN, id)
                folder_queries.append(folder_query)
            folder_query = QueryStringGroup(
                folder_queries, [Connector.OR for query in folder_queries[:-1]]
            )
            query_components.append(folder_query)

        # optional mimetype query
        if mimetype:
            mimetype = str(mimetype)
            type_query = QueryString(QueryTerm.MIMETYPE, Operator.EQUAL, mimetype)
            query_components.append(type_query)

        # optional auxiliary query
        if extra_conditions:
            query_components.append(extra_conditions)

        query = QueryStringGroup(query_components)
        # we are not handling multiple pages of matches here because
        # we only return the first match anyway
        response = (
            drive_client.files()
            .list(
                q=query.formatted,
                spaces="drive",
                fields="nextPageToken, files(id, name)",
                pageToken=None,
                supportsAllDrives=support_all_drives,
                includeItemsFromAllDrives=support_all_drives,
            )
            .execute()
        )

        files = response.get("files", [])
        if files:
            # TODO: better method for determining *best* match from a set of matches
            _logger.info("Matching file found, returning existing file...")
            return cls(files[0].get("id"), object_client)
        else:
            _logger.info("No matching file found, creating file now...")
            return cls.create(
                name=name,
                parent_folder_ids=parent_folder_ids,
                mimetype=mimetype,
                object_client=object_client,
            )

    def copy(self):

        raise NotImplementedError

    def move(
        self, destination_folder_ids: List[str], current_folder_ids: Optional[List[str]] = None
    ):
        """Move the file from a current folder to a new folder.
        If no current folder is specified, the current folder ID is derived.

        Args:
            destination_folder_id (str): A list of the folder IDs to move the file to.
            current_folder_id (str): A list of the current folder IDs to remove the file from.
        """
        if not current_folder_ids:
            current_folder_ids = self.fetch_metadata().get("parents")

        response = (
            self._drive_client.files()
            .update(
                fileId=self.id,
                addParents=destination_folder_ids,
                removeParents=current_folder_ids,
                fields="parents",
            )
            .execute()
        )

        return response.get("parents")

    def _cache_local_metadata_with_args_and_return(self, fields: List[str]):
        """Local metadata only has a potential subset of fields. Call this to rebuild
        with another potential set."""
        output: Dict = {}
        self._metadata = (
            self._drive_client.files().get(fileId=self.id, fields=f"{', '.join(fields)}")
        ).execute()

        if self._metadata:
            for field in fields:
                output[field] = self._metadata[field]
        return output

    def fetch_metadata(
        self, ignore_cache: bool = False, fields: Optional[List[str]] = None
    ) -> dict:
        """Metadata for the file, based on the files.get method.
        Default fields include kind, name, and mimetype. Additional fields available are found here:
        https://googleapis.github.io/google-api-python-client/docs/dyn/drive_v3.files.html#get

        Args:
            ignore_cache (bool): whether to first look at the cached metadata.
            fields (Optional[List[str]]): list of fields to return. Use ["*"] to return all.
        """

        # we cannot use the cache if there is none
        if self._metadata is None:
            ignore_cache = True

        # default fields to fetch, needed by default properties
        _fields = ["id", "kind", "name", "mimeType"]
        if fields:
            _fields.extend(fields)
        # see if we have cached the file metadata already
        if (
            ignore_cache is False
            and self._metadata
            and all([field in self._metadata.keys() for field in _fields])
        ):
            _logger.info("Using cached metadata...")
            return {key: value for key, value in self._metadata.items() if key in _fields}
        # fetch, cache
        return self._cache_local_metadata_with_args_and_return(fields=_fields)

    @property
    def kind(self):

        return self.fetch_metadata().get("kind")

    @property
    def name(self) -> Optional[str]:

        return self.fetch_metadata().get("name")

    @property
    def mimetype(self) -> Optional[str]:

        return self.fetch_metadata().get("mimeType")

    @property
    def url(self) -> str:

        return self._base_url.format(self.id)

    @property
    def comments(self) -> List[Comment]:

        return [
            Comment(item)
            for item in self._drive_client.comments()
            .list(fileId=self.id, fields=None)
            .execute()
            .get("items", [])
        ]

    def update(self):

        raise NotImplementedError

    def share(
        self,
        role: Union[PermissionType, str],
        user: Optional[str] = None,
        group: Optional[str] = None,
        domain: Optional[str] = None,
        anyone: bool = False,
    ):
        """Share the object with a provided permission with a user, group, domain, or everyone.
        More information on operations by role here:
        https://developers.google.com/drive/api/v3/ref-roles

        Args:
            role (PermissionType): role identifying operations that can be performed.
            user (Optional[str]): a user to share the file with.
            group (Optional[str]): a group to share the file with.
            domain (Optional[str]): a domain for a given permission role.
            anyone (bool): make the file accessible to anyone.
        """

        permissions: List[dict] = []

        # coerce any strings into a PermissionType
        role = PermissionType(role)

        if user:
            permissions.append({"role": role.value, "type": "user", "emailAddress": user})
        if group:
            permissions.append({"role": role.value, "type": "group", "emailAddress": group})
        if domain:
            permissions.append({"role": role.value, "type": "domain", "domain": domain})
        if anyone:
            permissions.append({"role": role.value, "type": "anyone"})
        for permission in permissions:
            self._drive_client.permissions().create(
                fileId=self.id, body=permission, supportsAllDrives=True
            ).execute()

    def download(self):

        raise NotImplementedError

    def delete(self):
        """Permanently deletes a file owned by the user without moving it to the trash."""

        self._drive_client.files().delete(fileId=self.id).execute()

_cache_local_metadata_with_args_and_return(fields)

Local metadata only has a potential subset of fields. Call this to rebuild with another potential set.

Source code in pygsuite/drive/drive_object.py
def _cache_local_metadata_with_args_and_return(self, fields: List[str]):
    """Local metadata only has a potential subset of fields. Call this to rebuild
    with another potential set."""
    output: Dict = {}
    self._metadata = (
        self._drive_client.files().get(fileId=self.id, fields=f"{', '.join(fields)}")
    ).execute()

    if self._metadata:
        for field in fields:
            output[field] = self._metadata[field]
    return output

_create(name=None, parent_folder_ids=None, mimetype=None, media_body=None, starred=False, extra_body=None, drive_client=None, object_client=None, **kwargs) classmethod

Base create method.

Parameters:

Name Type Description Default
name str

Name of the file.

None
parent_folder_ids List[str]

The IDs of the parent folders which contain the folder. If not specified as part of a create request, the file will be placed directly in the user's My Drive folder.

None
mimetype Union[str, MimeType]

Specified type of the file to create.

None
media_body BytesIO, MediaFileUpload, MediaIoBaseUpload

Content for the file.

None
starred bool

Whether the user has starred the file.

False
extra_body dict

Extra parameters for the request body.

None
drive_client Resource

client connection to the Drive API used to create file.

None
object_client Resource

optional domain client (e.g. SHEETS client) used by the created object.

None
Source code in pygsuite/drive/drive_object.py
@classmethod
def _create(
    cls,
    name: Optional[str] = None,
    parent_folder_ids: Optional[List[str]] = None,
    mimetype: Optional[Union[str, MimeType]] = None,
    media_body: Optional[Union[BytesIO, MediaFileUpload, MediaIoBaseUpload]] = None,
    starred: bool = False,
    extra_body: Optional[dict] = None,
    drive_client: Optional[Resource] = None,
    object_client: Optional[Resource] = None,
    **kwargs,
):
    """Base create method.

    Args:
        name (str): Name of the file.
        parent_folder_ids (List[str]): The IDs of the parent folders which contain the folder.
            If not specified as part of a create request, the file will be placed directly in the user's My Drive folder.
        mimetype (Union[str, MimeType]): Specified type of the file to create.
        media_body (BytesIO, MediaFileUpload, MediaIoBaseUpload): Content for the file.
        starred (bool): Whether the user has starred the file.
        extra_body (dict): Extra parameters for the request body.
        drive_client (Resource): client connection to the Drive API used to create file.
        object_client (Resource): optional domain client (e.g. SHEETS client) used by the created object.
    """

    # establish a client
    drive_client = drive_client or Clients.drive_client_v3

    # handle Google mimetypes
    mimetype = str(mimetype) if mimetype is not None else None

    # create request body
    body = {
        "name": name,
        "mimeType": mimetype,
        "parents": parent_folder_ids,
        "starred": starred,
    }

    if extra_body:
        body.update(extra_body)

    # handle media conversion for bytes-like objects
    if isinstance(media_body, BytesIO):
        # if a mimetype is not provided, find best match
        if not mimetype:
            logging.warning("No mimetype specified, attempting to determine one.")
            mimetype = filetype.guess_mime(media_body.read(2048))
            logging.info(f"MimeType found for file: {mimetype}")

        media_body = MediaIoBaseUpload(fd=media_body, mimetype=mimetype)

    # execute files.create request and return File object
    file = (
        drive_client.files()
        .create(body=body, media_body=media_body, fields="id", **kwargs)
        .execute()
    )

    return DriveObject(id=file.get("id"), client=object_client)

_drive_client()

Google Drive API client used for file manipulations

Source code in pygsuite/drive/drive_object.py
@lazy_property
def _drive_client(self):
    """Google Drive API client used for file manipulations"""
    return Clients.drive_client_v3

create(name=None, parent_folder_ids=None, mimetype=None, media_body=None, starred=False, extra_body=None, drive_client=None, object_client=None, **kwargs) classmethod

Create a new Google Drive object (e.g. File, Folder, Spreadsheet, Presentation, Document)

Parameters:

Name Type Description Default
name str

Name of the file.

None
parent_folder_ids List[str]

The IDs of the parent folders which contain the file. If not specified as part of a create request, the file will be placed directly in the user's My Drive folder.

None
mimetype Union[str, MimeType]

Specified type of the file to create.

None
media_body BytesIO, MediaFileUpload, MediaIoBaseUpload

Content for the file.

None
starred bool

Whether the user has starred the file.

False
extra_body dict

Extra parameters for the request body.

None
drive_client Resource

client connection to the Drive API used to create file.

None
object_client Resource

optional domain client (e.g. SHEETS client) used by the created object.

None

Returns the newly created pygsuite object.

Source code in pygsuite/drive/drive_object.py
@classmethod
def create(
    cls,
    name: Optional[str] = None,
    parent_folder_ids: Optional[List[str]] = None,
    mimetype: Optional[Union[str, MimeType]] = None,
    media_body: Optional[Union[BytesIO, MediaFileUpload, MediaIoBaseUpload]] = None,
    starred: bool = False,
    extra_body: Optional[dict] = None,
    drive_client: Optional[Resource] = None,
    object_client: Optional[Resource] = None,
    **kwargs,
):
    """Create a new Google Drive object (e.g. File, Folder, Spreadsheet, Presentation, Document)

    Args:
        name (str): Name of the file.
        parent_folder_ids (List[str]): The IDs of the parent folders which contain the file.
            If not specified as part of a create request, the file will be placed directly in the user's My Drive folder.
        mimetype (Union[str, MimeType]): Specified type of the file to create.
        media_body (BytesIO, MediaFileUpload, MediaIoBaseUpload): Content for the file.
        starred (bool): Whether the user has starred the file.
        extra_body (dict): Extra parameters for the request body.
        drive_client (Resource): client connection to the Drive API used to create file.
        object_client (Resource): optional domain client (e.g. SHEETS client) used by the created object.

    Returns the newly created pygsuite object.
    """
    drive_client = drive_client or Clients.drive_client_v3
    mimetype = mimetype or cls._mimetype

    new_file = cls._create(
        name=name,
        parent_folder_ids=parent_folder_ids,
        mimetype=str(mimetype),
        media_body=media_body,
        starred=starred,
        extra_body=extra_body,
        drive_client=drive_client,
        **kwargs,
    )
    return cls(id=new_file.id, client=object_client)

delete()

Permanently deletes a file owned by the user without moving it to the trash.

Source code in pygsuite/drive/drive_object.py
def delete(self):
    """Permanently deletes a file owned by the user without moving it to the trash."""

    self._drive_client.files().delete(fileId=self.id).execute()

fetch_metadata(ignore_cache=False, fields=None)

Metadata for the file, based on the files.get method. Default fields include kind, name, and mimetype. Additional fields available are found here: https://googleapis.github.io/google-api-python-client/docs/dyn/drive_v3.files.html#get

Parameters:

Name Type Description Default
ignore_cache bool

whether to first look at the cached metadata.

False
fields Optional[List[str]]

list of fields to return. Use ["*"] to return all.

None
Source code in pygsuite/drive/drive_object.py
def fetch_metadata(
    self, ignore_cache: bool = False, fields: Optional[List[str]] = None
) -> dict:
    """Metadata for the file, based on the files.get method.
    Default fields include kind, name, and mimetype. Additional fields available are found here:
    https://googleapis.github.io/google-api-python-client/docs/dyn/drive_v3.files.html#get

    Args:
        ignore_cache (bool): whether to first look at the cached metadata.
        fields (Optional[List[str]]): list of fields to return. Use ["*"] to return all.
    """

    # we cannot use the cache if there is none
    if self._metadata is None:
        ignore_cache = True

    # default fields to fetch, needed by default properties
    _fields = ["id", "kind", "name", "mimeType"]
    if fields:
        _fields.extend(fields)
    # see if we have cached the file metadata already
    if (
        ignore_cache is False
        and self._metadata
        and all([field in self._metadata.keys() for field in _fields])
    ):
        _logger.info("Using cached metadata...")
        return {key: value for key, value in self._metadata.items() if key in _fields}
    # fetch, cache
    return self._cache_local_metadata_with_args_and_return(fields=_fields)

get_safe(name, exact_match=True, parent_folder_ids=None, mimetype=None, support_all_drives=True, extra_conditions=None, drive_client=None, object_client=None) classmethod

Get a file or create one if not found

Parameters:

Name Type Description Default
name str

The case-sensitive name of the file to search for.

required
exact_match bool

Whether to only match the given name exactly, or return any name containing the string.

True
parent_folder_ids List[str]

The IDs of the parent folders which contain the file.

None
mimetype Union[GoogleMimeType, str]

A specific Google Docs type to match.

None
support_all_drives bool

Whether or not to search both My Drives and shared drives.

True
extra_conditions Union[QueryString, QueryStringGroup]

Any additional queries to pass to the files search.

None
drive_client Resource

client connection to the Drive API used to create file.

None
object_client Resource

optional domain client (e.g. SHEETS client) used by the created object.

None

Returns:

Type Description

An instantiated File object, or specific Google Docs type object, such as Spreadsheet, Presentation, or Document.

Source code in pygsuite/drive/drive_object.py
@classmethod
def get_safe(
    cls,
    name: str,
    exact_match: bool = True,
    parent_folder_ids: Optional[List[str]] = None,
    mimetype: Optional[Union[MimeType, str]] = None,
    support_all_drives: bool = True,
    extra_conditions: Optional[Union[QueryString, QueryStringGroup]] = None,
    drive_client: Optional[Resource] = None,
    object_client: Optional[Resource] = None,
):
    """Get a file or create one if not found

    Args:
        name (str): The case-sensitive name of the file to search for.
        exact_match (bool): Whether to only match the given name exactly, or return any name containing the string.
        parent_folder_ids (List[str]): The IDs of the parent folders which contain the file.
        mimetype (Union[GoogleMimeType, str]): A specific Google Docs type to match.
        support_all_drives (bool): Whether or not to search both My Drives and shared drives.
        extra_conditions (Union[QueryString, QueryStringGroup]): Any additional queries to pass to the files search.
        drive_client (Resource): client connection to the Drive API used to create file.
        object_client (Resource): optional domain client (e.g. SHEETS client) used by the created object.

    Returns:
        An instantiated File object, or specific Google Docs type object, such as Spreadsheet, Presentation, or Document.
    """
    # establish a client
    drive_client = drive_client or Clients.drive_client_v3
    # always restrict to the mimetype if set
    if not mimetype and cls._mimetype != MimeType.UNKNOWN:
        mimetype = cls._mimetype
    # name match query
    operator = Operator.EQUAL if exact_match else Operator.CONTAINS
    name_query = QueryString(QueryTerm.NAME, operator, name)
    base_query = name_query
    query_components: List[Union[QueryString, QueryStringGroup]] = [base_query]
    # optional folder query
    if parent_folder_ids:
        folder_query: Union[QueryString, QueryStringGroup]
        folder_queries = []
        for id in parent_folder_ids:
            folder_query = QueryString(QueryTerm.PARENTS, Operator.IN, id)
            folder_queries.append(folder_query)
        folder_query = QueryStringGroup(
            folder_queries, [Connector.OR for query in folder_queries[:-1]]
        )
        query_components.append(folder_query)

    # optional mimetype query
    if mimetype:
        mimetype = str(mimetype)
        type_query = QueryString(QueryTerm.MIMETYPE, Operator.EQUAL, mimetype)
        query_components.append(type_query)

    # optional auxiliary query
    if extra_conditions:
        query_components.append(extra_conditions)

    query = QueryStringGroup(query_components)
    # we are not handling multiple pages of matches here because
    # we only return the first match anyway
    response = (
        drive_client.files()
        .list(
            q=query.formatted,
            spaces="drive",
            fields="nextPageToken, files(id, name)",
            pageToken=None,
            supportsAllDrives=support_all_drives,
            includeItemsFromAllDrives=support_all_drives,
        )
        .execute()
    )

    files = response.get("files", [])
    if files:
        # TODO: better method for determining *best* match from a set of matches
        _logger.info("Matching file found, returning existing file...")
        return cls(files[0].get("id"), object_client)
    else:
        _logger.info("No matching file found, creating file now...")
        return cls.create(
            name=name,
            parent_folder_ids=parent_folder_ids,
            mimetype=mimetype,
            object_client=object_client,
        )

move(destination_folder_ids, current_folder_ids=None)

Move the file from a current folder to a new folder. If no current folder is specified, the current folder ID is derived.

Parameters:

Name Type Description Default
destination_folder_id str

A list of the folder IDs to move the file to.

required
current_folder_id str

A list of the current folder IDs to remove the file from.

required
Source code in pygsuite/drive/drive_object.py
def move(
    self, destination_folder_ids: List[str], current_folder_ids: Optional[List[str]] = None
):
    """Move the file from a current folder to a new folder.
    If no current folder is specified, the current folder ID is derived.

    Args:
        destination_folder_id (str): A list of the folder IDs to move the file to.
        current_folder_id (str): A list of the current folder IDs to remove the file from.
    """
    if not current_folder_ids:
        current_folder_ids = self.fetch_metadata().get("parents")

    response = (
        self._drive_client.files()
        .update(
            fileId=self.id,
            addParents=destination_folder_ids,
            removeParents=current_folder_ids,
            fields="parents",
        )
        .execute()
    )

    return response.get("parents")

share(role, user=None, group=None, domain=None, anyone=False)

Share the object with a provided permission with a user, group, domain, or everyone. More information on operations by role here: https://developers.google.com/drive/api/v3/ref-roles

Parameters:

Name Type Description Default
role PermissionType

role identifying operations that can be performed.

required
user Optional[str]

a user to share the file with.

None
group Optional[str]

a group to share the file with.

None
domain Optional[str]

a domain for a given permission role.

None
anyone bool

make the file accessible to anyone.

False
Source code in pygsuite/drive/drive_object.py
def share(
    self,
    role: Union[PermissionType, str],
    user: Optional[str] = None,
    group: Optional[str] = None,
    domain: Optional[str] = None,
    anyone: bool = False,
):
    """Share the object with a provided permission with a user, group, domain, or everyone.
    More information on operations by role here:
    https://developers.google.com/drive/api/v3/ref-roles

    Args:
        role (PermissionType): role identifying operations that can be performed.
        user (Optional[str]): a user to share the file with.
        group (Optional[str]): a group to share the file with.
        domain (Optional[str]): a domain for a given permission role.
        anyone (bool): make the file accessible to anyone.
    """

    permissions: List[dict] = []

    # coerce any strings into a PermissionType
    role = PermissionType(role)

    if user:
        permissions.append({"role": role.value, "type": "user", "emailAddress": user})
    if group:
        permissions.append({"role": role.value, "type": "group", "emailAddress": group})
    if domain:
        permissions.append({"role": role.value, "type": "domain", "domain": domain})
    if anyone:
        permissions.append({"role": role.value, "type": "anyone"})
    for permission in permissions:
        self._drive_client.permissions().create(
            fileId=self.id, body=permission, supportsAllDrives=True
        ).execute()

upload(filepath, name=None, parent_folder_ids=None, mimetype=None, convert_to=None, starred=False, drive_client=None, object_client=None, **kwargs) classmethod

Method to upload a local file to Google Drive.

Parameters:

Name Type Description Default
filepath str

Filepath of the file to upload.

required
name str

Name of the file in Google Drive once uploaded.

None
parent_folder_ids List[str]

The IDs of the parent folders which contain the file. If not specified as part of a create request, the file will be placed directly in the user's My Drive folder.

None
mimetype Union[str, MimeType]

Specified type of the file to create. mimetype is automatically determined if not specified.

None
convert_to str, GoogleDocFormat

Convert the upload file into a Google App file (e.g. CSV -> Google Sheet)

None
starred bool

Whether the user has starred the file.

False
drive_client Resource

client connection to the Drive API used to create file.

None
object_client Resource

optional domain client (e.g. SHEETS client) used by the created object.

None
Source code in pygsuite/drive/drive_object.py
@classmethod
def upload(
    cls,
    filepath: str,
    name: Optional[str] = None,
    parent_folder_ids: Optional[List[str]] = None,
    mimetype: Optional[Union[str, MimeType]] = None,
    convert_to: Optional[Union[str, GoogleDocFormat]] = None,
    starred: bool = False,
    drive_client: Optional[Resource] = None,
    object_client: Optional[Resource] = None,
    **kwargs,
):
    """Method to upload a local file to Google Drive.

    Args:
        filepath (str): Filepath of the file to upload.
        name (str): Name of the file in Google Drive once uploaded.
        parent_folder_ids (List[str]): The IDs of the parent folders which contain the file.
            If not specified as part of a create request, the file will be placed directly in the user's My Drive folder.
        mimetype (Union[str, MimeType]): Specified type of the file to create. mimetype is automatically determined if not specified.
        convert_to (str, GoogleDocFormat): Convert the upload file into a Google App file (e.g. CSV -> Google Sheet)
        starred (bool): Whether the user has starred the file.
        drive_client (Resource): client connection to the Drive API used to create file.
        object_client (Resource): optional domain client (e.g. SHEETS client) used by the created object.
    """
    # establish a client
    drive_client = drive_client or Clients.drive_client_v3

    # get upload file size
    filesize = os.path.getsize(filepath)

    # establish if the upload should be resumable
    # TODO: expand upon this and determine how this should work for users
    resumable = filesize > DRIVE_FILE_MAX_SINGLE_UPLOAD_SIZE

    # get filename and extension
    _, extension = os.path.splitext(filepath)

    # name of the file in Drive
    name = name if name else os.path.basename(filepath)

    # handle MimeType enums
    mimetype = str(mimetype) if mimetype is not None else None

    # first use the given mimetype (which can be None) to specify the upload file's mimetype
    media_body = MediaFileUpload(
        filename=filepath, mimetype=mimetype, chunksize=-1, resumable=resumable
    )

    # next, if converting, determine the mimetype of the Google app to convert to
    if convert_to:
        # try to coerce str into a GoogleDocFormat
        if isinstance(convert_to, str):
            try:
                convert_to = GoogleDocFormat[convert_to.upper()]
            except Exception as e:
                raise ValueError(
                    f"For converting to a Google Document, please use one of the following inputs:\n{[item.name for item in GoogleDocFormat]}"
                ) from e

        # find the corresponding mime type of the extension of the upload file
        try:
            mimetype = FILE_MIME_TYPE_MAP[convert_to][extension.lower()]
        except Exception as e:
            raise ValueError(
                f"File extension {extension.lower()} is not supported with the Google Document type {convert_to.value}"
            ) from e

    file = cls.create(
        name=name,
        parent_folder_ids=parent_folder_ids,
        mimetype=mimetype,
        media_body=media_body,
        starred=starred,
        drive_client=drive_client,
        object_client=object_client,
        **kwargs,
    )

    return file