or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auth.mdchannel.mddiscovery.mderrors.mdhttp.mdindex.mdmedia.mdmimeparse.mdmodel.mdschema.mdtesting.md

media.mddocs/

0

# Media Upload and Download

1

2

The media handling functionality provides robust support for uploading and downloading files to Google APIs with features like resumable transfers, progress tracking, and chunked processing for large files.

3

4

## Capabilities

5

6

### Media Upload Classes

7

8

Upload files and data to Google APIs with various source types and transfer options.

9

10

```python { .api }

11

class MediaUpload:

12

"""Abstract base class for media uploads."""

13

14

def chunksize(self):

15

"""

16

Get the chunk size for resumable uploads.

17

18

Returns:

19

int: Chunk size in bytes

20

"""

21

22

def mimetype(self):

23

"""

24

Get the MIME type of the media.

25

26

Returns:

27

str: MIME type string

28

"""

29

30

def size(self):

31

"""

32

Get the total size of the media.

33

34

Returns:

35

int: Size in bytes, or None if unknown

36

"""

37

38

def resumable(self):

39

"""

40

Check if the upload supports resumable transfers.

41

42

Returns:

43

bool: True if resumable, False otherwise

44

"""

45

46

def getbytes(self, begin, end):

47

"""

48

Get a range of bytes from the media.

49

50

Args:

51

begin (int): Starting byte position

52

end (int): Ending byte position

53

54

Returns:

55

bytes: The requested byte range

56

"""

57

58

class MediaFileUpload(MediaUpload):

59

"""Upload a file from the local filesystem."""

60

61

def __init__(self, filename, mimetype=None, chunksize=DEFAULT_CHUNK_SIZE,

62

resumable=False):

63

"""

64

Initialize a file upload.

65

66

Args:

67

filename (str): Path to the file to upload

68

mimetype (str, optional): MIME type of the file (auto-detected if None)

69

chunksize (int): Size of upload chunks in bytes (default: 1MB)

70

resumable (bool): Whether the upload should be resumable (default: False)

71

72

Raises:

73

FileNotFoundError: When the specified file does not exist

74

ValueError: When chunksize is invalid for resumable uploads

75

"""

76

77

class MediaInMemoryUpload(MediaUpload):

78

"""Upload data from memory (bytes or string)."""

79

80

def __init__(self, body, mimetype='application/octet-stream',

81

chunksize=DEFAULT_CHUNK_SIZE, resumable=False):

82

"""

83

Initialize an in-memory upload.

84

85

Args:

86

body (bytes or str): Data to upload

87

mimetype (str): MIME type of the data

88

chunksize (int): Size of upload chunks in bytes (default: 1MB)

89

resumable (bool): Whether the upload should be resumable (default: False)

90

91

Raises:

92

ValueError: When chunksize is invalid for resumable uploads

93

"""

94

95

class MediaIoBaseUpload(MediaUpload):

96

"""Upload data from a file-like object (IOBase)."""

97

98

def __init__(self, fd, mimetype='application/octet-stream',

99

chunksize=DEFAULT_CHUNK_SIZE, resumable=False):

100

"""

101

Initialize an IOBase upload.

102

103

Args:

104

fd (IOBase): File-like object to read data from

105

mimetype (str): MIME type of the data

106

chunksize (int): Size of upload chunks in bytes (default: 1MB)

107

resumable (bool): Whether the upload should be resumable (default: False)

108

109

Raises:

110

ValueError: When chunksize is invalid for resumable uploads

111

"""

112

```

113

114

### Media Download Classes

115

116

Download files and data from Google APIs with progress tracking and chunked processing.

117

118

