yicloud-sdk-python 0.1.0__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.
Files changed (59) hide show
  1. version.py +9 -0
  2. yicloud/__init__.py +7 -0
  3. yicloud/base/__init__.py +58 -0
  4. yicloud/base/auth/__init__.py +10 -0
  5. yicloud/base/auth/credential.py +64 -0
  6. yicloud/base/auth/sign.py +80 -0
  7. yicloud/base/client.py +313 -0
  8. yicloud/base/config.py +62 -0
  9. yicloud/base/errs/__init__.py +292 -0
  10. yicloud/base/log/__init__.py +43 -0
  11. yicloud/base/log/logger.py +123 -0
  12. yicloud/base/log/std.py +70 -0
  13. yicloud/base/msgs/__init__.py +226 -0
  14. yicloud/base/utils/__init__.py +6 -0
  15. yicloud/base/utils/helps.py +110 -0
  16. yicloud/base/utils/retry/__init__.py +27 -0
  17. yicloud/base/utils/retry/retry.py +162 -0
  18. yicloud/services/__init__.py +24 -0
  19. yicloud/services/bc/__init__.py +9 -0
  20. yicloud/services/bc/actions.py +23 -0
  21. yicloud/services/bc/client.py +19 -0
  22. yicloud/services/bc/models.py +61 -0
  23. yicloud/services/fs/__init__.py +29 -0
  24. yicloud/services/fs/actions.py +109 -0
  25. yicloud/services/fs/client.py +19 -0
  26. yicloud/services/fs/models.py +152 -0
  27. yicloud/services/iam/__init__.py +27 -0
  28. yicloud/services/iam/actions.py +304 -0
  29. yicloud/services/iam/client.py +19 -0
  30. yicloud/services/iam/models.py +276 -0
  31. yicloud/services/job/__init__.py +44 -0
  32. yicloud/services/job/actions.py +167 -0
  33. yicloud/services/job/client.py +19 -0
  34. yicloud/services/job/models.py +268 -0
  35. yicloud/services/mc/__init__.py +59 -0
  36. yicloud/services/mc/actions.py +221 -0
  37. yicloud/services/mc/client.py +21 -0
  38. yicloud/services/mc/models.py +322 -0
  39. yicloud/services/modelrepo/__init__.py +33 -0
  40. yicloud/services/modelrepo/actions.py +163 -0
  41. yicloud/services/modelrepo/client.py +19 -0
  42. yicloud/services/modelrepo/models.py +146 -0
  43. yicloud/services/modelset/__init__.py +45 -0
  44. yicloud/services/modelset/actions.py +130 -0
  45. yicloud/services/modelset/client.py +19 -0
  46. yicloud/services/modelset/models.py +356 -0
  47. yicloud/services/oss/__init__.py +25 -0
  48. yicloud/services/oss/actions.py +83 -0
  49. yicloud/services/oss/client.py +19 -0
  50. yicloud/services/oss/models.py +113 -0
  51. yicloud/services/registry/__init__.py +42 -0
  52. yicloud/services/registry/actions.py +208 -0
  53. yicloud/services/registry/client.py +19 -0
  54. yicloud/services/registry/models.py +183 -0
  55. yicloud_sdk_python-0.1.0.dist-info/METADATA +145 -0
  56. yicloud_sdk_python-0.1.0.dist-info/RECORD +59 -0
  57. yicloud_sdk_python-0.1.0.dist-info/WHEEL +5 -0
  58. yicloud_sdk_python-0.1.0.dist-info/licenses/LICENSE +202 -0
  59. yicloud_sdk_python-0.1.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,226 @@
