sunholo 0.61.0__tar.gz → 0.61.4__tar.gz

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.
Files changed (113) hide show
  1. {sunholo-0.61.0 → sunholo-0.61.4}/PKG-INFO +2 -2
  2. {sunholo-0.61.0 → sunholo-0.61.4}/setup.py +1 -1
  3. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/chat_history.py +1 -1
  4. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/components/vectorstore.py +1 -1
  5. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/utils/config.py +6 -17
  6. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo.egg-info/PKG-INFO +2 -2
  7. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo.egg-info/SOURCES.txt +0 -1
  8. sunholo-0.61.4/tests/test_config.py +15 -0
  9. sunholo-0.61.0/test/test_dispatch_to_qa.py +0 -73
  10. sunholo-0.61.0/tests/test_config.py +0 -40
  11. {sunholo-0.61.0 → sunholo-0.61.4}/LICENSE.txt +0 -0
  12. {sunholo-0.61.0 → sunholo-0.61.4}/MANIFEST.in +0 -0
  13. {sunholo-0.61.0 → sunholo-0.61.4}/README.md +0 -0
  14. {sunholo-0.61.0 → sunholo-0.61.4}/setup.cfg +0 -0
  15. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/__init__.py +0 -0
  16. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/__init__.py +0 -0
  17. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/dispatch_to_qa.py +0 -0
  18. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/fastapi/__init__.py +0 -0
  19. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/fastapi/base.py +0 -0
  20. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/fastapi/qna_routes.py +0 -0
  21. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/flask/__init__.py +0 -0
  22. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/flask/base.py +0 -0
  23. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/flask/qna_routes.py +0 -0
  24. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/langserve.py +0 -0
  25. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/pubsub.py +0 -0
  26. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/route.py +0 -0
  27. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/agents/special_commands.py +0 -0
  28. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/archive/__init__.py +0 -0
  29. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/archive/archive.py +0 -0
  30. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/auth/__init__.py +0 -0
  31. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/auth/run.py +0 -0
  32. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/bots/__init__.py +0 -0
  33. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/bots/discord.py +0 -0
  34. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/bots/github_webhook.py +0 -0
  35. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/bots/webapp.py +0 -0
  36. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/chunker/__init__.py +0 -0
  37. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/chunker/data_to_embed_pubsub.py +0 -0
  38. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/chunker/doc_handling.py +0 -0
  39. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/chunker/images.py +0 -0
  40. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/chunker/loaders.py +0 -0
  41. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/chunker/message_data.py +0 -0
  42. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/chunker/pdfs.py +0 -0
  43. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/chunker/publish.py +0 -0
  44. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/chunker/splitter.py +0 -0
  45. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/cli/__init__.py +0 -0
  46. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/cli/chat_vac.py +0 -0
  47. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/cli/cli.py +0 -0
  48. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/cli/cli_init.py +0 -0
  49. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/cli/configs.py +0 -0
  50. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/cli/deploy.py +0 -0
  51. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/cli/merge_texts.py +0 -0
  52. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/cli/run_proxy.py +0 -0
  53. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/cli/sun_rich.py +0 -0
  54. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/components/__init__.py +0 -0
  55. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/components/llm.py +0 -0
  56. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/components/prompt.py +0 -0
  57. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/components/retriever.py +0 -0
  58. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/__init__.py +0 -0
  59. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/alloydb.py +0 -0
  60. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/database.py +0 -0
  61. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/lancedb.py +0 -0
  62. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/sql/sb/create_function.sql +0 -0
  63. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/sql/sb/create_function_time.sql +0 -0
  64. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/sql/sb/create_table.sql +0 -0
  65. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  66. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/sql/sb/return_sources.sql +0 -0
  67. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/sql/sb/setup.sql +0 -0
  68. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/static_dbs.py +0 -0
  69. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/database/uuid.py +0 -0
  70. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/embedder/__init__.py +0 -0
  71. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/embedder/embed_chunk.py +0 -0
  72. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/gcs/__init__.py +0 -0
  73. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/gcs/add_file.py +0 -0
  74. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/gcs/download_url.py +0 -0
  75. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/gcs/metadata.py +0 -0
  76. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/langfuse/__init__.py +0 -0
  77. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/langfuse/callback.py +0 -0
  78. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/langfuse/prompts.py +0 -0
  79. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/llamaindex/__init__.py +0 -0
  80. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/llamaindex/generate.py +0 -0
  81. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/llamaindex/import_files.py +0 -0
  82. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/logging.py +0 -0
  83. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/lookup/__init__.py +0 -0
  84. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/lookup/model_lookup.yaml +0 -0
  85. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/patches/__init__.py +0 -0
  86. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/patches/langchain/__init__.py +0 -0
  87. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/patches/langchain/lancedb.py +0 -0
  88. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/patches/langchain/vertexai.py +0 -0
  89. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/pubsub/__init__.py +0 -0
  90. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/pubsub/process_pubsub.py +0 -0
  91. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/pubsub/pubsub_manager.py +0 -0
  92. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/qna/__init__.py +0 -0
  93. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/qna/parsers.py +0 -0
  94. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/qna/retry.py +0 -0
  95. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/streaming/__init__.py +0 -0
  96. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/streaming/content_buffer.py +0 -0
  97. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/streaming/langserve.py +0 -0
  98. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/streaming/streaming.py +0 -0
  99. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/summarise/__init__.py +0 -0
  100. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/summarise/summarise.py +0 -0
  101. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/utils/__init__.py +0 -0
  102. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/utils/big_context.py +0 -0
  103. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/utils/config_schema.py +0 -0
  104. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/utils/gcp.py +0 -0
  105. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/utils/parsers.py +0 -0
  106. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/utils/user_ids.py +0 -0
  107. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/vertex/__init__.py +0 -0
  108. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo/vertex/init_vertex.py +0 -0
  109. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo.egg-info/dependency_links.txt +0 -0
  110. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo.egg-info/entry_points.txt +0 -0
  111. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo.egg-info/requires.txt +0 -0
  112. {sunholo-0.61.0 → sunholo-0.61.4}/sunholo.egg-info/top_level.txt +0 -0
  113. {sunholo-0.61.0 → sunholo-0.61.4}/tests/test_chat_history.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.61.0
