sunholo 0.81.0__py3-none-any.whl → 0.81.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sunholo/auth/refresh.py CHANGED
@@ -4,17 +4,17 @@ import os
4
4
  import google.auth
5
5
  from google.auth.transport import requests
6
6
  from ..utils.gcp import is_running_on_gcp
7
-
8
-
9
7
  from ..custom_logging import log
10
8
 
11
9
  def get_default_email():
12
- if not refresh_credentials():
13
- log.error("Could not refresh the credentials properly.")
14
- return None
10
+
15
11
  # https://stackoverflow.com/questions/64234214/how-to-generate-a-blob-signed-url-in-google-cloud-run
16
12
 
17
- gcs_credentials, project_id = get_default_creds()
13
+ gcs_credentials, project_id = refresh_credentials()
14
+
15
+ if gcs_credentials is None:
16
+ log.error("Could not refresh the credentials properly.")
17
+ return None
18
18
 
19
19
  service_account_email = getattr(gcs_credentials, 'service_account_email', None)
20
20
  # If you use a service account credential, you can use the embedded email
@@ -26,7 +26,7 @@ def get_default_email():
26
26
  return None
27
27
 
28
28
  log.info(f"Found default email: {service_account_email=} for {project_id=}")
29
- return service_account_email
29
+ return service_account_email, gcs_credentials
30
30
 
31
31
  def get_default_creds():
32
32
  gcs_credentials = None
@@ -36,20 +36,24 @@ def get_default_creds():
36
36
  return gcs_credentials, project_id
37
37
 
38
38
  def refresh_credentials():
39
+ """
40
+ Need to refresh to get a valid email/token for signing URLs from a default service account
41
+ """
39
42
  if not is_running_on_gcp():
40
43
  log.debug("Not running on Google Cloud so no credentials available for GCS.")
41
- return False
44
+ return None, None
42
45
 
43
46
  gcs_credentials, project_id = get_default_creds()
44
47
 
45
48
  if not gcs_credentials.token or gcs_credentials.expired or not gcs_credentials.valid:
46
49
  try:
47
- gcs_credentials.refresh(requests.Request())
50
+ r = requests.Request()
51
+ gcs_credentials.refresh(r)
48
52
 
49
- return True
53
+ return gcs_credentials, project_id
50
54
 
51
55
  except Exception as e:
52
56
  log.error(f"Failed to refresh gcs credentials: {e}")
53
57
 
54
- return False
58
+ return None, None
55
59
 
sunholo/gcs/add_file.py CHANGED
@@ -22,7 +22,7 @@ except ImportError:
22
22
  storage = None
23
23
 
24
24
  from ..custom_logging import log
25
- from ..utils import load_config_key, ConfigManager
25
+ from ..utils import ConfigManager
26
26
 
27
27
 
28
28
  def handle_base64_image(base64_data: str, vector_name: str, extension: str):
@@ -1,3 +1,9 @@
1
+ from __future__ import annotations
2
+ from typing import Optional, Tuple, TYPE_CHECKING
3
+ if TYPE_CHECKING:
4
+ from PIL import Image
5
+ from google.cloud.storage.bucket import Bucket
6
+
1
7
  import os
2
8
  from urllib.parse import quote
3
9
  from datetime import datetime, timedelta
@@ -6,25 +12,20 @@ from datetime import datetime, timedelta
6
12
  from google.auth.exceptions import RefreshError
7
13
 
8
14
  try:
9
- from google.cloud import storage
15
+ from google.cloud import storage
10
16
  except ImportError:
11
17
  storage = None
12
18
 
13
19
  from ..custom_logging import log
14
- from ..utils.gcp import is_running_on_gcp
15
- from ..auth.refresh import refresh_credentials, get_default_creds, get_default_email
20
+ from ..auth.refresh import refresh_credentials, get_default_email
16
21
  from io import BytesIO
17
22
  try:
18
23
  from PIL import Image
19
24
  except ImportError:
20
25
  Image = None
21
26
 
22
- gcs_credentials = None
23
- project_id = None
24
- gcs_client = None
25
- gcs_bucket_cache = {}
26
27
 
27
- def get_image_from_gcs(gs_uri: str):
28
+ def get_image_from_gcs(gs_uri: str) -> Image.Image: # type: ignore
28
29
  """Converts image bytes from GCS to a PIL Image object."""
29
30
  image_bytes = get_bytes_from_gcs(gs_uri)
30
31
  if not Image:
@@ -35,7 +36,7 @@ def get_image_from_gcs(gs_uri: str):
35
36
  except IOError as e:
36
37
  raise ValueError("Unable to open image from bytes:", e)
37
38
 
38
- def get_bytes_from_gcs(gs_uri):
39
+ def get_bytes_from_gcs(gs_uri) -> Optional[bytes]:
39
40
  """
40
41
  Downloads a file from Google Cloud Storage and returns its bytes.
41
42
 
@@ -73,22 +74,39 @@ def get_bytes_from_gcs(gs_uri):
73
74
  log.error(f"Error downloading file from GCS: {str(err)}")
74
75
  return None
75
76
 
77
+ gcs_bucket_cache = {}
78
+ def get_bucket(bucket_name: str) -> Optional[Bucket]:
79
+ """
80
+ Gets a Cloud Storage bucket and initialised GCS client
81
+
82
+ Args:
83
+ bucket_name: Name of the bucket
76
84
 
