Metadata-Version: 2.4
Name: echoss-storage
Version: 2.1.0
Summary: echoss AI Bigdata Solution - Object Storage like S3 handler
Author-email: ckkim <ckkim@12cm.co.kr>
Project-URL: Homepage, https://github.com/12cmlab/echoss-storage
Keywords: echoss,object storage,s3handler,s3_handler
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Requires-Python: >=3.12
Description-Content-Type: text/markdown
Requires-Dist: echoss-fileformat>=1.3.2
Requires-Dist: boto3<2.0,>=1.40.0
Requires-Dist: opencv-python<5.0,>=4.10.0
Requires-Dist: numpy<3,>=2.0.0
Requires-Dist: Pillow<13,>=12.0.0
Requires-Dist: tqdm>=4.66.1
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"

# echoss-storage

echoss AI Bigdata Solution - Object Storage like S3 handler

AWS S3 와 S3 호환 저장소(네이버 클라우드 Object Storage 등)의 객체를 목록 조회·읽기·내려받기·올리기 하는 `S3ResourceHandler` 클래스입니다.
단계별 사용법은 저장소의 [tutorial.md](tutorial.md) 를 참조하세요.

## 설치

```bash
pip install -U echoss-storage
```

- `2.x`: Python `>=3.12`

## 빠른 시작

```python
from echoss_storage import S3ResourceHandler

s3 = S3ResourceHandler('config/s3_config.yaml', env='develop')   # yaml/json 경로 또는 dict

keys = s3.get_object_list('my-bucket', 'images/', pattern='.png', use_tqdm=False)
with s3.get_object_file('my-bucket', keys[0]) as f:
    image = f.as_pil_image()
```

## 설정

`S3ResourceHandler(config_file, env=None)`

- `config_file`: yaml 또는 json 파일 경로, 또는 dict
- `env`: 최상위에 환경별 절(`develop`, `test` 등)이 있을 때 고를 이름
- 고른 절 안에 `s3` 항목이 있으면 그 항목을 씁니다

| 키 | 필수 | 설명 |
|----|:---:|------|
| `bucket` | 사용처에 따라 | `s3tos3_put_object` 가 원본 버킷으로 씁니다 |
| `endpoint_url` | 아니오 | S3 호환 저장소 주소. AWS S3 는 비워 둡니다 |
| `region_name` | 아니오 (권장) | 없으면 프로필·`AWS_DEFAULT_REGION` 에서 찾고, 그래도 없으면 `us-east-1` |
| `access_key_id` / `secret_access_key` | 아니오 | 키 방식. **둘 다 쓰거나 둘 다 비웁니다** (하나만 있으면 `ValueError`) |
| `profile_name` | 아니오 | `~/.aws/config` 의 프로필 이름 (2.1.0~) |

## 인증 방식 (2.1.0~)

