volcengine-python-sdk 5.0.32__py2.py3-none-any.whl → 5.0.33__py2.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.4
2
2
  Name: volcengine-python-sdk
3
- Version: 5.0.32
3
+ Version: 5.0.33
4
4
  Summary: Volcengine SDK for Python
5
5
  Home-page: https://github.com/volcengine/volcengine-python-sdk
6
6
  Author-email: volc-engine <volc-sdk-team@bytedance.com>
@@ -1,5 +1,5 @@
1
- volcengine_python_sdk-5.0.32.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
2
- volcengine_python_sdk-5.0.32.dist-info/licenses/NOTICE.md,sha256=dqWX0O4-gFqGLdHJsXAiF6Q8JHlu_3nFaQSmrMHzujM,254
1
+ volcengine_python_sdk-5.0.33.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
2
+ volcengine_python_sdk-5.0.33.dist-info/licenses/NOTICE.md,sha256=dqWX0O4-gFqGLdHJsXAiF6Q8JHlu_3nFaQSmrMHzujM,254
3
3
  volcenginesdkacep/__init__.py,sha256=GZCeL2Dsp5v1XblcgInhNJzKW7X37XxrpMIE2Q3VL-c,31200
4
4
  volcenginesdkacep/api/__init__.py,sha256=MCzGEBg4XwY5aDIDy8nitUz4vu_2xmRRY83V6lqt460,138
5
5
  volcenginesdkacep/api/acep_api.py,sha256=ollQvh5qkrmNbENVBBh2JRha9aGDMUwtO7V6Q1A3-Js,410621
@@ -5381,8 +5381,8 @@ volcenginesdkconfig/models/update_rule_response.py,sha256=f16EgPddqWulPRT1Yw225x
5381
5381
  volcenginesdkconfig/models/update_rule_template_request.py,sha256=k4JyMyOEhL8Zvg9N6siac_6MlcB38ZoDeKfx5uVV4xo,10129
5382
5382
  volcenginesdkconfig/models/update_rule_template_response.py,sha256=eiATOg0bsvElLzs-K0Jt8x8k4JaLxlXUcsg3toMteCM,2814
5383
5383
  volcenginesdkcore/__init__.py,sha256=WkgQAEhL6zg4ofQI82LD-3K-ij28yT-lpMiDoKmppwM,318
5384
- volcenginesdkcore/api_client.py,sha256=3WucEvkL3BmKes9qXrk-R7urs3IV4jAy9oJrTpNvwVM,29339
5385
- volcenginesdkcore/configuration.py,sha256=mFDz9fJU3AhwRCY0-CaNJStPQ2VfNtW5di8mSaH2ImQ,12082
5384
+ volcenginesdkcore/api_client.py,sha256=xk2TgRm7PGtgDkAOvUwUA_z5E2Akb2Iy4IfRgViMKzc,29339
5385
+ volcenginesdkcore/configuration.py,sha256=uBLeXYDr1tkLYWERwK0oKph7z5pdJHH_yGipo-bYSWI,12082
5386
5386
  volcenginesdkcore/flatten.py,sha256=g3r61JS_AO7WV6ClRDkXgtnVXcw3c7tbZjeLAJxkSLc,3811
5387
5387
  volcenginesdkcore/metadata.py,sha256=lHsOz9JcwdM7oqBb5dhSl6z3qF-M3TnTFbCzxRV89f4,4529
5388
5388
  volcenginesdkcore/model.py,sha256=f3cvQ6QiQfecClucu-_-l5xVI3W5_vF-EKkjwZu7Vjc,177
@@ -5392,7 +5392,7 @@ volcenginesdkcore/universal.py,sha256=j1p9XAktEqIvVsWXm_sCI29jxf30YjqFEWBZAlkUEd
5392
5392
  volcenginesdkcore/auth/__init__.py,sha256=3g1cdl8E5ZJrjF_kijTELAIWTT74fNEYOPieE88DBBg,132
5393
5393
  volcenginesdkcore/auth/credential.py,sha256=adOo43AZi4BNL9sSYGe5v9YMn8vm2rL0vBU1iAe0jes,377
5394
5394
  volcenginesdkcore/auth/providers/__init__.py,sha256=Os4sb88zqpdSncVAiKTs8KPGarCViJeXpdUZ1ItnZSM,454
5395
- volcenginesdkcore/auth/providers/cli_config_provider.py,sha256=dqpcJfEtVIWI7_nChFEHn-qJWmuGvw4kJcDgcvhcge0,23693
5395
+ volcenginesdkcore/auth/providers/cli_config_provider.py,sha256=tmpyc4YpyJ5CRSCrR9IAsisMxsL6Xb4FWEfEIgsZuDo,44251
5396
5396
  volcenginesdkcore/auth/providers/default_provider.py,sha256=R-OxpYSlIfk_YcaAW23EcsoMCuMRAFJQ035baE_3NfQ,4234
5397
5397
  volcenginesdkcore/auth/providers/ecs_role_provider.py,sha256=lWllVPA01NpPaaqXdP9vCMwbxBgEQW1URfxMl9uOTyc,7529
5398
5398
  volcenginesdkcore/auth/providers/env_provider.py,sha256=LUrPFemUs0i8X-hLqXDEuz5CHgOsQG6XbxaROC0tpxA,1255
@@ -9395,7 +9395,7 @@ volcenginesdkgtm/models/rule_for_update_rule_input.py,sha256=Ldb6pTVTfOLVbTG98bd
9395
9395
  volcenginesdkgtm/models/source_flow_for_get_policy_output.py,sha256=tyXwIrVjy8Kwjqa16Y_UMFjtxIMJL7OSb2VKtWlfA1I,2821
9396
9396
  volcenginesdkgtm/models/start_routing_request.py,sha256=KDNWMAiV23QsfPbuZA3om2SmQE2j5tDCg5Q1tNWdrag,3552
9397
9397
  volcenginesdkgtm/models/start_routing_response.py,sha256=atUcMwhhXJzt0kYQpH35XNEw8zYWm2vXqK0TXeARRxM,2781
9398
- volcenginesdkgtm/models/statistic_for_update_load_input.py,sha256=8qlgcqwU7vJnwY96vsBDnnK8IwMv_DIwgwdfxFl7cKw,7368
9398
+ volcenginesdkgtm/models/statistic_for_update_load_input.py,sha256=TaSErSmDxX28BRhBHPlKZtPtHlch93VT_Fk0wKeGiVg,6615
9399
9399
  volcenginesdkgtm/models/statistics_for_get_policy_output.py,sha256=hi9vXAgJiYcqq0a91sX0s8_bmd9rP_dfLr14eGKLiFI,4421
9400
9400
  volcenginesdkgtm/models/stop_routing_request.py,sha256=oz24AtXhG8gn-NpB667E-x8a6I_iK73E07T_zTUoHsM,3543
9401
9401
  volcenginesdkgtm/models/stop_routing_response.py,sha256=9BuGoyBMymk2e1xT5OQYlT-2KJq9Ae7ipboxei7K65U,2776