```python { .api }

119

class MediaDownloadProgress:

120

"""Tracks the progress of a media download."""

121

122

def __init__(self, resumable_progress, total_size):

123

"""

124

Initialize download progress tracking.

125

126

Args:

127

resumable_progress (int): Bytes downloaded so far

128

total_size (int): Total size in bytes, or None if unknown

129

"""

130

131

@property

132

def resumable_progress(self):

133

"""

134

Get the number of bytes downloaded.

135

136

Returns:

137

int: Bytes downloaded so far

138

"""

139

140

@property

141

def total_size(self):

142

"""

143

Get the total download size.

144

145

Returns:

146

int: Total size in bytes, or None if unknown

147

"""

148

149

def progress(self):

150

"""

151

Get the download progress as a percentage.

152

153

Returns:

154

float: Progress percentage (0.0 to 1.0), or None if total size unknown

155

"""

156

157

class MediaIoBaseDownload:

158

"""Download media to a file-like object."""

159

160

def __init__(self, fd, request, chunksize=DEFAULT_CHUNK_SIZE):

161

"""

162

Initialize a media download.

163

164

Args:

165

fd (IOBase): File-like object to write downloaded data

166

request (HttpRequest): HTTP request for the media download

167

chunksize (int): Size of download chunks in bytes (default: 1MB)

168

"""

169

170

def next_chunk(self, num_retries=0):

171

"""

172

Download the next chunk of media.

173

174

Args:

175

num_retries (int): Number of retry attempts on failure

176

177

Returns:

178

tuple: (MediaDownloadProgress, bool) - progress object and completion status

179

180

Raises:

181

HttpError: When the download request fails

182

"""

183

```

184

185

### Upload Progress Tracking

186

187

```python { .api }

188

class MediaUploadProgress:

189

"""Tracks the progress of a resumable media upload."""

190

191

def __init__(self, resumable_progress, total_size):

192

"""

193

Initialize upload progress tracking.

194

195

Args:

196

resumable_progress (int): Bytes uploaded so far

197

total_size (int): Total size in bytes

198

"""

199

200

@property

201

def resumable_progress(self):

202

"""

203

Get the number of bytes uploaded.

204

205

Returns:

206

int: Bytes uploaded so far

207

"""

208

209

@property

210

def total_size(self):

211

"""

212

Get the total upload size.

213

214

Returns:

215

int: Total size in bytes

216

"""

217

218

def progress(self):

219

"""

220

Get the upload progress as a percentage.

221

222

Returns:

223

float: Progress percentage (0.0 to 1.0)

224

"""

225

```

226

227

## Usage Examples

228

229

### File Upload

230

231

```python

232

from googleapiclient import discovery

233

from googleapiclient.http import MediaFileUpload

234

235

# Build Drive service

236

service = discovery.build('drive', 'v3', credentials=credentials)

237

238

# Upload a file

239

file_metadata = {

240

'name': 'my-document.pdf',

241

'parents': ['folder_id'] # Optional: specify parent folder

242

}

243

244

media = MediaFileUpload(

245

'local-document.pdf',

246

mimetype='application/pdf',

247

resumable=True

248

)

249

250

file = service.files().create(

251

body=file_metadata,

252

media_body=media,

253

fields='id'

254

).execute()

255

256

print(f'File ID: {file.get("id")}')

257

```

258

259

### Resumable Upload with Progress Tracking

260

261

```python

262

from googleapiclient.http import MediaFileUpload

263

from googleapiclient.errors import HttpError

264

import time

265

266

def upload_with_progress(service, filename, file_metadata):

267

"""Upload file with progress tracking and resume capability."""

268

269

media = MediaFileUpload(

270

filename,

271

resumable=True,

272

chunksize=1024*1024 # 1MB chunks

273

)

274

275

request = service.files().create(

276

body=file_metadata,

277

media_body=media

278

)

279

280

response = None

281

while response is None:

282

try:

283

status, response = request.next_chunk()

284

if status:

285

progress = int(status.progress() * 100)

286

print(f"Upload progress: {progress}%")

287

except HttpError as error:

288

if error.resp.status in [500, 502, 503, 504]:

289

# Recoverable error, wait and retry

290

time.sleep(5)

291

continue

292

else:

293

raise

294

295

return response

296

297

# Use the function

298

file_metadata = {'name': 'large-file.zip'}

299

result = upload_with_progress(service, 'large-file.zip', file_metadata)

300

print(f'Upload completed. File ID: {result.get("id")}')

301

```

302

303

### In-Memory Upload

304

305

```python

306

from googleapiclient.http import MediaInMemoryUpload

307

import json

308

309

# Upload JSON data

310

data = {'key': 'value', 'numbers': [1, 2, 3]}

311

json_string = json.dumps(data)

312

313

media = MediaInMemoryUpload(

314

json_string.encode('utf-8'),

315

mimetype='application/json'

316

)

317

318

file_metadata = {'name': 'data.json'}

319

file = service.files().create(

320

body=file_metadata,

321

media_body=media

322

).execute()

323

```

