pydrivedol.base¶
Base objects for pydrivedol: download functions, GDFiles, GDReader, GDStore.
Two access levels, both returning bytes:
Public, no setup:
get_bytes()against Google’s unauthenticated download endpoint. It raisesNotPubliclySharedrather than handing back the HTML sign-in page Drive serves (with HTTP 200) when the file is not shared publicly.Authenticated: pass a PyDrive2
GoogleDrive– fromdrive_from_service_account()for headless use – asdrive=toget_bytes()/get_metadata(), or build aGDFiles(file-level Mapping, keyed by file id or URL),GDReader/GDStore(folder-level, keyed by relative path).
Module Attributes
enough to decide whether a download is worth making. |
Functions
|
Build an authenticated |
|
Download bytes from a Google Drive URL. |
|
Fetch a Drive file's metadata without downloading its content. |
|
Upload an |
Classes
|
Read-only Mapping of Google Drive files, keyed by file id or file URL. |
|
Read-only Mapping to Google Drive folder. |
|
Read-write MutableMapping to Google Drive folder. |
Exceptions
Raised when an unauthenticated download returns a sign-in page instead of file content. |
- pydrivedol.base.DEFAULT_METADATA_FIELDS = ('id', 'title', 'mimeType', 'fileSize', 'modifiedDate', 'alternateLink')¶
enough to decide whether a download is worth making.
- Type:
Metadata fields fetched by default
- class pydrivedol.base.GDFiles(drive, *, folder_url=None, max_levels=None, include_hidden=False)[source]¶
Bases:
MappingRead-only Mapping of Google Drive files, keyed by file id or file URL.
The file-level sibling of
GDReader. WhereGDReaderis scoped to a folder and keyed by relative path,GDFilesis keyed by whatever identifies a single file: a bare file id, or any Drive file URL – both normalise to the same key through_extract_file_id(), sofiles[url]andfiles[file_id]are one entry. Values arebytes, fetched over the authenticated API, so private files work as long as they are shared with the authenticated identity.That is the shape a caller has when files arrive as links – the usual Drive sharing idiom – rather than as a folder listing.
driveis required and injected: a file-level view is pointless without auth, since its whole reason to exist is reaching files the public endpoint cannot.Iteration requires a scope. Unscoped, this mapping covers the entire Drive, which is unbounded and paginated; enumerating it is never what a caller wants, so offering it would be a trap.
__iter__/__len__therefore raiseNotImplementedErrorunlessfolder_urlis given, in which case they yield that folder’s file ids (honouringmax_levelsandinclude_hidden, the same traversalGDReaderuses). Lookup always works, scoped or not – it is the primary use case and needs no listing.>>> drive = drive_from_service_account('service-account-key.json') >>> files = GDFiles(drive) >>> files.metadata(url)['fileSize'] # cheap: no download >>> content = files[url] # or files[file_id] >>> url in files # metadata probe, not a download TrueScoped, so it can be listed:
>>> scoped = GDFiles(drive, folder_url=folder_url) >>> list(scoped) # file ids- metadata(key, *, fields=('id', 'title', 'mimeType', 'fileSize', 'modifiedDate', 'alternateLink'))[source]¶
Metadata (name, size, mimeType, modifiedDate) for
key, without downloading it.Thin method form of
get_metadata()– see it for the field semantics.- Return type:
- class pydrivedol.base.GDReader(folder_url, *, max_levels=None, credentials_file='client_secrets.json', settings_file='settings.yaml', include_hidden=False, drive=None)[source]¶
Bases:
MappingRead-only Mapping to Google Drive folder.
Keys are relative file paths, values are file contents as bytes.
>>> reader = GDReader(folder_url) >>> list(reader)[:3] >>> content = reader['path/to/file.txt'] >>> len(reader) >>> 'file.txt' in reader >>> url = reader.get_url('file.txt')
- class pydrivedol.base.GDStore(folder_url, *, convert_office=False, **kwargs)[source]¶
Bases:
GDReader,MutableMappingRead-write MutableMapping to Google Drive folder.
Extends GDReader with write and delete operations.
>>> store = GDStore(folder_url) >>> store['file.txt'] = b'Hello' >>> store['dir/file.txt'] = b'Nested' >>> del store['file.txt']Pass
convert_office=Trueto makestore['x.xlsx'] = xlsx_bytescreate a *native Google Sheet* (xlsx → Sheet, docx → Doc, pptx → Slides) instead of an uploaded blob. For one-off control useupload()withconvert=True.- upload(key, value=None, *, path=None, convert=None, google_mimetype=None)[source]¶
Upload
value(bytes) or a filepathtokey; return the shareable URL.With
convert=True(or the store’sconvert_officedefault) an office file becomes a native Google doc — e.g.store.upload('schema.xlsx', xlsx_bytes, convert=True)yields a Google Sheet. Updates an existing same-named file in the target folder, else creates it.- Return type:
Bases:
RuntimeErrorRaised when an unauthenticated download returns a sign-in page instead of file content.
Google serves its HTML sign-in / permission interstitial with HTTP 200, so without an explicit check that page body would be returned as if it were the file: plausible-looking bytes that only blow up much later, in whatever tries to parse them. Catch this to fall back to an authenticated fetch (
get_bytes(url, drive=...)).
- pydrivedol.base.drive_from_service_account(key_file, *, scopes=('https://www.googleapis.com/auth/drive',), subject=None)[source]¶
Build an authenticated
GoogleDrivefrom a service-account key file.For headless / server use — no browser OAuth flow. Share the target Drive folder with the service account’s
client_email(Viewer for read, Editor for write). Pass the resulting drive toGDReader/GDStorevia theirdrive=argument.- Parameters:
>>> drive = drive_from_service_account('sa-key.json') >>> reader = GDReader(folder_url, drive=drive)
- pydrivedol.base.get_bytes(url, *, local_path=False, use_cache=False, drive=None, allow_html=False)[source]¶
Download bytes from a Google Drive URL.
Without
drivethis uses Google’s public download endpoint – no API setup, but it only reaches files shared “anyone with the link”, and it raisesNotPubliclySharedif Drive answers with its sign-in page instead of the file. Pass an authenticateddrive(seedrive_from_service_account()) to reach private files shared with that identity.- Parameters:
url (
str) – Google Drive file link (a bare file id is accepted too).local_path (
Union[bool,str]) – False (return bytes), True (save to temp), or str (save to path)use_cache (
Union[bool,str]) – False (no cache), True (use ~/.cache/pydrivedol/cached/), or str (use dir)drive – an authenticated PyDrive2
GoogleDrive. When given, the download goes through the API;None(default) keeps the public, unauthenticated behaviour exactly.allow_html (
bool) – by default an HTML payload from the public endpoint raises, because it is Google’s login page masquerading as file content. Set True only when the file you are downloading genuinely is HTML. Ignored on the authenticated path.
- Return type:
- Returns:
bytes if local_path is False or str, filepath str if local_path is True
- Raises:
NotPubliclyShared – the public endpoint returned a sign-in page; pass
drive=.
>>> content = get_bytes(url) >>> path = get_bytes(url, local_path=True) >>> content = get_bytes(url, local_path='/tmp/file.txt')A private file, shared with a service account:
>>> drive = drive_from_service_account('service-account-key.json') >>> content = get_bytes(private_url, drive=drive)
- pydrivedol.base.get_metadata(url_or_id, *, drive, fields=('id', 'title', 'mimeType', 'fileSize', 'modifiedDate', 'alternateLink'))[source]¶
Fetch a Drive file’s metadata without downloading its content.
The cheap half of
get_bytes(): use it to decide whether to download – an 18MB spreadsheet is not something you fetch just to learn its name.- Parameters:
url_or_id (
str) – a Drive file URL or a bare file id.drive – an authenticated PyDrive2
GoogleDrive(seedrive_from_service_account()).fields – which metadata fields to request;
Nonefetches everything Drive offers. The default,DEFAULT_METADATA_FIELDS, covers name (title),fileSize,mimeTypeandmodifiedDate.
- Return type:
- Returns:
A plain
dictof the requested fields that the file actually has.fileSizeis returned as anint(Drive sends it as a string), and is absent for Google-native files – Sheets/Docs/Slides have no stored byte size.
>>> drive = drive_from_service_account('service-account-key.json') >>> info = get_metadata(url, drive=drive) >>> info['title'], info['fileSize'] ('client_export.xlsx', 18512345)
- pydrivedol.base.xlsx_to_google_sheet(folder_url, title, xlsx, *, share_with=(), anyone_reader=False, credentials_file='client_secrets.json', settings_file='settings.yaml', drive=None)[source]¶
Upload an
.xlsxas a native Google Sheet and return its shareable URL.The whole point: Drive can convert an uploaded spreadsheet into an editable Google Sheet (preserving cell formatting), rather than parking an
.xlsxblob. This wraps that.- Parameters:
folder_url (
Optional[str]) – destination Drive folder URL (None→ the account’s root).title (
str) – the Google Sheet’s name.xlsx (
Union[str,Path,bytes]) – a path (str/Path) or rawbytes.share_with – emails to grant
writeraccess (no notification email sent).anyone_reader (
bool) – also grant anyone-with-linkreaderaccess.settings_file (
str) – PyDrive2 auth (ignored ifdriveis given).drive – an existing PyDrive2
GoogleDrive(skips auth).
- Return type:
- Returns:
The Google Sheet URL (
alternateLink).
>>> url = xlsx_to_google_sheet(folder_url, 'My Schema', '/tmp/schema.xlsx', ... anyone_reader=True)