설정에 키가 없으면 키를 넘기지 않고 boto3 기본 자격증명 탐색에 맡깁니다.
탐색 순서는 [boto3 Credentials](https://docs.aws.amazon.com/boto3/latest/guide/credentials.html) 문서를 따릅니다.

**1. Access Key 방식** (기존과 같음, S3 호환 저장소 포함)
```yaml
s3:
  bucket: 'your-bucket-name'
  endpoint_url: 'https://kr.object.ncloudstorage.com'
  region_name: 'kr-standard'
  access_key_id: 'YOUR_ACCESS_KEY_ID'
  secret_access_key: 'YOUR_SECRET_ACCESS_KEY'
```

**2. IAM 역할 - AWS 안** (EC2 / ECS / EKS / Lambda 에 붙인 역할)

키와 `endpoint_url` 을 비우면 실행 환경의 역할 임시 자격증명을 자동으로 쓰고, 만료 전에 갱신합니다.
```yaml
s3:
  bucket: 'your-bucket-name'
  region_name: 'ap-northeast-1'
```
- 그 서버에 `~/.aws/credentials` 나 `AWS_ACCESS_KEY_ID` 등이 남아 있으면 **그 키가 역할보다 먼저 쓰입니다.**
- 확인: `aws configure list` 의 `Type` 이 `iam-role` 이면 역할로 인증된 것입니다.

**3. 프로필 지정** (`profile_name`) — 다른 AWS 계정의 역할 넘겨받기, AWS 밖 서버(IAM Roles Anywhere) 등
```yaml
s3:
  bucket: 'your-bucket-name'
  region_name: 'ap-northeast-1'
  profile_name: 'my-profile'
```
- 프로필 내용(`role_arn` + `credential_source`, 또는 `credential_process`)은 `~/.aws/config` 에 둡니다.
  [boto3 Configuration](https://docs.aws.amazon.com/boto3/latest/guide/configuration.html),
  [Roles Anywhere credential helper](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/credential-helper.html)
- 2.1.0 에서 이 방식은 실환경 검증을 하지 않았습니다 (단위 시험만).

## 필요한 IAM 권한

| 메서드 | 필요한 동작 |
|--------|-------------|
| `get_object_list` | `s3:ListBucket` (버킷 ARN, 필요하면 `s3:prefix` 조건) |
| `get_object_file`, `get_object_info`, `download_object` | `s3:GetObject` |
| `upload_object` | `s3:PutObject` |
| `put_object`, `s3tos3_put_object` | `s3:PutObject` + ACL 이 켜진 버킷 (아래 주의) |
| `move_object` | `s3:GetObject`, `s3:PutObject`, `s3:DeleteObject` + ACL 이 켜진 버킷 |
| `get_bucket_list` | `s3:ListAllMyBuckets` |
| `remove_empty_folder` | `s3:ListBucket`, `s3:DeleteObject` |

## API

| 메서드 | 설명 | 반환 |
|--------|------|------|
| `get_bucket_list(include_date=False)` | 접속 계정의 버킷 목록 | `list[str]`, `include_date=True` 면 `{버킷: 'YYYY-MM-DD'}` |
| `get_object_list(bucket, s3_prefix, after_ts=0, pattern=None, use_tqdm=True)` | 접두어 아래 객체 키. `pattern` 은 키에 포함된 문자열(정규식 아님), `after_ts` 는 `"YYYY-MM-DD HH:MM:SS"`(서버 로컬 시각) 이후 수정분만. 폴더 표시 객체는 제외 | `list[str]` |
| `get_object_file(bucket, file_name)` | 객체 보기 객체 (`with` 사용 가능, 처음 읽을 때 내려받음) | `S3ResourceFileView` |
| `get_object_info(bucket, file_path)` | 마지막 수정 시각(UTC+9 로 변환)과 링크 | `('YYYY-MM-DD HH:MM:SS', url)` |
| `download_object(bucket_name, target_file_path, download_file_path)` | 객체 키 → 로컬 파일 | — |
| `upload_object(bucket_name, target_file_path, upload_file_path, ExtraArgs=None)` | 로컬 파일 → 객체 키. `ExtraArgs` 예: `{'ContentType': 'video/mp4'}` | — |
| `put_object(object_body, object_name, trg_bucket)` | 메모리 데이터 → 객체. 키가 `.json` 이면 dict 를 JSON 으로 변환. **`ACL='public-read'` 고정** | — |
| `s3tos3_put_object(src_file_name, trg_file_name, trg_s3_config, fin_print=True)` | 이 설정의 `bucket` 에서 다른 설정(`trg_s3_config`)의 `bucket` 으로 메모리 경유 복사. 대상 쪽은 `put_object` 사용 | — |
| `move_object(src_file_name, trg_file_name, bucket, acl='public-read')` | 같은 버킷 안 이동(복사 후 원본 삭제) | — |
| `remove_empty_folder(bucket)` | `Temp/` 아래 폴더 정리 | — |

`S3ResourceFileView`: `as_bytes()`, `as_text(encoding='utf-8')`, `as_json()`, `as_pil_image()`, `as_cv2_image()`, `save_to_disk(filepath)`, `get_content_type()`, `is_image()`

링크 형식 (`get_object_info`)
- `endpoint_url` 이 있으면 `{endpoint_url}/{bucket}/{key}`
- 없으면 `https://{bucket}.s3.{region}.amazonaws.com/{key}` (AWS 가상 호스트 방식). 버킷명에 점(`.`)이 있으면 이 형식의 HTTPS 인증서가 맞지 않습니다

## 주의

- **ACL 이 꺼진 버킷**: 새로 만든 AWS 버킷은 기본으로 ACL 이 꺼져 있고(Object Ownership: Bucket owner enforced), 이때 `public-read` 를 지정한 업로드는 `400 AccessControlListNotSupported` 로 실패합니다 ([AWS 문서](https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html)). `put_object`, `s3tos3_put_object`, `move_object` 가 해당합니다. 그런 버킷에는 `upload_object` 를 쓰세요.
- `remove_empty_folder` 는 이름과 달리 `Temp/` 아래 폴더의 객체까지 지울 수 있습니다(코드 기준). 실행 전에 대상을 확인하세요.

# 버전 History
- v2.1.0 add IAM role authentication: `access_key_id`/`secret_access_key` optional (absent -> boto3 default credential chain),
  optional `profile_name`, `region_name` now optional, `ValueError` when only one key is set,
  `get_object_info` builds AWS URL when `endpoint_url` is absent. Verified on EC2 IAM role (read).
- v2.0.1 reorganize README.md structure (intro -> install/import -> Resource Class -> history), no code change
- v2.0.0 BREAKING: build system moved from setup.py to pyproject.toml + pytest.ini,
  requires-python raised to >=3.12, dependency floors raised (numpy>=2.0, Pillow>=12.0,
  opencv-python>=4.10.0,<5.0, boto3>=1.40.0, echoss-fileformat>=1.3.2). Public API unchanged.
- v1.2.1 bump package version and update Pillow dependency to >=10.1.0,<11
- v1.2.0 update package dependency constraints for boto3, opencv-python, tqdm, and Pillow
- v1.1.6 hot fix as_pil_image() and add get_content_type() and is_image()
- v1.1.4 remove S3ClientHandler, add S3ResourceFileView class, change internal implementation
  - initial config: str or dict
  - add internal class S3ResouceFileView as return object get_object_file()
  - move read_file() to S3ResouceFileView as_json() or as_text()
  - move read_image() to S3ResouceFileView as_pil_image() or as as_cv2_image()
- v1.1.3 change package name from echoss_s3handler to echoss_storage and use echoss-fileformat
