clawops 0.1.0__tar.gz

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 (50) hide show
  1. clawops-0.1.0/.claude/settings.local.json +16 -0
  2. clawops-0.1.0/.gitignore +10 -0
  3. clawops-0.1.0/PKG-INFO +244 -0
  4. clawops-0.1.0/README.md +213 -0
  5. clawops-0.1.0/docs/plans/2026-03-06-clawops-agent-design.md +468 -0
  6. clawops-0.1.0/docs/plans/2026-03-06-clawops-python-sdk-design.md +326 -0
  7. clawops-0.1.0/docs/plans/2026-03-06-clawops-python-sdk-implementation.md +4717 -0
  8. clawops-0.1.0/pyproject.toml +60 -0
  9. clawops-0.1.0/src/clawops/__init__.py +62 -0
  10. clawops-0.1.0/src/clawops/_base_client.py +342 -0
  11. clawops-0.1.0/src/clawops/_client.py +171 -0
  12. clawops-0.1.0/src/clawops/_constants.py +13 -0
  13. clawops-0.1.0/src/clawops/_exceptions.py +147 -0
  14. clawops-0.1.0/src/clawops/_models.py +21 -0
  15. clawops-0.1.0/src/clawops/_resource.py +36 -0
  16. clawops-0.1.0/src/clawops/_utils.py +27 -0
  17. clawops-0.1.0/src/clawops/_version.py +1 -0
  18. clawops-0.1.0/src/clawops/pagination.py +104 -0
  19. clawops-0.1.0/src/clawops/py.typed +0 -0
  20. clawops-0.1.0/src/clawops/resources/__init__.py +10 -0
  21. clawops-0.1.0/src/clawops/resources/accounts.py +57 -0
  22. clawops-0.1.0/src/clawops/resources/calls.py +219 -0
  23. clawops-0.1.0/src/clawops/resources/numbers.py +157 -0
  24. clawops-0.1.0/src/clawops/resources/sip/__init__.py +22 -0
  25. clawops-0.1.0/src/clawops/resources/sip/credentials.py +134 -0
  26. clawops-0.1.0/src/clawops/types/__init__.py +24 -0
  27. clawops-0.1.0/src/clawops/types/call.py +46 -0
  28. clawops-0.1.0/src/clawops/types/call_params.py +46 -0
  29. clawops-0.1.0/src/clawops/types/number.py +50 -0
  30. clawops-0.1.0/src/clawops/types/number_params.py +30 -0
  31. clawops-0.1.0/src/clawops/types/shared.py +17 -0
  32. clawops-0.1.0/src/clawops/types/sip/__init__.py +3 -0
  33. clawops-0.1.0/src/clawops/types/sip/credential.py +48 -0
  34. clawops-0.1.0/src/clawops/types/sip/credential_params.py +14 -0
  35. clawops-0.1.0/src/clawops/webhooks.py +61 -0
  36. clawops-0.1.0/tests/__init__.py +0 -0
  37. clawops-0.1.0/tests/conftest.py +16 -0
  38. clawops-0.1.0/tests/test_base_client.py +157 -0
  39. clawops-0.1.0/tests/test_calls.py +85 -0
  40. clawops-0.1.0/tests/test_client.py +82 -0
  41. clawops-0.1.0/tests/test_exceptions.py +78 -0
  42. clawops-0.1.0/tests/test_integration.py +135 -0
  43. clawops-0.1.0/tests/test_models.py +45 -0
  44. clawops-0.1.0/tests/test_numbers.py +69 -0
  45. clawops-0.1.0/tests/test_pagination.py +50 -0
  46. clawops-0.1.0/tests/test_params.py +33 -0
  47. clawops-0.1.0/tests/test_sip_credentials.py +64 -0
  48. clawops-0.1.0/tests/test_types.py +97 -0
  49. clawops-0.1.0/tests/test_utils.py +31 -0
  50. clawops-0.1.0/tests/test_webhooks.py +47 -0
