codeplain 0.3.11.dev22__py3-none-any.whl → 0.3.12.dev23__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: codeplain
3
- Version: 0.3.11.dev22
3
+ Version: 0.3.12.dev23
4
4
  Summary: Transform plain language specifications into working code
5
5
  License-File: LICENSE
6
6
  Classifier: Environment :: Console
@@ -1,5 +1,5 @@
1
1
  change_detection.py,sha256=CazORZrezeZSw2I6VBvieN-c2SEjieZPo6pNrKwmMVA,6915
2
- codeplain_REST_api.py,sha256=ptb2u0mC5FJqMNeUbcc-bNXNhy9NRJZa5vI80uSFSwQ,22715
2
+ codeplain_REST_api.py,sha256=RGCoPyxzzdshJW96UDmwKjtgMk11iSyIK4iiHMdFIW8,25332
3
3
  concept_utils.py,sha256=TpyiQ4DfMtO231j-lPj65i0suRTPr8t9j3QNf9KiM4A,8080
4
4
  conformance_fix_journal.py,sha256=7wL3UOc3BWaUo5MCmiFbb3kIwOQ6iEpdQSyEmedo8Vk,9488
5
5
  diff_utils.py,sha256=AjiQlqo5pRos_8hVXZo5yBurl5BzSrTMGrQv4dCtRCg,1198
@@ -117,8 +117,8 @@ tui/spinner.py,sha256=Ro6Gd9Przf-whuHqPRY6HwI0T57yJjyNPbhDbigZKZE,2471
117
117
  tui/state_handlers.py,sha256=zbUS_D9eU8qIwVpaxPEp9zL9bpg8gXsWNoUaqg9TLrQ,16664
118
118
  tui/styles.css,sha256=kiC7Og_2G1E7owoiZgV95-3_dSeQnsNj3qzaY04xkDg,6727
119
119
  tui/widget_helpers.py,sha256=jitm2WHiKj-NVFL-hULxWzckPreRbUTl9OIZLN31-ek,6997
120
- codeplain-0.3.11.dev22.dist-info/METADATA,sha256=FkoMgKky0bzyU1gl-SJ38cgvxGf8BxzxcHmRRjrWkBs,7257
121
- codeplain-0.3.11.dev22.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
122
- codeplain-0.3.11.dev22.dist-info/entry_points.txt,sha256=oDZkBqu9WhtZApb_K6ia8-fn9aojwmAsgnKELceX5T4,46
123
- codeplain-0.3.11.dev22.dist-info/licenses/LICENSE,sha256=pCeKgQ1mXE5OmNUuKOfOZh1T1vqkeCUxghE7N8qgnzc,11345
124
- codeplain-0.3.11.dev22.dist-info/RECORD,,
120
+ codeplain-0.3.12.dev23.dist-info/METADATA,sha256=l_JE3UfPJT-Mwf0iCcx_uzEX_wFthjf6kF-K6htwRSo,7257
121
+ codeplain-0.3.12.dev23.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
122
+ codeplain-0.3.12.dev23.dist-info/entry_points.txt,sha256=oDZkBqu9WhtZApb_K6ia8-fn9aojwmAsgnKELceX5T4,46
123
+ codeplain-0.3.12.dev23.dist-info/licenses/LICENSE,sha256=pCeKgQ1mXE5OmNUuKOfOZh1T1vqkeCUxghE7N8qgnzc,11345
124
+ codeplain-0.3.12.dev23.dist-info/RECORD,,
codeplain_REST_api.py CHANGED
@@ -1,8 +1,11 @@
1
+ import socket
1
2
  import time
2
3
  from typing import Optional
3
4
 
4
5
  import requests
6
+ from requests.adapters import HTTPAdapter
5
7
  from requests.exceptions import ConnectionError, RequestException, Timeout
8
+ from urllib3.connection import HTTPConnection
6
9
 
7
10
  import plain2code_exceptions
