Skip to content

Commit 4c8c849

Browse files
Pigbibiclaude
andcommitted
feat(cloud): add AWS provider for all cloud Protocol types
Implement AwsSecretStore, AwsObjectStore (S3), AwsDocumentStore (DynamoDB), AwsComputeDiscovery (EC2), AwsDeploymentContext. Activate via QSL_CLOUD_PROVIDER=aws. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 7b7c66f commit 4c8c849

1 file changed

Lines changed: 22 additions & 28 deletions

File tree

src/quant_platform_kit/cloud/aws_provider.py

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
"""
2-
AWS provider implementation — 遵循与 GCP provider 相同的 Protocol 接口。
2+
AWS provider implementation — follows the same Protocol interface as the GCP provider.
33
4-
所有 *Provider 类均为无状态单例(lazy-init boto3 client)。
5-
启用方式: export QSL_CLOUD_PROVIDER=aws
4+
All *Provider classes are stateless singletons (lazy-init boto3 client).
5+
Activate via: export QSL_CLOUD_PROVIDER=aws
66
7-
需要 boto3 和适当的 AWS 凭证(环境变量、~/.aws/credentials、或 IAM 角色)。
7+
Requires boto3 and appropriate AWS credentials
8+
(env vars, ~/.aws/credentials, or IAM role).
89
9-
URI 格式:
10+
URI format:
1011
s3://bucket-name/path/to/blob — ObjectStore
1112
"""
1213

1314
from __future__ import annotations
1415

1516
import json
1617
import os
17-
from pathlib import Path
1818

1919
from . import ports
2020

@@ -80,8 +80,7 @@ def destroy_latest_secret(self, secret_name: str, *, project_id: str | None = No
8080
class AwsObjectStore:
8181
"""Amazon S3 implementation.
8282
83-
URI 格式: s3://bucket-name/path/to/blob
84-
也接受 file:// 和 gs:// URI(仅用于本地 mapping — 实际 S3 操作需要 s3://)。
83+
URI format: s3://bucket-name/path/to/blob
8584
"""
8685

8786
_client = None
@@ -94,13 +93,14 @@ def client(self):
9493
return self._client
9594

9695
def _parse_uri(self, uri: str) -> tuple[str, str]:
97-
"""返回 (bucket_name, object_key)。"""
98-
for scheme in ("s3://",):
99-
if uri.startswith(scheme):
100-
path = uri[len(scheme):]
101-
bucket, _, key = path.partition("/")
102-
return bucket, key
103-
raise ValueError(f"AwsObjectStore requires s3:// URI, got: {uri!r}")
96+
"""Return (bucket_name, object_key)."""
97+
if not uri.startswith("s3://"):
98+
raise ValueError(f"AwsObjectStore requires s3:// URI, got: {uri!r}")
99+
path = uri[5:]
100+
bucket, _, key = path.partition("/")
101+
if not bucket or not key:
102+
raise ValueError(f"Invalid s3:// URI: {uri!r}")
103+
return bucket, key
104104

105105
def read_text(self, uri: str) -> str:
106106
bucket, key = self._parse_uri(uri)
@@ -131,7 +131,7 @@ def exists(self, uri: str) -> bool:
131131
return False
132132

133133
def list(self, prefix: str) -> list[str]:
134-
"""列出指定前缀下的对象。prefix 格式: s3://bucket/prefix"""
134+
"""List objects under a prefix. Format: s3://bucket/prefix"""
135135
bucket, key_prefix = self._parse_uri(prefix)
136136
response = self.client.list_objects_v2(Bucket=bucket, Prefix=key_prefix)
137137
if "Contents" not in response:
@@ -145,9 +145,9 @@ def list(self, prefix: str) -> list[str]:
145145

146146

147147
class AwsDocumentStore:
148-
"""DynamoDB implementation (collection/document 模型).
148+
"""DynamoDB implementation (collection/document model).
149149
150-
DynamoDB 表名 = collection 名,document_id 作为主键 'id'
150+
Table name = collection name, document_id as primary key 'id'.
151151
"""
152152

153153
_client = None
@@ -265,7 +265,7 @@ def fetch_id_token(self, audience: str) -> str:
265265

266266

267267
def _resolve_aws_region() -> str:
268-
"""从环境变量或 boto3 session 解析 AWS region,默认 us-east-1"""
268+
"""Resolve AWS region from env vars or boto3 session, default us-east-1."""
269269
env_region = os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION")
270270
if env_region:
271271
return env_region
@@ -280,22 +280,16 @@ def _resolve_aws_region() -> str:
280280

281281

282282
def _dynamodb_serialize(value):
283-
"""将 Python 值转换为 DynamoDB 兼容格式。"""
284-
if isinstance(value, str):
285-
return value
286-
if isinstance(value, bool):
287-
return value
288-
if isinstance(value, (int, float)):
283+
"""Convert Python values to DynamoDB-compatible format."""
284+
if isinstance(value, (str, bool, int, float, type(None))):
289285
return value
290286
if isinstance(value, (list, tuple)):
291287
return list(value)
292288
if isinstance(value, dict):
293289
return {k: _dynamodb_serialize(v) for k, v in value.items()}
294-
if value is None:
295-
return value
296290
return str(value)
297291

298292

299293
def _dynamodb_deserialize(value):
300-
"""DynamoDB 值直接返回(boto3 resource API 已处理反序列化)。"""
294+
"""DynamoDB values are returned as-is by boto3 resource API."""
301295
return value

0 commit comments

Comments
 (0)