324

325

### Stream Upload

326

327

```python

328

from googleapiclient.http import MediaIoBaseUpload

329

import io

330

331

# Upload from a file-like object

332

data_stream = io.BytesIO(b'Hello, world! This is streaming data.')

333

334

media = MediaIoBaseUpload(

335

data_stream,

336

mimetype='text/plain',

337

resumable=True

338

)

339

340

file_metadata = {'name': 'stream-data.txt'}

341

file = service.files().create(

342

body=file_metadata,

343

media_body=media

344

).execute()

345

```

346

347

### File Download

348

349

```python

350

from googleapiclient.http import MediaIoBaseDownload

351

import io

352

353

# Download a file

354

request = service.files().get_media(fileId='file_id')

355

file_io = io.BytesIO()

356

downloader = MediaIoBaseDownload(file_io, request)

357

358

done = False

359

while done is False:

360

status, done = downloader.next_chunk()

361

if status:

362

progress = int(status.progress() * 100)

363

print(f"Download progress: {progress}%")

364

365

# File is now in file_io

366

file_content = file_io.getvalue()

367

print(f"Downloaded {len(file_content)} bytes")

368

```

369

370

### Download to File

371

372

```python

373

from googleapiclient.http import MediaIoBaseDownload

374

375

def download_file(service, file_id, local_filename):

376

"""Download a file to local filesystem."""

377

378

request = service.files().get_media(fileId=file_id)

379

380

with open(local_filename, 'wb') as f:

381

downloader = MediaIoBaseDownload(f, request)

382

done = False

383

384

while done is False:

385

status, done = downloader.next_chunk()

386

if status:

387

progress = int(status.progress() * 100)

388

print(f"Download {progress}% complete")

389

390

print(f"Download completed: {local_filename}")

391

392

# Use the function

393

download_file(service, 'file_id_here', 'downloaded-file.pdf')

394

```

395

396

### Batch Upload

397

398

```python

399

from googleapiclient import http

400

from googleapiclient.http import MediaFileUpload

401

402

def batch_upload_callback(request_id, response, exception):

403

if exception is not None:

404

print(f'Upload {request_id} failed: {exception}')

405

else:

406

print(f'Upload {request_id} completed: {response.get("id")}')

407

408

# Create batch for multiple uploads

409

batch = http.BatchHttpRequest(callback=batch_upload_callback)

410

411

files_to_upload = [

412

('file1.txt', 'First file'),

413

('file2.txt', 'Second file'),

414

('file3.txt', 'Third file')

415

]

416

417

for i, (filename, name) in enumerate(files_to_upload):

418

media = MediaFileUpload(filename, mimetype='text/plain')

419

file_metadata = {'name': name}

420

421

request = service.files().create(

422

body=file_metadata,

423

media_body=media

424

)

425

426

batch.add(request, request_id=f'upload_{i}')

427

428

# Execute all uploads

429

batch.execute()

430

```

431

432

### Upload with Retry Logic

433

434

```python

435

from googleapiclient.errors import HttpError, ResumableUploadError

436

import time

437

import random

438

439

def upload_with_retry(service, filename, file_metadata, max_retries=3):

440

"""Upload with exponential backoff retry logic."""

441

442

media = MediaFileUpload(filename, resumable=True)

443

request = service.files().create(body=file_metadata, media_body=media)

444

445

for attempt in range(max_retries):

446

try:

447

response = None

448

while response is None:

449

status, response = request.next_chunk()

450

if status:

451

print(f"Upload progress: {int(status.progress() * 100)}%")

452

return response

453

454

except (HttpError, ResumableUploadError) as error:

455

if attempt < max_retries - 1:

456

wait_time = (2 ** attempt) + (random.randint(0, 1000) / 1000)

457

print(f"Upload failed, retrying in {wait_time:.1f} seconds...")

458

time.sleep(wait_time)

459

continue

460

else:

461

raise

462

463

# Use retry upload

464

file_metadata = {'name': 'important-file.pdf'}

465

result = upload_with_retry(service, 'important-file.pdf', file_metadata)

466

print(f'Upload successful: {result.get("id")}')

467

```