libentry 1.11.3__py3-none-any.whl → 1.11.5__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.
libentry/api.py CHANGED
@@ -10,9 +10,9 @@ __all__ = [
10
10
  "APIClient",
11
11
  ]
12
12
 
13
- import os
14
13
  from dataclasses import dataclass, field
15
14
  from typing import Any, Callable, Iterable, List, Literal, Mapping, Optional, Tuple
15
+ from urllib.parse import urljoin
16
16
 
17
17
  import requests
18
18
 
@@ -31,6 +31,7 @@ class APIInfo:
31
31
  chunk_suffix: str = field(default=None)
32
32
  stream_prefix: str = field(default=None)
33
33
  stream_suffix: str = field(default=None)
34
+ error_prefix: str = field(default="ERROR: ")
34
35
  extra_info: Mapping[str, Any] = field(default_factory=dict)
35
36
 
36
37
 
@@ -190,7 +191,7 @@ class APIClient:
190
191
  self.verify = verify
191
192
 
192
193
  def get(self, path: str, timeout=60):
193
- api_url = os.path.join(self.base_url, path)
194
+ api_url = urljoin(self.base_url, path)
194
195
  response = requests.get(api_url, headers=self.headers, verify=self.verify, timeout=timeout)
195
196
 
196
197
  if response.status_code != 200:
@@ -212,8 +213,9 @@ class APIClient:
212
213
  chunk_delimiter: str = "\n\n",
213
214
  chunk_prefix: str = None,
214
215
  chunk_suffix: str = None,
216
+ error_prefix: str = "ERROR: "
215
217
  ):
216
- full_url = os.path.join(self.base_url, path)
218
+ full_url = urljoin(self.base_url, path)
217
219
 
218
220
  data = json.dumps(json_data) if json_data is not None else None
219
221
  response = requests.post(
@@ -239,6 +241,7 @@ class APIClient:
239
241
  chunk_delimiter=chunk_delimiter.encode() if chunk_delimiter else None,
240
242
  chunk_prefix=chunk_prefix.encode() if chunk_prefix else None,
241
243
  chunk_suffix=chunk_suffix.encode() if chunk_suffix else None,
244
+ error_prefix=error_prefix.encode() if error_prefix else None,
242
245
  )
243
246
  else:
244
247
  try:
@@ -251,13 +254,26 @@ class APIClient:
251
254
  response: requests.Response,
252
255
  chunk_delimiter: bytes,
253
256
  chunk_prefix: bytes,
254
- chunk_suffix: bytes
257
+ chunk_suffix: bytes,
258
+ error_prefix: bytes
255
259
  ) -> Iterable:
256
260
  try:
261
+ error = None
257
262
  for chunk in response.iter_lines(decode_unicode=False, delimiter=chunk_delimiter):
263
+ if error is not None:
264
+ # error is not None means there is a fatal exception raised from the server side.
265
+ # The client should just complete the stream and then raise the error to the upper.
266
+ continue
267
+
258
268
  if not chunk:
259
269
  continue
260
270
 
271
+ if error_prefix is not None:
272
+ if chunk.startswith(error_prefix):
273
+ chunk = chunk[len(error_prefix):]
274
+ error = ServiceError(chunk)
275
+ continue
276
+
261
277
  if chunk_prefix is not None:
262
278
  if chunk.startswith(chunk_prefix):
263
279
  chunk = chunk[len(chunk_prefix):]
@@ -271,5 +287,8 @@ class APIClient:
271
287
  continue
272
288
 
273
289
  yield _load_json_or_str(chunk)
290
+
291
+ if error is not None:
292
+ raise error
274
293
  finally:
275
294
  response.close()
libentry/service/flask.py CHANGED
@@ -33,16 +33,27 @@ class JSONDumper:
33
33
  if self.api_info.chunk_delimiter is not None:
34
34
  yield self.api_info.chunk_delimiter
35
35
 
36
- for item in response:
37
- text = self.dump(item)
36
+ try:
37
+ for item in response:
38
+ text = self.dump(item)
38
39
 
39
- if self.api_info.chunk_prefix is not None:
40
- yield self.api_info.chunk_prefix
40
+ if self.api_info.chunk_prefix is not None:
41
+ yield self.api_info.chunk_prefix
41
42
 
42
- yield text
43
+ yield text
43
44
 
44
- if self.api_info.chunk_suffix is not None:
45
- yield self.api_info.chunk_suffix
45
+ if self.api_info.chunk_suffix is not None:
46
+ yield self.api_info.chunk_suffix
47
+
48
+ if self.api_info.chunk_delimiter is not None:
49
+ yield self.api_info.chunk_delimiter
50
+ except Exception as e:
51
+ if isinstance(e, (SystemExit, KeyboardInterrupt)):
52
+ raise e
53
+ if self.api_info.error_prefix is not None:
54
+ yield self.api_info.error_prefix
55
+
56
+ yield self.dump_error(e)
46
57
 
47
58
  if self.api_info.chunk_delimiter is not None:
48
59
  yield self.api_info.chunk_delimiter
@@ -65,6 +76,19 @@ class JSONDumper:
65
76
  except TypeError:
66
77
  return repr(response)
67
78
 
79
+ @staticmethod
80
+ def dump_error(e: Exception) -> str:
81
+ err_cls = e.__class__
82
+ err_name = err_cls.__name__
83
+ module = err_cls.__module__
84
+ if module != "builtins":
85
+ err_name = f"{module}.{err_name}"
86
+ return json.dumps({
87
+ "error": err_name,
88
+ "message": str(e),
89
+ "traceback": traceback.format_exc()
90
+ }, indent=2)
91
+
68
92
 