@@ -11575,7 +11575,7 @@ volcenginesdklivesaas/models/list_activity_api_request.py,sha256=QuB4k1j8_TaMQFH
11575
11575
  volcenginesdklivesaas/models/list_activity_api_response.py,sha256=AYSOPD3SXOmdpIYYO1xVDJiPN8iFbgjODNIqa6pWn4w,6025
11576
11576
  volcenginesdklivesaas/models/list_activity_by_cache_api_request.py,sha256=KiHpTJRpsXNIfbbcWvQspBYcouC84jsAumRW7MYby4U,14895
11577
11577
  volcenginesdklivesaas/models/list_activity_by_cache_api_response.py,sha256=MtnemSo41lO9XscXKzZ-NIITIVc5sdcCGRLZ3u8Ttq8,6193
11578
- volcenginesdklivesaas/models/list_activity_media_api_request.py,sha256=0lw0dybAwRhrBtjSK-ndk73czOELGvwe-1npJu_ofcE,9606
11578
+ volcenginesdklivesaas/models/list_activity_media_api_request.py,sha256=NQUYJccpSJTWoYkYbyYohnyipRdRPO8DKMps0QrR04c,10444
11579
11579
  volcenginesdklivesaas/models/list_activity_media_api_response.py,sha256=ThfoI96iUIrR8Al7dHIGxFCl7B--clFjejWVEjbFEM0,4444
11580
11580
  volcenginesdklivesaas/models/list_an_activity_start_and_end_time_api_request.py,sha256=KPp00NCSYE6oZeAodgVfEv1XRmBzXZtMSPZw8h7Alt4,3842
11581
11581
  volcenginesdklivesaas/models/list_an_activity_start_and_end_time_api_response.py,sha256=NxY8CB9rz6YiuPsi9WTMkthgaij7tyBaOOmbD3L-OZU,4029
@@ -22510,7 +22510,7 @@ volcenginesdkwafruntime/api/__init__.py,sha256=di_9IIKQ0HCuzkGrTyZ6h38iP7y1xelH8
22510
22510
  volcenginesdkwafruntime/api/waf_runtime_api.py,sha256=eWgdzFcwflEkhkNrPzZL1mqSid7O1OWiwHGUyWJvZNA,4035
22511
22511
  volcenginesdkwafruntime/models/__init__.py,sha256=di_9IIKQ0HCuzkGrTyZ6h38iP7y1xelH8_IJbKi4aWA,71
22512
22512
  volcenginesdkwafruntime/models/llm_stream_session.py,sha256=U9cig3fuZRBT4Ov8_cUsWDKXcMLNjBDxKt-7IoewoUw,1589
22513
- volcengine_python_sdk-5.0.32.dist-info/METADATA,sha256=_y0nB0rAMfmt87cO5DvWliK4pdmqNCayYLdlctMPry4,8435
22514
- volcengine_python_sdk-5.0.32.dist-info/WHEEL,sha256=Mk1ST5gDzEO5il5kYREiBnzzM469m5sI8ESPl7TRhJY,110
22515
- volcengine_python_sdk-5.0.32.dist-info/top_level.txt,sha256=EWPYkwb-yVEO1fKOGHmIp8xZ5FoKVJmQ8njYtOV7XwA,2820
22516
- volcengine_python_sdk-5.0.32.dist-info/RECORD,,
22513
+ volcengine_python_sdk-5.0.33.dist-info/METADATA,sha256=_J8YoRxCLPMoJbWfAgQPHGM7yBAaDQ-ZA8eVNekkx7U,8435
22514
+ volcengine_python_sdk-5.0.33.dist-info/WHEEL,sha256=Mk1ST5gDzEO5il5kYREiBnzzM469m5sI8ESPl7TRhJY,110
22515
+ volcengine_python_sdk-5.0.33.dist-info/top_level.txt,sha256=EWPYkwb-yVEO1fKOGHmIp8xZ5FoKVJmQ8njYtOV7XwA,2820
22516
+ volcengine_python_sdk-5.0.33.dist-info/RECORD,,
@@ -69,7 +69,7 @@ class ApiClient(object):
69
69
  self.default_headers[header_name] = header_value
70
70
  self.cookie = cookie
71
71
  # Set default User-Agent.
72
- self.user_agent = 'volcstack-python-sdk/5.0.32'
72
+ self.user_agent = 'volcstack-python-sdk/5.0.33'
73
73
  self.client_side_validation = configuration.client_side_validation
74
74
 
75
75
  self.interceptor_chain = InterceptorChain()
@@ -3,11 +3,11 @@ import calendar
3
3
  import hashlib
4
4
  import json
5
5
  import os
6
- import tempfile
7
6
  import threading
8
7
  import time
9
8
 
10
- from datetime import datetime
9
+ import dateutil.parser
10
+ import six
11
11
 
12
12
  from .provider import Provider, CredentialValue
13
13
 
@@ -18,6 +18,9 @@ _PORTAL_ACCESS_TOKEN_HEADER = "x-bd-cloudidentity-bearer-token"
18
18
  _HTTP_TIMEOUT = 30
19
19
  _HTTP_MAX_RETRIES = 3
20
20
  _HTTP_RETRY_INTERVAL = 1
21
+ _LOGIN_CACHE_DIRECTORY_ENV = "VOLCENGINE_LOGIN_CACHE_DIRECTORY"
22
+ _DEFAULT_CONSOLE_LOGIN_ENDPOINT = "https://signin.volcengine.com"
23
+ _CONSOLE_LOGIN_TOKEN_PATH = "/authorize/oauth/token"
21
24
 
22
25
 
23
26
  class CLIConfigCredentialProvider(Provider):
@@ -34,7 +37,10 @@ class CLIConfigCredentialProvider(Provider):
34
37
  - "RamRoleArn": delegate to StsCredentialProvider
35
38
  - "OIDC": delegate to StsOidcCredentialProvider
36
39
  - "EcsRole": delegate to EcsRoleCredentialProvider
37
- - "sso": delegate to SsoCredentialProvider
40
+ - "sso": delegate to SsoCredentialProvider (SDK manages OAuth refresh in-memory,
41
+ never writes the cache file; ve sso login is the sole writer)
42
+ - "console-login": read CLI console-login cache; the SDK manages OAuth refresh
43
+ in-memory (never writes the cache file). ve login is the sole writer.
38
44
  - Other modes: raise RuntimeError (unsupported)
