appmesh 1.6.3__py3-none-any.whl → 1.6.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.
appmesh/client_http.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # client_http.py
2
- # pylint: disable=broad-exception-raised,line-too-long,broad-exception-caught,too-many-lines, import-outside-toplevel, protected-access
2
+ # pylint: disable=broad-exception-raised,line-too-long,broad-exception-caught,too-many-lines,import-outside-toplevel
3
3
  import abc
4
4
  import base64
5
5
  import json
@@ -17,69 +17,12 @@ from urllib import parse
17
17
  import aniso8601
18
18
  import jwt
19
19
  import requests
20
+ from requests.auth import _basic_auth_str
20
21
  from .app import App
21
22
  from .app_run import AppRun
22
23
  from .app_output import AppOutput
23
24
 
24
25
 
25
- class EncodingResponse:
26
- """Wrapper for requests.Response that handles encoding conversion on Windows."""
27
-
28
- def __init__(self, response: requests.Response):
29
- self._response = response
30
- self._converted_text = None
31
- self._should_convert = False
32
-
33
- # Check if we need to convert encoding on Windows
34
- if sys.platform == "win32":
35
- content_type = response.headers.get("Content-Type", "").lower()
36
- if response.status_code == HTTPStatus.OK and "text/plain" in content_type and "utf-8" in content_type:
37
- try:
38
- local_encoding = locale.getpreferredencoding()
39
-
40
- if local_encoding.lower() not in ["utf-8", "utf8"]:
41
- # Ensure response is decoded as UTF-8 first
42
- response.encoding = "utf-8"
43
- utf8_text = response.text # This gives us proper Unicode string
44
-
45
- # Convert Unicode to local encoding, then back to Unicode
46
- # This simulates how text would appear in local encoding
47
- try:
48
- local_bytes = utf8_text.encode(local_encoding, errors="replace")
49
- self._converted_text = local_bytes.decode(local_encoding)
50
- self._should_convert = True
51
- except (UnicodeEncodeError, LookupError):
52
- # If local encoding can't handle the characters, fall back to UTF-8
53
- self._converted_text = utf8_text
54
- self._should_convert = True
55
-
56
- except (UnicodeError, LookupError):
57
- # If any conversion fails, keep original UTF-8
58
- response.encoding = "utf-8"
59
-
60
- @property
61
- def text(self):
62
- """Return converted text if needed, otherwise original text."""
63
- if self._should_convert and self._converted_text is not None:
64
- return self._converted_text
65
- # return the original text from _response without modification
66
- return self._response.text
67
-
68
- def __getattr__(self, name):
69
- """Dynamically delegate attribute access to the original response"""
70
- return getattr(self._response, name)
71
-
72
- def __dir__(self):
73
- """Optional: allow dir() to show attributes of both wrapper and response"""
74
- return list(set(dir(self._response) + list(self.__dict__.keys())))
75
-
76
- @property
77
- def __class__(self):
78
- """Optional: allow isinstance checks for requests.Response"""
79
- # Pretend to be a requests.Response for isinstance checks
80
- return requests.Response
81
-
82
-
83
26
  class AppMeshClient(metaclass=abc.ABCMeta):
