Skip to content

Commit 92e079e

Browse files
Merge pull request #2 from Zipstack/fix/assign-api-key-in-init
fix: Assign api_key on init call
2 parents b5476b1 + ad4d7f2 commit 92e079e

File tree

8 files changed

+489
-23
lines changed

8 files changed

+489
-23
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,5 +159,7 @@ cython_debug/
159159
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
160160
.idea/
161161

162+
.vscode/
163+
162164
.pdm-python
163165
.python-version

pdm.lock

Lines changed: 404 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ dependencies = [
1010
"requests~=2.32.3",
1111
]
1212
readme = "README.md"
13-
urls = { Homepage = "https://llmwhisperer.unstract.com" }
13+
urls = { Homepage = "https://llmwhisperer.unstract.com", Source = "https://github.com/Zipstack/llm-whisperer-python-client" }
1414
license = {text = "AGPL v3"}
1515
authors = [
1616
{name = "Zipstack Inc", email = "devsupport@zipstack.com"},
@@ -29,6 +29,13 @@ classifiers = [
2929
]
3030

3131
[tool.pdm.dev-dependencies]
32+
test = [
33+
"pytest>=8.2.2",
34+
"pytest-mock>=3.14.0",
35+
"pytest-dotenv>=0.5.2",
36+
"pytest-cov>=5.0.0",
37+
"pytest-md-report>=0.6.2",
38+
]
3239
lint = [
3340
"autopep8~=2.0.2",
3441
"black~=23.3.0",
@@ -41,6 +48,10 @@ lint = [
4148
"mypy~=1.10.0"
4249
]
4350

51+
[tool.pdm.version]
52+
source = "file"
53+
path = "src/llmwhisperer/__init__.py"
54+
4455
[tool.isort]
4556
line_length = 120
4657
multi_line_output = 3
@@ -57,7 +68,13 @@ max-line-length = 120
5768
includes = ["src"]
5869
package-dir = "src"
5970

60-
[tool.pdm.version]
61-
source = "file"
62-
path = "src/llmwhisperer/__init__.py"
71+
[tool.pytest.ini_options]
72+
env_files = ["tests/.env"]
73+
addopts = "-s"
74+
log_level = "INFO"
75+
log_cli = true
6376

77+
[tool.pdm.scripts]
78+
test.cmd = "pytest"
79+
test.env_file = "tests/.env"
80+
test.help = "Runs pytests for LLM Whisperer client"

src/llmwhisperer/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
__version__ = "0.11.0"
2-
1+
__version__ = "0.1.1"
32

43
def get_sdk_version():
54
"""Returns the SDK version."""

src/llmwhisperer/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
import requests
2424

25+
from llmwhisperer.utils import LLMWhispererUtils
26+
2527
BASE_URL = "https://llmwhisperer-api.unstract.com/v1"
2628

2729

@@ -110,6 +112,9 @@ def __init__(
110112

111113
if api_key == "":
112114
self.api_key = os.getenv("LLMWHISPERER_API_KEY", "")
115+
else:
116+
self.api_key = api_key
117+
self.logger.debug("api_key set to %s", LLMWhispererUtils.redact_key(self.api_key))
113118

114119
self.api_timeout = api_timeout
115120

src/llmwhisperer/utils.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
class LLMWhispererUtils:
2+
@staticmethod
3+
def redact_key(api_key: str, reveal_length=4) -> str:
4+
"""Hides sensitive information partially. Useful for logging keys.
5+
6+
Args:
7+
api_key (str): API key to redact
8+
9+
Returns:
10+
str: Redacted API key
11+
"""
12+
if not isinstance(api_key, str):
13+
raise ValueError("API key must be a string")
14+
15+
if reveal_length < 0:
16+
raise ValueError("Reveal length must be a non-negative integer")
17+
18+
redacted_length = max(len(api_key) - reveal_length, 0)
19+
revealed_part = api_key[:reveal_length]
20+
redacted_part = "x" * redacted_length
21+
return revealed_part + redacted_part

tests/sample.env

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export LLMWHISPERER_BASE_URL=https://llmwhisperer-api.unstract.com/v1
2-
export LLMWHISPERER_LOG_LEVEL=DEBUG
3-
export LLMWHISPERER_API_KEY=
1+
LLMWHISPERER_BASE_URL=https://llmwhisperer-api.unstract.com/v1
2+
LLMWHISPERER_LOG_LEVEL=DEBUG
3+
LLMWHISPERER_API_KEY=

tests/test_client.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,36 @@
1+
import logging
12
import unittest
23

4+
import pytest
5+
36
from llmwhisperer.client import LLMWhispererClient
47

8+
logger = logging.getLogger(__name__)
59

6-
class TestLLMWhispererClient(unittest.TestCase):
7-
@unittest.skip("Skipping test_get_usage_info")
8-
def test_get_usage_info(self):
9-
client = LLMWhispererClient()
10-
usage_info = client.get_usage_info()
11-
print(usage_info)
12-
self.assertIsInstance(usage_info, dict)
1310

11+
@pytest.fixture
12+
def llm_whisperer_client():
13+
# Create an instance of the client
14+
client = LLMWhispererClient()
15+
return client
16+
17+
18+
def test_get_usage_info(llm_whisperer_client):
19+
usage_info = llm_whisperer_client.get_usage_info()
20+
logger.info(usage_info)
21+
assert isinstance(usage_info, dict), "usage_info should be a dictionary"
22+
expected_keys = [
23+
"current_page_count",
24+
"daily_quota",
25+
"monthly_quota",
26+
"overage_page_count",
27+
"subscription_plan",
28+
"today_page_count",
29+
]
30+
assert set(usage_info.keys()) == set(expected_keys), f"usage_info {usage_info} does not contain the expected keys"
31+
32+
33+
class TestLLMWhispererClient(unittest.TestCase):
1434
@unittest.skip("Skipping test_whisper")
1535
def test_whisper(self):
1636
client = LLMWhispererClient()
@@ -22,30 +42,31 @@ def test_whisper(self):
2242
timeout=200,
2343
store_metadata_for_highlighting=True,
2444
)
25-
print(response)
45+
logger.info(response)
2646
# self.assertIsInstance(response, dict)
2747

2848
@unittest.skip("Skipping test_whisper_status")
2949
def test_whisper_status(self):
3050
client = LLMWhispererClient()
3151
response = client.whisper_status(whisper_hash="7cfa5cbb|5f1d285a7cf18d203de7af1a1abb0a3a")
32-
print(response)
52+
logger.info(response)
3353
self.assertIsInstance(response, dict)
3454

3555
@unittest.skip("Skipping test_whisper_retrieve")
3656
def test_whisper_retrieve(self):
3757
client = LLMWhispererClient()
3858
response = client.whisper_retrieve(whisper_hash="7cfa5cbb|5f1d285a7cf18d203de7af1a1abb0a3a")
39-
print(response)
59+
logger.info(response)
4060
self.assertIsInstance(response, dict)
4161

62+
@unittest.skip("Skipping test_whisper_highlight_data")
4263
def test_whisper_highlight_data(self):
4364
client = LLMWhispererClient()
4465
response = client.highlight_data(
4566
whisper_hash="9924d865|5f1d285a7cf18d203de7af1a1abb0a3a",
4667
search_text="Indiranagar",
4768
)
48-
print(response)
69+
logger.info(response)
4970
self.assertIsInstance(response, dict)
5071

5172

0 commit comments

Comments
 (0)