3
+ Version: 0.61.4
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.61.0.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.61.4.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -1,7 +1,7 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
3
  # Define your base version
4
- version = '0.61.0'
4
+ version = '0.61.4'
5
5
 
6
6
  setup(
7
7
  name='sunholo',
@@ -74,7 +74,7 @@ def embeds_to_json(message: dict):
74
74
  # Output: '[{"type": "image", "url": "https://example.com/image.png"}]'
75
75
  ```
76
76
  """
77
- if len(message['embeds'] > 0):
77
+ if 'embeds' in message and len(message['embeds']) > 0:
78
78
  return json.dumps(message.get("embeds"))
79
79
  else:
80
80
  return ""
@@ -45,7 +45,7 @@ def pick_vectorstore(vs_str, vector_name, embeddings, read_only=None):
45
45
  return vectorstore
46
46
 
47
47
  elif vs_str == 'cloudsql' or vs_str == 'postgres':
48
- from langchain.vectorstores.pgvector import PGVector
48
+ from langchain_community.vectorstores import PGVector
49
49
 
50
50
  log.debug("Inititaing CloudSQL/Postgres pgvector")
51
51
  #setup_cloudsql(vector_name)
@@ -75,7 +75,7 @@ def load_all_configs():
75
75
  if filename in config_cache:
76
76
  cached_config, cache_time = config_cache[filename]
77
77
  if (current_time - cache_time) < timedelta(minutes=5):
78
- log.info(f"Returning cached config for {filename}")
78
+ log.debug(f"Returning cached config for {filename}")
79
79
  config = cached_config
80
80
  else:
81
81
  config = reload_config_file(config_file, filename)
@@ -167,7 +167,7 @@ def load_config(filename: str=None) -> tuple[dict, str]:
167
167
 
168
168
  return config, filename
169
169
 
170
- def load_config_key(key: str, vector_name: str, kind: str=None):
170
+ def load_config_key(key: str, vector_name: str, kind: str):
171
171
  """
172
172
  Load a specific key from a configuration file.
173
173
 
@@ -192,27 +192,16 @@ def load_config_key(key: str, vector_name: str, kind: str=None):
192
192
 
193
193
  configs_by_kind = load_all_configs()
194
194
 
195
- if kind:
196
- log.debug(f"Got kind: {kind} - applying to configs")
195
+ log.debug(f"Got kind: {kind} - applying to configs")
197
196
 
198
197
  if not configs_by_kind:
199
198
  log.warning("Did not load configs via folder")
200
199
 
201
- if kind and configs_by_kind.get(kind):
202
- config = configs_by_kind[kind]
203
- filename = kind
204
- else:
205
- config, filename = load_config(filename)
200
+ config = configs_by_kind[kind]
206
201
 
207
- log.debug(f"Fetching '{key}' for '{vector_name}'")
208
202
  apiVersion = config.get('apiVersion')
209
- kind = config.get('kind')
210
- vac = config.get('vac')
211
203
 
212
- if not apiVersion or not kind:
213
- raise ValueError("Deprecated config file, move to config with `apiVersion` and `kind` set")
214
-
215
- log.debug(f"Loaded config file {kind}/{apiVersion}")
204
+ log.debug(f"Fetching '{key}' for '{vector_name}' from '{kind}/{apiVersion}'")
216
205
 
217
206
  if kind == 'vacConfig':
218
207
  if vector_name == 'global':
@@ -226,7 +215,7 @@ def load_config_key(key: str, vector_name: str, kind: str=None):
226
215
  raise ValueError("Deprecated config file, move to config with `vac:` at top level for `vector_name`")
227
216
  vac_config = vac.get(vector_name)
228
217
  if not vac_config:
229
- raise ValueError(f"No config array was found for {vector_name} in {filename}")
218
+ raise ValueError(f"No config array was found for {vector_name} in {kind}")
230
219
 
231
220
  log.debug(f'vac_config: {vac_config} for {vector_name} - fetching "{key}"')
232
221
  key_value = vac_config.get(key)
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sunholo
3
- Version: 0.61.0
3
+ Version: 0.61.4
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.61.0.tar.gz
6
+ Download-URL: https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.61.4.tar.gz
7
7
  Author: Holosun ApS
8
8
  Author-email: multivac@sunholo.com
9
9
  License: Apache License, Version 2.0
@@ -106,6 +106,5 @@ sunholo/utils/parsers.py
106
106
  sunholo/utils/user_ids.py
107
107
  sunholo/vertex/__init__.py
108
108
  sunholo/vertex/init_vertex.py
109
- test/test_dispatch_to_qa.py
110
109
  tests/test_chat_history.py
111
110
  tests/test_config.py
@@ -0,0 +1,15 @@
1
+ import pytest
2
+ from unittest.mock import patch, mock_open
3
+ from sunholo.utils import config
4
+
5
+ def test_load_config():
6
+ expected_config = {"key": "value"}
7
+ with pytest.raises(FileNotFoundError):
8
+ config.load_config("non_existent_file")
9
+ with patch("builtins.open", mock_open(read_data='{"key": "value"}'), create=True):
10
+ result, _ = config.load_config("mock_file.json")
11
+ assert result == expected_config
12
+
13
+ def test_load_config_key():
14
+ with pytest.raises(KeyError):
15
+ config.load_config_key("non_existent_key", "mock_vector_name")
@@ -1,73 +0,0 @@
1
- import pytest
2
- import requests_mock
3
- from sunholo.agents import dispatch_to_qa
4
-
5
-
6
- def setup():
7
- user_input = 'mock_user_input'
8
- chat_history = 'mock_chat_history'
9
- vector_name = 'mock_vector_name'
10
- stream = 'mock_stream'
11
- return user_input, chat_history, vector_name, stream
12
-
13
-
14
- def test_prep_request_payload():
15
- user_input, chat_history, vector_name, stream = setup()
16
- # Call 'prep_request_payload' with the mock data
17
- qna_endpoint, qna_data = dispatch_to_qa.prep_request_payload(user_input, chat_history, vector_name, stream)
18
- # Check the returned 'qna_endpoint' and 'qna_data'
19
- assert qna_endpoint == 'expected_qna_endpoint'
20
- assert qna_data == 'expected_qna_data'
21
-
22
-
23
- def test_send_to_qa():
24
- user_input, chat_history, vector_name, stream = setup()
25
- mock_qna_endpoint = 'http://mock.qna.endpoint'
26
- mock_response = {'status': 'success'}
27
- with requests_mock.Mocker() as m:
28
- m.post(mock_qna_endpoint, json=mock_response)
29
- response = dispatch_to_qa.send_to_qa(user_input, chat_history, vector_name, stream)
30
- assert response == mock_response
31
-
32
- # Scenario where 'stream' is True and the response is a generator that yields response content chunks
33
- mock_response_chunk = 'mock_response_chunk'
34
- m.post(mock_qna_endpoint, text=mock_response_chunk)
35
- response = dispatch_to_qa.send_to_qa(user_input, chat_history, vector_name, True)
36
- assert next(response) == mock_response_chunk
37
-
38
- # Scenario where an HTTP error occurs
39
- m.post(mock_qna_endpoint, status_code=500)
40
- response = dispatch_to_qa.send_to_qa(user_input, chat_history, vector_name, stream)
41
- assert 'Error' in response
42
-
43
- # Scenario where any other error occurs
44
- m.post(mock_qna_endpoint, exc=requests_mock.exceptions.ReadTimeout)
45
- response = dispatch_to_qa.send_to_qa(user_input, chat_history, vector_name, stream)
46
- assert 'Error' in response
47
-
48
-
49
- def test_send_to_qa_async():
50
- user_input, chat_history, vector_name, stream = setup()
51
- mock_qna_endpoint = 'http://mock.qna.endpoint'
52
- mock_response = {'status': 'success'}
53
- import aiohttp
54
-
55
- @pytest.mark.asyncio
56
- async def test_send_to_qa_async():
57
- user_input, chat_history, vector_name, stream = setup()
58
- mock_qna_endpoint = 'http://mock.qna.endpoint'
59
- mock_response = {'status': 'success'}
60
- async with aiohttp.ClientSession() as session:
61
- async with session.post(mock_qna_endpoint, json=mock_response) as resp:
62
- response = await dispatch_to_qa.send_to_qa_async(user_input, chat_history, vector_name, stream)
63
- assert response == mock_response
64
-
65
- # Scenario where an HTTP error occurs
66
- async with session.post(mock_qna_endpoint, status=500) as resp:
67
- response = await dispatch_to_qa.send_to_qa_async(user_input, chat_history, vector_name, stream)
68
- assert 'Error' in response
69
-
70
- # Scenario where any other error occurs
71
- async with session.post(mock_qna_endpoint, raise_for_status=False) as resp:
72
- response = await dispatch_to_qa.send_to_qa_async(user_input, chat_history, vector_name, stream)
73
- assert 'Error' in response
@@ -1,40 +0,0 @@
1
- import pytest
2
- from sunholo.utils import config
3
-
4
- # Test for the `load_config` function
5
- def test_load_config():
6
- # Assuming the function is supposed to load a configuration from a file
7
- # and return a dictionary with the configuration data
8
- expected_config = {"key": "value"}
9
- with pytest.raises(FileNotFoundError):
10
- config.load_config("non_existent_file")
11
- with pytest.mock.patch("builtins.open", pytest.mock.mock_open(read_data="key: value"), create=True):
12
- assert config.load_config("mock_file.yaml") == expected_config
13
-
14
- # Test for the `load_config_key` function
15
- def test_load_config_key():
16
- # Assuming the function is supposed to load a specific key from the configuration
17
- expected_value = "value"
18
- with pytest.raises(KeyError):
19
- config.load_config_key("non_existent_key", "mock_vector_name")
20
- with pytest.mock.patch("sunholo.utils.config.load_all_configs", return_value={"mock_vector_name": {"key": "value"}}):
21
- assert config.load_config_key("key", "mock_vector_name") == expected_value
22
-
23
- # Test for the `get_module_filepath` function
24
- def test_get_module_filepath():
25
- # Assuming the function is supposed to return the absolute path of a module file
26
- expected_path = "/absolute/path/to/module/file"
27
- with pytest.mock.patch("os.path.dirname", return_value="/absolute/path/to"):
28
- assert config.get_module_filepath("module/file") == expected_path
29
-
30
- # Test for the `fetch_config` function
31
- def test_fetch_config():
32
- # Assuming the function is supposed to fetch configuration from a cloud storage bucket
33
- expected_update_time = "2022-01-01T00:00:00Z"
34
- with pytest.mock.patch("google.cloud.storage.Client") as mock_client:
35
- mock_bucket = mock_client.return_value.get_bucket.return_value
36
- mock_blob = mock_bucket.get_blob.return_value
37
- mock_blob.updated = expected_update_time
38
- assert config.fetch_config("bucket_name", "blob_name") == expected_update_time
39
- mock_bucket.get_blob.return_value = None
40
- assert config.fetch_config("bucket_name", "blob_name") is None
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes