Skip to content

Commit 48cc82a

Browse files
committed
move gcs and s3 deps to extras
1 parent 4bf4ed7 commit 48cc82a

File tree

12 files changed

+300
-30
lines changed

12 files changed

+300
-30
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ Within the activated Python environment, use the following command to install go
5454
pip install gokart
5555
```
5656

57+
If you use S3 or GCS as a data store, install the corresponding extras:
58+
59+
```bash
60+
pip install gokart[s3] # S3 support
61+
pip install gokart[gcs] # GCS support
62+
pip install gokart[all] # both S3 and GCS
63+
```
64+
5765

5866
# Quickstart
5967

docs/intro_to_gokart.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ Within the activated Python environment, use the following command to install go
1111
1212
pip install gokart
1313
14+
If you use S3 or GCS as a data store, install the corresponding extras:
15+
16+
.. code:: sh
17+
18+
pip install gokart[s3] # S3 support
19+
pip install gokart[gcs] # GCS support
20+
pip install gokart[all] # both S3 and GCS
1421
1522
1623
Quickstart

docs/task_settings.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,15 @@ It is recommended to use the config file since it does not change much.
2525
gokart.add_config('base.ini')
2626
2727
28-
To use the S3 or GCS repository, please set the bucket path as ``s3://{YOUR_REPOSITORY_NAME}`` or ``gs://{YOUR_REPOSITORY_NAME}`` respectively.
28+
To use the S3 or GCS repository, please install the corresponding extras and set the bucket path as ``s3://{YOUR_REPOSITORY_NAME}`` or ``gs://{YOUR_REPOSITORY_NAME}`` respectively.
2929

30-
If use S3 or GCS, please set credential information to Environment Variables.
30+
.. code:: sh
31+
32+
pip install gokart[s3] # for S3 support
33+
pip install gokart[gcs] # for GCS support
34+
pip install gokart[all] # for both S3 and GCS
35+
36+
Also, please set credential information to Environment Variables.
3137

3238
.. code:: sh
3339

gokart/gcs_config.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
import json
44
import os
5-
from typing import cast
5+
from typing import TYPE_CHECKING, cast
66

77
import luigi
8-
import luigi.contrib.gcs
9-
from google.oauth2.service_account import Credentials
8+
9+
if TYPE_CHECKING:
10+
import luigi.contrib.gcs
11+
from google.oauth2.service_account import Credentials
1012

1113

1214
class GCSConfig(luigi.Config):
@@ -19,9 +21,18 @@ def get_gcs_client(self) -> luigi.contrib.gcs.GCSClient:
1921
return self._client
2022

2123
def _get_gcs_client(self) -> luigi.contrib.gcs.GCSClient:
24+
try:
25+
import luigi.contrib.gcs
26+
except ImportError:
27+
raise ImportError('GCS support requires additional dependencies. Install them with: pip install gokart[gcs]') from None
2228
return luigi.contrib.gcs.GCSClient(oauth_credentials=self._load_oauth_credentials())
2329

2430
def _load_oauth_credentials(self) -> Credentials | None:
31+
try:
32+
from google.oauth2.service_account import Credentials
33+
except ImportError:
34+
raise ImportError('GCS support requires additional dependencies. Install them with: pip install gokart[gcs]') from None
35+
2536
json_str = os.environ.get(self.gcs_credential_name)
2637
if not json_str:
2738
return None

gokart/gcs_obj_metadata_client.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
from typing import Any, Final
1010
from urllib.parse import urlsplit
1111

12-
from googleapiclient.model import makepatch
13-
1412
from gokart.gcs_config import GCSConfig
1513
from gokart.required_task_output import RequiredTaskOutput
1614
from gokart.utils import FlattenableItems
@@ -39,6 +37,14 @@ def _path_to_bucket_and_key(path: str) -> tuple[str, str]:
3937
path_without_initial_slash = path[1:]
4038
return netloc, path_without_initial_slash
4139

40+
@staticmethod
41+
def _makepatch(original: dict[str, Any], modified: dict[str, Any]) -> dict[str, Any]:
42+
try:
43+
from googleapiclient.model import makepatch
44+
except ImportError:
45+
raise ImportError('GCS support requires additional dependencies. Install them with: pip install gokart[gcs]') from None
46+
return dict(makepatch(original, modified))
47+
4248
@staticmethod
4349
def add_task_state_labels(
4450
path: str,
@@ -78,7 +84,7 @@ def add_task_state_labels(
7884
.patch(
7985
bucket=bucket,
8086
object=obj,
81-
body=makepatch({'metadata': original_metadata}, {'metadata': patched_metadata}),
87+
body=GCSObjectMetadataClient._makepatch({'metadata': original_metadata}, {'metadata': patched_metadata}),
8288
)
8389
.execute()
8490
)

gokart/gcs_zip_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
import shutil
55
from typing import cast
66

7-
from gokart.gcs_config import GCSConfig
87
from gokart.zip_client import ZipClient, _unzip_file
98

109

1110
class GCSZipClient(ZipClient):
1211
def __init__(self, file_path: str, temporary_directory: str) -> None:
12+
from gokart.gcs_config import GCSConfig
13+
1314
self._file_path = file_path
1415
self._temporary_directory = temporary_directory
1516
self._client = GCSConfig().get_gcs_client()

gokart/object_storage.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,8 @@
44
from typing import cast
55

66
import luigi
7-
import luigi.contrib.gcs
8-
import luigi.contrib.s3
97
from luigi.format import Format
108

11-
from gokart.gcs_config import GCSConfig
12-
from gokart.gcs_zip_client import GCSZipClient
13-
from gokart.s3_config import S3Config
14-
from gokart.s3_zip_client import S3ZipClient
159
from gokart.zip_client import ZipClient
1610

1711
object_storage_path_prefix = ['s3://', 'gs://']
@@ -28,26 +22,48 @@ def if_object_storage_path(path: str) -> bool:
2822
@staticmethod
2923
def get_object_storage_target(path: str, format: Format) -> luigi.target.FileSystemTarget:
3024
if path.startswith('s3://'):
25+
try:
26+
import luigi.contrib.s3
27+
except ImportError:
28+
raise ImportError('S3 support requires additional dependencies. Install them with: pip install gokart[s3]') from None
29+
30+
from gokart.s3_config import S3Config
31+
3132
return luigi.contrib.s3.S3Target(path, client=S3Config().get_s3_client(), format=format)
3233
elif path.startswith('gs://'):
34+
try:
35+
import luigi.contrib.gcs
36+
except ImportError:
37+
raise ImportError('GCS support requires additional dependencies. Install them with: pip install gokart[gcs]') from None
38+
39+
from gokart.gcs_config import GCSConfig
40+
3341
return luigi.contrib.gcs.GCSTarget(path, client=GCSConfig().get_gcs_client(), format=format)
3442
else:
3543
raise
3644

3745
@staticmethod
3846
def exists(path: str) -> bool:
3947
if path.startswith('s3://'):
48+
from gokart.s3_config import S3Config
49+
4050
return cast(bool, S3Config().get_s3_client().exists(path))
4151
elif path.startswith('gs://'):
52+
from gokart.gcs_config import GCSConfig
53+
4254
return cast(bool, GCSConfig().get_gcs_client().exists(path))
4355
else:
4456
raise
4557

4658
@staticmethod
4759
def get_timestamp(path: str) -> datetime:
4860
if path.startswith('s3://'):
61+
from gokart.s3_config import S3Config
62+
4963
return cast(datetime, S3Config().get_s3_client().get_key(path).last_modified)
5064
elif path.startswith('gs://'):
65+
from gokart.gcs_config import GCSConfig
66+
5167
# for gcs object
5268
# should PR to luigi
5369
bucket, obj = GCSConfig().get_gcs_client()._path_to_bucket_and_key(path)
@@ -59,12 +75,21 @@ def get_timestamp(path: str) -> datetime:
5975
@staticmethod
6076
def get_zip_client(file_path: str, temporary_directory: str) -> ZipClient:
6177
if file_path.startswith('s3://'):
78+
from gokart.s3_zip_client import S3ZipClient
79+
6280
return S3ZipClient(file_path=file_path, temporary_directory=temporary_directory)
6381
elif file_path.startswith('gs://'):
82+
from gokart.gcs_zip_client import GCSZipClient
83+
6484
return GCSZipClient(file_path=file_path, temporary_directory=temporary_directory)
6585
else:
6686
raise
6787

6888
@staticmethod
6989
def is_buffered_reader(file: object) -> bool:
70-
return not isinstance(file, luigi.contrib.s3.ReadableS3File)
90+
try:
91+
import luigi.contrib.s3
92+
93+
return not isinstance(file, luigi.contrib.s3.ReadableS3File)
94+
except ImportError:
95+
return True

gokart/s3_config.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import os
44

55
import luigi
6-
import luigi.contrib.s3
76

87

98
class S3Config(luigi.Config):
@@ -12,12 +11,16 @@ class S3Config(luigi.Config):
1211

1312
_client = None
1413

15-
def get_s3_client(self) -> luigi.contrib.s3.S3Client:
14+
def get_s3_client(self):
1615
if self._client is None: # use cache as like singleton object
1716
self._client = self._get_s3_client()
1817
return self._client
1918

20-
def _get_s3_client(self) -> luigi.contrib.s3.S3Client:
19+
def _get_s3_client(self):
20+
try:
21+
import luigi.contrib.s3
22+
except ImportError:
23+
raise ImportError('S3 support requires additional dependencies. Install them with: pip install gokart[s3]') from None
2124
return luigi.contrib.s3.S3Client(
2225
aws_access_key_id=os.environ.get(self.aws_access_key_id_name), aws_secret_access_key=os.environ.get(self.aws_secret_access_key_name)
2326
)

gokart/s3_zip_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
import shutil
55
from typing import cast
66

7-
from gokart.s3_config import S3Config
87
from gokart.zip_client import ZipClient, _unzip_file
98

109

1110
class S3ZipClient(ZipClient):
1211
def __init__(self, file_path: str, temporary_directory: str) -> None:
12+
from gokart.s3_config import S3Config
13+
1314
self._file_path = file_path
1415
self._temporary_directory = temporary_directory
1516
self._client = S3Config().get_s3_client()

pyproject.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,10 @@ readme = "README.md"
1313
requires-python = ">=3.10, <4"
1414
dependencies = [
1515
"luigi>=3.8.0",
16-
"boto3",
1716
"slack-sdk",
1817
"pandas",
1918
"numpy",
20-
"google-auth",
2119
"pyarrow",
22-
"google-api-python-client",
2320
"APScheduler",
2421
"redis",
2522
"dill",
@@ -39,6 +36,9 @@ classifiers = [
3936
dynamic = ["version"]
4037

4138
[project.optional-dependencies]
39+
s3 = ["boto3"]
40+
gcs = ["google-auth", "google-api-python-client"]
41+
all = ["gokart[s3]", "gokart[gcs]"]
4242
polars = ["polars>=0.19.0"]
4343

4444
[project.urls]
@@ -48,6 +48,9 @@ Documentation = "https://gokart.readthedocs.io/en/latest/"
4848

4949
[dependency-groups]
5050
test = [
51+
"boto3",
52+
"google-auth",
53+
"google-api-python-client",
5154
"fakeredis",
5255
"lupa",
5356
"matplotlib",

0 commit comments

Comments
 (0)