84
27
  """
85
28
  Client SDK for interacting with the App Mesh service via REST API.
@@ -132,6 +75,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
132
75
  - wait_for_async_run()
133
76
  - run_app_sync()
134
77
  - run_task()
78
+ - cancle_task()
135
79
 
136
80
  # System Management
137
81
  - forward_to
@@ -180,6 +124,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
180
124
 
181
125
  JSON_KEY_MESSAGE = "message"
182
126
  HTTP_USER_AGENT = "appmesh/python"
127
+ HTTP_HEADER_KEY_AUTH = "Authorization"
183
128
  HTTP_HEADER_KEY_USER_AGENT = "User-Agent"
184
129
  HTTP_HEADER_KEY_X_TARGET_HOST = "X-Target-Host"
185
130
  HTTP_HEADER_KEY_X_FILE_PATH = "X-File-Path"
@@ -194,6 +139,53 @@ class AppMeshClient(metaclass=abc.ABCMeta):
194
139
  DELETE = "DELETE"
195
140
  POST_STREAM = "POST_STREAM"
196
141
 
142
+ class EncodingResponse(requests.Response):
143
+ """Response subclass that handles encoding conversion on Windows."""
144
+
145
+ def __init__(self, response: requests.Response):
146
+ super().__init__()
147
+
148
+ # copy essential fields from response
149
+ self.__dict__.update(response.__dict__)
150
+
151
+ self._converted_text = None
152
+ self._should_convert = False
153
+
154
+ # Check if we need to convert encoding on Windows
155
+ if sys.platform == "win32":
156
+ content_type = response.headers.get("Content-Type", "").lower()
157
+ if response.status_code == HTTPStatus.OK and "text/plain" in content_type and "utf-8" in content_type:
158
+ try:
159
+ local_encoding = locale.getpreferredencoding()
160
+
161
+ if local_encoding.lower() not in ["utf-8", "utf8"]:
162
+ # Ensure response is decoded as UTF-8 first
163
+ self.encoding = "utf-8"
164
+ utf8_text = self.text # This gives us proper Unicode string
165
+
166
+ # Convert Unicode to local encoding, then back to Unicode
167
+ # This simulates how text would appear in local encoding
168
+ try:
169
+ local_bytes = utf8_text.encode(local_encoding, errors="replace")
170
+ self._converted_text = local_bytes.decode(local_encoding)
171
+ self._should_convert = True
172
+ except (UnicodeEncodeError, LookupError):
173
+ # If local encoding can't handle the characters, fall back to UTF-8
174
+ self._converted_text = utf8_text
175
+ self._should_convert = True
176
+
177
+ except (UnicodeError, LookupError):
178
+ # If any conversion fails, keep original UTF-8
179
+ self.encoding = "utf-8"
180
+
181
+ @property
182
+ def text(self):
183
+ """Return converted text if needed, otherwise original text."""
184
+ if self._should_convert and self._converted_text is not None:
185
+ return self._converted_text
186
+ # return the original text from _response without modification
187
+ return super().text
188
+
197
189
  def __init__(
198
190
  self,
199
191
  rest_url: str = "https://127.0.0.1:6060",
@@ -239,7 +231,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
239
231
  # Token auto-refresh
240
232
  self._token_refresh_timer = None
241
233
  self._auto_refresh_token = auto_refresh_token
242
- self.jwt_token = jwt_token # Set property last after all dependencies are initialized
234
+ self.jwt_token = jwt_token # Set property last after all dependencies are initialized to setup refresh timer
243
235
 
244
236
  @staticmethod
245
237
  def _ensure_logging_configured():
@@ -316,7 +308,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
316
308
  check_interval = 1 # Almost immediate refresh
317
309
  else:
318
310
  # Check at earlier of 5 minutes before expiry or regular interval
319
- check_interval = min(time_to_expiry - self.TOKEN_REFRESH_OFFSET, self.TOKEN_REFRESH_INTERVAL)
311
+ check_interval = max(1, min(time_to_expiry - self.TOKEN_REFRESH_OFFSET, self.TOKEN_REFRESH_INTERVAL))
320
312
 
321
313
  # Create timer to execute refresh check
322
314
  self._token_refresh_timer = threading.Timer(check_interval, self._check_and_refresh_token)
@@ -482,7 +474,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
482
474
  AppMeshClient.Method.POST,
483
475
  path="/appmesh/login",
484
476
  header={
485
- "Authorization": "Basic " + base64.b64encode((user_name + ":" + user_pwd).encode()).decode(),
477
+ self.HTTP_HEADER_KEY_AUTH: _basic_auth_str(user_name, user_pwd),
486
478
  "X-Expire-Seconds": str(self._parse_duration(timeout_seconds)),
487
479
  **({"X-Audience": audience} if audience else {}),
488
480
  # **({"X-Totp-Code": totp_code} if totp_code else {}),
@@ -1160,7 +1152,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
1160
1152
  fp.write(chunk)
1161
1153
 
1162
1154
  # Apply file attributes (permissions, owner, group) if requested
1163
- if apply_file_attributes:
1155
+ if apply_file_attributes and sys.platform != "win32":
1164
1156
  if "X-File-Mode" in resp.headers:
1165
1157
  os.chmod(path=local_file, mode=int(resp.headers["X-File-Mode"]))
1166
1158
  if "X-File-User" in resp.headers and "X-File-Group" in resp.headers:
@@ -1406,9 +1398,8 @@ class AppMeshClient(metaclass=abc.ABCMeta):
1406
1398
 
1407
1399
  # Prepare headers
1408
1400
  header = {} if header is None else header
1409
- if self.jwt_token:
1410
- token = self._get_access_token()
1411
- header["Authorization"] = "Bearer " + token
1401
+ if token := self._get_access_token():
1402
+ header[self.HTTP_HEADER_KEY_AUTH] = f"Bearer {token}"
1412
1403
  if self.forward_to and len(self.forward_to) > 0:
1413
1404
  if ":" in self.forward_to:
1414
1405
  header[self.HTTP_HEADER_KEY_X_TARGET_HOST] = self.forward_to
@@ -1444,6 +1435,6 @@ class AppMeshClient(metaclass=abc.ABCMeta):
1444
1435
  raise Exception("Invalid http method", method)
1445
1436
 
1446
1437
  # Wrap the response for encoding handling
1447
- return EncodingResponse(resp)
1438
+ return AppMeshClient.EncodingResponse(resp)
1448
1439
  except requests.exceptions.RequestException as e:
1449
- raise Exception(f"HTTP request failed: {str(e)}")
1440
+ raise Exception(f"HTTP request failed: {str(e)}") from e
appmesh/client_tcp.py CHANGED
@@ -3,10 +3,11 @@
3
3
 
4
4
  import json
5
5
  import os
6
+ import sys
6
7
  import socket
7
8
  import uuid
8
9
  import requests
9
- from .client_http import AppMeshClient, EncodingResponse
10
+ from .client_http import AppMeshClient
10
11
  from .tcp_transport import TCPTransport
11
12
  from .tcp_messages import RequestMessage, ResponseMessage
12
13
 
@@ -56,7 +57,7 @@ class AppMeshClientTCP(AppMeshClient):
56
57
  rest_ssl_verify=AppMeshClient.DEFAULT_SSL_CA_CERT_PATH if os.path.exists(AppMeshClient.DEFAULT_SSL_CA_CERT_PATH) else False,
57
58
  rest_ssl_client_cert=None,
58
59
  jwt_token=None,
59
- tcp_address=("localhost", 6059),
60
+ tcp_address=("127.0.0.1", 6059),
60
61
  ):
61
62
  """Construct an App Mesh client TCP object to communicate securely with an App Mesh server over TLS.
