client.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  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 datetime import datetime
  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. @return: the UTC format string
  166. """
  167. return datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
  168. @staticmethod
  169. def default_string(
  170. real: str,
  171. default: str,
  172. ) -> str:
  173. """
  174. If not set the real, use default value
  175. @return: the return string
  176. """
  177. return real if real is not None else default
  178. @staticmethod
  179. def default_number(
  180. real: int,
  181. default: int,
  182. ) -> int:
  183. """
  184. If not set the real, use default value
  185. @return: the return number
  186. """
  187. return real if real is not None else default
  188. @staticmethod
  189. def to_form_string(
  190. val: dict,
  191. ) -> str:
  192. """
  193. Format a map to form string, like a=a%20b%20c
  194. @return: the form string
  195. """
  196. if not val:
  197. return ""
  198. keys = sorted(list(val))
  199. dic = {k: val[k] for k in keys if not isinstance(val[k], READABLE)}
  200. return urlencode(dic)
  201. @staticmethod
  202. def to_jsonstring(
  203. val: Any,
  204. ) -> str:
  205. """
  206. Stringify a value by JSON format
  207. @return: the JSON format string
  208. """
  209. if isinstance(val, str):
  210. return str(val)
  211. return json.dumps(
  212. val, cls=Client.__ModelEncoder, ensure_ascii=False, separators=(",", ":")
  213. )
  214. @staticmethod
  215. def empty(
  216. val: str,
  217. ) -> bool:
  218. """
  219. Check the string is empty?
  220. @return: if string is null or zero length, return true
  221. """
  222. return not val
  223. @staticmethod
  224. def equal_string(
  225. val1: str,
  226. val2: str,
  227. ) -> bool:
  228. """
  229. Check one string equals another one?
  230. @return: if equals, return true
  231. """
  232. return val1 == val2
  233. @staticmethod
  234. def equal_number(
  235. val1: int,
  236. val2: int,
  237. ) -> bool:
  238. """
  239. Check one number equals another one?
  240. @return: if equals, return true
  241. """
  242. return val1 == val2
  243. @staticmethod
  244. def is_unset(
  245. value: Any,
  246. ) -> bool:
  247. """
  248. Check one value is unset
  249. @return: if unset, return true
  250. """
  251. return value is None
  252. @staticmethod
  253. def stringify_map_value(
  254. m: Dict[str, Any],
  255. ) -> Dict[str, str]:
  256. """
  257. Stringify the value of map
  258. @return: the new stringified map
  259. """
  260. if m is None:
  261. return {}
  262. dic_result = {}
  263. for k, v in m.items():
  264. if v is not None:
  265. if isinstance(v, bytes):
  266. v = v.decode('utf-8')
  267. else:
  268. v = str(v)
  269. dic_result[k] = v
  270. return dic_result
  271. @staticmethod
  272. def anyify_map_value(
  273. m: Dict[str, str],
  274. ) -> Dict[str, Any]:
  275. """
  276. Anyify the value of map
  277. @return: the new anyfied map
  278. """
  279. return m
  280. @staticmethod
  281. def assert_as_boolean(
  282. value: Any,
  283. ) -> bool:
  284. """
  285. Assert a value, if it is a boolean, return it, otherwise throws
  286. @return: the boolean value
  287. """
  288. if not isinstance(value, bool):
  289. raise ValueError(f'{value} is not a bool')
  290. return value
  291. @staticmethod
  292. def assert_as_string(
  293. value: Any,
  294. ) -> str:
  295. """
  296. Assert a value, if it is a string, return it, otherwise throws
  297. @return: the string value
  298. """
  299. if not isinstance(value, str):
  300. raise ValueError(f'{value} is not a str')
  301. return value
  302. @staticmethod
  303. def assert_as_bytes(
  304. value: Any,
  305. ) -> bytes:
  306. """
  307. Assert a value, if it is a bytes, return it, otherwise throws
  308. @return: the bytes value
  309. """
  310. if not isinstance(value, bytes):
  311. raise ValueError(f'{value} is not a bytes')
  312. return value
  313. @staticmethod
  314. def assert_as_number(
  315. value: Any,
  316. ) -> int:
  317. """
  318. Assert a value, if it is a number, return it, otherwise throws
  319. @return: the number value
  320. """
  321. if not isinstance(value, (int, float)):
  322. raise ValueError(f'{value} is not a number')
  323. return value
  324. @staticmethod
  325. def assert_as_integer(
  326. value: Any,
  327. ) -> int:
  328. """
  329. Assert a value, if it is a integer, return it, otherwise throws
  330. @return: the integer value
  331. """
  332. if not isinstance(value, int):
  333. raise ValueError(f'{value} is not a int number')
  334. return value
  335. @staticmethod
  336. def assert_as_map(
  337. value: Any,
  338. ) -> Dict[str, Any]:
  339. """
  340. Assert a value, if it is a map, return it, otherwise throws
  341. @return: the map value
  342. """
  343. if not isinstance(value, dict):
  344. raise ValueError(f'{value} is not a dict')
  345. return value
  346. @staticmethod
  347. def get_user_agent(
  348. user_agent: str,
  349. ) -> str:
  350. """
  351. Get user agent, if it userAgent is not null, splice it with defaultUserAgent and return, otherwise return defaultUserAgent
  352. @return: the string value
  353. """
  354. if user_agent:
  355. return f'{Client.__get_default_agent()} {user_agent}'
  356. return Client.__get_default_agent()
  357. @staticmethod
  358. def is_2xx(
  359. code: int,
  360. ) -> bool:
  361. """
  362. If the code between 200 and 300, return true, or return false
  363. @return: boolean
  364. """
  365. return 200 <= code < 300
  366. @staticmethod
  367. def is_3xx(
  368. code: int,
  369. ) -> bool:
  370. """
  371. If the code between 300 and 400, return true, or return false
  372. @return: boolean
  373. """
  374. return 300 <= code < 400
  375. @staticmethod
  376. def is_4xx(
  377. code: int,
  378. ) -> bool:
  379. """
  380. If the code between 400 and 500, return true, or return false
  381. @return: boolean
  382. """
  383. return 400 <= code < 500
  384. @staticmethod
  385. def is_5xx(
  386. code: int,
  387. ) -> bool:
  388. """
  389. If the code between 500 and 600, return true, or return false
  390. @return: boolean
  391. """
  392. return 500 <= code < 600
  393. @staticmethod
  394. def validate_model(
  395. m: TeaModel,
  396. ) -> None:
  397. """
  398. Validate model
  399. @return: void
  400. """
  401. if isinstance(m, TeaModel):
  402. m.validate()
  403. @staticmethod
  404. def to_map(
  405. in_: TeaModel,
  406. ) -> Dict[str, Any]:
  407. """
  408. Model transforms to map[string]any
  409. @return: map[string]any
  410. """
  411. if isinstance(in_, TeaModel):
  412. return in_.to_map()
  413. else:
  414. return in_
  415. @staticmethod
  416. def sleep(
  417. millisecond: int,
  418. ) -> None:
  419. """
  420. Suspends the current thread for the specified number of milliseconds.
  421. """
  422. time.sleep(millisecond / 1000)
  423. @staticmethod
  424. async def sleep_async(
  425. millisecond: int,
  426. ) -> None:
  427. """
  428. Suspends the current thread for the specified number of milliseconds.
  429. """
  430. await asyncio.sleep(millisecond / 1000)
  431. @staticmethod
  432. def to_array(
  433. input: Any,
  434. ) -> List[Dict[str, Any]]:
  435. """
  436. Transform input as array.
  437. """
  438. if input is None:
  439. return []
  440. out = []
  441. for i in input:
  442. if isinstance(i, TeaModel):
  443. out.append(i.to_map())
  444. else:
  445. out.append(i)
  446. return out
  447. @staticmethod
  448. def assert_as_readable(
  449. value: Any,
  450. ) -> BinaryIO:
  451. """
  452. Assert a value, if it is a readable, return it, otherwise throws
  453. @return: the readable value
  454. """
  455. if isinstance(value, str):
  456. value = value.encode('utf-8')
  457. if isinstance(value, bytes):
  458. value = BytesIO(value)
  459. elif not isinstance(value, READABLE):
  460. raise ValueError(f'The value is not a readable')
  461. return value
  462. @staticmethod
  463. def assert_as_array(
  464. value: Any,
  465. ) -> list:
  466. if not isinstance(value, list):
  467. raise ValueError('The value is not a list')
  468. return value
  469. @staticmethod
  470. def get_host_name() -> str:
  471. """
  472. Get hostname of current machine
  473. @return: the string value
  474. """
  475. import socket
  476. try:
  477. return socket.gethostname()
  478. except Exception:
  479. return ''