69
93
  def create_model_from_signature(fn):
70
94
  sig = signature(fn)
@@ -122,14 +146,14 @@ class FlaskWrapper:
122
146
  except Exception as e:
123
147
  if isinstance(e, (SystemExit, KeyboardInterrupt)):
124
148
  raise e
125
- return self.app.error(self.make_err(e))
149
+ return self.app.error(self.dumper.dump_error(e))
126
150
  else:
127
151
  try:
128
152
  response = self.fn(**input_json)
129
153
  except Exception as e:
130
154
  if isinstance(e, (SystemExit, KeyboardInterrupt)):
131
155
  raise e
132
- return self.app.error(self.make_err(e))
156
+ return self.app.error(self.dumper.dump_error(e))
133
157
 
134
158
  if isinstance(response, (GeneratorType, range)):
135
159
  return self.app.response_class(
@@ -142,19 +166,6 @@ class FlaskWrapper:
142
166
  mimetype=self.api_info.mime_type
143
167
  )
144
168
 
145
- @staticmethod
146
- def make_err(e):
147
- err_cls = e.__class__
148
- err_name = err_cls.__name__
149
- module = err_cls.__module__
150
- if module != "builtins":
151
- err_name = f"{module}.{err_name}"
152
- return json.dumps({
153
- "error": err_name,
154
- "message": str(e),
155
- "traceback": traceback.format_exc()
156
- }, indent=2)
157
-
158
169
 
159
170
  class CustomGenerateJsonSchema(GenerateJsonSchema):
160
171
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: libentry
3
- Version: 1.11.3
3
+ Version: 1.11.5
4
4
  Summary: Entries for experimental utilities.
5
5
  Home-page: https://github.com/XoriieInpottn/libentry
6
6
  Author: xi
@@ -1,5 +1,5 @@
1
1
  libentry/__init__.py,sha256=rDBip9M1Xb1N4wMKE1ni_DldrQbkRjp8DxPkTp3K2qo,170
2
- libentry/api.py,sha256=m0j9aGPD4ewJdeQkooUoNJeTbrAtqlpSscmy3gfOTYw,7921
2
+ libentry/api.py,sha256=2LWDPP3QJRmwk5WfNI9y57uqjjEQilojlLg6v4pbuPk,8746
3
3
  libentry/argparse.py,sha256=Bk11H4WRKxcjMlSd0mjWj1T4NWh0JW5eA7TX3C21IoE,10116
4
4
  libentry/dataclasses.py,sha256=AQV2PuxplJCwGZ5HKX72U-z-POUhTdy3XtpEK9KNIGQ,4541
5
5
  libentry/executor.py,sha256=cTV0WxJi0nU1TP-cOwmeodN8DD6L1691M2HIQsJtGrU,6582
@@ -9,14 +9,14 @@ libentry/logging.py,sha256=IiYoCUzm8XTK1fduA-NA0FI2Qz_m81NEPV3d3tEfgdI,1349
9
9
  libentry/server.py,sha256=gYPoZXd0umlDYZf-6ZV0_vJadg3YQvnLDc6JFDJh9jc,1503
10
10
  libentry/service/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
11
11
  libentry/service/common.py,sha256=OVaW2afgKA6YqstJmtnprBCqQEUZEWotZ6tHavmJJeU,42
12
- libentry/service/flask.py,sha256=TZGyDXWh5r93uxklSpP7cKmD2r0ZswplMUK91Hxo4Do,9169
12
+ libentry/service/flask.py,sha256=jPpOSkxPRz0ma1d-O4zyqbxfy-XrEE2Hku-ccaCADNE,9627
13
13
  libentry/service/list.py,sha256=ElHWhTgShGOhaxMUEwVbMXos0NQKjHsODboiQ-3AMwE,1397
14
14
  libentry/service/running.py,sha256=FrPJoJX6wYxcHIysoatAxhW3LajCCm0Gx6l7__6sULQ,5105
15
15
  libentry/service/start.py,sha256=mZT7b9rVULvzy9GTZwxWnciCHgv9dbGN2JbxM60OMn4,1270
16
16
  libentry/service/stop.py,sha256=wOpwZgrEJ7QirntfvibGq-XsTC6b3ELhzRW2zezh-0s,1187
17
- libentry-1.11.3.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
18
- libentry-1.11.3.dist-info/METADATA,sha256=oNzYKmc3HwT6ZGKaT-EHVKzEGj99lYQJvXQmNVVJDkc,500
19
- libentry-1.11.3.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
20
- libentry-1.11.3.dist-info/top_level.txt,sha256=u2uF6-X5fn2Erf9PYXOg_6tntPqTpyT-yzUZrltEd6I,9
21
- libentry-1.11.3.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
22
- libentry-1.11.3.dist-info/RECORD,,
17
+ libentry-1.11.5.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
18
+ libentry-1.11.5.dist-info/METADATA,sha256=Mv2rrwKRRvjEE2B8kmkWZe7mRltbbXv8GF3E_DTGKNc,500
19
+ libentry-1.11.5.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
20
+ libentry-1.11.5.dist-info/top_level.txt,sha256=u2uF6-X5fn2Erf9PYXOg_6tntPqTpyT-yzUZrltEd6I,9
21
+ libentry-1.11.5.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
22
+ libentry-1.11.5.dist-info/RECORD,,