77
- if is_running_on_gcp():
78
- # Perform a refresh request to get the access token of the current credentials (Else, it's None)
79
- gcs_credentials, project_id = get_default_creds()
80
- # Prepare global variables for client reuse
85
+ Returns:
86
+
87
+ """
81
88
  if storage:
82
89
  gcs_client = storage.Client()
90
+ else:
91
+ raise ImportError("google storage pip required - install via `pip install sunholo[gcp]`")
83
92
 
84
- def get_bucket(bucket_name):
85
93
  if bucket_name not in gcs_bucket_cache:
86
94
  gcs_bucket_cache[bucket_name] = gcs_client.get_bucket(bucket_name)
87
95
  return gcs_bucket_cache[bucket_name]
88
96
 
89
- def sign_gcs_url(bucket_name:str, object_name:str, expiry_secs = 86400):
97
+ def sign_gcs_url(bucket_name:str, object_name:str, expiry_secs:int = 86400) -> Optional[str]:
98
+ """
99
+ Creates a signed URL so that users can download a file from Google Cloud Storage without authentication
100
+
101
+ Args:
102
+ bucket_name: Name of the bucket where the object lies
103
+ object_name: Object within the bucket
104
+ expiry_secs: How long the link will be valid - default 24hrs
90
105
 
91
- service_account_email = get_default_email()
106
+ Returns:
107
+ str: The signed URL or None if not avialable
108
+ """
109
+ service_account_email, gcs_credentials = get_default_email()
92
110
 
93
111
  expires = datetime.now() + timedelta(seconds=expiry_secs)
94
112
 
@@ -105,8 +123,8 @@ def sign_gcs_url(bucket_name:str, object_name:str, expiry_secs = 86400):
105
123
  return url
106
124
  except RefreshError:
107
125
  log.info("Refreshing gcs_credentials due to token expiration.")
108
- refreshed = refresh_credentials()
109
- if refreshed:
126
+ credentials, token = refresh_credentials()
127
+ if credentials:
110
128
  return sign_gcs_url(bucket_name, object_name, expiry_secs)
111
129
  log.error("Failed to refresh gcs credentials")
112
130
  return None
@@ -115,7 +133,7 @@ def sign_gcs_url(bucket_name:str, object_name:str, expiry_secs = 86400):
115
133
  return None
116
134
 
117
135
 
118
- def construct_download_link(source_uri: str) -> tuple[str, str, bool]:
136
+ def construct_download_link(source_uri: str) -> Tuple[str, str, bool]:
119
137
  """Creates a viewable Cloud Storage web browser link from a gs:// URI."""
120
138
  if not source_uri.startswith("gs://"):
121
139
  return source_uri, source_uri, False # Return the URI as is if it doesn't start with gs://
@@ -132,7 +150,7 @@ def construct_download_link(source_uri: str) -> tuple[str, str, bool]:
132
150
  return construct_download_link_simple(bucket_name, object_name)
133
151
 
134
152
 
135
- def construct_download_link_simple(bucket_name:str, object_name:str) -> tuple[str, str, bool]:
153
+ def construct_download_link_simple(bucket_name:str, object_name:str) -> Tuple[str, str, bool]:
136
154
  """Creates a viewable Cloud Storage web browser link from a gs:// URI.
137
155
 
138
156
  Args:
@@ -142,12 +160,14 @@ def construct_download_link_simple(bucket_name:str, object_name:str) -> tuple[st
142
160
  A URL that directly access the object in the Cloud Storage web browser.
143
161
  """
144
162
 
145
- public_url = f"https://storage.cloud.google.com/{bucket_name}/{quote(object_name)}"
163
+ if object_name.startswith("gs://"):
164
+ public_url = object_name.replace("gs://", "https://storage.cloud.google.com")
165
+ else:
166
+ public_url = f"https://storage.cloud.google.com/{bucket_name}/{quote(object_name)}"
146
167
  filename = os.path.basename(object_name)
147
- signed = False
148
- return public_url, filename, signed
168
+ return public_url, filename, False
149
169
 
