snowleopard 0.3.0__tar.gz → 0.3.2__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.
@@ -0,0 +1,17 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(mkdir:*)",
5
+ "Bash(uv add:*)",
6
+ "Bash(uv run pytest:*)",
7
+ "WebFetch(domain:www.python-httpx.org)",
8
+ "Bash(python -c:*)",
9
+ "Bash(uv run python:*)",
10
+ "WebFetch(domain:github.com)",
11
+ "Bash(uv run snowy response --help:*)",
12
+ "Bash(uv run:*)"
13
+ ],
14
+ "deny": [],
15
+ "ask": []
16
+ }
17
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: snowleopard
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: snowleopard.ai client library
5
5
  Author-email: Snowy <hello@snowleopard.ai>
6
6
  License: MIT License
@@ -4,10 +4,14 @@
4
4
 
5
5
  from snowleopard.async_client import AsyncSnowLeopardClient
6
6
  from snowleopard.client import SnowLeopardClient
7
+ from snowleopard.error import APIBadRequest, SnowLeopardHTTPError, SLException
7
8
 
8
- __version__ = "0.3.0"
9
+ __version__ = "0.3.2"
9
10
 
10
11
  __all__ = [
11
12
  "SnowLeopardClient",
12
13
  "AsyncSnowLeopardClient",
14
+ "SLException",
15
+ "APIBadRequest",
16
+ "SnowLeopardHTTPError",
13
17
  ]
@@ -7,8 +7,7 @@ from typing import AsyncGenerator, Optional, Dict, Any
7
7
 
8
8
  import httpx
9
9
  from snowleopard.client_base import SLClientBase
10
- from snowleopard.error import APIBadRequest
11
- from snowleopard.models import APIError, parse, ResponseDataObjects, RetrieveResponseObjects
10
+ from snowleopard.models import parse, ResponseDataObjects, RetrieveResponseObjects
12
11
 
13
12
 
14
13
  class AsyncSnowLeopardClient(SLClientBase):
@@ -50,13 +49,9 @@ class AsyncSnowLeopardClient(SLClientBase):
50
49
  self._build_path(datafile_id, "response"),
51
50
  json=self._build_request_body(user_query, known_data),
52
51
  ) as resp:
53
- if resp.status_code not in (400,):
54
- resp.raise_for_status()
52
+ self._raise_for_status(resp)
55
53
  async for line in resp.aiter_lines():
56
- resultObj = parse(json.loads(line))
57
- if isinstance(resultObj, APIError) and resp.status_code == 400:
58
- raise APIBadRequest(resultObj.description)
59
- yield resultObj
54
+ yield parse(json.loads(line))
60
55
 
61
56
  async def __aenter__(self):
62
57
  await self.client.__aenter__()
@@ -10,7 +10,7 @@ from typing import List, Optional, Dict, Any
10
10
 
11
11
  from httpx import HTTPStatusError
12
12
  from snowleopard import __version__, SnowLeopardClient
13
- from snowleopard.error import APIBadRequest
13
+ from snowleopard.error import APIBadRequest, SLException
14
14
 
15
15
 
16
16
  def _create_parser() -> argparse.ArgumentParser:
@@ -113,12 +113,9 @@ def _response(parsed_args):
113
113
  datafile_id=parsed_args.datafile,
114
114
  ):
115
115
  print(json.dumps(dataclasses.asdict(chunk)))
116
- except APIBadRequest as e:
116
+ except SLException as e:
117
117
  print(f"error: {str(e)}", file=sys.stderr)
118
118
  hadErrors = True
119
- except HTTPStatusError as e:
120
- print(str(e), file=sys.stderr)
121
- hadErrors = True
122
119
  if hadErrors:
123
120
  sys.exit(1)
124
121
 
@@ -7,8 +7,7 @@ from typing import Optional, Generator, Dict, Any
7
7
 
8
8
  import httpx
9
9
  from snowleopard.client_base import SLClientBase
10
- from snowleopard.error import APIBadRequest
11
- from snowleopard.models import APIError, parse, RetrieveResponseObjects, ResponseDataObjects
10
+ from snowleopard.models import parse, RetrieveResponseObjects, ResponseDataObjects
12
11
 
