Metadata-Version: 2.4
Name: originaiagent-core-master-sdk-python
Version: 0.5.0a1
Summary: Origin Core Master SDK (Python port of @originaiagent/core-master-sdk)
Project-URL: Homepage, https://github.com/originaiagent/origin-core/tree/main/packages/core-master-sdk-python
Project-URL: Repository, https://github.com/originaiagent/origin-core
Author: OriginAIAgent
License: Apache-2.0
License-File: LICENSE
Keywords: master-data,origin-core,sdk
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: httpx<1,>=0.27
Requires-Dist: pydantic<3,>=2.7
Provides-Extra: dev
Requires-Dist: pandas>=2.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov>=5; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Provides-Extra: pandas
Requires-Dist: pandas>=2.0; extra == 'pandas'
Description-Content-Type: text/markdown

# originaiagent-core-master-sdk-python

全 Python ツール共通の origin-core マスタ参照 SDK。TS 版 [`@originaiagent/core-master-sdk`](../core-master-sdk/README.md) の Python ポート (v0.2.0-alpha.1 と機能同等 / read-only + write 21 メソッド)。

- 設計書: [core-master-sdk-python-design.md](../../docs/core-master-sdk-python-design.md)
- TS-Python 対応表: [core-master-sdk-python-parity.md](../../docs/core-master-sdk-python-parity.md)
- Python 要件: **3.11 以降**

## インストール

Private repo のため `GITHUB_TOKEN` を環境変数に設定した上で pip から git URL で取得する。

```bash
# 最新 alpha をインストール
pip install "git+https://${GITHUB_TOKEN}@github.com/originaiagent/origin-core.git@core-master-sdk-python-v0.2.0-alpha.1#subdirectory=packages/core-master-sdk-python"
```

Streamlit Cloud では `.streamlit/secrets.toml` に `GITHUB_TOKEN` を置き、`requirements.txt` に上記 URL を 1 行追加するだけで導入できる。

## 環境変数

| 変数 | 必須 | 用途 |
|---|---|---|
| `CORE_MASTER_BASE_URL` | 必須 | Core API のベース URL (例: `https://your-core-api.example.com`) |
| `CORE_MASTER_INTERNAL_API_KEY` | 必須 | INTERNAL API キー。`INTERNAL_API_KEY` も後方互換フォールバックとして読むが、両方設定時は `CORE_MASTER_*` を優先し `warnings.warn` を出す |

## 使用例

### 1. sync で products を取得して DataFrame 表示

```python
from core_master_sdk import create_core_master
from core_master_sdk.pandas_helpers import products_to_df

# 引数を省略すると環境変数から自動読み込み
with create_core_master() as client:
    products = client.products.search("配線カバー", limit=50)
    df = products_to_df(products)
    print(df[["id", "product_name", "jan_code"]].head())
```

### 2. async で ASIN を一括逆引き

```python
import asyncio
from core_master_sdk import create_async_core_master

async def map_asins() -> None:
    async with create_async_core_master() as client:
        result = await client.mall_identifiers.amazon_asin_map(
            ["B000000001", "B000000002", "B000000003"]
        )
        print(result)  # {"B000000001": 422, "B000000002": 423, "B000000003": None}

asyncio.run(map_asins())
```

### 3. 書き込み (PATCH)

```python
from core_master_sdk import create_core_master

# 書き込み時は default_tool_name を指定するか、メソッド呼出時に tool_name を渡すのが推奨
with create_core_master(default_tool_name="my-tool") as client:
    # 1. Product 基本情報の更新
    updated = client.products.patch(123, {"product_name": "新名称"}, if_match="2026-04-22T10:00:00Z")

    # 2. Product Cost の更新 (change_reason 必須)
    client.product_costs.patch(456, {"cost": 1000, "change_reason": "原材料高騰"})

    # 3. Product Specs / SKUs の更新 (Read なし、Write のみ提供)
    client.product_specs.patch(789, {"spec_value": "New Value"})
    client.product_skus.patch("SKU-001", {"variation_name": "Red-M"})
```

