client.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. import json
  2. import platform
  3. import time
  4. import Tea
  5. import asyncio
  6. import threading
  7. import random
  8. import hashlib
  9. from email.utils import formatdate
  10. from urllib.parse import urlencode
  11. from io import BytesIO
  12. from Tea.model import TeaModel
  13. from Tea.stream import READABLE
  14. from typing import Any, BinaryIO, Dict, List
  15. _process_start_time = int(time.time() * 1000)
  16. _seqId = 0
  17. class Client:
  18. """
  19. This is a utility module
  20. """
  21. class __ModelEncoder(json.JSONEncoder):
  22. def default(self, o: Any) -> Any:
  23. if isinstance(o, TeaModel):
  24. return o.to_map()
  25. elif isinstance(o, bytes):
  26. return o.decode('utf-8')
  27. super().default(o)
  28. @staticmethod
  29. def __read_part(f, size=1024):
  30. while True:
  31. part = f.read(size)
  32. if part:
  33. yield part
  34. else:
  35. return
  36. @staticmethod
  37. def __get_default_agent():
  38. return f'AlibabaCloud ({platform.system()}; {platform.machine()}) ' \
  39. f'Python/{platform.python_version()} Core/{Tea.__version__} TeaDSL/1'
  40. @staticmethod
  41. def to_bytes(
  42. val: str,
  43. ) -> bytes:
  44. """
  45. Convert a string(utf8) to bytes
  46. @return: the return bytes
  47. """
  48. if isinstance(val, bytes):
  49. return val
  50. elif isinstance(val, str):
  51. return val.encode(encoding="utf-8")
  52. else:
  53. return str(val).encode(encoding="utf-8")
  54. @staticmethod
  55. def to_string(
  56. val: bytes,
  57. ) -> str:
  58. """
  59. Convert a bytes to string(utf8)
  60. @return: the return string
  61. """
  62. if isinstance(val, str):
  63. return val
  64. elif isinstance(val, bytes):
  65. return val.decode('utf-8')
  66. else:
  67. return str(val)
  68. @staticmethod
  69. def parse_json(
  70. val: str,
  71. ) -> Any:
  72. """
  73. Parse it by JSON format
  74. @return: the parsed result
  75. """
  76. try:
  77. return json.loads(val)
  78. except ValueError:
  79. raise RuntimeError(f'Failed to parse the value as json format, Value: "{val}".')
  80. @staticmethod
  81. async def read_as_bytes_async(stream) -> bytes:
  82. """
  83. Read data from a readable stream, and compose it to a bytes
  84. @param stream: the readable stream
  85. @return: the bytes result
  86. """
  87. if isinstance(stream, bytes):
  88. return stream
  89. elif isinstance(stream, str):
  90. return bytes(stream, encoding='utf-8')
  91. else:
  92. return await stream.read()
  93. @staticmethod
  94. async def read_as_string_async(stream) -> str:
  95. """
  96. Read data from a readable stream, and compose it to a string
  97. @param stream: the readable stream
  98. @return: the string result
  99. """
  100. buff = await Client.read_as_bytes_async(stream)
  101. return Client.to_string(buff)
  102. @staticmethod
  103. async def read_as_json_async(stream) -> Any:
  104. """
  105. Read data from a readable stream, and parse it by JSON format
  106. @param stream: the readable stream
  107. @return: the parsed result
  108. """
  109. return Client.parse_json(
  110. await Client.read_as_string_async(stream)
  111. )
  112. @staticmethod
  113. def read_as_bytes(stream) -> bytes:
  114. """
  115. Read data from a readable stream, and compose it to a bytes
  116. @param stream: the readable stream
  117. @return: the bytes result
  118. """
  119. if isinstance(stream, READABLE):
  120. b = b''
  121. for part in Client.__read_part(stream, 1024):
  122. b += part
  123. return b
  124. elif isinstance(stream, bytes):
  125. return stream
  126. else:
  127. return bytes(stream, encoding='utf-8')
  128. @staticmethod
  129. def read_as_string(stream) -> str:
  130. """
  131. Read data from a readable stream, and compose it to a string
  132. @param stream: the readable stream
  133. @return: the string result
  134. """
  135. buff = Client.read_as_bytes(stream)
  136. return Client.to_string(buff)
  137. @staticmethod
  138. def read_as_json(stream) -> Any:
  139. """
  140. Read data from a readable stream, and parse it by JSON format
  141. @param stream: the readable stream
  142. @return: the parsed result
  143. """
  144. return Client.parse_json(Client.read_as_string(stream))
  145. @staticmethod
  146. def get_nonce() -> str:
  147. """
  148. Generate a nonce string
  149. @return: the nonce string
  150. """
  151. global _seqId
  152. thread_id = threading.get_ident()
  153. current_time = int(time.time() * 1000)
  154. seq = _seqId
  155. _seqId += 1
  156. randNum = random.getrandbits(64)
  157. msg = f'{_process_start_time}-{thread_id}-{current_time}-{seq}-{randNum}'
  158. md5 = hashlib.md5()
  159. md5.update(msg.encode('utf-8'))
  160. return md5.hexdigest()
  161. @staticmethod
  162. def get_date_utcstring() -> str:
  163. """
  164. Get an UTC format string by current date, e.g. 'Thu, 06 Feb 2020 07:32:54 GMT'
  165. Always English (RFC 1123), independent of system locale.
  166. @return: the UTC format string
  167. """
  168. return formatdate(usegmt=True)
  169. @staticmethod
  170. def default_string(
  171. real: str,
  172. default: str,
  173. ) -> str:
  174. """
  175. If not set the real, use default value
  176. @return: the return string
  177. """
  178. return real if real is not None else default
  179. @staticmethod
  180. def default_number(
  181. real: int,
  182. default: int,
  183. ) -> int:
  184. """
  185. If not set the real, use default value
  186. @return: the return number
  187. """
  188. return real if real is not None else default
  189. @staticmethod
  190. def to_form_string(
  191. val: dict,
  192. ) -> str:
  193. """
  194. Format a map to form string, like a=a%20b%20c
  195. @return: the form string
  196. """
  197. if not val:
  198. return ""
  199. keys = sorted(list(val))
  200. dic = {k: val[k] for k in keys if not isinstance(val[k], READABLE)}
  201. return urlencode(dic)
  202. @staticmethod
  203. def to_jsonstring(
  204. val: Any,
  205. ) -> str:
  206. """
  207. Stringify a value by JSON format
  208. @return: the JSON format string
  209. """
  210. if isinstance(val, str):
  211. return str(val)
  212. return json.dumps(
  213. val, cls=Client.__ModelEncoder, ensure_ascii=False, separators=(",", ":")
  214. )
  215. @staticmethod
  216. def empty(
  217. val: str,
  218. ) -> bool:
  219. """
  220. Check the string is empty?
  221. @return: if string is null or zero length, return true
  222. """
  223. return not val
  224. @staticmethod
  225. def equal_string(
  226. val1: str,
  227. val2: str,
  228. ) -> bool:
  229. """
  230. Check one string equals another one?
  231. @return: if equals, return true
  232. """
  233. return val1 == val2
  234. @staticmethod
  235. def equal_number(
  236. val1: int,
  237. val2: int,
  238. ) -> bool:
  239. """
  240. Check one number equals another one?
  241. @return: if equals, return true
  242. """
  243. return val1 == val2
  244. @staticmethod
  245. def is_unset(
  246. value: Any,
  247. ) -> bool:
  248. """
  249. Check one value is unset
  250. @return: if unset, return true
  251. """
  252. return value is None
  253. @staticmethod
  254. def stringify_map_value(
  255. m: Dict[str, Any],
  256. ) -> Dict[str, str]:
  257. """
  258. Stringify the value of map
  259. @return: the new stringified map
  260. """
  261. if m is None:
  262. return {}
  263. dic_result = {}
  264. for k, v in m.items():
  265. if v is not None:
  266. if isinstance(v, bytes):
  267. v = v.decode('utf-8')
  268. else:
  269. v = str(v)
  270. dic_result[k] = v
  271. return dic_result
  272. @staticmethod
  273. def anyify_map_value(
  274. m: Dict[str, str],
  275. ) -> Dict[str, Any]:
  276. """
  277. Anyify the value of map
  278. @return: the new anyfied map
  279. """
  280. return m
  281. @staticmethod
  282. def assert_as_boolean(
  283. value: Any,
  284. ) -> bool:
  285. """
  286. Assert a value, if it is a boolean, return it, otherwise throws
  287. @return: the boolean value
  288. """
  289. if not isinstance(value, bool):
  290. raise ValueError(f'{value} is not a bool')
  291. return value
  292. @staticmethod
  293. def assert_as_string(
  294. value: Any,
  295. ) -> str:
  296. """
  297. Assert a value, if it is a string, return it, otherwise throws
  298. @return: the string value
  299. """
  300. if not isinstance(value, str):
  301. raise ValueError(f'{value} is not a str')
  302. return value
  303. @staticmethod
  304. def assert_as_bytes(
  305. value: Any,
  306. ) -> bytes:
  307. """
  308. Assert a value, if it is a bytes, return it, otherwise throws
  309. @return: the bytes value
  310. """
  311. if not isinstance(value, bytes):
  312. raise ValueError(f'{value} is not a bytes')
  313. return value
  314. @staticmethod
  315. def assert_as_number(
  316. value: Any,
  317. ) -> int:
  318. """
  319. Assert a value, if it is a number, return it, otherwise throws
  320. @return: the number value
  321. """
  322. if not isinstance(value, (int, float)):
  323. raise ValueError(f'{value} is not a number')
  324. return value
  325. @staticmethod
  326. def assert_as_integer(
  327. value: Any,
  328. ) -> int:
  329. """
  330. Assert a value, if it is a integer, return it, otherwise throws
  331. @return: the integer value
  332. """
  333. if not isinstance(value, int):
  334. raise ValueError(f'{value} is not a int number')
  335. return value
  336. @staticmethod
  337. def assert_as_map(
  338. value: Any,
  339. ) -> Dict[str, Any]:
  340. """
  341. Assert a value, if it is a map, return it, otherwise throws
  342. @return: the map value
  343. """
  344. if not isinstance(value, dict):
  345. raise ValueError(f'{value} is not a dict')
  346. return value
  347. @staticmethod
  348. def get_user_agent(
  349. user_agent: str,
  350. ) -> str:
  351. """
  352. Get user agent, if it userAgent is not null, splice it with defaultUserAgent and return, otherwise return defaultUserAgent
  353. @return: the string value
  354. """
  355. if user_agent:
  356. return f'{Client.__get_default_agent()} {user_agent}'
  357. return Client.__get_default_agent()
  358. @staticmethod
  359. def is_2xx(
  360. code: int,
  361. ) -> bool:
  362. """
  363. If the code between 200 and 300, return true, or return false
  364. @return: boolean
  365. """
  366. return 200 <= code < 300
  367. @staticmethod
  368. def is_3xx(
  369. code: int,
  370. ) -> bool:
  371. """
  372. If the code between 300 and 400, return true, or return false
  373. @return: boolean
  374. """
  375. return 300 <= code < 400
  376. @staticmethod
  377. def is_4xx(
  378. code: int,
  379. ) -> bool:
  380. """
  381. If the code between 400 and 500, return true, or return false
  382. @return: boolean
  383. """
  384. return 400 <= code < 500
  385. @staticmethod
  386. def is_5xx(
  387. code: int,
  388. ) -> bool:
  389. """
  390. If the code between 500 and 600, return true, or return false
  391. @return: boolean
  392. """
  393. return 500 <= code < 600
  394. @staticmethod
  395. def validate_model(
  396. m: TeaModel,
  397. ) -> None:
  398. """
  399. Validate model
  400. @return: void
  401. """
  402. if isinstance(m, TeaModel):
  403. m.validate()
  404. @staticmethod
  405. def to_map(
  406. in_: TeaModel,
  407. ) -> Dict[str, Any]:
  408. """
  409. Model transforms to map[string]any
  410. @return: map[string]any
  411. """
  412. if isinstance(in_, TeaModel):
  413. return in_.to_map()
  414. else:
  415. return in_
  416. @staticmethod
  417. def sleep(
  418. millisecond: int,
  419. ) -> None:
  420. """
  421. Suspends the current thread for the specified number of milliseconds.
  422. """
  423. time.sleep(millisecond / 1000)
  424. @staticmethod
  425. async def sleep_async(
  426. millisecond: int,
  427. ) -> None:
  428. """
  429. Suspends the current thread for the specified number of milliseconds.
  430. """
  431. await asyncio.sleep(millisecond / 1000)
  432. @staticmethod
  433. def to_array(
  434. input: Any,
  435. ) -> List[Dict[str, Any]]:
  436. """
  437. Transform input as array.
  438. """
  439. if input is None:
  440. return []
  441. out = []
  442. for i in input:
  443. if isinstance(i, TeaModel):
  444. out.append(i.to_map())
  445. else:
  446. out.append(i)
  447. return out
  448. @staticmethod
  449. def assert_as_readable(
  450. value: Any,
  451. ) -> BinaryIO:
  452. """
  453. Assert a value, if it is a readable, return it, otherwise throws
  454. @return: the readable value
  455. """
  456. if isinstance(value, str):
  457. value = value.encode('utf-8')
  458. if isinstance(value, bytes):
  459. value = BytesIO(value)
  460. elif not isinstance(value, READABLE):
  461. raise ValueError(f'The value is not a readable')
  462. return value
  463. @staticmethod
  464. def assert_as_array(
  465. value: Any,
  466. ) -> list:
  467. if not isinstance(value, list):
  468. raise ValueError('The value is not a list')
  469. return value
  470. @staticmethod
  471. def get_host_name() -> str:
  472. """
  473. Get hostname of current machine
  474. @return: the string value
  475. """
  476. import socket
  477. try:
  478. return socket.gethostname()
  479. except Exception:
  480. return ''