13
12
 
14
13
  class SnowLeopardClient(SLClientBase):
@@ -50,12 +49,9 @@ class SnowLeopardClient(SLClientBase):
50
49
  url=self._build_path(datafile_id, "response"),
51
50
  json=self._build_request_body(user_query, known_data),
52
51
  ) as resp:
53
- if resp.status_code not in (400,):
54
- resp.raise_for_status()
52
+ self._raise_for_status(resp)
55
53
  for line in resp.iter_lines():
56
54
  resultObj = parse(json.loads(line))
57
- if isinstance(resultObj, APIError) and resp.status_code == 400:
58
- raise APIBadRequest(resultObj.description)
59
55
  yield resultObj
60
56
 
61
57
  def __enter__(self):
@@ -9,8 +9,8 @@ from typing import Optional, Dict, Any
9
9
 
10
10
  import httpx
11
11
 
12
- from snowleopard.error import APIBadRequest
13
- from snowleopard.models import APIError, parse
12
+ from snowleopard.error import APIBadRequest, SnowLeopardHTTPError
13
+ from snowleopard.models import parse
14
14
 
15
15
 
16
16
  @dataclass
@@ -103,14 +103,17 @@ class SLClientBase:
103
103
  return body
104
104
 
105
105
  @staticmethod
106
- def _parse_retrieve(resp):
107
- if resp.status_code not in (400, 409):
106
+ def _raise_for_status(resp):
107
+ try:
108
108
  resp.raise_for_status()
109
+ except httpx.HTTPStatusError as e:
110
+ raise SnowLeopardHTTPError(e.response.status_code, e.response) from e
111
+
112
+ def _parse_retrieve(self, resp):
113
+ if resp.status_code != 409:
114
+ self._raise_for_status(resp)
109
115
  try:
110
- resultObj = parse(resp.json())
116
+ return parse(resp.json())
111
117
  except Exception:
112
- resp.raise_for_status()
118
+ self._raise_for_status(resp)
113
119
  raise
114
- if isinstance(resultObj, APIError) and resp.status_code == 400:
115
- raise APIBadRequest(resultObj.description)
116
- return resultObj
@@ -0,0 +1,32 @@
1
+ # -*- coding: utf-8 -*-
2
+ # copyright 2026 Snow Leopard, Inc
3
+ # released under the MIT license - see LICENSE file
4
+
5
+ import httpx
6
+
7
+ class SLException(Exception):
8
+ pass
9
+
10
+
11
+ class APIBadRequest(SLException):
12
+ """Raised when the request is invalid due to bad input.
13
+
14
+ This is raised for client-side validation errors, such as an empty or
15
+ whitespace-only query string.
16
+ """
17
+
18
+
19
+ class SnowLeopardHTTPError(SLException):
20
+ """Raised when the SnowLeopard API returns an unexpected HTTP error status."""
21
+
22
+ status_code: int
23
+ response: httpx.Response
24
+
25
+ def __init__(self, status_code: int, response: httpx.Response):
26
+ self.status_code = status_code
27
+ self.response = response
28
+ try:
29
+ body = response.text[:500]
30
+ except Exception:
31
+ body = "<response body unavailable>"
32
+ super().__init__(f"SnowLeopard API error (HTTP {status_code}): {body}")
@@ -99,6 +99,7 @@ class ResponseStatus(StrEnum):
99
99
  SUCCESS = "SUCCESS"
100
100
  BAD_REQUEST = "BAD_REQUEST"
101
101
  NOT_FOUND_IN_SCHEMA = "NOT_FOUND_IN_SCHEMA"
102
+ UNABLE_TO_UNDERSTAND_QUESTION = "UNABLE_TO_UNDERSTAND_QUESTION"
102
103
  UNKNOWN = "UNKNOWN"
103
104
  INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR"
104
105
  AUTHORIZATION_FAILED = "AUTHORIZATION_FAILED"
@@ -1,10 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # copyright 2026 Snow Leopard, Inc
3
- # released under the MIT license - see LICENSE file
4
-
5
- class SLException(Exception):
6
- pass
7
-
8
-
9
- class APIBadRequest(SLException):
10
- pass
File without changes
File without changes
File without changes
File without changes
File without changes