### 4. エラーハンドリング

```python
from core_master_sdk import (
    create_core_master,
    CoreMasterNotFound,
    CoreMasterAuthError,
)

with create_core_master() as client:
    try:
        product = client.products.get_by_id(999999)
    except CoreMasterNotFound:
        product = None  # 静かに握りつぶして OK
    except CoreMasterAuthError:
        raise  # env 設定ミスなので上位で止める
```

### Streamlit アプリに組み込む

`examples/streamlit_demo.py` 参照。`streamlit run examples/streamlit_demo.py` で動作する。

## 提供リソース (21 メソッド × sync+async)

| リソース | メソッド |
|---|---|
| `products` | `list` / `get_by_id` / `by_ids` / `search` / `get_by_logi_id` / **`patch`** |
| `product_groups` | `list` / `get_by_id` |
| `product_costs` | `list_by_product_id` / `get_latest_by_product_id` / **`patch`** |
| `product_specs` | **`patch`** |
| `product_skus` | **`patch`** |
| `mall_identifiers` | `list_by_product_id` / `lookup` / `lookup_bulk` / `amazon_asin_map` |
| `mall_code_definitions` | `list` / `get_by_mall_id` |
| `malls` | `list` / `get_by_id` |

詳細は TS-Python 対応表 ([parity.md](../../docs/core-master-sdk-python-parity.md)) を参照。

## 例外階層

```
CoreMasterError (Exception)
├── CoreMasterAuthError              (401/403, retryable=False)
├── CoreMasterNotFound               (404,    retryable=False)
├── CoreMasterPreconditionFailedError (412,    retryable=False)
├── CoreMasterValidationError        (400/422, retryable=False)
├── CoreMasterRateLimitError          (429,    retryable=True)
└── CoreMasterUpstreamError           (5xx/network/timeout, retryable=True)
```

GET および **PATCH** は `retries=2` で retry (指数バックオフ + jitter)。PATCH は Idempotency-Key を retry 間で固定して安全性を確保しています。
429 / 5xx / タイムアウト / ネットワーク断が retry 対象。

## Caveats / 既知の制約

### `product_skus.patch` は last-write-wins

`product_skus` テーブルには `updated_at` カラムが物理的に存在しないため、If-Match ヘッダでの楽観ロックが server 側で適用されません (v0.3 server 実装 `server/routes/masterV1Write.ts` 参照)。
SDK 側で `if_match=...` を渡しても、server はそのヘッダを無視し、直近の書き込みで上書きする **last-write-wins** 挙動になります。

- 同時編集が発生しうる業務フローで `product_skus.patch` を使う場合は、SDK 呼び出し側で楽観ロックを別途実装する (例: 事前 SELECT → アプリ側で diff 判定 → 書込) か、**単一ワーカーからのみ呼び出す**運用を推奨します。
- `products.patch` / `product_specs.patch` / `product_costs.patch` は `updated_at` カラムがあるため、`if_match=<ISO 8601>` を渡せば 412 (`CoreMasterPreconditionFailedError`) が返り楽観ロックとして機能します。

### PATCH の retry と副作用

PATCH は `retries=2` で retry されます。`Idempotency-Key` は **retry 間で固定** され、server 側 `audit_log_core_writes` の UNIQUE 制約で二重実行を防止します。未指定時は SDK が `uuid.uuid4().hex` を自動付与します。

## 開発

```bash
cd packages/core-master-sdk-python
python3.11 -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/pytest --cov
```

## バージョニング

- `0.2.0a1`: Write support (PATCH 4 resource) 追加, retry 緩和
- `0.1.0a1`: Initial read-only release (14 メソッド)

TS 版と機能マイルストーンで一致させるが、patch レベルでは独立インクリメントされることがある (設計書 §10.1)。

## 関連

- 設計書: [docs/core-master-sdk-design.md](../../docs/core-master-sdk-design.md) (TS 版共通設計)
- Core API: `server/routes/masterV1.ts` (13 GET エンドポイント)

## License

Apache License 2.0. See [LICENSE](./LICENSE) for details.