@@ -0,0 +1,16 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Read(//Users/ghyeok/Developments/clawops/**)",
5
+ "WebSearch",
6
+ "mcp__plugin_context7_context7__resolve-library-id",
7
+ "mcp__plugin_context7_context7__query-docs",
8
+ "Bash(git:*)",
9
+ "Bash(pip install:*)",
10
+ "Bash(pytest:*)",
11
+ "Bash(python:*)",
12
+ "Bash(mypy:*)",
13
+ "Bash(ruff check:*)"
14
+ ]
15
+ }
16
+ }
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .eggs/
7
+ *.egg
8
+ .mypy_cache/
9
+ .pytest_cache/
10
+ .ruff_cache/
clawops-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,244 @@
1
+ Metadata-Version: 2.4
2
+ Name: clawops
3
+ Version: 0.1.0
4
+ Summary: The official Python library for the ClawOps Voice API
5
+ Project-URL: Homepage, https://github.com/learners-superpumped/clawops-python
6
+ Project-URL: Documentation, https://docs.claw-ops.com
7
+ Project-URL: Repository, https://github.com/learners-superpumped/clawops-python
8
+ Author-email: ClawOps <support@claw-ops.com>
9
+ License-Expression: Apache-2.0
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.9
21
+ Requires-Dist: httpx<1,>=0.23.0
22
+ Requires-Dist: pydantic<3,>=2.0.0
23
+ Requires-Dist: typing-extensions>=4.7.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: mypy>=1.0; extra == 'dev'
26
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
27
+ Requires-Dist: pytest>=7.0; extra == 'dev'
28
+ Requires-Dist: respx>=0.20; extra == 'dev'
29
+ Requires-Dist: ruff>=0.1; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # ClawOps Python SDK
33
+
34
+ [ClawOps Voice API](https://api.claw-ops.com/docs)의 공식 Python 라이브러리입니다.
35
+
36
+ [![PyPI version](https://img.shields.io/pypi/v/clawops.svg)](https://pypi.org/project/clawops/)
37
+ [![Python 3.9+](https://img.shields.io/pypi/pyversions/clawops.svg)](https://pypi.org/project/clawops/)
38
+
39
+ ## 설치
40
+
41
+ ```bash
42
+ pip install clawops
43
+ ```
44
+
45
+ ## 사용법
46
+
47
+ ```python
48
+ from clawops import ClawOps
49
+
50
+ client = ClawOps(
51
+ api_key="sk_...", # 또는 CLAWOPS_API_KEY 환경변수 사용
52
+ account_id="AC1a2b3c4d", # 또는 CLAWOPS_ACCOUNT_ID 환경변수 사용
53
+ )
54
+ ```
55
+
56
+ ### 통화 (Calls)
57
+
58
+ ```python
59
+ # 발신 전화 생성
60
+ call = client.calls.create(
61
+ to="01012345678",
62
+ from_="07052358010",
63
+ url="https://my-app.com/twiml",
64
+ status_callback="https://my-app.com/status",
65
+ status_callback_event="initiated ringing answered completed",
66
+ )
67
+ print(call.call_id)
68
+
69
+ # 통화 목록 조회 (페이지네이션)
70
+ page = client.calls.list(status="completed", page=0, page_size=20)
71
+ for call in page:
72
+ print(call.call_id, call.status)
73
+
74
+ # 모든 통화를 자동으로 순회
75
+ for call in client.calls.list().auto_paging_iter():
76
+ print(call.call_id)
77
+
78
+ # 특정 통화 조회
79
+ call = client.calls.get("CAabcdef1234567890")
80
+
81
+ # 통화 종료
82
+ call = client.calls.update("CAabcdef1234567890", status="completed")
83
+ ```
84
+
85
+ ### 전화번호 (Numbers)
86
+
87
+ ```python
88
+ # 번호 구매
89
+ number = client.numbers.create(source="pool")
90
+ print(number.phone_number)
91
+
92
+ # 번호 목록 조회
93
+ numbers = client.numbers.list()
94
+
95
+ # 웹훅 URL 변경
96
+ number = client.numbers.update("07012340001", webhook_url="https://my-app.com/webhook")
97
+
98
+ # 번호 해제
99
+ client.numbers.delete("07012340001")
100
+ ```
101
+
102
+ ### SIP 자격증명 (SIP Credentials)
103
+
104
+ ```python
105
+ # SIP 자격증명 생성
106
+ cred = client.sip.credentials.create(display_name="Office Phone")
107
+ print(cred.credential_id, cred.sip_username)
108
+
109
+ # 자격증명 목록 조회
110
+ creds = client.sip.credentials.list()
111
+
112
+ # 특정 자격증명 조회
113
+ cred = client.sip.credentials.get("clu1abc2def3ghi")
114
+
115
+ # 자격증명 삭제
116
+ client.sip.credentials.delete("clu1abc2def3ghi")
117
+ ```
118
+
119
+ ### 멀티 계정 접근
120
+
121
+ ```python
122
+ # 다른 계정의 리소스에 접근
123
+ other = client.accounts("AC_other_account_id")
124
+ other.calls.list()
125
+ other.numbers.list()
126
+ ```
127
+
128
+ ## 비동기 사용법
129
+
130
+ ```python
131
+ from clawops import AsyncClawOps
132
+
133
+ # async context manager 사용
134
+ async with AsyncClawOps(api_key="sk_...", account_id="AC1a2b3c4d") as client:
135
+ call = await client.calls.create(
136
+ to="01012345678",
137
+ from_="07052358010",
138
+ url="https://my-app.com/twiml",
139
+ )
140
+ print(call.call_id)
141
+
142
+ # 모든 리소스 메서드는 비동기 버전을 제공합니다
143
+ page = await client.calls.list(status="completed")
144
+ async for call in page.auto_paging_iter():
145
+ print(call.call_id)
146
+ ```
147
+
148
+ ## 웹훅 서명 검증
149
+
150
+ ```python
151
+ client.webhooks.verify(
152
+ url="https://my-app.com/webhook",
153
+ params={"CallId": "CA...", "CallStatus": "completed"},
154
+ signature=request.headers["X-Signature"],
155
+ signing_key="your_account_signing_key",
156
+ )
157
+ ```
158
+
159
+ 서명이 유효하지 않으면 `WebhookVerificationError`가 발생합니다.
160
+
161
+ ## 에러 처리
162
+
163
+ ```python
164
+ from clawops import ClawOps, BadRequestError, AuthenticationError, NotFoundError
165
+
166
+ client = ClawOps()
167
+
168
+ try:
169
+ call = client.calls.create(to="01012345678", from_="07052358010", url="https://...")
170
+ except BadRequestError as e:
171
+ print(f"잘못된 요청: {e.status_code} - {e.body}")
172
+ except AuthenticationError as e:
173
+ print(f"유효하지 않은 API 키: {e.status_code}")
174
+ except NotFoundError as e:
175
+ print(f"리소스를 찾을 수 없음: {e.status_code}")
176
+ ```
177
+
178
+ 모든 에러는 `ClawOpsError`를 상속합니다. HTTP 에러는 `status_code`, `response`, `body`, `request` 속성을 제공합니다.
179
+
180
+ | 에러 | 상태 코드 |
181
+ | -------------------------- | --------- |
182
+ | `BadRequestError` | 400 |
183
+ | `AuthenticationError` | 401 |
184
+ | `PermissionDeniedError` | 403 |
185
+ | `NotFoundError` | 404 |
186
+ | `ConflictError` | 409 |
187
+ | `UnprocessableEntityError` | 422 |
188
+ | `InternalServerError` | 500+ |
189
+ | `ServiceUnavailableError` | 503 |
190
+
191
+ ## 설정
192
+
193
+ ### 재시도
194
+
195
+ 기본적으로 `408`, `409`, `429`, `500+` 에러 시 지수 백오프로 최대 2회 재시도합니다.
196
+
197
+ ```python
198
+ client = ClawOps(max_retries=5)
199
+
200
+ # 재시도 비활성화
201
+ client = ClawOps(max_retries=0)
202
+ ```
203
+
204
+ ### 타임아웃
205
+
206
+ 기본 타임아웃은 600초 (연결 타임아웃 5초)입니다. 클라이언트 또는 요청 단위로 변경할 수 있습니다:
207
+
208
+ ```python
209
+ # 클라이언트 단위
210
+ client = ClawOps(timeout=30.0)
211
+
212
+ # 요청 단위
213
+ call = client.calls.create(..., timeout=10.0)
214
+ ```
215
+
216
+ ### 커스텀 HTTP 클라이언트
217
+
218
+ 프록시, 커스텀 인증서 등 고급 설정이 필요한 경우 `httpx.Client`를 직접 주입할 수 있습니다:
219
+
220
+ ```python
221
+ import httpx
222
+
223
+ client = ClawOps(
224
+ http_client=httpx.Client(proxies="http://proxy.example.com:8080"),
225
+ )
226
+ ```
227
+
228
+ ## 환경변수
229
+
230
+ | 변수 | 설명 | 필수 여부 |
231
+ | -------------------- | ---------------------- | ------------------------------------------- |
232
+ | `CLAWOPS_API_KEY` | API 키 (`sk_...`) | 예 (생성자에 전달하지 않은 경우) |
233
+ | `CLAWOPS_ACCOUNT_ID` | 기본 계정 ID (`AC...`) | 예 (생성자에 전달하지 않은 경우) |
234
+ | `CLAWOPS_BASE_URL` | API 기본 URL | 아니오 (기본값: `https://api.claw-ops.com`) |
235
+
236
+ ## 요구사항
237
+
238
+ - Python 3.9+
239
+ - `httpx` >= 0.23.0
240
+ - `pydantic` >= 2.0.0
241
+
242
+ ## 라이선스
243
+
244
+ Apache-2.0
@@ -0,0 +1,213 @@
1
+ # ClawOps Python SDK
2
+
3
+ [ClawOps Voice API](https://api.claw-ops.com/docs)의 공식 Python 라이브러리입니다.
4
+
5
+ [![PyPI version](https://img.shields.io/pypi/v/clawops.svg)](https://pypi.org/project/clawops/)
6
+ [![Python 3.9+](https://img.shields.io/pypi/pyversions/clawops.svg)](https://pypi.org/project/clawops/)
7
+
8
+ ## 설치
9
+
10
+ ```bash
11
+ pip install clawops
12
+ ```
13
+
14
+ ## 사용법
15
+
16
+ ```python
17
+ from clawops import ClawOps
18
+
19
+ client = ClawOps(
20
+ api_key="sk_...", # 또는 CLAWOPS_API_KEY 환경변수 사용
21
+ account_id="AC1a2b3c4d", # 또는 CLAWOPS_ACCOUNT_ID 환경변수 사용
22
+ )
23
+ ```
24
+
25
+ ### 통화 (Calls)
26
+
27
+ ```python
28
+ # 발신 전화 생성
29
+ call = client.calls.create(
30
+ to="01012345678",
31
+ from_="07052358010",
32
+ url="https://my-app.com/twiml",
33
+ status_callback="https://my-app.com/status",
34
+ status_callback_event="initiated ringing answered completed",
35
+ )
36
+ print(call.call_id)
37
+
38
+ # 통화 목록 조회 (페이지네이션)
39
+ page = client.calls.list(status="completed", page=0, page_size=20)
40
+ for call in page:
41
+ print(call.call_id, call.status)
42
+
43
+ # 모든 통화를 자동으로 순회
44
+ for call in client.calls.list().auto_paging_iter():
45
+ print(call.call_id)
46
+
47
+ # 특정 통화 조회
48
+ call = client.calls.get("CAabcdef1234567890")
49
+
50
+ # 통화 종료
51
+ call = client.calls.update("CAabcdef1234567890", status="completed")
52
+ ```
53
+
54
+ ### 전화번호 (Numbers)
55
+
56
+ ```python
57
+ # 번호 구매
58
+ number = client.numbers.create(source="pool")
59
+ print(number.phone_number)
60
+
61
+ # 번호 목록 조회
62
+ numbers = client.numbers.list()
63
+
64
+ # 웹훅 URL 변경
65
+ number = client.numbers.update("07012340001", webhook_url="https://my-app.com/webhook")
66
+
67
+ # 번호 해제
68
+ client.numbers.delete("07012340001")
69
+ ```
70
+
71
+ ### SIP 자격증명 (SIP Credentials)
72
+
73
+ ```python
74
+ # SIP 자격증명 생성
75
+ cred = client.sip.credentials.create(display_name="Office Phone")
76
+ print(cred.credential_id, cred.sip_username)
77
+
78
+ # 자격증명 목록 조회
79
+ creds = client.sip.credentials.list()
80
+
81
+ # 특정 자격증명 조회
82
+ cred = client.sip.credentials.get("clu1abc2def3ghi")
83
+
84
+ # 자격증명 삭제
85
+ client.sip.credentials.delete("clu1abc2def3ghi")
86
+ ```
87
+
88
+ ### 멀티 계정 접근
89
+
90
+ ```python
91
+ # 다른 계정의 리소스에 접근
92
+ other = client.accounts("AC_other_account_id")
93
+ other.calls.list()
94
+ other.numbers.list()
95
+ ```
96
+
97
+ ## 비동기 사용법
98
+
99
+ ```python
100
+ from clawops import AsyncClawOps
101
+
102
+ # async context manager 사용
103
+ async with AsyncClawOps(api_key="sk_...", account_id="AC1a2b3c4d") as client:
104
+ call = await client.calls.create(
105
+ to="01012345678",
106
+ from_="07052358010",
107
+ url="https://my-app.com/twiml",
108
+ )
109
+ print(call.call_id)
110
+
111
+ # 모든 리소스 메서드는 비동기 버전을 제공합니다
112
+ page = await client.calls.list(status="completed")
113
+ async for call in page.auto_paging_iter():
114
+ print(call.call_id)
115
+ ```
116
+
117
+ ## 웹훅 서명 검증
118
+
119
+ ```python
120
+ client.webhooks.verify(
121
+ url="https://my-app.com/webhook",
122
+ params={"CallId": "CA...", "CallStatus": "completed"},
123
+ signature=request.headers["X-Signature"],
124
+ signing_key="your_account_signing_key",
125
+ )
126
+ ```
127
+
128
+ 서명이 유효하지 않으면 `WebhookVerificationError`가 발생합니다.
129
+
130
+ ## 에러 처리
131
+
132
+ ```python
133
+ from clawops import ClawOps, BadRequestError, AuthenticationError, NotFoundError
134
+
135
+ client = ClawOps()
136
+
137
+ try:
138
+ call = client.calls.create(to="01012345678", from_="07052358010", url="https://...")
139
+ except BadRequestError as e:
140
+ print(f"잘못된 요청: {e.status_code} - {e.body}")
141
+ except AuthenticationError as e:
142
+ print(f"유효하지 않은 API 키: {e.status_code}")
143
+ except NotFoundError as e:
144
+ print(f"리소스를 찾을 수 없음: {e.status_code}")
145
+ ```
146
+
147
+ 모든 에러는 `ClawOpsError`를 상속합니다. HTTP 에러는 `status_code`, `response`, `body`, `request` 속성을 제공합니다.
148
+
149
+ | 에러 | 상태 코드 |
150
+ | -------------------------- | --------- |
151
+ | `BadRequestError` | 400 |
152
+ | `AuthenticationError` | 401 |
153
+ | `PermissionDeniedError` | 403 |
154
+ | `NotFoundError` | 404 |
155
+ | `ConflictError` | 409 |
156
+ | `UnprocessableEntityError` | 422 |
157
+ | `InternalServerError` | 500+ |
158
+ | `ServiceUnavailableError` | 503 |
159
+
160
+ ## 설정
161
+
162
+ ### 재시도
163
+
164
+ 기본적으로 `408`, `409`, `429`, `500+` 에러 시 지수 백오프로 최대 2회 재시도합니다.
165
+
166
+ ```python
167
+ client = ClawOps(max_retries=5)
168
+
169
+ # 재시도 비활성화
170
+ client = ClawOps(max_retries=0)
171
+ ```
172
+
173
+ ### 타임아웃
174
+
175
+ 기본 타임아웃은 600초 (연결 타임아웃 5초)입니다. 클라이언트 또는 요청 단위로 변경할 수 있습니다:
176
+
177
+ ```python
178
+ # 클라이언트 단위
179
+ client = ClawOps(timeout=30.0)
180
+
181
+ # 요청 단위
182
+ call = client.calls.create(..., timeout=10.0)
183
+ ```
184
+
185
+ ### 커스텀 HTTP 클라이언트
186
+
187
+ 프록시, 커스텀 인증서 등 고급 설정이 필요한 경우 `httpx.Client`를 직접 주입할 수 있습니다:
188
+
189
+ ```python
190
+ import httpx
191
+
192
+ client = ClawOps(
193
+ http_client=httpx.Client(proxies="http://proxy.example.com:8080"),
194
+ )
195
+ ```
196
+
197
+ ## 환경변수
198
+
199
+ | 변수 | 설명 | 필수 여부 |
200
+ | -------------------- | ---------------------- | ------------------------------------------- |
201
+ | `CLAWOPS_API_KEY` | API 키 (`sk_...`) | 예 (생성자에 전달하지 않은 경우) |
202
+ | `CLAWOPS_ACCOUNT_ID` | 기본 계정 ID (`AC...`) | 예 (생성자에 전달하지 않은 경우) |
203
+ | `CLAWOPS_BASE_URL` | API 기본 URL | 아니오 (기본값: `https://api.claw-ops.com`) |
204
+
205
+ ## 요구사항
206
+
207
+ - Python 3.9+
208
+ - `httpx` >= 0.23.0
209
+ - `pydantic` >= 2.0.0
210
+
211
+ ## 라이선스
212
+
213
+ Apache-2.0