libentry 1.21__py3-none-any.whl → 1.21.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.
libentry/__init__.py CHANGED
@@ -5,4 +5,3 @@ from .executor import *
5
5
  from .dataclasses import *
6
6
  from .experiment import *
7
7
  from .logging import *
8
- from .server import *
libentry/api.py CHANGED
@@ -12,9 +12,10 @@ __all__ = [
12
12
 
13
13
  from dataclasses import dataclass, field
14
14
  from time import sleep
15
- from typing import Any, Callable, Iterable, List, Literal, Mapping, Optional, Tuple
15
+ from typing import Any, AsyncIterable, Callable, Iterable, List, Literal, Mapping, Optional, Tuple, Union
16
16
  from urllib.parse import urljoin
17
17
 
18
+ import httpx
18
19
  from urllib3 import PoolManager
19
20
  from urllib3.exceptions import HTTPError, TimeoutError
20
21
 
@@ -170,7 +171,7 @@ class ServiceError(RuntimeError):
170
171
  ErrorCallback = Callable[[Exception], None]
171
172
 
172
173
 
173
- class APIClient:
174
+ class BaseClient:
174
175
 
175
176
  def __init__(
176
177
  self,
@@ -181,6 +182,8 @@ class APIClient:
181
182
  user_agent: str = "API Client",
182
183
  connection: str = "close",
183
184
  verify=False,
185
+ stream_read_size: int = 512,
186
+ charset: str = "UTF-8",
184
187
  **extra_headers
185
188
  ) -> None:
186
189
  self.base_url = base_url
@@ -194,43 +197,89 @@ class APIClient:
194
197
  if api_key is not None:
195
198
  self.headers["Authorization"] = f"Bearer {api_key}"
196
199
  self.verify = verify
197
- self.charset = "UTF-8"
200
+ self.stream_read_size = stream_read_size
201
+ self.charset = charset
198
202
 
199
203
  DEFAULT_CONN_POOL_SIZE = 10
200
- CONN_POOL = (
201
- PoolManager(DEFAULT_CONN_POOL_SIZE),
202
- PoolManager(DEFAULT_CONN_POOL_SIZE, cert_reqs='CERT_NONE')
204
+ URLLIB3_POOL = (
205
+ PoolManager(DEFAULT_CONN_POOL_SIZE, cert_reqs='CERT_NONE'),
206
+ PoolManager(DEFAULT_CONN_POOL_SIZE)
203
207
  )
204
208
 
205
- def _request(
209
+ def _single_request(
210
+ self,
211
+ method: str,
212
+ url: str,
213
+ body: Optional[Union[bytes, str]],
214
+ headers: Optional[Mapping[str, str]],
215
+ timeout: float,
216
+ stream: bool,
217
+ verify: bool,
218
+ ) -> Union[bytes, Iterable[bytes]]:
219
+ response = self.URLLIB3_POOL[int(verify)].request(
220
+ method=method,
221
+ url=url,
222
+ body=body,
223
+ headers=headers,
224
+ timeout=timeout,
225
+ preload_content=not stream
226
+ )
227
+
228
+ if response.status != 200:
229
+ try:
230
+ raise ServiceError(response.data.decode(self.charset))
231
+ finally:
232
+ response.release_conn()
233
+
234
+ if not stream:
235
+ try:
236
+ return response.data
237
+ finally:
238
+ response.release_conn()
239
+ else:
240
+ def iter_content():
241
+ try:
242
+ if hasattr(response, "stream"):
243
+ yield from response.stream(self.stream_read_size, decode_content=True)
244
+ else:
245
+ while True:
246
+ data = response.read(self.stream_read_size)
247
+ if not data:
248
+ break
249
+ yield data
250
+ finally:
251
+ response.release_conn()
252
+
253
+ return iter_content()
254
+
255
+ def request(
206
256
  self,
207
257
  method: Literal["GET", "POST"],
208
258
  url: str,
209
- body: Optional[str] = None,
259
+ body: Optional[Union[bytes, str]] = None,
210
260
  headers: Optional[Mapping[str, str]] = None,
211
- stream: bool = False,
212
- num_trials: int = 5,
213
261
  timeout: float = 15,
262
+ num_trials: int = 5,
214
263
  interval: float = 1,
215
264
  retry_factor: float = 0.5,
216
265
  on_error: Optional[ErrorCallback] = None,
266
+ stream: bool = False,
217
267
  verify: Optional[bool] = None,
218
- ):
268
+ ) -> Union[bytes, Iterable[bytes]]:
219
269
  headers = self.headers if headers is None else headers
220
270
  verify = self.verify if verify is None else verify
221
- preload_content = not stream
222
271
 
223
- pool = self.CONN_POOL[int(not verify)]
224
272
  err = None
225
273
  for i in range(num_trials):
226
274
  try:
227
- return pool.request(
275
+ return self._single_request(
228
276
  method=method,
229
277
  url=url,
230
278
  body=body,
231
279
  headers=headers,
232
280
  timeout=timeout * (1 + i * retry_factor),
233
- preload_content=preload_content
281
+ stream=stream,
282
+ verify=verify,
234
283
  )
235
284
  except TimeoutError as e:
236
285
  err = e
@@ -243,98 +292,289 @@ class APIClient:
243
292
  sleep(interval)
244
293
  raise err
245
294
 
246
- def get(
295
+ HTTPX_POOL = httpx.Limits(max_keepalive_connections=DEFAULT_CONN_POOL_SIZE)
296
+
297
+ async def _single_request_async(
247
298
  self,
248
- path: Optional[str] = None, *,
299
+ method: str,
300
+ url: str,
301
+ body: Optional[Union[bytes, str]],
302
+ headers: Optional[Mapping[str, str]],
303
+ timeout: float,
304
+ stream: bool,
305
+ verify: bool,
306
+ ):
307
+ if not stream:
308
+ async with httpx.AsyncClient(headers=headers, verify=verify) as client:
309
+ response = await client.request(
310
+ method=method,
311
+ url=url,
312
+ content=body,
313
+ timeout=timeout
314
+ )
315
+ try:
316
+ if response.status_code != 200:
317
+ raise ServiceError(response.content.decode(self.charset))
318
+ return response.content
319
+ finally:
320
+ await response.aclose()
321
+ else:
322
+ client = httpx.AsyncClient(headers=headers, verify=verify)
323
+ response = client.stream(
324
+ method=method,
325
+ url=url,
326
+ content=body,
327
+ timeout=timeout
328
+ )
329
+
330
+ async def iter_content():
331
+ try:
332
+ async with response as r:
333
+ if r.status_code != 200:
334
+ content = await r.aread()
335
+ raise ServiceError(content.decode(self.charset))
336
+ async for data in r.aiter_bytes():
337
+ yield data
338
+ finally:
339
+ await client.aclose()
340
+
341
+ return iter_content()
342
+
343
+ async def request_async(
344
+ self,
345
+ method: Literal["GET", "POST"],
346
+ url: str,
347
+ body: Optional[Union[bytes, str]] = None,
348
+ headers: Optional[Mapping[str, str]] = None,
349
+ timeout: float = 15,
249
350
  num_trials: int = 5,
351
+ interval: float = 1,
352
+ retry_factor: float = 0.5,
353
+ on_error: Optional[ErrorCallback] = None,
354
+ stream: bool = False,
355
+ verify: Optional[bool] = None,
356
+ ):
357
+ headers = self.headers if headers is None else headers
358
+ verify = self.verify if verify is None else verify
359
+
360
+ err = None
361
+ for i in range(num_trials):
362
+ try:
363
+ return await self._single_request_async(
364
+ method=method,
365
+ url=url,
366
+ body=body,
367
+ headers=headers,
368
+ timeout=timeout * (1 + i * retry_factor),
369
+ stream=stream,
370
+ verify=verify,
371
+ )
372
+ except httpx.TimeoutException as e:
373
+ err = e
374
+ if callable(on_error):
375
+ on_error(e)
376
+ except httpx.HTTPError as e:
377
+ err = e
378
+ if callable(on_error):
379
+ on_error(e)
380
+ sleep(interval)
381
+ raise err
382
+
383
+
384
+ class APIClient(BaseClient):
385
+
386
+ def request(
387
+ self,
388
+ method: Literal["GET", "POST"],
389
+ path: str,
390
+ json_data: Optional[Mapping] = None,
391
+ *,
392
+ headers: Optional[Mapping[str, str]] = None,
250
393
  timeout: float = 15,
394
+ num_trials: int = 5,
251
395
  interval: float = 1,
252
396
  retry_factor: float = 0.5,
253
- on_error: Optional[ErrorCallback] = None
397
+ on_error: Optional[ErrorCallback] = None,
398
+ stream: bool = False,
399
+ chunk_delimiter: str = "\n\n",
400
+ chunk_prefix: str = None,
401
+ chunk_suffix: str = None,
402
+ error_prefix: str = "ERROR: ",
403
+ exhaust_stream: bool = False,
404
+ verify: Optional[bool] = None,
254
405
  ):
255
406
  full_url = urljoin(self.base_url, path)
256
- response = self._request(
257
- method="GET",
258
- url=full_url,
259
- num_trials=num_trials,
407
+ headers = {**self.headers}
408
+ headers["Accept"] = headers["Accept"] + f"; stream={int(stream)}"
409
+ body = json.dumps(json_data) if json_data is not None else None
410
+ content = super().request(
411
+ method,
412
+ full_url,
413
+ body=body,
414
+ headers=headers,
260
415
  timeout=timeout,
416
+ num_trials=num_trials,
261
417
  interval=interval,
262
418
  retry_factor=retry_factor,
263
- on_error=on_error
419
+ on_error=on_error,
420
+ stream=stream,
421
+ verify=verify,
264
422
  )
423
+ if not stream:
424
+ return _load_json_or_str(content.decode(self.charset))
425
+ else:
426
+ def iter_lines(data_list: Iterable[bytes]) -> Iterable[str]:
427
+ delimiter = chunk_delimiter.encode(self.charset) if chunk_delimiter is not None else None
428
+ pending = None
429
+ for data in data_list:
430
+ if pending is not None:
431
+ data = pending + data
265
432
 
266
- if response.status != 200:
267
- text = response.data.decode(self.charset)
268
- response.release_conn()
269
- raise ServiceError(text)
433
+ lines = data.split(delimiter) if delimiter else data.splitlines()
434
+ pending = lines.pop() if lines and lines[-1] and lines[-1][-1] == data[-1] else None
435
+
436
+ for line in lines:
437
+ yield line.decode(self.charset)
438
+
439
+ if pending is not None:
440
+ yield pending.decode(self.charset)
441
+
442
+ def iter_chunks(lines: Iterable[str]):
443
+ error = None
444
+ for chunk in lines:
445
+ if error is not None:
446
+ # error is not None means there is a fatal exception raised from the server side.
447
+ # The client should just complete the stream and then raise the error to the upper.
448
+ continue
449
+
450
+ if not chunk:
451
+ continue
270
452
 
271
- try:
272
- return _load_json_or_str(response.data.decode(self.charset))
273
- finally:
274
- response.release_conn()
453
+ if error_prefix is not None:
454
+ if chunk.startswith(error_prefix):
455
+ chunk = chunk[len(error_prefix):]
456
+ error = ServiceError(chunk)
457
+ continue
458
+
459
+ if chunk_prefix is not None:
460
+ if chunk.startswith(chunk_prefix):
461
+ chunk = chunk[len(chunk_prefix):]
462
+ else:
463
+ continue
464
+
465
+ if chunk_suffix is not None:
466
+ if chunk.endswith(chunk_suffix):
467
+ chunk = chunk[:-len(chunk_suffix)]
468
+ else:
469
+ continue
470
+
471
+ yield _load_json_or_str(chunk)
472
+
473
+ if error is not None:
474
+ raise error
475
+
476
+ gen = iter_lines(content)
477
+ gen = iter_chunks(gen)
478
+ return gen if not exhaust_stream else [*gen]
479
+
480
+ def get(
481
+ self,
482
+ path: Optional[str] = None,
483
+ *,
484
+ timeout: float = 15,
485
+ num_trials: int = 5,
486
+ interval: float = 1,
487
+ retry_factor: float = 0.5,
488
+ on_error: Optional[ErrorCallback] = None
489
+ ):
490
+ return self.request(
491
+ "GET",
492
+ path,
493
+ timeout=timeout,
494
+ num_trials=num_trials,
495
+ interval=interval,
496
+ retry_factor=retry_factor,
497
+ on_error=on_error,
498
+ )
275
499
 
276
500
  def post(
277
501
  self,
278
502
  path: Optional[str] = None,
279
- json_data: Optional[Mapping] = None, *,
503
+ json_data: Optional[Mapping] = None,
504
+ *,
505
+ timeout: float = 15,
506
+ num_trials: int = 5,
507
+ interval: float = 1,
508
+ retry_factor: float = 0.5,
509
+ on_error: Optional[ErrorCallback] = None,
280
510
  stream: bool = False,
511
+ chunk_delimiter: str = "\n\n",
512
+ chunk_prefix: str = None,
513
+ chunk_suffix: str = None,
514
+ error_prefix: str = "ERROR: ",
281
515
  exhaust_stream: bool = False,
282
- num_trials: int = 5,
516
+ ):
517
+ return self.request(
518
+ "POST",
519
+ path,
520
+ json_data=json_data,
521
+ timeout=timeout,
522
+ num_trials=num_trials,
523
+ interval=interval,
524
+ retry_factor=retry_factor,
525
+ on_error=on_error,
526
+ stream=stream,
527
+ chunk_delimiter=chunk_delimiter,
528
+ chunk_prefix=chunk_prefix,
529
+ chunk_suffix=chunk_suffix,
530
+ error_prefix=error_prefix,
531
+ exhaust_stream=exhaust_stream,
532
+ )
533
+
534
+ async def request_async(
535
+ self,
536
+ method: Literal["GET", "POST"],
537
+ path: str,
538
+ json_data: Optional[Mapping] = None,
539
+ *,
540
+ headers: Optional[Mapping[str, str]] = None,
283
541
  timeout: float = 15,
542
+ num_trials: int = 5,
284
543
  interval: float = 1,
285
544
  retry_factor: float = 0.5,
286
545
  on_error: Optional[ErrorCallback] = None,
546
+ stream: bool = False,
287
547
  chunk_delimiter: str = "\n\n",
288
548
  chunk_prefix: str = None,
289
549
  chunk_suffix: str = None,
290
550
  error_prefix: str = "ERROR: ",
291
- stream_read_size: int = 512
551
+ exhaust_stream: bool = False,
552
+ verify: Optional[bool] = None,
292
553
  ):
293
554
  full_url = urljoin(self.base_url, path)
294
-
295
555
  headers = {**self.headers}
296
556
  headers["Accept"] = headers["Accept"] + f"; stream={int(stream)}"
297
557
  body = json.dumps(json_data) if json_data is not None else None
298
- response = self._request(
299
- "POST",
300
- url=full_url,
558
+ content = await super().request_async(
559
+ method,
560
+ full_url,
301
561
  body=body,
302
562
  headers=headers,
303
- stream=stream,
304
- num_trials=num_trials,
305
563
  timeout=timeout,
564
+ num_trials=num_trials,
306
565
  interval=interval,
307
566
  retry_factor=retry_factor,
308
- on_error=on_error
567
+ on_error=on_error,
568
+ stream=stream,
569
+ verify=verify,
309
570
  )
310
- if response.status != 200:
311
- text = response.data.decode(self.charset)
312
- response.release_conn()
313
- raise ServiceError(text)
314
-
315
571
  if not stream:
316
- try:
317
- return _load_json_or_str(response.data.decode(self.charset))
318
- finally:
319
- response.release_conn()
572
+ return _load_json_or_str(content.decode(self.charset))
320
573
  else:
321
- def iter_content():
322
- try:
323
- if hasattr(response, "stream"):
324
- yield from response.stream(stream_read_size, decode_content=True)
325
- else:
326
- while True:
327
- data = response.read(stream_read_size)
328
- if not data:
329
- break
330
- yield data
331
- finally:
332
- response.release_conn()
333
-
334
- def iter_lines(contents: Iterable[bytes]) -> Iterable[str]:
574
+ async def iter_lines(data_list: AsyncIterable[bytes]) -> AsyncIterable[str]:
335
575
  delimiter = chunk_delimiter.encode(self.charset) if chunk_delimiter is not None else None
336
576
  pending = None
337
- for data in contents:
577
+ async for data in data_list:
338
578
  if pending is not None:
339
579
  data = pending + data
340
580
 
@@ -347,9 +587,9 @@ class APIClient:
347
587
  if pending is not None:
348
588
  yield pending.decode(self.charset)
349
589
 
350
- def iter_chunks(lines: Iterable[str]):
590
+ async def iter_chunks(lines: AsyncIterable[str]) -> AsyncIterable:
351
591
  error = None
352
- for chunk in lines:
592
+ async for chunk in lines:
353
593
  if error is not None:
354
594
  # error is not None means there is a fatal exception raised from the server side.
355
595
  # The client should just complete the stream and then raise the error to the upper.
@@ -381,7 +621,60 @@ class APIClient:
381
621
  if error is not None:
382
622
  raise error
383
623
 
384
- gen = iter_content()
385
- gen = iter_lines(gen)
624
+ gen = iter_lines(content)
386
625
  gen = iter_chunks(gen)
387
626
  return gen if not exhaust_stream else [*gen]
627
+
628
+ async def get_async(
629
+ self,
630
+ path: Optional[str] = None,
631
+ *,
632
+ timeout: float = 15,
633
+ num_trials: int = 5,
634
+ interval: float = 1,
635
+ retry_factor: float = 0.5,
636
+ on_error: Optional[ErrorCallback] = None
637
+ ):
638
+ return await self.request_async(
639
+ "GET",
640
+ path,
641
+ timeout=timeout,
642
+ num_trials=num_trials,
643
+ interval=interval,
644
+ retry_factor=retry_factor,
645
+ on_error=on_error,
646
+ )
647
+
648
+ async def post_async(
649
+ self,
650
+ path: Optional[str] = None,
651
+ json_data: Optional[Mapping] = None,
652
+ *,
653
+ timeout: float = 15,
654
+ num_trials: int = 5,
655
+ interval: float = 1,
656
+ retry_factor: float = 0.5,
657
+ on_error: Optional[ErrorCallback] = None,
658
+ stream: bool = False,
659
+ chunk_delimiter: str = "\n\n",
660
+ chunk_prefix: str = None,
661
+ chunk_suffix: str = None,
662
+ error_prefix: str = "ERROR: ",
663
+ exhaust_stream: bool = False,
664
+ ):
665
+ return await self.request_async(
666
+ "POST",
667
+ path,
668
+ json_data=json_data,
669
+ timeout=timeout,
670
+ num_trials=num_trials,
671
+ interval=interval,
672
+ retry_factor=retry_factor,
673
+ on_error=on_error,
674
+ stream=stream,
675
+ chunk_delimiter=chunk_delimiter,
676
+ chunk_prefix=chunk_prefix,
677
+ chunk_suffix=chunk_suffix,
678
+ error_prefix=error_prefix,
679
+ exhaust_stream=exhaust_stream,
680
+ )
libentry/test_api.py CHANGED
@@ -43,8 +43,7 @@ def test(request: TestRequest):
43
43
  try:
44
44
  kwargs = dict(
45
45
  on_error=lambda err: print(f"[{tid}:{cid}:RETRY] {err}"),
46
- timeout=request.timeout,
47
- stream=request.stream
46
+ timeout=request.timeout
48
47
  )
49
48
  t = time()
50
49
  if request.method == "GET":
@@ -56,6 +55,7 @@ def test(request: TestRequest):
56
55
  response = APIClient().post(
57
56
  request.url,
58
57
  request.data,
58
+ stream=request.stream,
59
59
  **kwargs
60
60
  )
61
61
  if not request.stream:
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.1
2
2
  Name: libentry
3
- Version: 1.21
3
+ Version: 1.21.2
4
4
  Summary: Entries for experimental utilities.
5
5
  Home-page: https://github.com/XoriieInpottn/libentry
6
6
  Author: xi
@@ -9,23 +9,13 @@ License: Apache-2.0 license
9
9
  Platform: any
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Description-Content-Type: text/markdown
12
- License-File: LICENSE
13
- Requires-Dist: pydantic
12
+ Requires-Dist: Flask
14
13
  Requires-Dist: PyYAML
14
+ Requires-Dist: gunicorn
15
+ Requires-Dist: httpx
15
16
  Requires-Dist: numpy
17
+ Requires-Dist: pydantic
16
18
  Requires-Dist: urllib3
17
- Requires-Dist: Flask
18
- Requires-Dist: gunicorn
19
- Dynamic: author
20
- Dynamic: author-email
21
- Dynamic: classifier
22
- Dynamic: description
23
- Dynamic: description-content-type
24
- Dynamic: home-page
25
- Dynamic: license
26
- Dynamic: platform
27
- Dynamic: requires-dist
28
- Dynamic: summary
29
19
 
30
20
  # libentry
31
21
 
@@ -39,3 +29,5 @@ Dynamic: summary
39
29
  2. Use its post() or get() method to send the request.
40
30
 
41
31
 
32
+
33
+
@@ -1,5 +1,5 @@
1
- libentry/__init__.py,sha256=rDBip9M1Xb1N4wMKE1ni_DldrQbkRjp8DxPkTp3K2qo,170
2
- libentry/api.py,sha256=bs4mpOLRA6i9gAWPGzeNarpKssZs2UlaP2xuQbAi9NQ,12063
1
+ libentry/__init__.py,sha256=ko2YBIIx5H3dD0tedBkialzJGEDczFaP_PZmT1cIlak,148
2
+ libentry/api.py,sha256=zlZF0IWyQu8GPEVAM0J6K8BOSgqI06p8JJVoCNaTCBo,22110
3
3
  libentry/argparse.py,sha256=NxzXV-jBN51ReZsNs5aeyOfzwYQ5A5nJ95rWoa-FYCs,10415
4
4
  libentry/dataclasses.py,sha256=AQV2PuxplJCwGZ5HKX72U-z-POUhTdy3XtpEK9KNIGQ,4541
5
5
  libentry/executor.py,sha256=cTV0WxJi0nU1TP-cOwmeodN8DD6L1691M2HIQsJtGrU,6582
@@ -7,8 +7,7 @@ libentry/experiment.py,sha256=ejgAHDXWIe9x4haUzIFuz1WasLY0_aD1z_vyEVGjTu8,4922
7
7
  libentry/json.py,sha256=1-Kv5ZRb5dBrOTU84n6sZtYZV3xE-O6wEt_--ynbSaU,1209
8
8
  libentry/logging.py,sha256=IiYoCUzm8XTK1fduA-NA0FI2Qz_m81NEPV3d3tEfgdI,1349
9
9
  libentry/schema.py,sha256=o6JcdR00Yj4_Qjmlo100OlQpMVnl0PgvvwVVrL9limw,8268
10
- libentry/server.py,sha256=gYPoZXd0umlDYZf-6ZV0_vJadg3YQvnLDc6JFDJh9jc,1503
11
- libentry/test_api.py,sha256=GFmirvxfCAQ-nhh6QXyB5EpF4WaENCc3Eoymuk5JxBQ,4448
10
+ libentry/test_api.py,sha256=Xw7B7sH6g1iCTV5sFzyBF3JAJzeOr9xg0AyezTNsnIk,4452
12
11
  libentry/service/__init__.py,sha256=1oLL20yLB1GL9IbFiZD8OReDqiCpFr-yetIR6x1cNkI,23
13
12
  libentry/service/common.py,sha256=OVaW2afgKA6YqstJmtnprBCqQEUZEWotZ6tHavmJJeU,42
14
13
  libentry/service/flask.py,sha256=Alpsix01ROqI28k-dabD8wJlWAWs-ObNc1nJ-LxOXn4,13349
@@ -16,10 +15,10 @@ libentry/service/list.py,sha256=ElHWhTgShGOhaxMUEwVbMXos0NQKjHsODboiQ-3AMwE,1397
16
15
  libentry/service/running.py,sha256=FrPJoJX6wYxcHIysoatAxhW3LajCCm0Gx6l7__6sULQ,5105
17
16
  libentry/service/start.py,sha256=mZT7b9rVULvzy9GTZwxWnciCHgv9dbGN2JbxM60OMn4,1270
18
17
  libentry/service/stop.py,sha256=wOpwZgrEJ7QirntfvibGq-XsTC6b3ELhzRW2zezh-0s,1187
19
- libentry-1.21.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
20
- libentry-1.21.dist-info/METADATA,sha256=_WRBE701A14mz9idf8wRi6UnN6ZSo9e8X1KyjNxj1zw,1017
21
- libentry-1.21.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
22
- libentry-1.21.dist-info/entry_points.txt,sha256=1v_nLVDsjvVJp9SWhl4ef2zZrsLTBtFWgrYFgqvQBgc,61
23
- libentry-1.21.dist-info/top_level.txt,sha256=u2uF6-X5fn2Erf9PYXOg_6tntPqTpyT-yzUZrltEd6I,9
24
- libentry-1.21.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
25
- libentry-1.21.dist-info/RECORD,,
18
+ libentry-1.21.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
19
+ libentry-1.21.2.dist-info/METADATA,sha256=M2-N8UEjYrgrXC-85vZ2-ts0SeNjOTx9_Vjclgdu8Xg,813
20
+ libentry-1.21.2.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
21
+ libentry-1.21.2.dist-info/entry_points.txt,sha256=vgHmJZhM-kqM7U9S179UwDD3pM232tpzJ5NntncXi_8,62
22
+ libentry-1.21.2.dist-info/top_level.txt,sha256=u2uF6-X5fn2Erf9PYXOg_6tntPqTpyT-yzUZrltEd6I,9
23
+ libentry-1.21.2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
24
+ libentry-1.21.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: bdist_wheel (0.45.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
2
  libentry_test_api = libentry.test_api:main
3
+
libentry/server.py DELETED
@@ -1,53 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- import os
4
- from socketserver import ThreadingMixIn
5
- from threading import Thread
6
- from xmlrpc.server import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
7
-
8
- from libentry.logging import logger
9
-
10
- __all__ = [
11
- 'XMLRPCServerMixIn',
12
- ]
13
-
14
-
15
- class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
16
- pass
17
-
18
-
19
- class MultRequestHandler(SimpleXMLRPCRequestHandler):
20
- rpc_paths = ('/RPC2', '/RPC3')
21
-
22
- def log_message(self, fmt, *args):
23
- logger.info(fmt % args)
24
-
25
-
26
- class XMLRPCServerMixIn:
27
-
28
- def __init__(self, log_request=True):
29
- self.log_request = log_request
30
-
31
- def serve_forever(self, addr, daemon=False):
32
- if 'RANK' in os.environ:
33
- rank = int(os.environ['RANK'])
34
- if rank > 0:
35
- return
36
-
37
- with ThreadXMLRPCServer(
38
- addr,
39
- requestHandler=MultRequestHandler,
40
- allow_none=True,
41
- logRequests=self.log_request
42
- ) as server:
43
- server.register_introspection_functions()
44
- server.register_multicall_functions()
45
- server.register_instance(self)
46
- if daemon:
47
- if hasattr(self, 'serve_thread'):
48
- raise RuntimeError('Server is already running.')
49
- serve_thread = Thread(target=server.serve_forever, daemon=daemon)
50
- serve_thread.start()
51
- setattr(self, 'serve_thread', serve_thread)
52
- else:
53
- server.serve_forever()