62
63
 
@@ -78,7 +79,7 @@ class AppMeshClientTCP(AppMeshClient):
78
79
  jwt_token (str, optional): JWT token for authentication. Used in methods requiring login and user authorization.
79
80
 
80
81
  tcp_address (Tuple[str, int], optional): Address and port for establishing a TCP connection to the server.
81
- Defaults to `("localhost", 6059)`.
82
+ Defaults to `("127.0.0.1", 6059)`.
82
83
  """
83
84
  self.tcp_transport = TCPTransport(address=tcp_address, ssl_verify=rest_ssl_verify, ssl_client_cert=rest_ssl_client_cert)
84
85
  super().__init__(rest_ssl_verify=rest_ssl_verify, rest_ssl_client_cert=rest_ssl_client_cert, jwt_token=jwt_token)
@@ -115,8 +116,8 @@ class AppMeshClientTCP(AppMeshClient):
115
116
  self.tcp_transport.connect()
116
117
 
117
118
  appmesh_request = RequestMessage()
118
- if super().jwt_token:
119
- appmesh_request.headers["Authorization"] = "Bearer " + super().jwt_token
119
+ if token := self._get_access_token():
120
+ appmesh_request.headers[self.HTTP_HEADER_KEY_AUTH] = token
120
121
  if super().forward_to and len(super().forward_to) > 0:
121
122
  raise Exception("Not support forward request in TCP mode")
122
123
  appmesh_request.headers[self.HTTP_HEADER_KEY_USER_AGENT] = self.HTTP_USER_AGENT_TCP
@@ -159,7 +160,7 @@ class AppMeshClientTCP(AppMeshClient):
159
160
  if appmesh_resp.body_msg_type:
160
161
  response.headers["Content-Type"] = appmesh_resp.body_msg_type
161
162
 
162
- return EncodingResponse(response)
163
+ return AppMeshClient.EncodingResponse(response)
163
164
 
164
165
  ########################################
165
166
  # File management
@@ -189,7 +190,7 @@ class AppMeshClientTCP(AppMeshClient):
189
190
  break
190
191
  fp.write(chunk_data)
191
192
 
192
- if apply_file_attributes:
193
+ if apply_file_attributes and sys.platform != "win32":
193
194
  if "X-File-Mode" in resp.headers:
194
195
  os.chmod(path=local_file, mode=int(resp.headers["X-File-Mode"]))
195
196
  if "X-File-User" in resp.headers and "X-File-Group" in resp.headers:
appmesh/server_http.py CHANGED
@@ -17,7 +17,7 @@ class AppMeshServer(metaclass=abc.ABCMeta):
17
17
  Server SDK for App Mesh application interacting with the local App Mesh REST service over HTTPS.
18
18
 
19
19
  Build-in runtime environment variables required:
20
- - APP_MESH_PROCESS_ID
20
+ - APP_MESH_PROCESS_KEY
21
21
  - APP_MESH_APPLICATION_NAME
22
22
 
23
23
  Methods:
@@ -58,10 +58,10 @@ class AppMeshServer(metaclass=abc.ABCMeta):
58
58
  @staticmethod
59
59
  def _get_runtime_env() -> Tuple[str, str]:
60
60
  """Read and validate required runtime environment variables."""
61
- process_id = os.getenv("APP_MESH_PROCESS_ID")
61
+ process_id = os.getenv("APP_MESH_PROCESS_KEY")
62
62
  app_name = os.getenv("APP_MESH_APPLICATION_NAME")
63
63
  if not process_id:
64
- raise Exception("Missing environment variable: APP_MESH_PROCESS_ID. This must be set by App Mesh service.")
64
+ raise Exception("Missing environment variable: APP_MESH_PROCESS_KEY. This must be set by App Mesh service.")
65
65
  if not app_name:
66
66
  raise Exception("Missing environment variable: APP_MESH_APPLICATION_NAME. This must be set by App Mesh service.")
67
67
  return process_id, app_name
appmesh/server_tcp.py CHANGED
@@ -20,7 +20,7 @@ class AppMeshServerTCP(AppMeshServer):
20
20
  self,
21
21
  rest_ssl_verify=AppMeshClient.DEFAULT_SSL_CA_CERT_PATH if os.path.exists(AppMeshClient.DEFAULT_SSL_CA_CERT_PATH) else False,
22
22
  rest_ssl_client_cert=None,
23
- tcp_address: Tuple[str, int] = ("localhost", 6059),
23
+ tcp_address: Tuple[str, int] = ("127.0.0.1", 6059),
24
24
  *,
25
25
  logger_: Optional[logging.Logger] = None,
26
26
  ):
appmesh/tcp_transport.py CHANGED
@@ -36,7 +36,7 @@ class TCPTransport:
36
36
  - `tuple`: A pair of paths (`cert_file`, `key_file`), where `cert_file` is the client certificate file path and `key_file` is the private key file path.
37
37
 
38
38
  tcp_address (Tuple[str, int], optional): Address and port for establishing a TCP connection to the server.
39
- Defaults to `("localhost", 6059)`.
39
+ Defaults to `("127.0.0.1", 6059)`.
40
40
  """
