Skip to content

Commit fef4f6f

Browse files
committed
major: Revamp repo and pip package structure
The structure of the respository was quite legacy. Here it is updated to a more modern pip package that should be easier to maintain. Most of the changes are cosmetic, the functionality didn't change. Still, the API is now slightly different as the GoogleDriveDownloader class has been replaced by a simple function. Since the logic is stateless, there was no reason to have this class around. The only package dependency, i.e. requests, has been added to the toml config so that it will be finally handled via pip at installation time (see: #29). The examples in the README have been updated as the previous links were not working anymore.
1 parent be1aba9 commit fef4f6f

File tree

9 files changed

+138
-131
lines changed

9 files changed

+138
-131
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.idea/
2+
data/
3+
dist/
4+
venv/

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,25 @@
22
Minimal class to download shared files from Google Drive.
33

44
### How to install:
5-
Installing is as simple as
5+
6+
This package is on [PyPI](https://pypi.org/project/googledrivedownloader/). Installing is as simple as
67

78
```
89
pip install googledrivedownloader
910
```
1011

1112
### Hello World
12-
You will need to obtain the sharable link from Google Drive:
1313

1414
```python
15-
from google_drive_downloader import GoogleDriveDownloader as gdd
15+
from googledrivedownloader import download_file_from_google_drive
1616

17-
gdd.download_file_from_google_drive(file_id='1iytA1n2z4go3uVCwE__vIKouTKyIDjEq',
18-
dest_path='./data/mnist.zip',
19-
unzip=True)
17+
# Single image file
18+
download_file_from_google_drive(file_id='1H1ett7yg-TdtTt6mj2jwmeGZaC8iY1CH',
19+
dest_path='data/crossing.jpg')
20+
# Zip archive
21+
download_file_from_google_drive(file_id='13nD8T7_Q9fkQzq9bXF2oasuIZWao8uio',
22+
dest_path='data/docs.zip', unzip=True)
2023
```
21-
This will download a `mnist.zip` file into a `data` folder and unzip it.
2224

2325

2426
### Tips

google_drive_downloader/__init__.py

Lines changed: 0 additions & 1 deletion
This file was deleted.

google_drive_downloader/google_drive_downloader.py

Lines changed: 0 additions & 105 deletions
This file was deleted.

pyproject.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[build-system]
2+
requires = ["hatchling"]
3+
build-backend = "hatchling.build"
4+
5+
[project]
6+
name = "googledrivedownloader"
7+
version = "1.0.0"
8+
dependencies = [
9+
"requests",
10+
]
11+
authors = [
12+
{ name = "Davide Abati and Andrea Palazzi"},
13+
]
14+
maintainers = [
15+
{name = "Andrea Palazzi", email = "[email protected]"}
16+
]
17+
description = "Minimal class to download shared files from Google Drive."
18+
readme = "README.md"
19+
requires-python = ">=3.8"
20+
21+
[project.urls]
22+
Homepage = "https://github.com/ndrplz/google-drive-downloader"
23+
Issues = "https://github.com/ndrplz/google-drive-downloader/issues"

setup.cfg

Lines changed: 0 additions & 5 deletions
This file was deleted.

setup.py

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/googledrivedownloader/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .download import download_file_from_google_drive
2+
3+
__all__ = ['download_file_from_google_drive']

src/googledrivedownloader/download.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import warnings
2+
import zipfile
3+
from os import makedirs
4+
from os.path import dirname
5+
from os.path import exists
6+
from sys import stdout
7+
8+
from requests import Session
9+
10+
CHUNK_SIZE = 32768
11+
DOWNLOAD_URL = 'https://docs.google.com/uc?export=download'
12+
13+
14+
# From https://stackoverflow.com/questions/1094841/reusable-library-to-get-human-readable-version-of-file-size
15+
def _sizeof_fmt(num, suffix='B'):
16+
for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
17+
if abs(num) < 1024.0:
18+
return '{:.1f} {}{}'.format(num, unit, suffix)
19+
num /= 1024.0
20+
return '{:.1f} {}{}'.format(num, 'Yi', suffix)
21+
22+
23+
def _get_confirm_token(response):
24+
for key, value in response.cookies.items():
25+
if key.startswith('download_warning'):
26+
return value
27+
return None
28+
29+
30+
def _save_response_content(response, destination, showsize, current_size):
31+
with open(destination, 'wb') as f:
32+
for chunk in response.iter_content(CHUNK_SIZE):
33+
if chunk: # filter out keep-alive new chunks
34+
f.write(chunk)
35+
if showsize:
36+
print('\r' + _sizeof_fmt(current_size[0]), end=' ')
37+
stdout.flush()
38+
current_size[0] += CHUNK_SIZE
39+
40+
41+
def download_file_from_google_drive(file_id, dest_path, overwrite=False, unzip=False, showsize=False):
42+
"""
43+
Downloads a shared file from Google Drive into a given folder.
44+
Optionally unzips it.
45+
46+
Parameters
47+
----------
48+
file_id: str
49+
the file identifier.
50+
You can obtain it from the sharable link.
51+
dest_path: str
52+
the destination where to save the downloaded file.
53+
Must be a path (for example: './downloaded_file.txt')
54+
overwrite: bool
55+
optional, if True forces re-download and overwrite.
56+
unzip: bool
57+
optional, if True unzips a file.
58+
If the file is not a zip file, ignores it.
59+
showsize: bool
60+
optional, if True print the current download size.
61+
Returns
62+
-------
63+
None
64+
"""
65+
66+
destination_directory = dirname(dest_path)
67+
if destination_directory and not exists(destination_directory):
68+
makedirs(destination_directory)
69+
70+
if not exists(dest_path) or overwrite:
71+
72+
session = Session()
73+
74+
print('Downloading {} into {}... '.format(file_id, dest_path), end='')
75+
stdout.flush()
76+
77+
response = session.get(DOWNLOAD_URL, params={'id': file_id}, stream=True)
78+
79+
token = _get_confirm_token(response)
80+
if token:
81+
params = {'id': file_id, 'confirm': token}
82+
response = session.get(DOWNLOAD_URL, params=params, stream=True)
83+
84+
if showsize:
85+
print() # Skip to the next line
86+
87+
current_download_size = [0]
88+
_save_response_content(response, dest_path, showsize, current_download_size)
89+
print('Done.')
90+
91+
if unzip:
92+
try:
93+
print('Unzipping...', end='')
94+
stdout.flush()
95+
with zipfile.ZipFile(dest_path, 'r') as z:
96+
z.extractall(destination_directory)
97+
print('Done.')
98+
except zipfile.BadZipfile:
99+
warnings.warn('Ignoring `unzip` since "{}" does not look like a valid zip file'.format(file_id))

0 commit comments

Comments
 (0)