8
11
  from plain2code_console import RETRY_COLOR
@@ -15,6 +18,57 @@ RETRY_DELAY = 3
15
18
  # at exit, and requests waits indefinitely by default.
16
19
  REPORT_TIMEOUT_SECONDS = 5
17
20
 
21
+ # A render call can leave the connection with nothing on it for several minutes while the
22
+ # service works on the answer. Network equipment between the two, such as the address
23
+ # translation a CI runner sits behind, drops a connection that quiet and tells neither end.
24
+ # The answer then has nowhere to go and the client waits for it for as long as it is allowed
25
+ # to run. These probes put a packet on the connection often enough to keep it, and they end
26
+ # it when the other end has really gone.
27
+ KEEPALIVE_IDLE_SECONDS = 60
28
+ KEEPALIVE_INTERVAL_SECONDS = 30
29
+ KEEPALIVE_FAILED_PROBES = 4
30
+
31
+
32
+ def keepalive_socket_options():
33
+ """The socket options that keep a long, quiet request alive, for the platforms that have them."""
34
+ options = list(HTTPConnection.default_socket_options)
35
+ options.append((socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1))
36
+ # The option that sets the idle time is named differently per platform, and Windows has
37
+ # none of the three. Whatever is missing is left out; the keepalive itself still applies.
38
+ for idle_option in ("TCP_KEEPIDLE", "TCP_KEEPALIVE"):
39
+ if hasattr(socket, idle_option):
40
+ options.append((socket.IPPROTO_TCP, getattr(socket, idle_option), KEEPALIVE_IDLE_SECONDS))
41
+ break
42
+ if hasattr(socket, "TCP_KEEPINTVL"):
43
+ options.append((socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, KEEPALIVE_INTERVAL_SECONDS))
44
+ if hasattr(socket, "TCP_KEEPCNT"):
45
+ options.append((socket.IPPROTO_TCP, socket.TCP_KEEPCNT, KEEPALIVE_FAILED_PROBES))
46
+ return options
47
+
48
+
49
+ class KeepaliveAdapter(HTTPAdapter):
50
+ """Opens every connection with keepalive on, whether it goes direct or through a proxy."""
51
+
52
+ def init_poolmanager(self, *args, **kwargs):
53
+ kwargs["socket_options"] = keepalive_socket_options()
54
+ return super().init_poolmanager(*args, **kwargs)
55
+
56
+ def proxy_manager_for(self, proxy, **proxy_kwargs):
57
+ # A request that goes through a proxy is served from a separate pool, which the
58
+ # options above never reach. A render behind a proxy is as quiet as any other and
59
+ # needs the same keepalive.
60
+ proxy_kwargs["socket_options"] = keepalive_socket_options()
61
+ return super().proxy_manager_for(proxy, **proxy_kwargs)
62
+
63
+
64
+ def new_session():
65
+ """A requests session whose connections carry keepalive."""
66
+ session = requests.Session()
67
+ session.mount("https://", KeepaliveAdapter())
68
+ session.mount("http://", KeepaliveAdapter())
69
+ return session
70
+
71
+
18
72
  RETRY_ERROR_CODES = [
19
73
  "LLMInternalError",
20
74
  ]
@@ -36,6 +90,7 @@ class CodeplainAPI:
36
90
  def __init__(self, api_key, console):
37
91
  self.api_key = api_key
38
92
  self.console = console
93
+ self.session = new_session()
39
94
 
40
95
  @property
41
96
  def api_url(self):
@@ -139,7 +194,7 @@ class CodeplainAPI:
139
194
 
140
195
  for attempt in range(num_retries + 1):
141
196
  try:
142
- response = requests.post(endpoint_url, headers=headers, json=payload, timeout=timeout)
197
+ response = self.session.post(endpoint_url, headers=headers, json=payload, timeout=timeout)
143
198
 
144
199
  try:
145
200
  response_json = response.json()