41
41
  self.tcp_address = address
42
42
  self.ssl_verify = ssl_verify
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: appmesh
3
- Version: 1.6.3
3
+ Version: 1.6.5
4
4
  Summary: Client SDK for App Mesh
5
5
  Home-page: https://github.com/laoshanxi/app-mesh
6
6
  Author: laoshanxi
@@ -0,0 +1,16 @@
1
+ appmesh/__init__.py,sha256=TY1y5B5cE57uhraEzCFOZRWuo9SY1R-fYNRan8hCZOM,1670
2
+ appmesh/app.py,sha256=crD4DRFZJuHtZMfSsz7C-EwvjPmGZbFXYXvA_wCdvdI,10734
3
+ appmesh/app_output.py,sha256=vfn322AyixblI8DbXds08h6L_ybObiaRSifsA1-Xcoo,1035
4
+ appmesh/app_run.py,sha256=aYq852a29OThIi32Xtx5s0sTXZ97T0lHD5WXH8yfPoc,2018
5
+ appmesh/appmesh_client.py,sha256=ywB2222PtJUffdfdxZcBfdhZs1KYyc7JvzMxwuK2qyI,378
6
+ appmesh/client_http.py,sha256=Clx0Wx8I8Wo8T63f2dco_vDI12mbcqKOMt7d7xBXJFc,57516
7
+ appmesh/client_http_oauth.py,sha256=1d51o0JX_xtB8d2bEuM7_XJHcwMnhcjkbIq7GE1Zxm8,6120
8
+ appmesh/client_tcp.py,sha256=hQ4s9ab1Drqaqhfx-pmLhqhFL48jbwNbkzOv1fCSUnw,11444
9
+ appmesh/server_http.py,sha256=H6DfMhU2NxlBqxjmRG2C8NXMaGDxy_5QVyBmaVrelfI,4322
10
+ appmesh/server_tcp.py,sha256=-CU5tw97WJmDcUNsNPWqpdZ0wxRzRD6kUP3XyNZUTHc,1444
11
+ appmesh/tcp_messages.py,sha256=H9S_iCy0IuufY2v50_SUgRvcyQmJsySG65tBe_xb3Ko,1878
12
+ appmesh/tcp_transport.py,sha256=0hRSp5fpL9wKB05JIyIRIuyBC8w1IdokryhMDHqtN4M,8946
13
+ appmesh-1.6.5.dist-info/METADATA,sha256=vYzVg5U0rZNL8_HaPR3-CPuw2RFoLsUiB8UB7YDNyJI,11828
14
+ appmesh-1.6.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ appmesh-1.6.5.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
16
+ appmesh-1.6.5.dist-info/RECORD,,
@@ -1,16 +0,0 @@
1
- appmesh/__init__.py,sha256=TY1y5B5cE57uhraEzCFOZRWuo9SY1R-fYNRan8hCZOM,1670
2
- appmesh/app.py,sha256=crD4DRFZJuHtZMfSsz7C-EwvjPmGZbFXYXvA_wCdvdI,10734
3
- appmesh/app_output.py,sha256=vfn322AyixblI8DbXds08h6L_ybObiaRSifsA1-Xcoo,1035
4
- appmesh/app_run.py,sha256=aYq852a29OThIi32Xtx5s0sTXZ97T0lHD5WXH8yfPoc,2018
5
- appmesh/appmesh_client.py,sha256=ywB2222PtJUffdfdxZcBfdhZs1KYyc7JvzMxwuK2qyI,378
6
- appmesh/client_http.py,sha256=WLdHmi2ryzCiXFyIIAbKH3arfcs__rxt4kwehpO_w6s,57711
7
- appmesh/client_http_oauth.py,sha256=1d51o0JX_xtB8d2bEuM7_XJHcwMnhcjkbIq7GE1Zxm8,6120
8
- appmesh/client_tcp.py,sha256=OrKmJ-SMSmCPXj5WVhWwBXiK8Z_WyCrDmTim0pe1pc0,11407
9
- appmesh/server_http.py,sha256=vf_Kh7ZIyEuBijZp8I2Rv-Fy9gxFdPFn5Pp2rUNCT1U,4319
10
- appmesh/server_tcp.py,sha256=biBFF5IGWFOw2ru831cfmzn1DVXcBm9e-W6CP2VkfzE,1444
11
- appmesh/tcp_messages.py,sha256=H9S_iCy0IuufY2v50_SUgRvcyQmJsySG65tBe_xb3Ko,1878
12
- appmesh/tcp_transport.py,sha256=f28zfZNH46tUHfT8F1PrCM1wUXiSBIW7R3ipMsXJqIU,8946
13
- appmesh-1.6.3.dist-info/METADATA,sha256=Hcymb5xi90fgxLHqHNWHzicT2KLZzGPo4DonII-IQBQ,11828
14
- appmesh-1.6.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
- appmesh-1.6.3.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
16
- appmesh-1.6.3.dist-info/RECORD,,