1
+ import contextvars
2
+ from typing import Any, Dict, Generic, Optional, Tuple, TypeVar, Union, get_args, get_origin
3
+ from abc import ABC, abstractmethod
4
+ from dataclasses import dataclass, fields, is_dataclass
5
+
6
+
7
+ # === Response Types ===
8
+
9
+ class Response(ABC):
10
+ """Response interface matching Go SDK's Response."""
11
+
12
+ @abstractmethod
13
+ def get_code(self) -> int: ...
14
+
15
+ @abstractmethod
16
+ def get_msg(self) -> str: ...
17
+
18
+ @abstractmethod
19
+ def get_data(self) -> Any: ...
20
+
21
+ @abstractmethod
22
+ def get_cost(self) -> int: ...
23
+
24
+ @abstractmethod
25
+ def get_err(self) -> str: ...
26
+
27
+ @abstractmethod
28
+ def fill_from_json(self, data: bytes): ...
29
+
30
+
31
+ @dataclass
32
+ class Header:
33
+ """Header struct matching Go SDK's Header."""
34
+ code: int
35
+ msg: str
36
+ cost: int = 0
37
+ err: str = ""
38
+
39
+ def get_code(self) -> int:
40
+ return self.code
41
+
42
+ def get_msg(self) -> str:
43
+ return self.msg
44
+
45
+ def get_cost(self) -> int:
46
+ return self.cost
47
+
48
+ def get_err(self) -> str:
49
+ return self.err
50
+
51
+ def __str__(self) -> str:
52
+ return f"code:{self.code}, msg:{self.msg}, cost:{self.cost}, error:{self.err}"
53
+
54
+
55
+ T = TypeVar("T")
56
+
57
+
58
+ def _dict_to_dataclass(target_type, data):
59
+ """Recursively convert a dict to a typed dataclass instance."""
60
+ if not is_dataclass(target_type) or not isinstance(data, dict):
61
+ return data
62
+
63
+ field_types = {f.name: f.type for f in fields(target_type)}
64
+
65
+ kwargs = {}
66
+ for key, value in data.items():
67
+ if key in field_types:
68
+ kwargs[key] = _convert_value(field_types[key], value)
69
+
70
+ return target_type(**kwargs)
71
+
72
+
73
+ def _convert_value(field_type, value):
74
+ """Convert a value to match the target type annotation."""
75
+ if value is None:
76
+ return None
77
+
78
+ origin = get_origin(field_type)
79
+ args = get_args(field_type)
80
+
81
+ # Handle Optional[X] = Union[X, None]
82
+ if origin is Union:
83
+ non_none = [a for a in args if a is not type(None)]
84
+ if len(non_none) == 1:
85
+ return _convert_value(non_none[0], value)
86
+ return value
87
+
88
+ # Handle List[X]
89
+ if origin is list:
90
+ if args and is_dataclass(args[0]):
91
+ return [_dict_to_dataclass(args[0], item) if isinstance(item, dict) else item for item in value]
92
+ return value
93
+
94
+ # Handle Dict[str, X]
95
+ if origin is dict:
96
+ if args and len(args) == 2 and is_dataclass(args[1]):
97
+ return {k: _dict_to_dataclass(args[1], v) if isinstance(v, dict) else v for k, v in value.items()}
98
+ return value
99
+
100
+ # Handle direct dataclass field
101
+ if is_dataclass(field_type) and isinstance(value, dict):
102
+ return _dict_to_dataclass(field_type, value)
103
+
104
+ return value
105
+
106
+
107
+ @dataclass
108
+ class Rsp(Generic[T], Response):
109
+ """Generic response type matching Go SDK's Rsp[T]."""
110
+ header: Header
111
+ data: Optional[T] = None
112
+
113
+ def __init__(self, header: Optional[Header] = None, data: Optional[T] = None):
114
+ if header is None:
115
+ header = Header(code=0, msg="")
116
+ self.header = header
117
+ self.data = data
118
+
119
+ @classmethod
120
+ def empty(cls) -> "Rsp[None]":
121
+ return Rsp(header=Header(code=0, msg=""), data=None)
122
+
123
+ def get_code(self) -> int:
124
+ return self.header.code
125
+
126
+ def get_msg(self) -> str:
127
+ return self.header.msg
128
+
129
+ def get_data(self) -> Any:
130
+ return self.data
131
+
132
+ def get_cost(self) -> int:
133
+ return self.header.cost
134
+
135
+ def get_err(self) -> str:
136
+ return self.header.err
137
+
138
+ def fill_from_json(self, data: bytes):
139
+ """Fill data from JSON bytes."""
140
+ pass # Implementation optional
141
+
142
+ def get_typed_data(self) -> Optional[T]:
143
+ if self.data is None:
144
+ return None
145
+ if not isinstance(self.data, dict):
146
+ return self.data
147
+
148
+ orig = getattr(self, "__orig_class__", None)
149
+ if orig is not None:
150
+ type_args = getattr(orig, "__args__", None)
151
+ if type_args and type_args[0] is not None and type_args[0] is not type(None):
152
+ target = type_args[0]
153
+ if is_dataclass(target):
154
+ return _dict_to_dataclass(target, self.data)
155
+
156
+ return self.data
157
+
158
+
159
+ # Type aliases matching Go SDK
160
+ RawRsp = Rsp[Any]
161
+ Empty = Rsp[None]
162
+
163
+
164
+ # === Context Metadata ===
165
+
166
+ # Context var for storing response metadata
167
+ _ctx_meta = contextvars.ContextVar[Optional["RspMeta"]]("rsp_meta", default=None)
168
+
169
+
170
+ @dataclass
171
+ class RspMeta:
172
+ """Response metadata matching Go SDK's RspMeta."""
173
+ request_id: str = ""
174
+ cost: int = 0
175
+ err: str = ""
176
+
177
+
178
+ # Type alias for context (None represents no context)
179
+ Context = Optional[Dict[str, Any]]
180
+
181
+
182
+ def with_meta_ctx(ctx: Context = None) -> Tuple[Context, RspMeta]:
183
+ """Create a new context with response metadata."""
184
+ meta = RspMeta()
185
+ # Store meta reference in context dict
186
+ if ctx is None:
187
+ ctx = {}
188
+ ctx["_meta"] = meta
189
+ return ctx, meta
190
+
191
+
192
+ def new_meta_ctx() -> Tuple[Context, RspMeta]:
193
+ """Create a new meta context with empty base context."""
194
+ return with_meta_ctx(None)
195
+
196
+
197
+ def get_rsp_meta(ctx: Context) -> Tuple[Optional[RspMeta], bool]:
198
+ """Get response metadata from context."""
199
+ if ctx is None:
200
+ return None, False
201
+
202
+ meta = ctx.get("_meta")
203
+ if meta is not None:
204
+ return meta, True
205
+ return None, False
206
+
207
+
208
+ def clear_meta_ctx(ctx: Context = None):
209
+ """Clear the meta context."""
210
+ if ctx is not None:
211
+ ctx.pop("_meta", None)
212
+
213
+
214
+ __all__ = [
215
+ "Response",
216
+ "Header",
217
+ "Rsp",
218
+ "RawRsp",
219
+ "Empty",
220
+ "RspMeta",
221
+ "with_meta_ctx",
222
+ "new_meta_ctx",
223
+ "get_rsp_meta",
224
+ "clear_meta_ctx",
225
+ "Context",
226
+ ]
@@ -0,0 +1,6 @@
1
+ from yicloud.base.utils.helps import get_current_func_name, build_query
2
+
3
+ __all__ = [
4
+ "get_current_func_name",
5
+ "build_query",
6
+ ]
@@ -0,0 +1,110 @@
1
+ import inspect
2
+ import dataclasses
3
+ from typing import Any, Optional, Type, get_type_hints
4
+ from collections import OrderedDict
5
+ from urllib.parse import urlencode
6
+
7
+
8
+ def get_current_func_name() -> str:
9
+ """Get current function name for path construction."""
10
+ try:
11
+ frame = inspect.stack()[1]
12
+ return frame.function
13
+ except (IndexError, ValueError):
14
+ return "unknown"
15
+
16
+
17
+ def parse_json_tag(field_name: str, field_type: Type, default_value: Any = None):
18
+ """
19
+ Parse json tag from field (simulating Go's json tag behavior).
20
+
21
+ Since Python doesn't have struct tags, we use a convention:
22
+ - Field name in snake_case maps to PascalCase for json key
23
+ - We'll use a helper class attribute or __json__ dict for customization
24
+
25
+ For simplicity, we'll convert snake_case to CamelCase like Go.
26
+ """
27
+ # Default key: convert to PascalCase from snake_case
28
+ if "_" in field_name:
29
+ parts = field_name.split("_")
30
+ key = "".join(p.capitalize() for p in parts)
31
+ else:
32
+ key = field_name[0].upper() + field_name[1:] if field_name else field_name
33
+
34
+ # For now, we don't have a way to specify omitempty or skip in Python
35
+ # without using custom decorators or separate metadata
36
+ omitempty = False
37
+ skip = False
38
+
39
+ # Check if field value is Optional (has None as default)
40
+ if default_value is None:
41
+ # For Optional fields, we treat them as pointer-like in Go
42
+ pass
43
+
44
+ return key, omitempty, skip
45
+
46
+
47
+ def build_query(kvs: Any) -> str:
48
+ """
49
+ Build query string from dataclass/dict using field annotations.
50
+ Matches Go SDK's BuildQuery behavior.
51
+
52
+ For dataclasses, uses the field name (converted to CamelCase) as key.
53
+ For None values in Optional fields, skips them.
54
+ For zero values in non-Optional fields without omitempty, includes them.
55
+
56
+ Supported types: str, int, float, bool
57
+ """
58
+ if kvs is None:
59
+ return ""
60
+
61
+ if isinstance(kvs, str):
62
+ return kvs
63
+
64
+ values = OrderedDict()
65
+
66
+ # Handle dataclass
67
+ if dataclasses.is_dataclass(kvs):
68
+ for field in dataclasses.fields(kvs):
69
+ field_name = field.name
70
+ field_value = getattr(kvs, field_name)
71
+
72
+ # Parse the json tag (key name)
73
+ # In Python, we convert snake_case to CamelCase
74
+ key, omitempty, skip = parse_json_tag(field_name, field.type)
75
+
76
+ if skip:
77
+ continue
78
+
79
+ # Handle Optional/None fields (like Go pointers)
80
+ if field_value is None:
81
+ # Check if field has a default of None (Optional)
82
+ # If so, skip (like nil pointer in Go)
83
+ if field.default is dataclasses.MISSING and field.default_factory is dataclasses.MISSING:
84
+ # No default, None means explicit skip? Actually in Go, nil = always skip
85
+ continue
86
+ else:
87
+ # Has default of None, skip if None
88
+ continue
89
+
90
+ # Handle omitempty for non-None values
91
+ if omitempty and field_value in ("", 0, False, [], {}):
92
+ continue
93
+
94
+ # Convert value to string
95
+ if isinstance(field_value, bool):
96
+ values[key] = "true" if field_value else "false"
97
+ else:
98
+ values[key] = str(field_value)
99
+
100
+ # Handle dict
101
+ elif isinstance(kvs, dict):
102
+ for key, value in kvs.items():
103
+ if value is None:
104
+ continue
105
+ if isinstance(value, bool):
106
+ values[key] = "true" if value else "false"
107
+ else:
108
+ values[key] = str(value)
109
+
110
+ return urlencode(values)
@@ -0,0 +1,27 @@
1
+ from yicloud.base.utils.retry.retry import (
2
+ retry,
3
+ is_retry_err,
4
+ retryErr,
5
+ with_attempts,
6
+ with_logs,
7
+ with_retry_if,
8
+ with_on_retry,
9
+ with_duration,
10
+ with_factor,
11
+ with_jitter,
12
+ Context,
13
+ )
14
+
15
+ __all__ = [
16
+ "retry",
17
+ "is_retry_err",
18
+ "retryErr",
19
+ "with_attempts",
20
+ "with_logs",
21
+ "with_retry_if",
22
+ "with_on_retry",
23
+ "with_duration",
24
+ "with_factor",
25
+ "with_jitter",
26
+ "Context",
27
+ ]
@@ -0,0 +1,162 @@
1
+ import time
2
+ import random
3
+ import math
4
+ from typing import Callable, Optional, Any, Dict, Tuple
5
+
6
+
7
+ class retryErr(Exception):
8
+ """Retry error wrapping the original error."""
9
+
10
+ def __init__(self, desc: str, origin: Optional[Exception] = None):
11
+ self.desc = desc
12
+ self.origin = origin
13
+
14
+ def __str__(self) -> str:
15
+ if self.origin:
16
+ return f"{self.desc}: {self.origin}"
17
+ return self.desc
18
+
19
+ def __cause__(self) -> Optional[Exception]:
20
+ return self.origin
21
+
22
+
23
+ def is_retry_err(err: Exception) -> Tuple[Optional[Exception], bool]:
24
+ """Check if error is a retry error."""
25
+ if isinstance(err, retryErr):
26
+ return err.origin, True
27
+ return None, False
28
+
29
+
30
+ class retryOptions:
31
+ """Retry options."""
32
+
33
+ def __init__(self):
34
+ self.attempts = 3
35
+ self.duration = 1.0 # seconds
36
+ self.factor = 2.0
37
+ self.jitter = 0.1
38
+ self.enable_log = False
39
+ self.retry_if: Optional[Callable[[Exception], bool]] = None
40
+ self.on_retry: Optional[Callable[[int, Exception, float], None]] = None
41
+
42
+
43
+ def default_options() -> retryOptions:
44
+ return retryOptions()
45
+
46
+
47
+ def with_attempts(n: int) -> Callable[[retryOptions], None]:
48
+ return lambda o: setattr(o, 'attempts', n)
49
+
50
+
51
+ def with_logs(enable: bool) -> Callable[[retryOptions], None]:
52
+ return lambda o: setattr(o, 'enable_log', enable)
53
+
54
+
55
+ def with_retry_if(fn: Callable[[Exception], bool]) -> Callable[[retryOptions], None]:
56
+ return lambda o: setattr(o, 'retry_if', fn)
57
+
58
+
59
+ def with_on_retry(fn: Callable[[int, Exception, float], None]) -> Callable[[retryOptions], None]:
60
+ return lambda o: setattr(o, 'on_retry', fn)
61
+
62
+
63
+ def with_duration(d: float) -> Callable[[retryOptions], None]:
64
+ return lambda o: setattr(o, 'duration', d)
65
+
66
+
67
+ def with_factor(f: float) -> Callable[[retryOptions], None]:
68
+ return lambda o: setattr(o, 'factor', f)
69
+
70
+
71
+ def with_jitter(j: float) -> Callable[[retryOptions], None]:
72
+ return lambda o: setattr(o, 'jitter', j)
73
+
74
+
75
+ def jitter(duration: float, max_factor: float) -> float:
76
+ """Add random jitter to duration."""
77
+ if max_factor <= 0:
78
+ return duration
79
+ return duration * (1 + random.random() * max_factor)
80
+
81
+
82
+ def next_sleep(o: retryOptions, step: int) -> float:
83
+ """Calculate next sleep duration."""
84
+ d = float(o.duration)
85
+
86
+ if o.factor != 0:
87
+ d = d * math.pow(o.factor, float(step))
88
+
89
+ if o.jitter > 0:
90
+ d = jitter(d, float(o.jitter))
91
+
92
+ return d
93
+
94
+
95
+ Context = Optional[Dict[str, Any]]
96
+
97
+
98
+ def retry(
99
+ ctx: Context,
100
+ fn: Callable[[Context], Any],
101
+ *opts: Callable[[retryOptions], None]
102
+ ) -> Any:
103
+ """
104
+ Retry function with exponential backoff and jitter.
105
+
106
+ Args:
107
+ ctx: Optional context dict (can be None)
108
+ fn: Function to execute, takes context as argument
109
+ *opts: Retry options
110
+
111
+ Returns:
112
+ Result of fn if successful
113
+
114
+ Raises:
115
+ retryErr if all attempts fail
116
+ """
117
+ cfg = default_options()
118
+ for opt in opts:
119
+ opt(cfg)
120
+
121
+ err: Optional[Exception] = None
122
+ for i in range(cfg.attempts):
123
+ # Execute the function
124
+ try:
125
+ result = fn(ctx)
126
+ return result
127
+ except Exception as e:
128
+ err = e
129
+
130
+ # Check if should retry based on retry_if
131
+ if cfg.retry_if is not None and not cfg.retry_if(e):
132
+ raise e
133
+
134
+ # Last attempt, break
135
+ if i == cfg.attempts - 1:
136
+ break
137
+
138
+ # Calculate sleep time
139
+ sleep = next_sleep(cfg, i)
140
+
141
+ # Call on_retry callback
142
+ if cfg.on_retry is not None:
143
+ cfg.on_retry(i + 1, e, sleep)
144
+
145
+ # Log if enabled
146
+ if cfg.enable_log:
147
+ from ... import log
148
+ log.warnf(
149
+ "retry %d/%d after %s, err: %s",
150
+ i + 1,
151
+ cfg.attempts,
152
+ sleep,
153
+ str(e),
154
+ )
155
+
156
+ # Sleep
157
+ time.sleep(sleep)
158
+
159
+ raise retryErr(
160
+ f"after {cfg.attempts} attempts, last error: {err}",
161
+ err if err else None
162
+ )
@@ -0,0 +1,24 @@
1
+ # Services package
2
+ # All service modules matching Go SDK structure
3
+
4
+ from . import iam
5
+ from . import job
6
+ from . import bc
7
+ from . import mc
8
+ from . import oss
9
+ from . import registry
10
+ from . import modelset
11
+ from . import modelrepo
12
+ from . import fs
13
+
14
+ __all__ = [
15
+ "iam",
16
+ "job",
17
+ "bc",
18
+ "mc",
19
+ "oss",
20
+ "registry",
21
+ "modelset",
22
+ "modelrepo",
23
+ "fs",
24
+ ]
@@ -0,0 +1,9 @@
1
+ from yicloud.services.bc.client import BCClient as Client, client, use_client
2
+ from . import actions, models
3
+
4
+ from .actions import list_billing_details
5
+ from .models import (
6
+ ListBillingDetailsReq,
7
+ ListBillingDetailsRes,
8
+ InstanceUsageView,
9
+ )
@@ -0,0 +1,23 @@
1
+ from typing import Optional
2
+
3
+ from yicloud.base import msgs
4
+ from yicloud.services.bc import models
5
+ from yicloud.services.bc.client import client
6
+
7
+ _PRODUCT_CODE = "bc"
8
+ _LAST_VERSION = "v1alpha1"
9
+
10
+
11
+ def list_billing_details(ctx: Optional[dict], req: models.ListBillingDetailsReq) -> models.ListBillingDetailsRes:
12
+ """
13
+ GET /bc/v1alpha1/ListBillingDetails
14
+ Action: ListBillingDetails
15
+
16
+ Returns ListBillingDetailsRes on success.
17
+
18
+ Raises YiCloudException on error.
19
+ """
20
+ path = f"/{_PRODUCT_CODE}/{_LAST_VERSION}/ListBillingDetails"
21
+ rsp = msgs.Rsp[models.ListBillingDetailsRes]()
22
+ client.base.get(ctx, path, req, rsp)
23
+ return rsp.get_typed_data()
@@ -0,0 +1,19 @@
1
+ from yicloud.base import Client
2
+
3
+
4
+ class BCClient:
5
+ """BC (Billing Center) service client, matching Go SDK's services/bc/client.go."""
6
+
7
+ def __init__(self, base_client: Client = None):
8
+ self.base = base_client
9
+ self.product_code = "bc"
10
+ self.last_version = "v1alpha1"
11
+
12
+
13
+ # Singleton matching Go SDK
14
+ client: BCClient = BCClient()
15
+
16
+
17
+ def use_client(cli: Client) -> None:
18
+ """Set the base client for BC service."""
19
+ client.base = cli
@@ -0,0 +1,61 @@
1
+ # Code generated from Go SDK's services/bc/models.go. DO NOT EDIT.
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Optional
5
+
6
+
7
+ @dataclass
8
+ class ListBillingDetailsReq:
9
+ """List billing details request."""
10
+ Tenant: str = ""
11
+ Project: str = ""
12
+ StartTime: str = ""
13
+ EndTime: str = ""
14
+ BillingCycle: str = ""
15
+ ProductName: str = ""
16
+ BillingMode: str = ""
17
+ InstanceId: str = ""
18
+ InstanceName: str = ""
19
+ ResourceCreator: str = ""
20
+ RelatedResourceId: str = ""
21
+ RelatedResourceName: str = ""
22
+ RelatedResourceType: str = ""
23
+ SortBy: str = ""
24
+ SortOrder: str = ""
25
+ Limit: int = 0
26
+ Offset: int = 0
27
+
28
+
29
+ @dataclass
30
+ class InstanceUsageView:
31
+ """Instance usage view."""
32
+ Tenant: str = ""
33
+ BillingCycle: str = ""
34
+ BillingTime: str = ""
35
+ ProductName: str = ""
36
+ BillingMode: str = ""
37
+ MetricCode: str = ""
38
+ MetricUnit: str = ""
39
+ UsageDurationHours: float = 0.0
40
+ UsageAmount: float = 0.0
41
+ InstanceCount: int = 0
42
+ UsageTimeRangeStart: str = ""
43
+ UsageTimeRangeEnd: str = ""
44
+ InstanceId: str = ""
45
+ InstanceName: str = ""
46
+ InstanceIdName: str = ""
47
+ RayJobName: str = ""
48
+ RayGroupName: str = ""
49
+ SpecDesc: str = ""
50
+ RelatedResourceName: str = ""
51
+ Project: str = ""
52
+ ResourceCreator: str = ""
53
+
54
+
55
+ @dataclass
56
+ class ListBillingDetailsRes:
57
+ """List billing details response."""
58
+ Items: list[InstanceUsageView] = field(default_factory=list)
59
+ Total: int = 0
60
+ Limit: int = 0
61
+ Offset: int = 0
@@ -0,0 +1,29 @@
1
+ from yicloud.services.fs.client import FSClient as Client, client, use_client
2
+ from . import actions, models
3
+
4
+ from .actions import (
5
+ list_dir,
6
+ get_file_info,
7
+ create_fileset_with_quota,
8
+ delete_fileset,
9
+ list_filesets_with_quota_info,
10
+ set_fileset_quota,
11
+ get_fileset,
12
+ )
13
+ from .models import (
14
+ FileInfo,
15
+ FilesetInfo,
16
+ PaginatedFileInfo,
17
+ FilesetWithQuotaInfo,
18
+ GetFSBucketResponse,
19
+ BucketResponse,
20
+ PaginatedFileSetWithQuotaInfo,
21
+ ListDirRequest,
22
+ GetFileInfoRequest,
23
+ Authorization,
24
+ CreateFilesetWithQuotaRequest,
25
+ DeleteFilesetRequest,
26
+ SetFilesetQuotaRequest,
27
+ GetFilesetRequest,
28
+ ListFilesetsWithQuotaInfoRequest,
29
+ )