39
45
  """
40
46
 
@@ -50,6 +56,9 @@ class CLIConfigCredentialProvider(Provider):
50
56
  self._resolved_config_path = None
51
57
 
52
58
  def _init_delegate(self):
59
+ self._delegate = None
60
+ self._static_cred = None
61
+
53
62
  profile, profile_name, config = self._load_profile()
54
63
  raw_mode = profile.get("mode", "") or ""
55
64
  mode = raw_mode.lower().strip()
@@ -68,6 +77,9 @@ class CLIConfigCredentialProvider(Provider):
68
77
  elif mode == "sso":
69
78
  self._static_cred = None
70
79
  self._delegate = self._create_sso_delegate(profile, profile_name, config)
80
+ elif mode == "console-login":
81
+ self._static_cred = None
82
+ self._delegate = self._create_console_login_delegate(profile, profile_name)
71
83
  else:
72
84
  raise RuntimeError(
73
85
  "{}: unsupported mode: {}".format(self.PROVIDER_NAME, mode)
@@ -294,6 +306,29 @@ class CLIConfigCredentialProvider(Provider):
294
306
  cache_dir=cache_dir,
295
307
  )
296
308
 
309
+ def _create_console_login_delegate(self, profile, profile_name):
310
+ login_session = (profile.get("login-session") or "").strip()
311
+ if not login_session:
312
+ raise RuntimeError(
313
+ "{}: profile '{}' mode is console-login but login-session is not set; run 've login' first.".format(
314
+ self.PROVIDER_NAME, profile_name
315
+ )
316
+ )
317
+
318
+ config_path = self._resolved_config_path or (
319
+ self._config_path
320
+ or os.environ.get("VOLCENGINE_CLI_CONFIG_FILE")
321
+ or os.path.expanduser("~/.volcengine/config.json")
322
+ )
323
+ cache_dir = (
324
+ os.environ.get(_LOGIN_CACHE_DIRECTORY_ENV)
325
+ or os.path.join(os.path.dirname(config_path), "login", "cache")
326
+ )
327
+ return ConsoleLoginCredentialProvider(
328
+ login_session=login_session,
329
+ cache_dir=cache_dir,
330
+ )
331
+
297
332
 
298
333
  def _unix_timestamp_to_epoch(ts):
299
334
  """Convert a Unix timestamp (seconds, milliseconds, microseconds, or
@@ -316,26 +351,24 @@ def _token_cache_filename(start_url, session_name):
316
351
  return "{}.json".format(digest)
317
352
 
318
353
 
354
+ def _login_cache_filename(login_session):
355
+ return "{}.json".format(hashlib.sha1(login_session.encode("utf-8")).hexdigest())
356
+
357
+
319
358
  def _parse_rfc3339(value):
320
- """Parse an RFC 3339 timestamp string into a datetime (UTC)."""
359
+ """Parse an RFC 3339 timestamp string into a datetime.
360
+
361
+ Uses python-dateutil (already a project dependency) for Py2/Py3
362
+ compatibility; handles trailing 'Z' and explicit timezone offsets
363
+ (e.g. '+08:00') uniformly.
364
+ """
321
365
  value = value.strip()
322
366
  if not value:
323
367
  raise ValueError("expires_at is empty")
324
- # Python 3.7+ datetime.fromisoformat doesn't handle trailing Z
325
- if value.endswith("Z"):
326
- value = value[:-1] + "+00:00"
327
368
  try:
328
- return datetime.fromisoformat(value)
329
- except (ValueError, AttributeError):
330
- pass
331
- # Fallback for Python < 3.7 or unusual formats
332
- for fmt in ("%Y-%m-%dT%H:%M:%S%z", "%Y-%m-%dT%H:%M:%S.%f%z",
333
- "%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%S.%f"):
334
- try:
335
- return datetime.strptime(value, fmt)
336
- except ValueError:
337
- continue
338
- raise ValueError("cannot parse expires_at: {}".format(value))
369
+ return dateutil.parser.parse(value)
370
+ except (ValueError, OverflowError, TypeError) as e:
371
+ raise ValueError("cannot parse expires_at: {}: {}".format(value, e))
339
372
 
340
373
 
341
374
  def _rfc3339_to_epoch(value):
@@ -346,21 +379,396 @@ def _rfc3339_to_epoch(value):
346
379
  return calendar.timegm(exp_dt.timetuple())
347
380
 
348
381
 
349
- def _write_json_file_atomic(path, data):
350
- """Write JSON data to a file atomically."""
351
- dir_name = os.path.dirname(path)
352
- fd, tmp_path = tempfile.mkstemp(dir=dir_name, prefix=".tmp-", suffix=".json")
382
+ def _console_login_cache_expiration(token_cache, cache_path, provider_name):
383
+ _raw_ia = token_cache.get("issued_at")
384
+ issued_at = _raw_ia.strip() if isinstance(_raw_ia, six.string_types) else ""
385
+ if not issued_at:
386
+ raise RuntimeError(
387
+ "{}: console-login token cache '{}' does not contain issued_at.".format(
388
+ provider_name, cache_path
389
+ )
390
+ )
391
+ expires_in = token_cache.get("expires_in", 0)
392
+ try:
393
+ expires_in = int(expires_in)
394
+ except (TypeError, ValueError):
395
+ expires_in = 0
396
+ if expires_in <= 0:
397
+ raise RuntimeError(
398
+ "{}: console-login token cache '{}' does not contain valid expires_in.".format(
399
+ provider_name, cache_path
400
+ )
401
+ )
353
402
  try:
354
- with os.fdopen(fd, 'w') as f:
355
- json.dump(data, f)
356
- os.chmod(tmp_path, 0o600)
357
- os.rename(tmp_path, path)
358
- except Exception:
403
+ issued_at_epoch = _rfc3339_to_epoch(issued_at)
404
+ except ValueError as e:
405
+ raise RuntimeError(
406
+ "{}: failed to parse console-login issued_at in '{}': {}".format(
407
+ provider_name, cache_path, e
408
+ )
409
+ )
410
+ return issued_at_epoch + expires_in
411
+
412
+
413
+ def _parse_console_login_access_token(access_token, cache_path, provider_name):
414
+ if isinstance(access_token, dict):
415
+ sts_creds = access_token
416
+ elif isinstance(access_token, six.string_types):
417
+ try:
418
+ sts_creds = json.loads(access_token)
419
+ except ValueError as e:
420
+ raise RuntimeError(
421
+ "{}: failed to parse console-login access_token in '{}': {}".format(
422
+ provider_name, cache_path, e
423
+ )
424
+ )
425
+ else:
426
+ raise RuntimeError(
427
+ "{}: console-login token cache '{}' does not contain valid access_token.".format(
428
+ provider_name, cache_path
429
+ )
430
+ )
431
+
432
+ if not isinstance(sts_creds, dict):
433
+ raise RuntimeError(
434
+ "{}: console-login access_token in '{}' is not an object.".format(
435
+ provider_name, cache_path
436
+ )
437
+ )
438
+
439
+ _raw_ak = sts_creds.get("access_key_id")
440
+ ak = _raw_ak.strip() if isinstance(_raw_ak, six.string_types) else ""
441
+ _raw_sk = sts_creds.get("secret_access_key")
442
+ sk = _raw_sk.strip() if isinstance(_raw_sk, six.string_types) else ""
443
+ _raw_tok = sts_creds.get("session_token")
444
+ token = _raw_tok.strip() if isinstance(_raw_tok, six.string_types) else ""
445
+ if not ak or not sk or not token:
446
+ raise RuntimeError(
447
+ "{}: console-login access_token in '{}' is missing STS credential fields.".format(
448
+ provider_name, cache_path
449
+ )
450
+ )
451
+
452
+ return {
453
+ "access_key_id": ak,
454
+ "secret_access_key": sk,
455
+ "session_token": token,
456
+ }
457
+
458
+
459
+
460
+ class ConsoleLoginCredentialProvider(Provider):
461
+ """Reads and refreshes STS credentials for the CLI 've login' flow.
462
+
463
+ Contract:
464
+ - Disk reads happen on bootstrap and on the invalid_grant fallback only;
465
+ the provider never writes the cache file. ve cli remains the sole
466
+ writer.
467
+ - When the in-memory access_token expires, the provider exchanges the
468
+ cached refresh_token at signin.volcengine.com/authorize/oauth/token and
469
+ updates the in-memory cache only.
470
+ - If the signin service rejects the refresh_token with invalid_grant,
471
+ the provider re-reads the disk cache once. If the disk holds a newer
472
+ refresh_token (i.e. ve cli refreshed it under us), it retries; if the
473
+ disk RT is the same, the user must run `ve login` again.
474
+ """
475
+
476
+ PROVIDER_NAME = "ConsoleLoginCredentialProvider"
477
+
478
+ def __init__(self, login_session, cache_dir):
479
+ self._login_session = login_session
480
+ self._cache_dir = cache_dir
481
+
482
+ self._credentials = None
483
+ self._expiration = None # epoch seconds
484
+ # _cache holds the most recently observed login cache dict, including
485
+ # refresh_token / client_id / scope / endpoint_url, so that the SDK can
486
+ # silently refresh access_token without re-reading the file on every
487
+ # call.
488
+ self._cache = None
489
+ self._lock = threading.Lock()
490
+
491
+ def retrieve(self):
492
+ return self.get_credentials()
493
+
494
+ def is_expired(self):
495
+ if self._credentials is None:
496
+ return True
497
+ if self._expiration is not None:
498
+ return time.time() >= self._expiration - 60
499
+ return False
500
+
501
+ def refresh(self):
502
+ with self._lock:
503
+ if self.is_expired():
504
+ self._do_refresh()
505
+
506
+ def get_credentials(self):
507
+ self.refresh()
508
+ return self._credentials
509
+
510
+ def _do_refresh(self):
511
+ # Bootstrap from disk only when the in-memory cache is empty; on every
512
+ # subsequent expiry we try the in-memory refresh_token first and only
513
+ # re-read the disk file as a fallback when the server rejects the RT.
514
+ if self._cache is None:
515
+ self._cache = self._load_cache_from_disk()
516
+
517
+ cache_path = os.path.join(
518
+ self._cache_dir, _login_cache_filename(self._login_session)
519
+ )
520
+
521
+ # Fast path: the cached access_token is still within its TTL.
522
+ applied = self._try_apply_from_cache(self._cache, cache_path)
523
+ if applied:
524
+ return
525
+
526
+ # Slow path: refresh in-memory using the cached refresh_token.
527
+ try:
528
+ self._refresh_with_oauth(self._cache, cache_path)
529
+ return
530
+ except _ConsoleLoginInvalidGrantError as exc:
531
+ invalid_grant_exc = exc
532
+ # Fallback: re-read the disk cache once. If ve login ran concurrently
533
+ # and wrote a new refresh_token, retrying with the disk RT may succeed.
534
+ # Any I/O or parse error surfaces with the actionable ve login hint.
535
+ try:
536
+ disk_cache = self._load_cache_from_disk()
537
+ except (RuntimeError, IOError, OSError) as e:
538
+ raise RuntimeError(
539
+ "{}: failed to reload console-login cache from disk; "
540
+ "please run 've login' to re-authenticate. "
541
+ "underlying error: {}".format(self.PROVIDER_NAME, e)
542
+ )
543
+ _disk_rt = disk_cache.get("refresh_token")
544
+ if not (isinstance(_disk_rt, six.string_types) and _disk_rt.strip()):
545
+ raise RuntimeError(
546
+ "{}: console-login refresh token rejected and disk cache lacks "
547
+ "refresh_token; please run 've login' to re-authenticate.".format(
548
+ self.PROVIDER_NAME
549
+ )
550
+ )
551
+ if disk_cache.get("refresh_token") == self._cache.get("refresh_token"):
552
+ raise RuntimeError(
553
+ "{}: console-login refresh token rejected by signin service "
554
+ "(disk cache has the same RT); please run 've login' to "
555
+ "re-authenticate. underlying error: {}".format(
556
+ self.PROVIDER_NAME, invalid_grant_exc
557
+ )
558
+ )
559
+ self._cache = disk_cache
560
+ # If the disk cache holds a fresh access_token (e.g. ve login ran
561
+ # concurrently), apply it directly without another OAuth round-trip.
562
+ # Otherwise exchange the disk refresh_token via OAuth once.
563
+ if self._try_apply_from_cache(self._cache, cache_path):
564
+ return
565
+ try:
566
+ self._refresh_with_oauth(self._cache, cache_path)
567
+ except _ConsoleLoginInvalidGrantError as exc2:
568
+ raise RuntimeError(
569
+ "{}: console-login refresh token rejected; reloaded disk cache "
570
+ "but new RT also failed; please run 've login'. underlying error: {}".format(
571
+ self.PROVIDER_NAME, exc2
572
+ )
573
+ )
574
+
575
+
576
+
577
+ def _load_cache_from_disk(self):
578
+ cache_path = os.path.join(
579
+ self._cache_dir, _login_cache_filename(self._login_session)
580
+ )
581
+ if not os.path.isfile(cache_path):
582
+ raise RuntimeError(
583
+ "{}: console-login token cache file '{}' does not exist; "
584
+ "please run 've login' to re-authenticate.".format(
585
+ self.PROVIDER_NAME, cache_path
586
+ )
587
+ )
588
+ try:
589
+ with open(cache_path, 'r') as f:
590
+ try:
591
+ return json.load(f)
592
+ except ValueError as e:
593
+ raise RuntimeError(
594
+ "{}: failed to parse console-login token cache '{}': {}; "
595
+ "please run 've login' to re-authenticate.".format(
596
+ self.PROVIDER_NAME, cache_path, e
597
+ )
598
+ )
599
+ except (IOError, OSError) as e:
600
+ raise RuntimeError(
601
+ "{}: failed to read console-login token cache '{}': {}; "
602
+ "please run 've login' to re-authenticate.".format(
603
+ self.PROVIDER_NAME, cache_path, e
604
+ )
605
+ )
606
+
607
+ def _try_apply_from_cache(self, cache, cache_path):
608
+ """Try to apply cache.access_token as live STS without calling OAuth.
609
+
610
+ Returns True iff the cache contains a non-expired access_token that
611
+ parses into STS credentials. Returns False on any expiry/parse miss
612
+ so the caller can fall through to OAuth refresh."""
613
+ try:
614
+ exp_epoch = _console_login_cache_expiration(
615
+ cache, cache_path, self.PROVIDER_NAME
616
+ )
617
+ except RuntimeError:
618
+ return False
619
+ if time.time() >= exp_epoch - 60:
620
+ return False
621
+ try:
622
+ sts_creds = _parse_console_login_access_token(
623
+ cache.get("access_token"), cache_path, self.PROVIDER_NAME
624
+ )
625
+ except RuntimeError:
626
+ return False
627
+ self._credentials = CredentialValue(
628
+ ak=sts_creds["access_key_id"],
629
+ sk=sts_creds["secret_access_key"],
630
+ session_token=sts_creds["session_token"],
631
+ provider_name=self.PROVIDER_NAME,
632
+ )
633
+ self._expiration = exp_epoch
634
+ return True
635
+
636
+ def _refresh_with_oauth(self, cache, cache_path):
637
+ """Refresh access_token via OAuth refresh_token grant; in-memory only.
638
+
639
+ On HTTP 400 invalid_grant the server has declared the refresh_token
640
+ unusable; raise _ConsoleLoginInvalidGrantError so the caller can run
641
+ the disk-reload fallback. All other failures raise RuntimeError."""
642
+ _raw_rt = cache.get("refresh_token")
643
+ refresh_token = _raw_rt.strip() if isinstance(_raw_rt, six.string_types) else ""
644
+ if not refresh_token:
645
+ raise RuntimeError(
646
+ "{}: console-login cache lacks refresh_token; please run 've login' first.".format(
647
+ self.PROVIDER_NAME
648
+ )
649
+ )
650
+ _raw_cid = cache.get("client_id")
651
+ client_id = _raw_cid.strip() if isinstance(_raw_cid, six.string_types) else ""
652
+ if not client_id:
653
+ raise RuntimeError(
654
+ "{}: console-login cache lacks client_id; please run 've login' to regenerate.".format(
655
+ self.PROVIDER_NAME
656
+ )
657
+ )
658
+ _raw_ep = cache.get("endpoint_url")
659
+ endpoint = (_raw_ep.strip() if isinstance(_raw_ep, six.string_types) else "") or _DEFAULT_CONSOLE_LOGIN_ENDPOINT
660
+ _raw_scope = cache.get("scope")
661
+ scope = _raw_scope.strip() if isinstance(_raw_scope, six.string_types) else ""
662
+ url = "{}{}".format(endpoint.rstrip("/"), _CONSOLE_LOGIN_TOKEN_PATH)
663
+ body = {
664
+ "grant_type": "refresh_token",
665
+ "client_id": client_id,
666
+ "refresh_token": refresh_token,
667
+ }
668
+ if scope:
669
+ body["scope"] = scope
670
+ try:
671
+ from urllib.parse import urlencode
672
+ except ImportError:
673
+ from urllib import urlencode
674
+ encoded = urlencode(body)
675
+ encoded_bytes = encoded.encode("utf-8")
676
+ # Py3: urllib.request + urllib.error; Py2: urllib2 exposes everything.
677
+ try:
678
+ import urllib.request as _urlreq
679
+ import urllib.error as _urlerr
680
+ except ImportError:
681
+ import urllib2 as _urlreq # noqa: F401
682
+ _urlerr = _urlreq
683
+ # Providing data= implies POST on both Py2 and Py3 without needing
684
+ # the method= kwarg (which urllib2.Request does not accept).
685
+ req = _urlreq.Request(
686
+ url, encoded_bytes,
687
+ {"Content-Type": "application/x-www-form-urlencoded"},
688
+ )
689
+ try:
690
+ resp = _urlreq.urlopen(req, timeout=_HTTP_TIMEOUT)
691
+ try:
692
+ resp_bytes = resp.read()
693
+ finally:
694
+ resp.close()
695
+ except _urlerr.HTTPError as e:
696
+ err_body = e.read().decode("utf-8", "replace") if hasattr(e, "read") else ""
697
+ err_code = ""
698
+ try:
699
+ err_code = (json.loads(err_body or "{}").get("error") or "")
700
+ except ValueError:
701
+ pass
702
+ if e.code == 400 and err_code == "invalid_grant":
703
+ raise _ConsoleLoginInvalidGrantError(
704
+ "console-login refresh_token rejected (invalid_grant): {}".format(err_body)
705
+ )
706
+ raise RuntimeError(
707
+ "{}: console-login refresh failed with HTTP {}: {}".format(
708
+ self.PROVIDER_NAME, e.code, err_body
709
+ )
710
+ )
711
+ except Exception as e:
712
+ raise RuntimeError(
713
+ "{}: console-login refresh request failed: {}".format(self.PROVIDER_NAME, e)
714
+ )
715
+
716
+ try:
717
+ payload = json.loads(resp_bytes)
718
+ except ValueError as e:
719
+ raise RuntimeError(
720
+ "{}: console-login refresh response not JSON: {}".format(self.PROVIDER_NAME, e)
721
+ )
722
+
723
+ if not isinstance(payload, dict):
724
+ raise RuntimeError(
725
+ "{}: console-login refresh response is not a JSON object.".format(
726
+ self.PROVIDER_NAME
727
+ )
728
+ )
729
+
730
+ _raw_access = payload.get("access_token")
731
+ new_access = _raw_access.strip() if isinstance(_raw_access, six.string_types) else ""
359
732
  try:
360
- os.remove(tmp_path)
361
- except OSError:
362
- pass
363
- raise
733
+ new_expires = int(payload.get("expires_in", 0))
734
+ except (TypeError, ValueError) as e:
735
+ raise RuntimeError(
736
+ "{}: console-login refresh response has invalid expires_in: {}".format(
737
+ self.PROVIDER_NAME, e
738
+ )
739
+ )
740
+ if not new_access or new_expires <= 0:
741
+ raise RuntimeError(
742
+ "{}: console-login refresh response missing access_token or expires_in".format(
743
+ self.PROVIDER_NAME
744
+ )
745
+ )
746
+ cache["access_token"] = new_access
747
+ _raw_rt = payload.get("refresh_token")
748
+ new_rt = _raw_rt.strip() if isinstance(_raw_rt, six.string_types) else ""
749
+ if new_rt:
750
+ cache["refresh_token"] = new_rt
751
+ _raw_id = payload.get("id_token")
752
+ new_id = _raw_id.strip() if isinstance(_raw_id, six.string_types) else ""
753
+ if new_id:
754
+ cache["id_token"] = new_id
755
+ _raw_tt = payload.get("token_type")
756
+ if isinstance(_raw_tt, six.string_types) and _raw_tt.strip():
757
+ cache["token_type"] = _raw_tt
758
+ cache["issued_at"] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
759
+ cache["expires_in"] = new_expires
760
+
761
+ # Now the in-memory cache is fresh; apply it (or surface a malformed-
762
+ # STS error from _try_apply_from_cache).
763
+ if not self._try_apply_from_cache(cache, cache_path):
764
+ raise RuntimeError(
765
+ "{}: console-login refresh succeeded but the new access_token "
766
+ "could not be parsed into STS credentials".format(self.PROVIDER_NAME)
767
+ )
768
+
769
+
770
+ class _ConsoleLoginInvalidGrantError(Exception):
771
+ """Sentinel raised when the signin OAuth endpoint returns invalid_grant."""
364
772
 
365
773
 
366
774
  class SsoCredentialProvider(Provider):
@@ -384,6 +792,10 @@ class SsoCredentialProvider(Provider):
384
792
 
385
793
  self._credentials = None
386
794
  self._expiration = None # epoch seconds
795
+ # _cache holds the most recently observed SSO token cache dict, including
796
+ # refresh_token / client_id / client_secret, so that the SDK can silently
797
+ # refresh the access_token without re-reading the file on every call.
798
+ self._cache = None
387
799
  self._lock = threading.Lock()
388
800
 
389
801
  def retrieve(self):
@@ -412,38 +824,53 @@ class SsoCredentialProvider(Provider):
412
824
  self._credentials = cred
413
825
  return
414
826
 
415
- # Load SSO token cache
416
827
  token_path = os.path.join(
417
828
  self._cache_dir,
418
829
  _token_cache_filename(self._start_url, self._session_name),
419
830
  )
420
- if not os.path.isfile(token_path):
421
- raise RuntimeError(
422
- "{}: SSO token cache file not found at '{}'.".format(
423
- self.PROVIDER_NAME, token_path
424
- )
425
- )
426
831
 
427
- with open(token_path, 'r') as f:
832
+ # Bootstrap from disk only when the in-memory cache is empty; on every
833
+ # subsequent expiry we use the in-memory cache (which already has any
834
+ # rotated refresh_token from a previous cycle).
835
+ if self._cache is None:
836
+ if not os.path.isfile(token_path):
837
+ raise RuntimeError(
838
+ "{}: SSO token cache file not found at '{}'; "
839
+ "please run 've sso login' to re-authenticate.".format(
840
+ self.PROVIDER_NAME, token_path
841
+ )
842
+ )
428
843
  try:
429
- token_cache = json.load(f)
844
+ with open(token_path, 'r') as f:
845
+ self._cache = json.load(f)
430
846
  except ValueError as e:
431
847
  raise RuntimeError(
432
- "{}: failed to parse SSO token cache '{}': {}".format(
848
+ "{}: failed to parse SSO token cache '{}': {}; "
849
+ "please run 've sso login' to re-authenticate.".format(
850
+ self.PROVIDER_NAME, token_path, e
851
+ )
852
+ )
853
+ except (IOError, OSError) as e:
854
+ raise RuntimeError(
855
+ "{}: failed to read SSO token cache '{}': {}; "
856
+ "please run 've sso login' to re-authenticate.".format(
433
857
  self.PROVIDER_NAME, token_path, e
434
858
  )
435
859
  )
436
860
 
437
- access_token = (token_cache.get("access_token") or "").strip()
861
+ _raw_at = self._cache.get("access_token")
862
+ access_token = _raw_at.strip() if isinstance(_raw_at, six.string_types) else ""
438
863
  if not access_token:
439
864
  raise RuntimeError(
440
- "{}: SSO token cache '{}' does not contain access_token.".format(
865
+ "{}: SSO token cache '{}' does not contain access_token; "
866
+ "please run 've sso login' to re-authenticate.".format(
441
867
  self.PROVIDER_NAME, token_path
442
868
  )
443
869
  )
444
870
 
445
871
  # Check if access token is expired
446
- expires_at = (token_cache.get("expires_at") or "").strip()
872
+ _raw_ea = self._cache.get("expires_at")
873
+ expires_at = _raw_ea.strip() if isinstance(_raw_ea, six.string_types) else ""
447
874
  token_expired = False
448
875
  if expires_at:
449
876
  try:
@@ -451,13 +878,14 @@ class SsoCredentialProvider(Provider):
451
878
  token_expired = time.time() > exp_epoch
452
879
  except ValueError as e:
453
880
  raise RuntimeError(
454
- "{}: failed to parse expires_at in '{}': {}".format(
881
+ "{}: failed to parse expires_at in '{}': {}; "
882
+ "please run 've sso login' to re-authenticate.".format(
455
883
  self.PROVIDER_NAME, token_path, e
456
884
  )
457
885
  )
458
886
 
459
887
  if token_expired:
460
- access_token = self._refresh_access_token(token_cache, token_path)
888
+ access_token = self._refresh_access_token(token_path)
461
889
 
462
890
  # Get role credentials from portal
463
891
  self._fetch_role_credentials(access_token)
@@ -487,12 +915,19 @@ class SsoCredentialProvider(Provider):
487
915
  provider_name=self.PROVIDER_NAME,
488
916
  )
489
917
 
490
- def _refresh_access_token(self, token_cache, token_path):
491
- """Refresh the SSO access token using the OAuth token endpoint."""
492
- refresh_token = (token_cache.get("refresh_token") or "").strip()
918
+ def _refresh_access_token(self, token_path):
919
+ """Refresh the SSO access token using the OAuth token endpoint.
920
+
921
+ Operates on self._cache so that any rotated refresh_token is preserved
922
+ across subsequent expiry cycles (in-memory refresh, never writes disk).
923
+ """
924
+ token_cache = self._cache
925
+ _raw_sso_rt = token_cache.get("refresh_token")
926
+ refresh_token = _raw_sso_rt.strip() if isinstance(_raw_sso_rt, six.string_types) else ""
493
927
  if not refresh_token:
494
928
  raise RuntimeError(
495
- "{}: SSO token cache '{}' does not contain refresh_token.".format(
929
+ "{}: SSO token cache '{}' does not contain refresh_token; "
930
+ "please run 've sso login' to re-authenticate.".format(
496
931
  self.PROVIDER_NAME, token_path
497
932
  )
498
933
  )
@@ -503,16 +938,20 @@ class SsoCredentialProvider(Provider):
503
938
  exp_epoch = _unix_timestamp_to_epoch(client_secret_expires_at)
504
939
  if time.time() >= exp_epoch:
505
940
  raise RuntimeError(
506
- "{}: refresh token in '{}' has expired.".format(
941
+ "{}: refresh token in '{}' has expired; "
942
+ "please run 've sso login' to re-authenticate.".format(
507
943
  self.PROVIDER_NAME, token_path
508
944
  )
509
945
  )
510
946
 
511
- client_id = (token_cache.get("client_id") or "").strip()
512
- client_secret = (token_cache.get("client_secret") or "").strip()
947
+ _raw_cid = token_cache.get("client_id")
948
+ client_id = _raw_cid.strip() if isinstance(_raw_cid, six.string_types) else ""
949
+ _raw_cs = token_cache.get("client_secret")
950
+ client_secret = _raw_cs.strip() if isinstance(_raw_cs, six.string_types) else ""
513
951
  if not client_id or not client_secret:
514
952
  raise RuntimeError(
515
- "{}: SSO token cache '{}' does not contain client_id/client_secret.".format(
953
+ "{}: SSO token cache '{}' does not contain client_id/client_secret; "
954
+ "please run 've sso login' to re-authenticate.".format(
516
955
  self.PROVIDER_NAME, token_path
517
956
  )
518
957
  )
@@ -527,63 +966,93 @@ class SsoCredentialProvider(Provider):
527
966
  # Pass a dict body; RESTClient auto-serializes with Content-Type:
528
967
  # application/json (see volcenginesdkcore/rest.py). Do NOT json.dumps
529
968
  # here or it will be double-encoded.
530
- resp_body = ApiClient(Configuration())._do_http_request(
531
- oauth_url,
532
- method="POST",
533
- data={
534
- "grant_type": "refresh_token",
535
- "client_id": client_id,
536
- "client_secret": client_secret,
537
- "refresh_token": refresh_token,
538
- },
539
- headers={"Content-Type": "application/json"},
540
- timeout=_HTTP_TIMEOUT,
541
- max_retries=_HTTP_MAX_RETRIES,
542
- retry_interval=_HTTP_RETRY_INTERVAL,
543
- request_name="OAuth token refresh",
544
- # OAuth refresh_token grants may rotate the refresh token on use;
545
- # replaying a successful-but-response-lost POST would invalidate
546
- # the local refresh_token. Fail fast on 5xx instead.
547
- retry_on_5xx=False,
548
- provider_name=self.PROVIDER_NAME,
549
- )
969
+ try:
970
+ resp_body = ApiClient(Configuration())._do_http_request(
971
+ oauth_url,
972
+ method="POST",
973
+ data={
974
+ "grant_type": "refresh_token",
975
+ "client_id": client_id,
976
+ "client_secret": client_secret,
977
+ "refresh_token": refresh_token,
978
+ },
979
+ headers={"Content-Type": "application/json"},
980
+ timeout=_HTTP_TIMEOUT,
981
+ max_retries=_HTTP_MAX_RETRIES,
982
+ retry_interval=_HTTP_RETRY_INTERVAL,
983
+ request_name="OAuth token refresh",
984
+ # OAuth refresh_token grants may rotate the refresh token on use;
985
+ # replaying a successful-but-response-lost POST would invalidate
986
+ # the local refresh_token. Fail fast on 5xx instead.
987
+ retry_on_5xx=False,
988
+ provider_name=self.PROVIDER_NAME,
989
+ )
990
+ except RuntimeError as e:
991
+ raise RuntimeError(
992
+ "{}: SSO OAuth token refresh failed; "
993
+ "please run 've sso login' to re-authenticate. "
994
+ "underlying error: {}".format(self.PROVIDER_NAME, e)
995
+ )
550
996
 
551
997
  try:
552
998
  resp_data = json.loads(resp_body)
553
999
  except ValueError as e:
554
1000
  raise RuntimeError(
555
- "{}: failed to parse OAuth token response: {}".format(
1001
+ "{}: failed to parse OAuth token response: {}; "
1002
+ "please run 've sso login' to re-authenticate.".format(
556
1003
  self.PROVIDER_NAME, e
557
1004
  )
558
1005
  )
559
1006
 
560
- new_access_token = (resp_data.get("access_token") or "").strip()
1007
+ if not isinstance(resp_data, dict):
1008
+ raise RuntimeError(
1009
+ "{}: OAuth token response is not a JSON object; "
1010
+ "please run 've sso login' to re-authenticate.".format(
1011
+ self.PROVIDER_NAME
1012
+ )
1013
+ )
1014
+
1015
+ _raw_access_token = resp_data.get("access_token")
1016
+ new_access_token = _raw_access_token.strip() if isinstance(_raw_access_token, six.string_types) else ""
561
1017
  if not new_access_token:
562
1018
  raise RuntimeError(
563
- "{}: OAuth token response did not contain access_token.".format(
1019
+ "{}: OAuth token response did not contain access_token; "
1020
+ "please run 've sso login' to re-authenticate.".format(
564
1021
  self.PROVIDER_NAME
565
1022
  )
566
1023
  )
567
1024
 
568
- expires_in = resp_data.get("expires_in", 0)
1025
+ try:
1026
+ expires_in = int(resp_data.get("expires_in", 0))
1027
+ except (TypeError, ValueError) as e:
1028
+ raise RuntimeError(
1029
+ "{}: OAuth token response has invalid expires_in: {}; "
1030
+ "please run 've sso login' to re-authenticate.".format(
1031
+ self.PROVIDER_NAME, e
1032
+ )
1033
+ )
569
1034
  if expires_in <= 0:
570
1035
  raise RuntimeError(
571
- "{}: OAuth token response did not contain valid expires_in.".format(
1036
+ "{}: OAuth token response did not contain valid expires_in; "
1037
+ "please run 've sso login' to re-authenticate.".format(
572
1038
  self.PROVIDER_NAME
573
1039
  )
574
1040
  )
575
1041
 
576
- # Update the cache
1042
+ # Write back into self._cache so any rotated refresh_token survives
1043
+ # the next expiry cycle (in-memory only; disk is never written).
577
1044
  token_cache["access_token"] = new_access_token
578
- new_refresh = (resp_data.get("refresh_token") or "").strip()
1045
+ _raw_refresh = resp_data.get("refresh_token")
1046
+ new_refresh = _raw_refresh.strip() if isinstance(_raw_refresh, six.string_types) else ""
579
1047
  if new_refresh:
580
1048
  token_cache["refresh_token"] = new_refresh
581
1049
  token_cache["expires_at"] = time.strftime(
582
1050
  "%Y-%m-%dT%H:%M:%SZ", time.gmtime(time.time() + expires_in)
583
1051
  )
584
1052
 
585
- _write_json_file_atomic(token_path, token_cache)
586
-
1053
+ # SDK never writes the sso cache file: ve cli is the single writer; the
1054
+ # SDK only refreshes the in-memory self._cache to avoid concurrent
1055
+ # write races with cli.
587
1056
  return new_access_token
588
1057
 
589
1058
  def _fetch_role_credentials(self, access_token):
@@ -627,9 +1096,12 @@ class SsoCredentialProvider(Provider):
627
1096
  result = resp_data.get("Result") or resp_data.get("result") or {}
628
1097
  role_creds = result.get("RoleCredentials") or result.get("roleCredentials") or {}
629
1098
 
630
- ak = (role_creds.get("AccessKeyId") or "").strip()
631
- sk = (role_creds.get("SecretAccessKey") or "").strip()
632
- token = (role_creds.get("sessionToken") or role_creds.get("SessionToken") or "").strip()
1099
+ _raw_ak = role_creds.get("AccessKeyId")
1100
+ ak = _raw_ak.strip() if isinstance(_raw_ak, six.string_types) else ""
1101
+ _raw_sk = role_creds.get("SecretAccessKey")
1102
+ sk = _raw_sk.strip() if isinstance(_raw_sk, six.string_types) else ""
1103
+ _raw_tok = role_creds.get("sessionToken") or role_creds.get("SessionToken")
1104
+ token = _raw_tok.strip() if isinstance(_raw_tok, six.string_types) else ""
633
1105
 
634
1106
  if not ak or not sk:
635
1107
  # Check ResponseMetadata for error
@@ -291,7 +291,7 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)):
291
291
  "OS: {env}\n" \
292
292
  "Python Version: {pyversion}\n" \
293
293
  "Version of the API: 0.1.0\n" \
294
- "SDK Package Version: 5.0.32".\
294
+ "SDK Package Version: 5.0.33".\
295
295
  format(env=sys.platform, pyversion=sys.version)
296
296
 
297
297
  @property
@@ -34,10 +34,10 @@ class StatisticForUpdateLoadInput(object):
34
34
  """
35
35
  swagger_types = {
36
36
  'addr_value': 'str',
37
- 'capacity': 'int',
38
- 'current_load': 'int',
37
+ 'capacity': 'float',
38
+ 'current_load': 'float',
39
39
  'pool_name': 'str',
40
- 'target_load': 'int'
40
+ 'target_load': 'float'
41
41
  }
42
42
 
43
43
  attribute_map = {
@@ -99,7 +99,7 @@ class StatisticForUpdateLoadInput(object):
99
99
 
100
100
 
101
101
  :return: The capacity of this StatisticForUpdateLoadInput. # noqa: E501
102
- :rtype: int
102
+ :rtype: float
103
103
  """
104
104
  return self._capacity
105
105
 
@@ -109,11 +109,8 @@ class StatisticForUpdateLoadInput(object):
109
109
 
110
110
 
111
111
  :param capacity: The capacity of this StatisticForUpdateLoadInput. # noqa: E501
112
- :type: int
112
+ :type: float
113
113
  """
114
- if (self._configuration.client_side_validation and
115
- capacity is not None and capacity < 0): # noqa: E501
116
- raise ValueError("Invalid value for `capacity`, must be a value greater than or equal to `0`") # noqa: E501
117
114
 
118
115
  self._capacity = capacity
119
116
 
@@ -123,7 +120,7 @@ class StatisticForUpdateLoadInput(object):
123
120
 
124
121
 
125
122
  :return: The current_load of this StatisticForUpdateLoadInput. # noqa: E501
126
- :rtype: int
123
+ :rtype: float
127
124
  """
128
125
  return self._current_load
129
126
 
@@ -133,11 +130,8 @@ class StatisticForUpdateLoadInput(object):
133
130
 
134
131
 
135
132
  :param current_load: The current_load of this StatisticForUpdateLoadInput. # noqa: E501
136
- :type: int
133
+ :type: float
137
134
  """
138
- if (self._configuration.client_side_validation and
139
- current_load is not None and current_load < 0): # noqa: E501
140
- raise ValueError("Invalid value for `current_load`, must be a value greater than or equal to `0`") # noqa: E501
141
135
 
142
136
  self._current_load = current_load
143
137
 
@@ -168,7 +162,7 @@ class StatisticForUpdateLoadInput(object):
168
162
 
169
163
 
170
164
  :return: The target_load of this StatisticForUpdateLoadInput. # noqa: E501
171
- :rtype: int
165
+ :rtype: float
172
166
  """
173
167
  return self._target_load
174
168
 
@@ -178,11 +172,8 @@ class StatisticForUpdateLoadInput(object):
178
172
 
179
173
 
180
174
  :param target_load: The target_load of this StatisticForUpdateLoadInput. # noqa: E501
181
- :type: int
175
+ :type: float
182
176
  """
183
- if (self._configuration.client_side_validation and
184
- target_load is not None and target_load < 0): # noqa: E501
185
- raise ValueError("Invalid value for `target_load`, must be a value greater than or equal to `0`") # noqa: E501
186
177
 
187
178
  self._target_load = target_load
188
179
 
@@ -35,6 +35,7 @@ class ListActivityMediaAPIRequest(object):
35
35
  swagger_types = {
36
36
  'folder_id': 'int',
37
37
  'include_sub_folder': 'bool',
38
+ 'is_close_dated': 'bool',
38
39
  'name': 'str',
39
40
  'order_key': 'str',
40
41
  'page_num': 'int',
@@ -47,6 +48,7 @@ class ListActivityMediaAPIRequest(object):
47
48
  attribute_map = {
48
49
  'folder_id': 'FolderId',
49
50
  'include_sub_folder': 'IncludeSubFolder',
51
+ 'is_close_dated': 'IsCloseDated',
50
52
  'name': 'Name',
51
53
  'order_key': 'OrderKey',
52
54
  'page_num': 'PageNum',
@@ -56,7 +58,7 @@ class ListActivityMediaAPIRequest(object):
56
58
  'vid': 'Vid'
57
59
  }
58
60
 
59
- def __init__(self, folder_id=None, include_sub_folder=None, name=None, order_key=None, page_num=None, page_size=None, search_type=None, source_type=None, vid=None, _configuration=None): # noqa: E501
61
+ def __init__(self, folder_id=None, include_sub_folder=None, is_close_dated=None, name=None, order_key=None, page_num=None, page_size=None, search_type=None, source_type=None, vid=None, _configuration=None): # noqa: E501
60
62
  """ListActivityMediaAPIRequest - a model defined in Swagger""" # noqa: E501
61
63
  if _configuration is None:
62
64
  _configuration = Configuration()
@@ -64,6 +66,7 @@ class ListActivityMediaAPIRequest(object):
64
66
 
65
67
  self._folder_id = None
66
68
  self._include_sub_folder = None
69
+ self._is_close_dated = None
67
70
  self._name = None
68
71
  self._order_key = None
69
72
  self._page_num = None
@@ -77,6 +80,8 @@ class ListActivityMediaAPIRequest(object):
77
80
  self.folder_id = folder_id
78
81
  if include_sub_folder is not None:
79
82
  self.include_sub_folder = include_sub_folder
83
+ if is_close_dated is not None:
84
+ self.is_close_dated = is_close_dated
80
85
  if name is not None:
81
86
  self.name = name
82
87
  if order_key is not None:
@@ -133,6 +138,27 @@ class ListActivityMediaAPIRequest(object):
133
138
 
134
139
  self._include_sub_folder = include_sub_folder
135
140
 
141
+ @property
142
+ def is_close_dated(self):
143
+ """Gets the is_close_dated of this ListActivityMediaAPIRequest. # noqa: E501
144
+
145
+
146
+ :return: The is_close_dated of this ListActivityMediaAPIRequest. # noqa: E501
147
+ :rtype: bool
148
+ """
149
+ return self._is_close_dated
150
+
151
+ @is_close_dated.setter
152
+ def is_close_dated(self, is_close_dated):
153
+ """Sets the is_close_dated of this ListActivityMediaAPIRequest.
154
+
155
+
156
+ :param is_close_dated: The is_close_dated of this ListActivityMediaAPIRequest. # noqa: E501
157
+ :type: bool
158
+ """
159
+
160
+ self._is_close_dated = is_close_dated
161
+
136
162
  @property
137
163
  def name(self):
138
164
  """Gets the name of this ListActivityMediaAPIRequest. # noqa: E501