150
- def parse_gs_uri(gs_uri: str) -> tuple[str, str]:
170
+ def parse_gs_uri(gs_uri: str) -> Tuple[str, str]:
151
171
  """Parses a gs:// URI into the bucket name and object name.
152
172
 
153
173
  Args:
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.81.0
3
+ Version: 0.81.2
4
4
  Summary: Large Language Model DevOps - a package to help deploy LLMs to the Cloud.
5
5
  Home-page: https://github.com/sunholo-data/sunholo-py
6
- Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.81.0.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.81.2.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -19,7 +19,7 @@ sunholo/archive/__init__.py,sha256=qNHWm5rGPVOlxZBZCpA1wTYPbalizRT7f8X4rs2t290,3
19
19
  sunholo/archive/archive.py,sha256=PxVfDtO2_2ZEEbnhXSCbXLdeoHoQVImo4y3Jr2XkCFY,1204
20
20
  sunholo/auth/__init__.py,sha256=TeP-OY0XGxYV_8AQcVGoh35bvyWhNUcMRfhuD5l44Sk,91
21
21
  sunholo/auth/gcloud.py,sha256=PdbwkuTdRi4RKBmgG9uwsReegqC4VG15_tw5uzmA7Fs,298
22
- sunholo/auth/refresh.py,sha256=dg1ntPeZG51R9RUNnIJgdIzlPua2vbG5JVE1Lr1xB74,1838
22
+ sunholo/auth/refresh.py,sha256=6AEWX87G3I9BCqrgGJjHGrrWABBXHuaGDKU9ZEcVeXM,2017
23
23
  sunholo/auth/run.py,sha256=zZWRIxfG93eZMCE-feiHRQTLMcHz4U6-yseGgZfu1LI,2776
24
24
  sunholo/azure/__init__.py,sha256=S1WQ5jndzNgzhSBh9UpX_yw7hRVm3hCzkAWNxUdK4dA,48
25
25
  sunholo/azure/auth.py,sha256=Y3fDqFLYwbsIyi5hS5L-3hYnwrLWVL96yPng5Sj5c2c,2236
@@ -78,9 +78,9 @@ sunholo/discovery_engine/get_ai_search_chunks.py,sha256=VPzdYoBP_E6Bko0KpX656QiI
78
78
  sunholo/embedder/__init__.py,sha256=sI4N_CqgEVcrMDxXgxKp1FsfsB4FpjoXgPGkl4N_u4I,44
79
79
  sunholo/embedder/embed_chunk.py,sha256=MCbTePWjUbIRVDFFhHJ94BvOZvIom62-mTr0PmfQyt0,6951
80
80
  sunholo/gcs/__init__.py,sha256=SZvbsMFDko40sIRHTHppA37IijvJTae54vrhooEF5-4,90
81
- sunholo/gcs/add_file.py,sha256=0GruAKsvVO9qVddwJ1ugr4ldpk_QKXmhKKVio2QwuPE,7124
81
+ sunholo/gcs/add_file.py,sha256=wkBQBfnjUbItnRNGiG9oBr7Jf2QfLpZf2nA5zT435ss,7107
82
82
  sunholo/gcs/download_folder.py,sha256=ijJTnS595JqZhBH8iHFErQilMbkuKgL-bnTCMLGuvlA,1614
83
- sunholo/gcs/download_url.py,sha256=i_LKd3fJQNDqpUzDgSSehWVSzOPA-HPM7o0Tf8nLrM4,5235
83
+ sunholo/gcs/download_url.py,sha256=Al7IbNXiaZ-zV09GHhUE9hx013lghJtE9nW8SJx_sas,5938
84
84
  sunholo/gcs/metadata.py,sha256=oQLcXi4brsZ74aegWyC1JZmhlaEV270HS5_UWtAYYWE,898
85
85
  sunholo/invoke/__init__.py,sha256=bELcqIjzKvaupcIN5OQmDgGx_8jARtH9T6PCe8UgcvE,99
86
86
  sunholo/invoke/direct_vac_func.py,sha256=wvrYDZNLoLeO_uQiqRdGUlhwjhLr05dVNBST9TxwwBA,4478
@@ -134,9 +134,9 @@ sunholo/vertex/init.py,sha256=1OQwcPBKZYBTDPdyU7IM4X4OmiXLdsNV30C-fee2scQ,2875
134
134
  sunholo/vertex/memory_tools.py,sha256=pgSahVDh7GPEulu3nl-w0jb5lTClb4TCnVxPnMokNZY,7533
135
135
  sunholo/vertex/safety.py,sha256=S9PgQT1O_BQAkcqauWncRJaydiP8Q_Jzmu9gxYfy1VA,2482
136
136
  sunholo/vertex/type_dict_to_json.py,sha256=uTzL4o9tJRao4u-gJOFcACgWGkBOtqACmb6ihvCErL8,4694
137
- sunholo-0.81.0.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
138
- sunholo-0.81.0.dist-info/METADATA,sha256=jscapxO2wqyFdzlfqahL6VpisfqyNsETdfmHZwJR7I0,7348
139
- sunholo-0.81.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
140
- sunholo-0.81.0.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
141
- sunholo-0.81.0.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
142
- sunholo-0.81.0.dist-info/RECORD,,
137
+ sunholo-0.81.2.dist-info/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
138
+ sunholo-0.81.2.dist-info/METADATA,sha256=qIVU2f03S9E678dvZfzckg3hw8bkVTGQ-8ytTlesoek,7348
139
+ sunholo-0.81.2.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
140
+ sunholo-0.81.2.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
141
+ sunholo-0.81.2.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
142
+ sunholo-0.81.2.dist-info/RECORD,,