@xyd-js/opensdk-python 0.0.0-build-f0c10f6-20260703195526
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.
- package/CHANGELOG.md +10 -0
- package/LICENSE +21 -0
- package/__fixtures__/-2.complex.openai/admin__organization__admin_api_keys__create/input.json +325 -0
- package/__fixtures__/-2.complex.openai/admin__organization__admin_api_keys__create/output.py +26 -0
- package/__fixtures__/-2.complex.openai/admin__organization__admin_api_keys__delete/input.json +201 -0
- package/__fixtures__/-2.complex.openai/admin__organization__admin_api_keys__delete/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__admin_api_keys__list/input.json +400 -0
- package/__fixtures__/-2.complex.openai/admin__organization__admin_api_keys__list/output.py +29 -0
- package/__fixtures__/-2.complex.openai/admin__organization__admin_api_keys__retrieve/input.json +304 -0
- package/__fixtures__/-2.complex.openai/admin__organization__admin_api_keys__retrieve/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__audit_logs__list/input.json +2602 -0
- package/__fixtures__/-2.complex.openai/admin__organization__audit_logs__list/output.py +29 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__activate__create/input.json +308 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__activate__create/output.py +32 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__create/input.json +308 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__create/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__deactivate__create/input.json +308 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__deactivate__create/output.py +32 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__delete/input.json +196 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__delete/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__list/input.json +356 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__list/output.py +29 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__retrieve/input.json +300 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__retrieve/output.py +30 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__update/input.json +310 -0
- package/__fixtures__/-2.complex.openai/admin__organization__certificates__update/output.py +30 -0
- package/__fixtures__/-2.complex.openai/admin__organization__costs__list/input.json +1062 -0
- package/__fixtures__/-2.complex.openai/admin__organization__costs__list/output.py +29 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__create/input.json +239 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__create/output.py +26 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__delete/input.json +206 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__delete/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__list/input.json +316 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__list/output.py +29 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__roles__create/input.json +364 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__roles__create/output.py +34 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__roles__delete/input.json +210 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__roles__delete/output.py +36 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__roles__list/input.json +398 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__roles__list/output.py +37 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__update/input.json +241 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__update/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__users__create/input.json +237 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__users__create/output.py +34 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__users__delete/input.json +211 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__users__delete/output.py +36 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__users__list/input.json +314 -0
- package/__fixtures__/-2.complex.openai/admin__organization__groups__users__list/output.py +37 -0
- package/__fixtures__/-2.complex.openai/admin__organization__invites__create/input.json +386 -0
- package/__fixtures__/-2.complex.openai/admin__organization__invites__create/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__invites__delete/input.json +203 -0
- package/__fixtures__/-2.complex.openai/admin__organization__invites__delete/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__invites__list/input.json +414 -0
- package/__fixtures__/-2.complex.openai/admin__organization__invites__list/output.py +29 -0
- package/__fixtures__/-2.complex.openai/admin__organization__invites__retrieve/input.json +337 -0
- package/__fixtures__/-2.complex.openai/admin__organization__invites__retrieve/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__api_keys__delete/input.json +279 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__api_keys__delete/output.py +36 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__api_keys__list/input.json +475 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__api_keys__list/output.py +37 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__api_keys__retrieve/input.json +400 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__api_keys__retrieve/output.py +36 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__archive/input.json +247 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__archive/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__certificates__activate__create/input.json +324 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__certificates__activate__create/output.py +40 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__certificates__deactivate__create/input.json +324 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__certificates__deactivate__create/output.py +40 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__certificates__list/input.json +372 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__certificates__list/output.py +37 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__create/input.json +281 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__create/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__groups__create/input.json +274 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__groups__create/output.py +34 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__groups__delete/input.json +211 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__groups__delete/output.py +36 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__groups__list/input.json +342 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__groups__list/output.py +37 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__list/input.json +330 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__list/output.py +29 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__rate_limits__list_rate_limits/input.json +358 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__rate_limits__list_rate_limits/output.py +37 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__rate_limits__update_rate_limit/input.json +407 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__rate_limits__update_rate_limit/output.py +38 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__retrieve/input.json +247 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__retrieve/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__service_accounts__create/input.json +372 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__service_accounts__create/output.py +34 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__service_accounts__delete/input.json +216 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__service_accounts__delete/output.py +36 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__service_accounts__list/input.json +391 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__service_accounts__list/output.py +37 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__service_accounts__retrieve/input.json +253 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__service_accounts__retrieve/output.py +36 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__update/input.json +356 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__update/output.py +30 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__users__create/input.json +349 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__users__create/output.py +36 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__users__delete/input.json +279 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__users__delete/output.py +36 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__users__list/input.json +387 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__users__list/output.py +37 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__users__retrieve/input.json +250 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__users__retrieve/output.py +36 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__users__update/input.json +339 -0
- package/__fixtures__/-2.complex.openai/admin__organization__projects__users__update/output.py +38 -0
- package/__fixtures__/-2.complex.openai/admin__organization__roles__create/input.json +283 -0
- package/__fixtures__/-2.complex.openai/admin__organization__roles__create/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__roles__delete/input.json +206 -0
- package/__fixtures__/-2.complex.openai/admin__organization__roles__delete/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__roles__list/input.json +338 -0
- package/__fixtures__/-2.complex.openai/admin__organization__roles__list/output.py +29 -0
- package/__fixtures__/-2.complex.openai/admin__organization__roles__update/input.json +296 -0
- package/__fixtures__/-2.complex.openai/admin__organization__roles__update/output.py +30 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__audio_speeches__list/input.json +1108 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__audio_speeches__list/output.py +35 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__audio_transcriptions__list/input.json +1108 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__audio_transcriptions__list/output.py +35 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__code_interpreter_sessions__list/input.json +1054 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__code_interpreter_sessions__list/output.py +35 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__completions__list/input.json +1123 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__completions__list/output.py +35 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__embeddings__list/input.json +1108 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__embeddings__list/output.py +35 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__images__list/input.json +1176 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__images__list/output.py +35 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__moderations__list/input.json +1108 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__moderations__list/output.py +35 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__vector_stores__list/input.json +1054 -0
- package/__fixtures__/-2.complex.openai/admin__organization__usage__vector_stores__list/output.py +35 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__delete/input.json +202 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__delete/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__list/input.json +557 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__list/output.py +29 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__retrieve/input.json +472 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__retrieve/output.py +28 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__roles__create/input.json +611 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__roles__create/output.py +34 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__roles__delete/input.json +210 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__roles__delete/output.py +36 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__roles__list/input.json +398 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__roles__list/output.py +37 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__update/input.json +528 -0
- package/__fixtures__/-2.complex.openai/admin__organization__users__update/output.py +30 -0
- package/__fixtures__/-2.complex.openai/audio__speech__create/input.json +388 -0
- package/__fixtures__/-2.complex.openai/audio__speech__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/audio__transcriptions__create/input.json +999 -0
- package/__fixtures__/-2.complex.openai/audio__transcriptions__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/audio__translations__create/input.json +430 -0
- package/__fixtures__/-2.complex.openai/audio__translations__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/audio__voice_consents__create/input.json +244 -0
- package/__fixtures__/-2.complex.openai/audio__voice_consents__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/audio__voice_consents__delete/input.json +190 -0
- package/__fixtures__/-2.complex.openai/audio__voice_consents__delete/output.py +22 -0
- package/__fixtures__/-2.complex.openai/audio__voice_consents__list/input.json +285 -0
- package/__fixtures__/-2.complex.openai/audio__voice_consents__list/output.py +23 -0
- package/__fixtures__/-2.complex.openai/audio__voice_consents__retrieve/input.json +212 -0
- package/__fixtures__/-2.complex.openai/audio__voice_consents__retrieve/output.py +22 -0
- package/__fixtures__/-2.complex.openai/audio__voice_consents__update/input.json +236 -0
- package/__fixtures__/-2.complex.openai/audio__voice_consents__update/output.py +22 -0
- package/__fixtures__/-2.complex.openai/audio__voices__create/input.json +235 -0
- package/__fixtures__/-2.complex.openai/audio__voices__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/batches__cancel/input.json +594 -0
- package/__fixtures__/-2.complex.openai/batches__cancel/output.py +16 -0
- package/__fixtures__/-2.complex.openai/batches__create/input.json +701 -0
- package/__fixtures__/-2.complex.openai/batches__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/batches__list/input.json +665 -0
- package/__fixtures__/-2.complex.openai/batches__list/output.py +17 -0
- package/__fixtures__/-2.complex.openai/batches__retrieve/input.json +594 -0
- package/__fixtures__/-2.complex.openai/batches__retrieve/output.py +16 -0
- package/__fixtures__/-2.complex.openai/beta__assistants__create/input.json +1029 -0
- package/__fixtures__/-2.complex.openai/beta__assistants__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/beta__assistants__delete/input.json +190 -0
- package/__fixtures__/-2.complex.openai/beta__assistants__delete/output.py +22 -0
- package/__fixtures__/-2.complex.openai/beta__assistants__list/input.json +796 -0
- package/__fixtures__/-2.complex.openai/beta__assistants__list/output.py +23 -0
- package/__fixtures__/-2.complex.openai/beta__assistants__retrieve/input.json +694 -0
- package/__fixtures__/-2.complex.openai/beta__assistants__retrieve/output.py +22 -0
- package/__fixtures__/-2.complex.openai/beta__assistants__update/input.json +1045 -0
- package/__fixtures__/-2.complex.openai/beta__assistants__update/output.py +24 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__sessions__cancel/input.json +482 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__sessions__cancel/output.py +28 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__sessions__create/input.json +738 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__sessions__create/output.py +28 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__threads__delete/input.json +200 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__threads__delete/output.py +28 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__threads__items__list/input.json +1218 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__threads__items__list/output.py +37 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__threads__list/input.json +444 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__threads__list/output.py +29 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__threads__retrieve/input.json +328 -0
- package/__fixtures__/-2.complex.openai/beta__chat_kit__threads__retrieve/output.py +28 -0
- package/__fixtures__/-2.complex.openai/beta__threads__create/input.json +665 -0
- package/__fixtures__/-2.complex.openai/beta__threads__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/beta__threads__delete/input.json +189 -0
- package/__fixtures__/-2.complex.openai/beta__threads__delete/output.py +22 -0
- package/__fixtures__/-2.complex.openai/beta__threads__messages__create/input.json +938 -0
- package/__fixtures__/-2.complex.openai/beta__threads__messages__create/output.py +30 -0
- package/__fixtures__/-2.complex.openai/beta__threads__messages__delete/input.json +203 -0
- package/__fixtures__/-2.complex.openai/beta__threads__messages__delete/output.py +30 -0
- package/__fixtures__/-2.complex.openai/beta__threads__messages__list/input.json +945 -0
- package/__fixtures__/-2.complex.openai/beta__threads__messages__list/output.py +31 -0
- package/__fixtures__/-2.complex.openai/beta__threads__messages__retrieve/input.json +832 -0
- package/__fixtures__/-2.complex.openai/beta__threads__messages__retrieve/output.py +30 -0
- package/__fixtures__/-2.complex.openai/beta__threads__messages__update/input.json +855 -0
- package/__fixtures__/-2.complex.openai/beta__threads__messages__update/output.py +32 -0
- package/__fixtures__/-2.complex.openai/beta__threads__new_and_run/input.json +1899 -0
- package/__fixtures__/-2.complex.openai/beta__threads__new_and_run/output.py +22 -0
- package/__fixtures__/-2.complex.openai/beta__threads__retrieve/input.json +283 -0
- package/__fixtures__/-2.complex.openai/beta__threads__retrieve/output.py +22 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__cancel/input.json +1181 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__cancel/output.py +30 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__create/input.json +1851 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__create/output.py +30 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__list/input.json +1285 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__list/output.py +31 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__retrieve/input.json +1181 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__retrieve/output.py +30 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__steps__list/input.json +1066 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__steps__list/output.py +39 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__steps__retrieve/input.json +964 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__steps__retrieve/output.py +40 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__submit_tool_outputs__create/input.json +1246 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__submit_tool_outputs__create/output.py +38 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__update/input.json +1204 -0
- package/__fixtures__/-2.complex.openai/beta__threads__runs__update/output.py +32 -0
- package/__fixtures__/-2.complex.openai/beta__threads__update/input.json +315 -0
- package/__fixtures__/-2.complex.openai/beta__threads__update/output.py +24 -0
- package/__fixtures__/-2.complex.openai/chat__completions__create/input.json +3325 -0
- package/__fixtures__/-2.complex.openai/chat__completions__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/chat__completions__delete/input.json +192 -0
- package/__fixtures__/-2.complex.openai/chat__completions__delete/output.py +22 -0
- package/__fixtures__/-2.complex.openai/chat__completions__list/input.json +1069 -0
- package/__fixtures__/-2.complex.openai/chat__completions__list/output.py +23 -0
- package/__fixtures__/-2.complex.openai/chat__completions__messages__list/input.json +770 -0
- package/__fixtures__/-2.complex.openai/chat__completions__messages__list/output.py +31 -0
- package/__fixtures__/-2.complex.openai/chat__completions__retrieve/input.json +938 -0
- package/__fixtures__/-2.complex.openai/chat__completions__retrieve/output.py +22 -0
- package/__fixtures__/-2.complex.openai/chat__completions__update/input.json +973 -0
- package/__fixtures__/-2.complex.openai/chat__completions__update/output.py +22 -0
- package/__fixtures__/-2.complex.openai/completions__create/input.json +788 -0
- package/__fixtures__/-2.complex.openai/completions__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/containers__create/input.json +671 -0
- package/__fixtures__/-2.complex.openai/containers__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/containers__delete/input.json +142 -0
- package/__fixtures__/-2.complex.openai/containers__delete/output.py +16 -0
- package/__fixtures__/-2.complex.openai/containers__files__content/input.json +154 -0
- package/__fixtures__/-2.complex.openai/containers__files__content/output.py +24 -0
- package/__fixtures__/-2.complex.openai/containers__files__create/input.json +261 -0
- package/__fixtures__/-2.complex.openai/containers__files__create/output.py +24 -0
- package/__fixtures__/-2.complex.openai/containers__files__delete/input.json +154 -0
- package/__fixtures__/-2.complex.openai/containers__files__delete/output.py +24 -0
- package/__fixtures__/-2.complex.openai/containers__files__list/input.json +337 -0
- package/__fixtures__/-2.complex.openai/containers__files__list/output.py +25 -0
- package/__fixtures__/-2.complex.openai/containers__files__retrieve/input.json +235 -0
- package/__fixtures__/-2.complex.openai/containers__files__retrieve/output.py +24 -0
- package/__fixtures__/-2.complex.openai/containers__list/input.json +438 -0
- package/__fixtures__/-2.complex.openai/containers__list/output.py +17 -0
- package/__fixtures__/-2.complex.openai/containers__retrieve/input.json +329 -0
- package/__fixtures__/-2.complex.openai/containers__retrieve/output.py +16 -0
- package/__fixtures__/-2.complex.openai/conversations__create/input.json +6737 -0
- package/__fixtures__/-2.complex.openai/conversations__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/conversations__delete/input.json +186 -0
- package/__fixtures__/-2.complex.openai/conversations__delete/output.py +16 -0
- package/__fixtures__/-2.complex.openai/conversations__items__create/input.json +8352 -0
- package/__fixtures__/-2.complex.openai/conversations__items__create/output.py +25 -0
- package/__fixtures__/-2.complex.openai/conversations__items__delete/input.json +213 -0
- package/__fixtures__/-2.complex.openai/conversations__items__delete/output.py +24 -0
- package/__fixtures__/-2.complex.openai/conversations__items__list/input.json +6695 -0
- package/__fixtures__/-2.complex.openai/conversations__items__list/output.py +25 -0
- package/__fixtures__/-2.complex.openai/conversations__items__retrieve/input.json +6597 -0
- package/__fixtures__/-2.complex.openai/conversations__items__retrieve/output.py +26 -0
- package/__fixtures__/-2.complex.openai/conversations__retrieve/input.json +198 -0
- package/__fixtures__/-2.complex.openai/conversations__retrieve/output.py +16 -0
- package/__fixtures__/-2.complex.openai/conversations__update/input.json +233 -0
- package/__fixtures__/-2.complex.openai/conversations__update/output.py +16 -0
- package/__fixtures__/-2.complex.openai/embeddings__create/input.json +395 -0
- package/__fixtures__/-2.complex.openai/embeddings__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/evals__create/input.json +1424 -0
- package/__fixtures__/-2.complex.openai/evals__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/evals__delete/input.json +232 -0
- package/__fixtures__/-2.complex.openai/evals__delete/output.py +16 -0
- package/__fixtures__/-2.complex.openai/evals__list/input.json +1251 -0
- package/__fixtures__/-2.complex.openai/evals__list/output.py +17 -0
- package/__fixtures__/-2.complex.openai/evals__retrieve/input.json +1127 -0
- package/__fixtures__/-2.complex.openai/evals__retrieve/output.py +16 -0
- package/__fixtures__/-2.complex.openai/evals__runs__cancel/input.json +4445 -0
- package/__fixtures__/-2.complex.openai/evals__runs__cancel/output.py +24 -0
- package/__fixtures__/-2.complex.openai/evals__runs__create/input.json +4526 -0
- package/__fixtures__/-2.complex.openai/evals__runs__create/output.py +24 -0
- package/__fixtures__/-2.complex.openai/evals__runs__delete/input.json +246 -0
- package/__fixtures__/-2.complex.openai/evals__runs__delete/output.py +24 -0
- package/__fixtures__/-2.complex.openai/evals__runs__list/input.json +4579 -0
- package/__fixtures__/-2.complex.openai/evals__runs__list/output.py +25 -0
- package/__fixtures__/-2.complex.openai/evals__runs__output_items__list/input.json +685 -0
- package/__fixtures__/-2.complex.openai/evals__runs__output_items__list/output.py +33 -0
- package/__fixtures__/-2.complex.openai/evals__runs__output_items__retrieve/input.json +560 -0
- package/__fixtures__/-2.complex.openai/evals__runs__output_items__retrieve/output.py +32 -0
- package/__fixtures__/-2.complex.openai/evals__runs__retrieve/input.json +4445 -0
- package/__fixtures__/-2.complex.openai/evals__runs__retrieve/output.py +24 -0
- package/__fixtures__/-2.complex.openai/evals__update/input.json +1160 -0
- package/__fixtures__/-2.complex.openai/evals__update/output.py +18 -0
- package/__fixtures__/-2.complex.openai/files__content/input.json +151 -0
- package/__fixtures__/-2.complex.openai/files__content/output.py +16 -0
- package/__fixtures__/-2.complex.openai/files__create/input.json +379 -0
- package/__fixtures__/-2.complex.openai/files__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/files__delete/input.json +184 -0
- package/__fixtures__/-2.complex.openai/files__delete/output.py +16 -0
- package/__fixtures__/-2.complex.openai/files__list/input.json +397 -0
- package/__fixtures__/-2.complex.openai/files__list/output.py +17 -0
- package/__fixtures__/-2.complex.openai/files__retrieve/input.json +295 -0
- package/__fixtures__/-2.complex.openai/files__retrieve/output.py +16 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__alpha__graders__run__create/input.json +1225 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__alpha__graders__run__create/output.py +34 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__alpha__graders__validate__create/input.json +991 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__alpha__graders__validate__create/output.py +32 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__checkpoints__permissions__create/input.json +297 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__checkpoints__permissions__create/output.py +29 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__checkpoints__permissions__delete/input.json +208 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__checkpoints__permissions__delete/output.py +30 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__checkpoints__permissions__list/input.json +325 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__checkpoints__permissions__list/output.py +31 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__cancel/input.json +1645 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__cancel/output.py +22 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__checkpoints__list/input.json +383 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__checkpoints__list/output.py +31 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__create/input.json +1887 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__list/input.json +1714 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__list/output.py +23 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__list_events/input.json +330 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__list_events/output.py +25 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__pause/input.json +1645 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__pause/output.py +22 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__resume/input.json +1645 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__resume/output.py +22 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__retrieve/input.json +1645 -0
- package/__fixtures__/-2.complex.openai/fine_tuning__jobs__retrieve/output.py +22 -0
- package/__fixtures__/-2.complex.openai/images__edits__create/input.json +744 -0
- package/__fixtures__/-2.complex.openai/images__edits__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/images__generations__create/input.json +789 -0
- package/__fixtures__/-2.complex.openai/images__generations__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/images__variations__create/input.json +550 -0
- package/__fixtures__/-2.complex.openai/images__variations__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/models__delete/input.json +184 -0
- package/__fixtures__/-2.complex.openai/models__delete/output.py +16 -0
- package/__fixtures__/-2.complex.openai/models__list/input.json +221 -0
- package/__fixtures__/-2.complex.openai/models__list/output.py +15 -0
- package/__fixtures__/-2.complex.openai/models__retrieve/input.json +199 -0
- package/__fixtures__/-2.complex.openai/models__retrieve/output.py +16 -0
- package/__fixtures__/-2.complex.openai/moderations__create/input.json +831 -0
- package/__fixtures__/-2.complex.openai/moderations__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/projects__groups__roles__create/input.json +368 -0
- package/__fixtures__/-2.complex.openai/projects__groups__roles__create/output.py +30 -0
- package/__fixtures__/-2.complex.openai/projects__groups__roles__delete/input.json +214 -0
- package/__fixtures__/-2.complex.openai/projects__groups__roles__delete/output.py +32 -0
- package/__fixtures__/-2.complex.openai/projects__groups__roles__list/input.json +402 -0
- package/__fixtures__/-2.complex.openai/projects__groups__roles__list/output.py +33 -0
- package/__fixtures__/-2.complex.openai/projects__roles__create/input.json +289 -0
- package/__fixtures__/-2.complex.openai/projects__roles__create/output.py +24 -0
- package/__fixtures__/-2.complex.openai/projects__roles__delete/input.json +210 -0
- package/__fixtures__/-2.complex.openai/projects__roles__delete/output.py +24 -0
- package/__fixtures__/-2.complex.openai/projects__roles__list/input.json +344 -0
- package/__fixtures__/-2.complex.openai/projects__roles__list/output.py +25 -0
- package/__fixtures__/-2.complex.openai/projects__roles__update/input.json +300 -0
- package/__fixtures__/-2.complex.openai/projects__roles__update/output.py +26 -0
- package/__fixtures__/-2.complex.openai/projects__users__roles__create/input.json +615 -0
- package/__fixtures__/-2.complex.openai/projects__users__roles__create/output.py +30 -0
- package/__fixtures__/-2.complex.openai/projects__users__roles__delete/input.json +214 -0
- package/__fixtures__/-2.complex.openai/projects__users__roles__delete/output.py +32 -0
- package/__fixtures__/-2.complex.openai/projects__users__roles__list/input.json +402 -0
- package/__fixtures__/-2.complex.openai/projects__users__roles__list/output.py +33 -0
- package/__fixtures__/-2.complex.openai/realtime__calls__accept/input.json +1768 -0
- package/__fixtures__/-2.complex.openai/realtime__calls__accept/output.py +24 -0
- package/__fixtures__/-2.complex.openai/realtime__calls__create/input.json +1790 -0
- package/__fixtures__/-2.complex.openai/realtime__calls__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/realtime__calls__hangup/input.json +147 -0
- package/__fixtures__/-2.complex.openai/realtime__calls__hangup/output.py +22 -0
- package/__fixtures__/-2.complex.openai/realtime__calls__refer/input.json +175 -0
- package/__fixtures__/-2.complex.openai/realtime__calls__refer/output.py +22 -0
- package/__fixtures__/-2.complex.openai/realtime__calls__reject/input.json +175 -0
- package/__fixtures__/-2.complex.openai/realtime__calls__reject/output.py +24 -0
- package/__fixtures__/-2.complex.openai/realtime__client_secrets__create/input.json +2407 -0
- package/__fixtures__/-2.complex.openai/realtime__client_secrets__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/realtime__sessions__create/input.json +1400 -0
- package/__fixtures__/-2.complex.openai/realtime__sessions__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/realtime__transcription_sessions__create/input.json +562 -0
- package/__fixtures__/-2.complex.openai/realtime__transcription_sessions__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/realtime__translations__client_secrets__create/input.json +498 -0
- package/__fixtures__/-2.complex.openai/realtime__translations__client_secrets__create/output.py +28 -0
- package/__fixtures__/-2.complex.openai/responses__cancel/input.json +9526 -0
- package/__fixtures__/-2.complex.openai/responses__cancel/output.py +16 -0
- package/__fixtures__/-2.complex.openai/responses__compact__create/input.json +8721 -0
- package/__fixtures__/-2.complex.openai/responses__compact__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/responses__create/input.json +9862 -0
- package/__fixtures__/-2.complex.openai/responses__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/responses__delete/input.json +194 -0
- package/__fixtures__/-2.complex.openai/responses__delete/output.py +16 -0
- package/__fixtures__/-2.complex.openai/responses__input_items__list/input.json +6686 -0
- package/__fixtures__/-2.complex.openai/responses__input_items__list/output.py +25 -0
- package/__fixtures__/-2.complex.openai/responses__input_tokens__count/input.json +7368 -0
- package/__fixtures__/-2.complex.openai/responses__input_tokens__count/output.py +22 -0
- package/__fixtures__/-2.complex.openai/responses__retrieve/input.json +9550 -0
- package/__fixtures__/-2.complex.openai/responses__retrieve/output.py +18 -0
- package/__fixtures__/-2.complex.openai/skills__content/input.json +152 -0
- package/__fixtures__/-2.complex.openai/skills__content/output.py +16 -0
- package/__fixtures__/-2.complex.openai/skills__create/input.json +258 -0
- package/__fixtures__/-2.complex.openai/skills__create/output.py +14 -0
- package/__fixtures__/-2.complex.openai/skills__delete/input.json +186 -0
- package/__fixtures__/-2.complex.openai/skills__delete/output.py +16 -0
- package/__fixtures__/-2.complex.openai/skills__list/input.json +323 -0
- package/__fixtures__/-2.complex.openai/skills__list/output.py +17 -0
- package/__fixtures__/-2.complex.openai/skills__retrieve/input.json +226 -0
- package/__fixtures__/-2.complex.openai/skills__retrieve/output.py +16 -0
- package/__fixtures__/-2.complex.openai/skills__update/input.json +251 -0
- package/__fixtures__/-2.complex.openai/skills__update/output.py +16 -0
- package/__fixtures__/-2.complex.openai/skills__versions__content/input.json +166 -0
- package/__fixtures__/-2.complex.openai/skills__versions__content/output.py +24 -0
- package/__fixtures__/-2.complex.openai/skills__versions__create/input.json +284 -0
- package/__fixtures__/-2.complex.openai/skills__versions__create/output.py +24 -0
- package/__fixtures__/-2.complex.openai/skills__versions__delete/input.json +209 -0
- package/__fixtures__/-2.complex.openai/skills__versions__delete/output.py +24 -0
- package/__fixtures__/-2.complex.openai/skills__versions__list/input.json +341 -0
- package/__fixtures__/-2.complex.openai/skills__versions__list/output.py +25 -0
- package/__fixtures__/-2.complex.openai/skills__versions__retrieve/input.json +240 -0
- package/__fixtures__/-2.complex.openai/skills__versions__retrieve/output.py +24 -0
- package/__fixtures__/-2.complex.openai/uploads__cancel/input.json +407 -0
- package/__fixtures__/-2.complex.openai/uploads__cancel/output.py +16 -0
- package/__fixtures__/-2.complex.openai/uploads__complete/input.json +443 -0
- package/__fixtures__/-2.complex.openai/uploads__complete/output.py +18 -0
- package/__fixtures__/-2.complex.openai/uploads__create/input.json +501 -0
- package/__fixtures__/-2.complex.openai/uploads__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/uploads__parts__create/input.json +229 -0
- package/__fixtures__/-2.complex.openai/uploads__parts__create/output.py +24 -0
- package/__fixtures__/-2.complex.openai/vector_stores__create/input.json +507 -0
- package/__fixtures__/-2.complex.openai/vector_stores__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/vector_stores__delete/input.json +184 -0
- package/__fixtures__/-2.complex.openai/vector_stores__delete/output.py +16 -0
- package/__fixtures__/-2.complex.openai/vector_stores__file_batches__cancel/input.json +300 -0
- package/__fixtures__/-2.complex.openai/vector_stores__file_batches__cancel/output.py +24 -0
- package/__fixtures__/-2.complex.openai/vector_stores__file_batches__create/input.json +314 -0
- package/__fixtures__/-2.complex.openai/vector_stores__file_batches__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/vector_stores__file_batches__list_files/input.json +571 -0
- package/__fixtures__/-2.complex.openai/vector_stores__file_batches__list_files/output.py +27 -0
- package/__fixtures__/-2.complex.openai/vector_stores__file_batches__retrieve/input.json +302 -0
- package/__fixtures__/-2.complex.openai/vector_stores__file_batches__retrieve/output.py +24 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__content/input.json +249 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__content/output.py +25 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__create/input.json +527 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__create/output.py +24 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__delete/input.json +198 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__delete/output.py +24 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__list/input.json +562 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__list/output.py +25 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__retrieve/input.json +432 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__retrieve/output.py +24 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__update/input.json +455 -0
- package/__fixtures__/-2.complex.openai/vector_stores__files__update/output.py +24 -0
- package/__fixtures__/-2.complex.openai/vector_stores__list/input.json +468 -0
- package/__fixtures__/-2.complex.openai/vector_stores__list/output.py +17 -0
- package/__fixtures__/-2.complex.openai/vector_stores__retrieve/input.json +366 -0
- package/__fixtures__/-2.complex.openai/vector_stores__retrieve/output.py +16 -0
- package/__fixtures__/-2.complex.openai/vector_stores__search/input.json +637 -0
- package/__fixtures__/-2.complex.openai/vector_stores__search/output.py +19 -0
- package/__fixtures__/-2.complex.openai/vector_stores__update/input.json +409 -0
- package/__fixtures__/-2.complex.openai/vector_stores__update/output.py +18 -0
- package/__fixtures__/-2.complex.openai/videos__characters__create/input.json +216 -0
- package/__fixtures__/-2.complex.openai/videos__characters__create/output.py +22 -0
- package/__fixtures__/-2.complex.openai/videos__characters__retrieve/input.json +193 -0
- package/__fixtures__/-2.complex.openai/videos__characters__retrieve/output.py +22 -0
- package/__fixtures__/-2.complex.openai/videos__create/input.json +465 -0
- package/__fixtures__/-2.complex.openai/videos__create/output.py +16 -0
- package/__fixtures__/-2.complex.openai/videos__delete/input.json +190 -0
- package/__fixtures__/-2.complex.openai/videos__delete/output.py +16 -0
- package/__fixtures__/-2.complex.openai/videos__download_content/input.json +181 -0
- package/__fixtures__/-2.complex.openai/videos__download_content/output.py +18 -0
- package/__fixtures__/-2.complex.openai/videos__edits__create/input.json +422 -0
- package/__fixtures__/-2.complex.openai/videos__edits__create/output.py +20 -0
- package/__fixtures__/-2.complex.openai/videos__extensions__create/input.json +446 -0
- package/__fixtures__/-2.complex.openai/videos__extensions__create/output.py +20 -0
- package/__fixtures__/-2.complex.openai/videos__list/input.json +477 -0
- package/__fixtures__/-2.complex.openai/videos__list/output.py +17 -0
- package/__fixtures__/-2.complex.openai/videos__remix/input.json +405 -0
- package/__fixtures__/-2.complex.openai/videos__remix/output.py +16 -0
- package/__fixtures__/-2.complex.openai/videos__retrieve/input.json +380 -0
- package/__fixtures__/-2.complex.openai/videos__retrieve/output.py +16 -0
- package/__fixtures__/1.basic/input.json +249 -0
- package/__fixtures__/1.basic/output/petstore/__init__.py +6 -0
- package/__fixtures__/1.basic/output/petstore/_client.py +21 -0
- package/__fixtures__/1.basic/output/petstore/_pagination.py +42 -0
- package/__fixtures__/1.basic/output/petstore/_transport.py +391 -0
- package/__fixtures__/1.basic/output/petstore/models.py +33 -0
- package/__fixtures__/1.basic/output/petstore/resources.py +25 -0
- package/__fixtures__/1.basic/output/pyproject.toml +12 -0
- package/__fixtures__/1.basic/output/tests/conftest.py +16 -0
- package/__fixtures__/1.basic/output/tests/test_pets.py +36 -0
- package/__fixtures__/1.basic/output/tests/utils.py +28 -0
- package/__fixtures__/2.wire/input.json +351 -0
- package/__fixtures__/2.wire/output/pyproject.toml +12 -0
- package/__fixtures__/2.wire/output/tests/conftest.py +16 -0
- package/__fixtures__/2.wire/output/tests/test_items.py +18 -0
- package/__fixtures__/2.wire/output/tests/test_tokens.py +17 -0
- package/__fixtures__/2.wire/output/tests/test_uploads.py +27 -0
- package/__fixtures__/2.wire/output/tests/utils.py +28 -0
- package/__fixtures__/2.wire/output/wire_service/__init__.py +6 -0
- package/__fixtures__/2.wire/output/wire_service/_client.py +23 -0
- package/__fixtures__/2.wire/output/wire_service/_pagination.py +42 -0
- package/__fixtures__/2.wire/output/wire_service/_transport.py +391 -0
- package/__fixtures__/2.wire/output/wire_service/models.py +44 -0
- package/__fixtures__/2.wire/output/wire_service/resources.py +38 -0
- package/__tests__/docs.test.ts +115 -0
- package/__tests__/e2e/harness.ts +79 -0
- package/__tests__/e2e/openai.test.ts +14 -0
- package/__tests__/e2e/publish.test.ts +19 -0
- package/__tests__/opensdk-python.test.ts +134 -0
- package/__tests__/utils.ts +117 -0
- package/biome.json +25 -0
- package/dist/index.cjs +1274 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +32 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +1246 -0
- package/dist/index.js.map +1 -0
- package/index.ts +1 -0
- package/package.json +30 -0
- package/src/emitter.ts +95 -0
- package/src/example-py.ts +60 -0
- package/src/index.ts +4 -0
- package/src/method.ts +13 -0
- package/src/naming.ts +45 -0
- package/src/project.ts +446 -0
- package/src/publish.ts +22 -0
- package/src/pytype.ts +86 -0
- package/src/runtime.ts +551 -0
- package/src/tests-py.ts +197 -0
- package/src/types.ts +8 -0
- package/tsconfig.json +18 -0
- package/tsup.config.ts +19 -0
- package/vitest.config.ts +8 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1246 @@
|
|
|
1
|
+
// src/emitter.ts
|
|
2
|
+
import { walkMethods } from "@xyd-js/opensdk-core";
|
|
3
|
+
import { generate, planOperation as planOperation3 } from "@xyd-js/opensdk-framework";
|
|
4
|
+
|
|
5
|
+
// src/method.ts
|
|
6
|
+
function pyPageName(plan) {
|
|
7
|
+
return plan.pageName === "CursorPage" || plan.pageName === "Page" ? plan.pageName : null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// src/naming.ts
|
|
11
|
+
function splitWords(input) {
|
|
12
|
+
return input.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").split(/[^a-zA-Z0-9]+/).map((w) => w.trim().toLowerCase()).filter(Boolean);
|
|
13
|
+
}
|
|
14
|
+
function safeIdent(s) {
|
|
15
|
+
return /^[0-9]/.test(s) ? `_${s}` : s;
|
|
16
|
+
}
|
|
17
|
+
function pascalCase(input) {
|
|
18
|
+
const s = splitWords(input).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
19
|
+
return safeIdent(s);
|
|
20
|
+
}
|
|
21
|
+
function snakeCase(input) {
|
|
22
|
+
const s = safeIdent(splitWords(input).join("_"));
|
|
23
|
+
return PY_KEYWORDS.has(s) ? `${s}_` : s;
|
|
24
|
+
}
|
|
25
|
+
function pyModuleName(input) {
|
|
26
|
+
const s = splitWords(input).join("_").replace(/[^a-z0-9_]/g, "");
|
|
27
|
+
return s || "client";
|
|
28
|
+
}
|
|
29
|
+
function screamingSnakeCase(input) {
|
|
30
|
+
return safeIdent(splitWords(input).join("_").toUpperCase().replace(/[^A-Z0-9_]/g, ""));
|
|
31
|
+
}
|
|
32
|
+
var PY_KEYWORDS = /* @__PURE__ */ new Set([
|
|
33
|
+
"and",
|
|
34
|
+
"as",
|
|
35
|
+
"assert",
|
|
36
|
+
"async",
|
|
37
|
+
"await",
|
|
38
|
+
"break",
|
|
39
|
+
"class",
|
|
40
|
+
"continue",
|
|
41
|
+
"def",
|
|
42
|
+
"del",
|
|
43
|
+
"elif",
|
|
44
|
+
"else",
|
|
45
|
+
"except",
|
|
46
|
+
"finally",
|
|
47
|
+
"for",
|
|
48
|
+
"from",
|
|
49
|
+
"global",
|
|
50
|
+
"if",
|
|
51
|
+
"import",
|
|
52
|
+
"in",
|
|
53
|
+
"is",
|
|
54
|
+
"lambda",
|
|
55
|
+
"none",
|
|
56
|
+
"nonlocal",
|
|
57
|
+
"not",
|
|
58
|
+
"or",
|
|
59
|
+
"pass",
|
|
60
|
+
"raise",
|
|
61
|
+
"return",
|
|
62
|
+
"try",
|
|
63
|
+
"while",
|
|
64
|
+
"with",
|
|
65
|
+
"yield"
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
// src/project.ts
|
|
69
|
+
import {
|
|
70
|
+
sdkBehavior
|
|
71
|
+
} from "@xyd-js/opensdk-core";
|
|
72
|
+
import { planOperation } from "@xyd-js/opensdk-framework";
|
|
73
|
+
|
|
74
|
+
// src/pytype.ts
|
|
75
|
+
var PyUses = class {
|
|
76
|
+
constructor() {
|
|
77
|
+
this.typing = /* @__PURE__ */ new Set();
|
|
78
|
+
}
|
|
79
|
+
use(name) {
|
|
80
|
+
this.typing.add(name);
|
|
81
|
+
}
|
|
82
|
+
/** The `from typing import ...` line, or null when nothing is used. */
|
|
83
|
+
typingImport() {
|
|
84
|
+
if (this.typing.size === 0) return null;
|
|
85
|
+
const order = ["Any", "BinaryIO", "Optional", "Union"];
|
|
86
|
+
return `from typing import ${order.filter((n) => this.typing.has(n)).join(", ")}`;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
function pyType(ref, uses) {
|
|
90
|
+
if (!ref) return anyType(uses);
|
|
91
|
+
const base = pyBase(ref, uses);
|
|
92
|
+
return ref.nullable ? optionalize(base, uses) : base;
|
|
93
|
+
}
|
|
94
|
+
function pyBase(ref, uses) {
|
|
95
|
+
switch (ref.kind) {
|
|
96
|
+
case "scalar":
|
|
97
|
+
return pyScalar(ref.scalar, ref.format, uses);
|
|
98
|
+
case "ref":
|
|
99
|
+
return ref.name ? pascalCase(ref.name) : anyType(uses);
|
|
100
|
+
case "array":
|
|
101
|
+
return `list[${pyType(ref.items, uses)}]`;
|
|
102
|
+
case "map":
|
|
103
|
+
return `dict[str, ${pyType(ref.values, uses)}]`;
|
|
104
|
+
default:
|
|
105
|
+
return anyType(uses);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function pyScalar(scalar, format, uses) {
|
|
109
|
+
switch (scalar) {
|
|
110
|
+
case "string":
|
|
111
|
+
if (format === "binary") {
|
|
112
|
+
uses.use("Union");
|
|
113
|
+
uses.use("BinaryIO");
|
|
114
|
+
return "Union[bytes, BinaryIO]";
|
|
115
|
+
}
|
|
116
|
+
return "str";
|
|
117
|
+
case "integer":
|
|
118
|
+
return "int";
|
|
119
|
+
case "number":
|
|
120
|
+
return "float";
|
|
121
|
+
case "boolean":
|
|
122
|
+
return "bool";
|
|
123
|
+
default:
|
|
124
|
+
return anyType(uses);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function anyType(uses) {
|
|
128
|
+
uses.use("Any");
|
|
129
|
+
return "Any";
|
|
130
|
+
}
|
|
131
|
+
function optionalize(type, uses) {
|
|
132
|
+
if (type.startsWith("Optional[")) return type;
|
|
133
|
+
uses.use("Optional");
|
|
134
|
+
return `Optional[${type}]`;
|
|
135
|
+
}
|
|
136
|
+
function isPassthroughType(type) {
|
|
137
|
+
return type === "Any" || type === "str" || type === "int" || type === "float" || type === "bool";
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/project.ts
|
|
141
|
+
function resolvePythonOptions(spec, options) {
|
|
142
|
+
var _a, _b, _c;
|
|
143
|
+
const pkg = options.packageName ?? pyModuleName(spec.info.title);
|
|
144
|
+
return {
|
|
145
|
+
pkg,
|
|
146
|
+
baseURL: options.baseURL ?? ((_a = spec.servers) == null ? void 0 : _a[0]) ?? "",
|
|
147
|
+
envVar: ((_c = (_b = spec.security) == null ? void 0 : _b.find((s) => s.envVar)) == null ? void 0 : _c.envVar) ?? `${screamingSnakeCase(pkg)}_API_KEY`
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function pyproject(pkg, spec) {
|
|
151
|
+
var _a, _b;
|
|
152
|
+
const info = spec.info;
|
|
153
|
+
const lines = [
|
|
154
|
+
"[build-system]",
|
|
155
|
+
'requires = ["setuptools>=61"]',
|
|
156
|
+
'build-backend = "setuptools.build_meta"',
|
|
157
|
+
"",
|
|
158
|
+
"[project]",
|
|
159
|
+
`name = ${JSON.stringify(pkg.replace(/_/g, "-"))}`,
|
|
160
|
+
`version = ${JSON.stringify(info.version || "0.0.0")}`
|
|
161
|
+
];
|
|
162
|
+
if (info.description) lines.push(`description = ${JSON.stringify(info.description)}`);
|
|
163
|
+
lines.push('requires-python = ">=3.9"');
|
|
164
|
+
if ((_a = info.contact) == null ? void 0 : _a.name) lines.push(`authors = [{ name = ${JSON.stringify(info.contact.name)} }]`);
|
|
165
|
+
if ((_b = info.license) == null ? void 0 : _b.identifier) lines.push(`license = { text = ${JSON.stringify(info.license.identifier)} }`);
|
|
166
|
+
const urls = [];
|
|
167
|
+
if (info.homepage) urls.push(`Homepage = ${JSON.stringify(info.homepage)}`);
|
|
168
|
+
if (info.repository) urls.push(`Repository = ${JSON.stringify(info.repository)}`);
|
|
169
|
+
if (urls.length) lines.push("", "[project.urls]", ...urls);
|
|
170
|
+
lines.push("", "[tool.setuptools.packages.find]", `include = [${JSON.stringify(pkg)}]`);
|
|
171
|
+
return `${lines.join("\n")}
|
|
172
|
+
`;
|
|
173
|
+
}
|
|
174
|
+
function modelsPy(spec) {
|
|
175
|
+
const ctx = { uses: new PyUses(), needsField: false };
|
|
176
|
+
const types = spec.types || [];
|
|
177
|
+
const aliasKinds = /* @__PURE__ */ new Set(["alias", "union"]);
|
|
178
|
+
const structsEnums = types.filter((t) => !aliasKinds.has(t.kind));
|
|
179
|
+
const aliases = orderAliases(types.filter((t) => aliasKinds.has(t.kind)));
|
|
180
|
+
const decls = [...structsEnums, ...aliases].map((t) => namedType(t, ctx)).filter(Boolean);
|
|
181
|
+
const lines = [
|
|
182
|
+
"from __future__ import annotations",
|
|
183
|
+
"",
|
|
184
|
+
`from dataclasses import dataclass${ctx.needsField ? ", field" : ""}`,
|
|
185
|
+
"from enum import Enum"
|
|
186
|
+
];
|
|
187
|
+
const typingLine = ctx.uses.typingImport();
|
|
188
|
+
if (typingLine) lines.push(typingLine);
|
|
189
|
+
return `${lines.join("\n")}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
${decls.join("\n\n\n")}
|
|
193
|
+
`;
|
|
194
|
+
}
|
|
195
|
+
function typeRefNames(ref, out) {
|
|
196
|
+
if (!ref) return;
|
|
197
|
+
if (ref.kind === "ref" && ref.name) out.add(ref.name);
|
|
198
|
+
typeRefNames(ref.items, out);
|
|
199
|
+
typeRefNames(ref.values, out);
|
|
200
|
+
}
|
|
201
|
+
function orderAliases(aliases) {
|
|
202
|
+
const byName = new Map(aliases.map((a) => [a.name, a]));
|
|
203
|
+
const ordered = [];
|
|
204
|
+
const done = /* @__PURE__ */ new Set();
|
|
205
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
206
|
+
const visit = (a) => {
|
|
207
|
+
if (done.has(a.name) || visiting.has(a.name)) return;
|
|
208
|
+
visiting.add(a.name);
|
|
209
|
+
const refs = /* @__PURE__ */ new Set();
|
|
210
|
+
if (a.kind === "alias") typeRefNames(a.of, refs);
|
|
211
|
+
for (const r of refs) {
|
|
212
|
+
const dep = byName.get(r);
|
|
213
|
+
if (dep && dep !== a) visit(dep);
|
|
214
|
+
}
|
|
215
|
+
visiting.delete(a.name);
|
|
216
|
+
done.add(a.name);
|
|
217
|
+
ordered.push(a);
|
|
218
|
+
};
|
|
219
|
+
for (const a of aliases) visit(a);
|
|
220
|
+
return ordered;
|
|
221
|
+
}
|
|
222
|
+
function namedType(type, ctx) {
|
|
223
|
+
switch (type.kind) {
|
|
224
|
+
case "enum":
|
|
225
|
+
return enumType(type);
|
|
226
|
+
case "alias":
|
|
227
|
+
return `${pascalCase(type.name)} = ${pyType(type.of, ctx.uses)}`;
|
|
228
|
+
case "union":
|
|
229
|
+
ctx.uses.use("Any");
|
|
230
|
+
return `${pascalCase(type.name)} = Any`;
|
|
231
|
+
default:
|
|
232
|
+
return structType(type, ctx);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function structType(type, ctx) {
|
|
236
|
+
const name = pascalCase(type.name);
|
|
237
|
+
const fields = type.fields || [];
|
|
238
|
+
if (fields.length === 0) return `@dataclass
|
|
239
|
+
class ${name}:
|
|
240
|
+
pass`;
|
|
241
|
+
const required = fields.filter((f) => f.required);
|
|
242
|
+
const optional = fields.filter((f) => !f.required);
|
|
243
|
+
const lines = [...required, ...optional].map((f) => structFieldLine(f, ctx));
|
|
244
|
+
return `@dataclass
|
|
245
|
+
class ${name}:
|
|
246
|
+
${lines.join("\n")}`;
|
|
247
|
+
}
|
|
248
|
+
function structFieldLine(f, ctx) {
|
|
249
|
+
const py = snakeCase(f.name);
|
|
250
|
+
const type = pyType(f.type, ctx.uses);
|
|
251
|
+
const wire = py === f.name ? null : `metadata={"wire": ${JSON.stringify(f.name)}}`;
|
|
252
|
+
if (f.required) {
|
|
253
|
+
if (!wire) return ` ${py}: ${type}`;
|
|
254
|
+
ctx.needsField = true;
|
|
255
|
+
return ` ${py}: ${type} = field(${wire})`;
|
|
256
|
+
}
|
|
257
|
+
const opt = optionalize(type, ctx.uses);
|
|
258
|
+
if (!wire) return ` ${py}: ${opt} = None`;
|
|
259
|
+
ctx.needsField = true;
|
|
260
|
+
return ` ${py}: ${opt} = field(default=None, ${wire})`;
|
|
261
|
+
}
|
|
262
|
+
function enumType(type) {
|
|
263
|
+
const name = pascalCase(type.name);
|
|
264
|
+
const base = type.base === "integer" ? "int" : "str";
|
|
265
|
+
const values = type.values || [];
|
|
266
|
+
if (values.length === 0) return `class ${name}(${base}, Enum):
|
|
267
|
+
pass`;
|
|
268
|
+
const members = values.map((v) => {
|
|
269
|
+
const member = screamingSnakeCase(String(v.name ?? v.value)) || "VALUE";
|
|
270
|
+
const lit = base === "int" ? String(v.value) : JSON.stringify(String(v.value));
|
|
271
|
+
return ` ${member} = ${lit}`;
|
|
272
|
+
});
|
|
273
|
+
return `class ${name}(${base}, Enum):
|
|
274
|
+
${members.join("\n")}`;
|
|
275
|
+
}
|
|
276
|
+
function resourcesPy(spec, types) {
|
|
277
|
+
const ctx = {
|
|
278
|
+
types,
|
|
279
|
+
behavior: sdkBehavior(spec),
|
|
280
|
+
uses: new PyUses(),
|
|
281
|
+
transportImports: /* @__PURE__ */ new Set(),
|
|
282
|
+
pages: /* @__PURE__ */ new Set()
|
|
283
|
+
};
|
|
284
|
+
const classes = [];
|
|
285
|
+
const emit = (resources, parent) => {
|
|
286
|
+
var _a;
|
|
287
|
+
for (const r of resources) {
|
|
288
|
+
const segments = [...parent, r.name];
|
|
289
|
+
classes.push(resourceClass(r, segments, ctx));
|
|
290
|
+
if ((_a = r.resources) == null ? void 0 : _a.length) emit(r.resources, segments);
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
emit(spec.resources || [], []);
|
|
294
|
+
const lines = ["from __future__ import annotations", ""];
|
|
295
|
+
const typingLine = ctx.uses.typingImport();
|
|
296
|
+
if (typingLine) lines.push(typingLine, "");
|
|
297
|
+
if (ctx.pages.size > 0) {
|
|
298
|
+
const pageNames = ["CursorPage", "Page"].filter((n) => ctx.pages.has(n));
|
|
299
|
+
lines.push(`from ._pagination import ${pageNames.join(", ")}`);
|
|
300
|
+
}
|
|
301
|
+
const transportNames = ["Transport", ...["decode", "join_csv"].filter((n) => ctx.transportImports.has(n))];
|
|
302
|
+
lines.push(`from ._transport import ${transportNames.join(", ")}`);
|
|
303
|
+
lines.push("from .models import * # noqa: F401,F403");
|
|
304
|
+
return `${lines.join("\n")}
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
${classes.join("\n\n\n")}
|
|
308
|
+
`;
|
|
309
|
+
}
|
|
310
|
+
function resourceClassName(segments) {
|
|
311
|
+
return `${segments.map((s) => pascalCase(s)).join("")}Resource`;
|
|
312
|
+
}
|
|
313
|
+
function resourceClass(resource, segments, ctx) {
|
|
314
|
+
const cls = resourceClassName(segments);
|
|
315
|
+
const subs = resource.resources || [];
|
|
316
|
+
const ctorLines = [" self._transport = transport"];
|
|
317
|
+
for (const sub of subs)
|
|
318
|
+
ctorLines.push(` self.${snakeCase(sub.name)} = ${resourceClassName([...segments, sub.name])}(transport)`);
|
|
319
|
+
const ctor = ` def __init__(self, transport: Transport) -> None:
|
|
320
|
+
${ctorLines.join("\n")}`;
|
|
321
|
+
const methods = (resource.methods || []).map((m) => methodDef(m, ctx));
|
|
322
|
+
return `class ${cls}:
|
|
323
|
+
${[ctor, ...methods].join("\n\n")}`;
|
|
324
|
+
}
|
|
325
|
+
function methodDef(method, ctx) {
|
|
326
|
+
const plan = planOperation(method, ctx.types);
|
|
327
|
+
const name = snakeCase(method.action);
|
|
328
|
+
const { path: pathParams, query: queryParams, header: headerParams } = plan.paramGroups;
|
|
329
|
+
const rawContentType = plan.binaryContentType;
|
|
330
|
+
const positional = pathParams.map((p) => `${snakeCase(p.name)}: ${pyType(p.type, ctx.uses)}`);
|
|
331
|
+
const kwArgs = [];
|
|
332
|
+
for (const p of [...queryParams, ...headerParams]) kwArgs.push(paramArg(p, ctx));
|
|
333
|
+
const bodyParams = bodyFieldList(method, ctx.types);
|
|
334
|
+
for (const b of bodyParams) {
|
|
335
|
+
const type = pyType(b.type, ctx.uses);
|
|
336
|
+
kwArgs.push(
|
|
337
|
+
b.required ? `${snakeCase(b.name)}: ${type}` : `${snakeCase(b.name)}: ${optionalize(type, ctx.uses)} = None`
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
const params = ["self", ...positional, ...kwArgs.length ? ["*", ...kwArgs] : []].join(", ");
|
|
341
|
+
const httpMethod = method.httpMethod.toUpperCase();
|
|
342
|
+
const callArgs = [JSON.stringify(httpMethod), pathExpr(method.path, pathParams.length > 0)];
|
|
343
|
+
if (queryParams.length) {
|
|
344
|
+
callArgs.push(`query={${queryParams.map((q) => queryEntry(q, ctx)).join(", ")}}`);
|
|
345
|
+
}
|
|
346
|
+
if (bodyParams.length) {
|
|
347
|
+
const entries = bodyParams.map((b) => `${JSON.stringify(b.name)}: ${snakeCase(b.name)}`).join(", ");
|
|
348
|
+
callArgs.push(`body={${entries}}`);
|
|
349
|
+
}
|
|
350
|
+
const headerEntries = headerParams.map((h) => `${JSON.stringify(h.wireName ?? h.name)}: ${snakeCase(h.name)}`);
|
|
351
|
+
if (rawContentType) headerEntries.unshift(`"Accept": ${JSON.stringify(rawContentType)}`);
|
|
352
|
+
if (headerEntries.length) callArgs.push(`headers={${headerEntries.join(", ")}}`);
|
|
353
|
+
let encoding = plan.encoding ?? "json";
|
|
354
|
+
if (bodyParams.length && encoding === "json" && bodyParams.some((b) => isBinaryTypeRef(b.type, ctx.types))) {
|
|
355
|
+
encoding = "multipart";
|
|
356
|
+
}
|
|
357
|
+
if (bodyParams.length && encoding !== "json") callArgs.push(`encoding=${JSON.stringify(encoding)}`);
|
|
358
|
+
if (rawContentType) callArgs.push("raw=True");
|
|
359
|
+
if (plan.injectIdempotencyKey && ctx.behavior.idempotency.autoGenerateForPost) {
|
|
360
|
+
callArgs.push("idempotency=True");
|
|
361
|
+
}
|
|
362
|
+
const call = `self._transport.request(${callArgs.join(", ")})`;
|
|
363
|
+
const { annotation, body } = returnPlan(plan, call, ctx);
|
|
364
|
+
const guards = pathParamGuards(pathParams);
|
|
365
|
+
const fullBody = guards ? `${guards}
|
|
366
|
+
${body}` : body;
|
|
367
|
+
return ` def ${name}(${params}) -> ${annotation}:
|
|
368
|
+
${fullBody}`;
|
|
369
|
+
}
|
|
370
|
+
function pathParamGuards(pathParams) {
|
|
371
|
+
var _a;
|
|
372
|
+
const lines = [];
|
|
373
|
+
for (const p of pathParams) {
|
|
374
|
+
if (((_a = p.type) == null ? void 0 : _a.kind) !== "scalar" || p.type.scalar !== "string" || p.required === false) continue;
|
|
375
|
+
const n = snakeCase(p.name);
|
|
376
|
+
lines.push(` if not ${n}:`);
|
|
377
|
+
lines.push(` raise ValueError(f"Expected a non-empty value for \`${n}\` but received {${n}!r}")`);
|
|
378
|
+
}
|
|
379
|
+
return lines.join("\n");
|
|
380
|
+
}
|
|
381
|
+
function paramArg(p, ctx) {
|
|
382
|
+
const type = pyType(p.type, ctx.uses);
|
|
383
|
+
if (p.required) return `${snakeCase(p.name)}: ${type}`;
|
|
384
|
+
return `${snakeCase(p.name)}: ${optionalize(type, ctx.uses)} = None`;
|
|
385
|
+
}
|
|
386
|
+
function queryEntry(q, ctx) {
|
|
387
|
+
var _a;
|
|
388
|
+
const wire = JSON.stringify(q.wireName ?? q.name);
|
|
389
|
+
const value = snakeCase(q.name);
|
|
390
|
+
if (((_a = q.type) == null ? void 0 : _a.kind) === "array" && q.explode === false) {
|
|
391
|
+
ctx.transportImports.add("join_csv");
|
|
392
|
+
return `${wire}: join_csv(${value})`;
|
|
393
|
+
}
|
|
394
|
+
return `${wire}: ${value}`;
|
|
395
|
+
}
|
|
396
|
+
function returnPlan(plan, call, ctx) {
|
|
397
|
+
var _a;
|
|
398
|
+
const { method } = plan;
|
|
399
|
+
if (plan.binaryContentType) return { annotation: "bytes", body: ` return ${call}` };
|
|
400
|
+
const page = pyPageName(plan);
|
|
401
|
+
if (page) {
|
|
402
|
+
ctx.pages.add(page);
|
|
403
|
+
const item = pyType((_a = method.pagination) == null ? void 0 : _a.itemType, ctx.uses);
|
|
404
|
+
return { annotation: `${page}[${item}]`, body: ` return ${page}.from_response(${item}, ${call})` };
|
|
405
|
+
}
|
|
406
|
+
const primary = method.primaryResponse;
|
|
407
|
+
if (!primary) return { annotation: "None", body: ` ${call}` };
|
|
408
|
+
const type = pyType(primary, ctx.uses);
|
|
409
|
+
if (isPassthroughType(type)) return { annotation: type, body: ` return ${call}` };
|
|
410
|
+
ctx.transportImports.add("decode");
|
|
411
|
+
return { annotation: type, body: ` return decode(${type}, ${call})` };
|
|
412
|
+
}
|
|
413
|
+
function isBinaryTypeRef(ref, types, seen = /* @__PURE__ */ new Set()) {
|
|
414
|
+
if (!ref) return false;
|
|
415
|
+
if (ref.kind === "scalar") return ref.scalar === "string" && ref.format === "binary";
|
|
416
|
+
if (ref.kind === "array") return isBinaryTypeRef(ref.items, types, seen);
|
|
417
|
+
if (ref.kind === "ref" && ref.name) {
|
|
418
|
+
if (seen.has(ref.name)) return false;
|
|
419
|
+
seen.add(ref.name);
|
|
420
|
+
const named = types.get(ref.name);
|
|
421
|
+
if (!named) return false;
|
|
422
|
+
if (named.kind === "union") {
|
|
423
|
+
return (named.variants || []).some((v) => isBinaryTypeRef(v, types, seen));
|
|
424
|
+
}
|
|
425
|
+
if (named.kind === "alias") return isBinaryTypeRef(named.of, types, seen);
|
|
426
|
+
}
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
function bodyFieldList(method, types) {
|
|
430
|
+
var _a;
|
|
431
|
+
const ref = (_a = method.requestBody) == null ? void 0 : _a.type;
|
|
432
|
+
if ((ref == null ? void 0 : ref.kind) !== "ref" || !ref.name) return [];
|
|
433
|
+
const named = types.get(ref.name);
|
|
434
|
+
return ((named == null ? void 0 : named.fields) || []).map((f) => ({ name: f.name, type: f.type, required: f.required === true }));
|
|
435
|
+
}
|
|
436
|
+
function pathExpr(path, hasParams) {
|
|
437
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
438
|
+
if (!hasParams) return JSON.stringify(p);
|
|
439
|
+
const fstr = p.replace(/\{([^}]+)\}/g, (_, name) => `{${snakeCase(name)}}`);
|
|
440
|
+
return `f${JSON.stringify(fstr)}`;
|
|
441
|
+
}
|
|
442
|
+
function clientPy(spec, envVar) {
|
|
443
|
+
const resources = spec.resources || [];
|
|
444
|
+
const attrLines = resources.map(
|
|
445
|
+
(r) => ` self.${snakeCase(r.name)} = ${resourceClassName([r.name])}(self._transport)`
|
|
446
|
+
);
|
|
447
|
+
const imports = resources.map((r) => resourceClassName([r.name])).join(", ");
|
|
448
|
+
return `from __future__ import annotations
|
|
449
|
+
|
|
450
|
+
import os
|
|
451
|
+
from typing import Optional
|
|
452
|
+
|
|
453
|
+
from ._transport import Transport
|
|
454
|
+
from .resources import ${imports}
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
class Client:
|
|
458
|
+
def __init__(
|
|
459
|
+
self,
|
|
460
|
+
api_key: Optional[str] = None,
|
|
461
|
+
base_url: Optional[str] = None,
|
|
462
|
+
timeout: Optional[float] = None,
|
|
463
|
+
) -> None:
|
|
464
|
+
key = api_key if api_key is not None else os.environ.get(${JSON.stringify(envVar)})
|
|
465
|
+
self._transport = Transport(base_url=base_url, api_key=key, timeout=timeout)
|
|
466
|
+
${attrLines.join("\n")}
|
|
467
|
+
`;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// src/runtime.ts
|
|
471
|
+
import { sdkBehavior as sdkBehavior2 } from "@xyd-js/opensdk-core";
|
|
472
|
+
function pyStr(value) {
|
|
473
|
+
return JSON.stringify(value);
|
|
474
|
+
}
|
|
475
|
+
function pyBool(value) {
|
|
476
|
+
return value ? "True" : "False";
|
|
477
|
+
}
|
|
478
|
+
function pyFloat(value) {
|
|
479
|
+
return Number.isInteger(value) ? `${value}.0` : String(value);
|
|
480
|
+
}
|
|
481
|
+
function pyFrozenset(items) {
|
|
482
|
+
return items.length ? `frozenset({${items.join(", ")}})` : "frozenset()";
|
|
483
|
+
}
|
|
484
|
+
function pyStrDict(record) {
|
|
485
|
+
const entries = Object.entries(record).map(([key, value]) => `${pyStr(key)}: ${pyStr(value)}`);
|
|
486
|
+
return `{${entries.join(", ")}}`;
|
|
487
|
+
}
|
|
488
|
+
function errorClassName(kind) {
|
|
489
|
+
if (kind === "API") return "APIError";
|
|
490
|
+
return kind.endsWith("Error") ? kind : `${kind}Error`;
|
|
491
|
+
}
|
|
492
|
+
function errorClassNames(spec) {
|
|
493
|
+
const behavior = sdkBehavior2(spec);
|
|
494
|
+
const names = /* @__PURE__ */ new Set();
|
|
495
|
+
for (const kind of Object.values(behavior.errors.statusCodeMap)) names.add(errorClassName(kind));
|
|
496
|
+
names.add(errorClassName(behavior.errors.serverErrorKind));
|
|
497
|
+
names.add(errorClassName(behavior.errors.clientErrorKind));
|
|
498
|
+
names.delete("APIError");
|
|
499
|
+
return [...names].sort();
|
|
500
|
+
}
|
|
501
|
+
function errorClassesBlock(behavior) {
|
|
502
|
+
const mapped = Object.entries(behavior.errors.statusCodeMap).map(([status, kind]) => [Number(status), kind]).sort((a, b) => a[0] - b[0]);
|
|
503
|
+
const byClass = /* @__PURE__ */ new Map();
|
|
504
|
+
for (const [status, kind] of mapped) {
|
|
505
|
+
const cls = errorClassName(kind);
|
|
506
|
+
if (cls === "APIError") continue;
|
|
507
|
+
const entry = byClass.get(cls) || { kind, statuses: [] };
|
|
508
|
+
entry.statuses.push(status);
|
|
509
|
+
byClass.set(cls, entry);
|
|
510
|
+
}
|
|
511
|
+
const serverClass = errorClassName(behavior.errors.serverErrorKind);
|
|
512
|
+
const clientClass = errorClassName(behavior.errors.clientErrorKind);
|
|
513
|
+
const errorClass = (cls, kind, doc) => `class ${cls}(APIError):
|
|
514
|
+
"""${doc}"""
|
|
515
|
+
|
|
516
|
+
kind = ${pyStr(kind)}`;
|
|
517
|
+
const classes = [];
|
|
518
|
+
for (const [cls, { kind, statuses }] of byClass) {
|
|
519
|
+
classes.push(errorClass(cls, kind, `The mapped error kind for HTTP ${statuses.join("/")} responses.`));
|
|
520
|
+
}
|
|
521
|
+
if (serverClass !== "APIError" && !byClass.has(serverClass)) {
|
|
522
|
+
classes.push(errorClass(serverClass, behavior.errors.serverErrorKind, "Catch-all for unmapped 5xx responses."));
|
|
523
|
+
}
|
|
524
|
+
if (clientClass !== "APIError" && !byClass.has(clientClass) && clientClass !== serverClass) {
|
|
525
|
+
classes.push(
|
|
526
|
+
errorClass(clientClass, behavior.errors.clientErrorKind, "Catch-all for unmapped non-5xx error responses.")
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
const tableEntries = mapped.map(([status, kind]) => ` ${status}: ${errorClassName(kind)},`);
|
|
530
|
+
const table = tableEntries.length ? `_STATUS_TO_ERROR: dict[int, type] = {
|
|
531
|
+
${tableEntries.join("\n")}
|
|
532
|
+
}` : "_STATUS_TO_ERROR: dict[int, type] = {}";
|
|
533
|
+
return `${classes.join("\n\n\n")}
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
${table}
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
def _error_for_status(status_code: int, headers: dict[str, str], body: bytes) -> APIError:
|
|
540
|
+
"""The policy-mapped exception: exact status map first, then the 5xx catch-all, then the client catch-all."""
|
|
541
|
+
cls = _STATUS_TO_ERROR.get(status_code)
|
|
542
|
+
if cls is None:
|
|
543
|
+
cls = ${serverClass} if status_code >= 500 else ${clientClass}
|
|
544
|
+
return cls(status_code, headers, body)`;
|
|
545
|
+
}
|
|
546
|
+
function transportPy(spec, pkg, baseURL) {
|
|
547
|
+
var _a;
|
|
548
|
+
const behavior = sdkBehavior2(spec);
|
|
549
|
+
const security = (_a = spec.security) == null ? void 0 : _a[0];
|
|
550
|
+
let authLine = "";
|
|
551
|
+
if (security) {
|
|
552
|
+
const name = security.name || "";
|
|
553
|
+
switch (security.kind) {
|
|
554
|
+
case "apiKey-header":
|
|
555
|
+
authLine = ` request_headers[${JSON.stringify(name)}] = self.api_key
|
|
556
|
+
`;
|
|
557
|
+
break;
|
|
558
|
+
case "apiKey-query":
|
|
559
|
+
authLine = ` params[${JSON.stringify(name)}] = self.api_key
|
|
560
|
+
`;
|
|
561
|
+
break;
|
|
562
|
+
default:
|
|
563
|
+
authLine = ` request_headers["Authorization"] = "Bearer " + self.api_key
|
|
564
|
+
`;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
const authBlock = authLine ? ` if self.api_key:
|
|
568
|
+
${authLine}` : "";
|
|
569
|
+
const userAgent = behavior.userAgent.sdkIdentifierTemplate.replace(/\{package\}/g, pkg).replace(/\{language\}/g, "python").replace(/\{version\}/g, spec.info.version || "0.0.0");
|
|
570
|
+
const timeoutMs = behavior.timeout.defaultTimeoutMs;
|
|
571
|
+
const defaultTimeout = timeoutMs > 0 ? pyFloat(timeoutMs / 1e3) : "None";
|
|
572
|
+
const timeoutEnvVar = behavior.timeout.timeoutEnvVar;
|
|
573
|
+
const retry = behavior.retry;
|
|
574
|
+
const errorDocUrlTemplate = behavior.errors.errorDocUrlTemplate;
|
|
575
|
+
const includeRuntimeVersion = behavior.userAgent.includeRuntimeVersion;
|
|
576
|
+
const constants = [
|
|
577
|
+
`DEFAULT_BASE_URL = ${pyStr(baseURL)}`,
|
|
578
|
+
`USER_AGENT = ${pyStr(userAgent)}`,
|
|
579
|
+
`AI_AGENT_ENV_VARS = ${pyStrDict(behavior.userAgent.aiAgentEnvVars)}`,
|
|
580
|
+
`DEFAULT_TIMEOUT: Optional[float] = ${defaultTimeout}`,
|
|
581
|
+
...timeoutEnvVar ? [`TIMEOUT_ENV_VAR = ${pyStr(timeoutEnvVar)}`] : [],
|
|
582
|
+
`MAX_RETRIES = ${retry.maxRetries}`,
|
|
583
|
+
`RETRYABLE_STATUS_CODES = ${pyFrozenset(retry.retryableStatusCodes.map(String))}`,
|
|
584
|
+
`RETRY_CONNECTION_ERRORS = ${pyBool(retry.retryConnectionErrors)}`,
|
|
585
|
+
`HONOR_RETRY_AFTER_HEADER = ${pyBool(retry.honorRetryAfterHeader)}`,
|
|
586
|
+
`BACKOFF_INITIAL_DELAY = ${pyFloat(retry.backoff.initialDelayMs / 1e3)}`,
|
|
587
|
+
`BACKOFF_MAX_DELAY = ${pyFloat(retry.backoff.maxDelayMs / 1e3)}`,
|
|
588
|
+
`BACKOFF_MULTIPLIER = ${pyFloat(retry.backoff.multiplier)}`,
|
|
589
|
+
`BACKOFF_JITTER = ${pyFloat(retry.backoff.jitter)}`,
|
|
590
|
+
`REQUEST_ID_HEADER = ${pyStr(behavior.telemetry.requestIdHeader)}`,
|
|
591
|
+
`IDEMPOTENCY_HEADER = ${pyStr(behavior.idempotency.headerName)}`,
|
|
592
|
+
...errorDocUrlTemplate ? [`ERROR_DOC_URL_TEMPLATE = ${pyStr(errorDocUrlTemplate)}`] : [],
|
|
593
|
+
`GUARDED_OPTION_KEYS = ${pyFrozenset(behavior.requestGuard.optionKeys.map(pyStr))}`
|
|
594
|
+
].join("\n");
|
|
595
|
+
const errorDocStr = errorDocUrlTemplate ? `
|
|
596
|
+
|
|
597
|
+
def __str__(self) -> str:
|
|
598
|
+
url = ERROR_DOC_URL_TEMPLATE.replace("{kind}", self.kind).replace("{status}", str(self.status_code))
|
|
599
|
+
return self.message + " (" + url + ")"` : "";
|
|
600
|
+
const runtimeVersionLine = includeRuntimeVersion ? '\n ua += " python/" + platform.python_version()' : "";
|
|
601
|
+
return `from __future__ import annotations
|
|
602
|
+
|
|
603
|
+
import dataclasses
|
|
604
|
+
import datetime
|
|
605
|
+
import email.utils
|
|
606
|
+
import json
|
|
607
|
+
import os${includeRuntimeVersion ? "\nimport platform" : ""}
|
|
608
|
+
import random
|
|
609
|
+
import time
|
|
610
|
+
import typing
|
|
611
|
+
import urllib.error
|
|
612
|
+
import urllib.parse
|
|
613
|
+
import urllib.request
|
|
614
|
+
import uuid
|
|
615
|
+
from enum import Enum
|
|
616
|
+
from typing import Any, Optional
|
|
617
|
+
|
|
618
|
+
${constants}
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
class APIError(Exception):
|
|
622
|
+
"""A non-2xx API response: status code, headers, raw body, request id and a best-effort message."""
|
|
623
|
+
|
|
624
|
+
kind = "API"
|
|
625
|
+
|
|
626
|
+
def __init__(self, status_code: int, headers: dict[str, str], body: bytes) -> None:
|
|
627
|
+
self.status_code = status_code
|
|
628
|
+
self.headers = headers
|
|
629
|
+
self.body = body
|
|
630
|
+
self.request_id = _header(headers, REQUEST_ID_HEADER)
|
|
631
|
+
self.message = _error_message(body) or "HTTP " + str(status_code)
|
|
632
|
+
super().__init__(self.message)${errorDocStr}
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
${errorClassesBlock(behavior)}
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
def _error_message(body: bytes) -> Optional[str]:
|
|
639
|
+
"""Best-effort message from a JSON error envelope ({"error": {"message": ...}} etc.)."""
|
|
640
|
+
try:
|
|
641
|
+
payload = json.loads(body.decode("utf-8"))
|
|
642
|
+
except Exception:
|
|
643
|
+
return None
|
|
644
|
+
if not isinstance(payload, dict):
|
|
645
|
+
return None
|
|
646
|
+
error = payload.get("error")
|
|
647
|
+
if isinstance(error, dict) and isinstance(error.get("message"), str):
|
|
648
|
+
return error["message"]
|
|
649
|
+
if isinstance(error, str):
|
|
650
|
+
return error
|
|
651
|
+
for key in ("message", "detail"):
|
|
652
|
+
if isinstance(payload.get(key), str):
|
|
653
|
+
return payload[key]
|
|
654
|
+
return None
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
def _header(headers: dict[str, str], name: str) -> Optional[str]:
|
|
658
|
+
"""Case-insensitive header lookup."""
|
|
659
|
+
target = name.lower()
|
|
660
|
+
for key, value in headers.items():
|
|
661
|
+
if key.lower() == target:
|
|
662
|
+
return value
|
|
663
|
+
return None
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
def _user_agent() -> str:
|
|
667
|
+
"""The policy User-Agent: SDK identifier, plus an AI-agent slug when a known agent env var is set."""
|
|
668
|
+
ua = USER_AGENT${runtimeVersionLine}
|
|
669
|
+
for env_var, slug in AI_AGENT_ENV_VARS.items():
|
|
670
|
+
if os.environ.get(env_var):
|
|
671
|
+
ua += " agent/" + slug
|
|
672
|
+
break
|
|
673
|
+
return ua
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
def _default_timeout() -> Optional[float]:
|
|
677
|
+
${timeoutEnvVar ? ` """The policy default timeout in seconds; TIMEOUT_ENV_VAR (milliseconds) overrides it when set."""
|
|
678
|
+
raw = os.environ.get(TIMEOUT_ENV_VAR)
|
|
679
|
+
if raw:
|
|
680
|
+
try:
|
|
681
|
+
return float(raw) / 1000.0
|
|
682
|
+
except ValueError:
|
|
683
|
+
pass
|
|
684
|
+
return DEFAULT_TIMEOUT` : ` """The policy default timeout in seconds (None = no deadline)."""
|
|
685
|
+
return DEFAULT_TIMEOUT`}
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
def _retry_delay(attempt: int, headers: Optional[dict[str, str]]) -> float:
|
|
689
|
+
"""Seconds to sleep before retry attempt (0-based): a Retry-After header
|
|
690
|
+
wins when honored; otherwise min(initial * multiplier**attempt, max) plus
|
|
691
|
+
proportional random jitter."""
|
|
692
|
+
if HONOR_RETRY_AFTER_HEADER and headers:
|
|
693
|
+
retry_after = _retry_after_seconds(headers)
|
|
694
|
+
if retry_after is not None:
|
|
695
|
+
return retry_after
|
|
696
|
+
delay = min(BACKOFF_INITIAL_DELAY * (BACKOFF_MULTIPLIER ** attempt), BACKOFF_MAX_DELAY)
|
|
697
|
+
return delay + delay * BACKOFF_JITTER * random.random()
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
def _retry_after_seconds(headers: dict[str, str]) -> Optional[float]:
|
|
701
|
+
"""A Retry-After header as seconds: both the integer-seconds and the HTTP-date forms."""
|
|
702
|
+
value = _header(headers, "Retry-After")
|
|
703
|
+
if value is None:
|
|
704
|
+
return None
|
|
705
|
+
value = value.strip()
|
|
706
|
+
if value.isdigit():
|
|
707
|
+
return float(value)
|
|
708
|
+
try:
|
|
709
|
+
parsed = email.utils.parsedate_to_datetime(value)
|
|
710
|
+
except (TypeError, ValueError):
|
|
711
|
+
return None
|
|
712
|
+
if parsed is None:
|
|
713
|
+
return None
|
|
714
|
+
if parsed.tzinfo is None:
|
|
715
|
+
parsed = parsed.replace(tzinfo=datetime.timezone.utc)
|
|
716
|
+
return max(0.0, (parsed - datetime.datetime.now(datetime.timezone.utc)).total_seconds())
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def _guard_options(params: Optional[dict[str, Any]]) -> None:
|
|
720
|
+
"""Fail fast when a request-option key (api_key, max_retries, ...) is
|
|
721
|
+
misplaced into request params \u2014 a misplaced credential would otherwise be
|
|
722
|
+
sent on the wire and end up in provider logs."""
|
|
723
|
+
for key in params or ():
|
|
724
|
+
if key in GUARDED_OPTION_KEYS:
|
|
725
|
+
raise ValueError(
|
|
726
|
+
"request option " + repr(key) + " must be set on the client, not passed as a request parameter"
|
|
727
|
+
)
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
def encode(value: Any) -> Any:
|
|
731
|
+
"""Wire-encode a request value: dataclasses -> dicts keyed by wire name
|
|
732
|
+
(None fields dropped), enums -> their values; lists/dicts recurse."""
|
|
733
|
+
if isinstance(value, Enum):
|
|
734
|
+
return encode(value.value)
|
|
735
|
+
if dataclasses.is_dataclass(value) and not isinstance(value, type):
|
|
736
|
+
out: dict[str, Any] = {}
|
|
737
|
+
for f in dataclasses.fields(value):
|
|
738
|
+
item = getattr(value, f.name)
|
|
739
|
+
if item is None:
|
|
740
|
+
continue
|
|
741
|
+
out[f.metadata.get("wire", f.name)] = encode(item)
|
|
742
|
+
return out
|
|
743
|
+
if isinstance(value, (list, tuple)):
|
|
744
|
+
return [encode(item) for item in value]
|
|
745
|
+
if isinstance(value, dict):
|
|
746
|
+
return {key: encode(item) for key, item in value.items()}
|
|
747
|
+
return value
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
def decode(tp: Any, value: Any) -> Any:
|
|
751
|
+
"""Best-effort decode of parsed JSON into the generated models: dataclasses
|
|
752
|
+
are built field-by-field (honoring wire names), enums by value; unknown
|
|
753
|
+
shapes are returned as-is."""
|
|
754
|
+
if value is None or tp is None or tp is Any:
|
|
755
|
+
return value
|
|
756
|
+
origin = typing.get_origin(tp)
|
|
757
|
+
if origin is not None:
|
|
758
|
+
args = typing.get_args(tp)
|
|
759
|
+
if origin is list and isinstance(value, list):
|
|
760
|
+
item_tp = args[0] if args else Any
|
|
761
|
+
return [decode(item_tp, item) for item in value]
|
|
762
|
+
if origin is dict and isinstance(value, dict):
|
|
763
|
+
value_tp = args[1] if len(args) > 1 else Any
|
|
764
|
+
return {key: decode(value_tp, item) for key, item in value.items()}
|
|
765
|
+
if origin is typing.Union:
|
|
766
|
+
for arg in args:
|
|
767
|
+
if arg is type(None):
|
|
768
|
+
continue
|
|
769
|
+
try:
|
|
770
|
+
decoded = decode(arg, value)
|
|
771
|
+
except Exception:
|
|
772
|
+
continue
|
|
773
|
+
if decoded is not value:
|
|
774
|
+
return decoded
|
|
775
|
+
return value
|
|
776
|
+
return value
|
|
777
|
+
if isinstance(tp, type) and issubclass(tp, Enum):
|
|
778
|
+
try:
|
|
779
|
+
return tp(value)
|
|
780
|
+
except ValueError:
|
|
781
|
+
return value
|
|
782
|
+
if isinstance(tp, type) and dataclasses.is_dataclass(tp) and isinstance(value, dict):
|
|
783
|
+
try:
|
|
784
|
+
hints = typing.get_type_hints(tp)
|
|
785
|
+
except Exception:
|
|
786
|
+
hints = {}
|
|
787
|
+
kwargs: dict[str, Any] = {}
|
|
788
|
+
for f in dataclasses.fields(tp):
|
|
789
|
+
wire = f.metadata.get("wire", f.name)
|
|
790
|
+
if wire in value:
|
|
791
|
+
kwargs[f.name] = decode(hints.get(f.name, Any), value[wire])
|
|
792
|
+
elif f.default is dataclasses.MISSING and f.default_factory is dataclasses.MISSING:
|
|
793
|
+
kwargs[f.name] = None
|
|
794
|
+
return tp(**kwargs)
|
|
795
|
+
return value
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
def join_csv(value: Optional[list]) -> Optional[str]:
|
|
799
|
+
"""Serialize an explode=false array parameter as one comma-joined value."""
|
|
800
|
+
if value is None:
|
|
801
|
+
return None
|
|
802
|
+
return ",".join(_text(encode(item)) for item in value)
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
def _text(value: Any) -> str:
|
|
806
|
+
if isinstance(value, bool):
|
|
807
|
+
return "true" if value else "false"
|
|
808
|
+
if isinstance(value, (dict, list)):
|
|
809
|
+
return json.dumps(value)
|
|
810
|
+
return str(value)
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
def _query_value(value: Any) -> Any:
|
|
814
|
+
encoded = encode(value)
|
|
815
|
+
if isinstance(encoded, list):
|
|
816
|
+
return [_text(item) for item in encoded]
|
|
817
|
+
return _text(encoded)
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
def _multipart(payload: dict[str, Any]) -> tuple[bytes, str]:
|
|
821
|
+
"""Encode a multipart/form-data body (stdlib-only, manual boundary).
|
|
822
|
+
bytes / file-like values become file parts; lists become repeated parts."""
|
|
823
|
+
boundary = uuid.uuid4().hex
|
|
824
|
+
chunks: list[bytes] = []
|
|
825
|
+
for name, value in payload.items():
|
|
826
|
+
items = value if isinstance(value, list) else [value]
|
|
827
|
+
for item in items:
|
|
828
|
+
chunks.append(("--" + boundary + "\\r\\n").encode("utf-8"))
|
|
829
|
+
if isinstance(item, bytes) or hasattr(item, "read"):
|
|
830
|
+
content = item if isinstance(item, bytes) else item.read()
|
|
831
|
+
if isinstance(content, str):
|
|
832
|
+
content = content.encode("utf-8")
|
|
833
|
+
filename = str(getattr(item, "name", name)).replace("\\\\", "/").split("/")[-1] or name
|
|
834
|
+
disposition = 'Content-Disposition: form-data; name="' + name + '"; filename="' + filename + '"\\r\\n'
|
|
835
|
+
chunks.append(disposition.encode("utf-8"))
|
|
836
|
+
chunks.append(b"Content-Type: application/octet-stream\\r\\n\\r\\n")
|
|
837
|
+
chunks.append(content)
|
|
838
|
+
else:
|
|
839
|
+
chunks.append(('Content-Disposition: form-data; name="' + name + '"\\r\\n\\r\\n').encode("utf-8"))
|
|
840
|
+
chunks.append(_text(item).encode("utf-8"))
|
|
841
|
+
chunks.append(b"\\r\\n")
|
|
842
|
+
chunks.append(("--" + boundary + "--\\r\\n").encode("utf-8"))
|
|
843
|
+
return b"".join(chunks), "multipart/form-data; boundary=" + boundary
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
class Transport:
|
|
847
|
+
def __init__(
|
|
848
|
+
self,
|
|
849
|
+
base_url: Optional[str] = None,
|
|
850
|
+
api_key: Optional[str] = None,
|
|
851
|
+
timeout: Optional[float] = None,
|
|
852
|
+
) -> None:
|
|
853
|
+
self.base_url = (base_url or DEFAULT_BASE_URL).rstrip("/")
|
|
854
|
+
self.api_key = api_key
|
|
855
|
+
self.timeout = timeout if timeout is not None else _default_timeout()
|
|
856
|
+
self.user_agent = _user_agent()
|
|
857
|
+
|
|
858
|
+
def request(
|
|
859
|
+
self,
|
|
860
|
+
method: str,
|
|
861
|
+
path: str,
|
|
862
|
+
query: Optional[dict[str, Any]] = None,
|
|
863
|
+
body: Optional[dict[str, Any]] = None,
|
|
864
|
+
headers: Optional[dict[str, Any]] = None,
|
|
865
|
+
encoding: str = "json",
|
|
866
|
+
raw: bool = False,
|
|
867
|
+
idempotency: bool = False,
|
|
868
|
+
) -> Any:
|
|
869
|
+
_guard_options(query)
|
|
870
|
+
_guard_options(body)
|
|
871
|
+
url = self.base_url + path
|
|
872
|
+
params = {k: _query_value(v) for k, v in (query or {}).items() if v is not None}
|
|
873
|
+
request_headers: dict[str, str] = {k: _text(v) for k, v in (headers or {}).items() if v is not None}
|
|
874
|
+
request_headers.setdefault("User-Agent", self.user_agent)
|
|
875
|
+
data = None
|
|
876
|
+
if body is not None:
|
|
877
|
+
payload = {k: encode(v) for k, v in body.items() if v is not None}
|
|
878
|
+
if encoding == "multipart":
|
|
879
|
+
data, content_type = _multipart(payload)
|
|
880
|
+
request_headers["Content-Type"] = content_type
|
|
881
|
+
elif encoding == "form":
|
|
882
|
+
data = urllib.parse.urlencode(payload, doseq=True).encode("utf-8")
|
|
883
|
+
request_headers["Content-Type"] = "application/x-www-form-urlencoded"
|
|
884
|
+
else:
|
|
885
|
+
data = json.dumps(payload).encode("utf-8")
|
|
886
|
+
request_headers["Content-Type"] = "application/json"
|
|
887
|
+
${authBlock} if idempotency:
|
|
888
|
+
# One key per logical call, generated before the retry loop so every
|
|
889
|
+
# retry of this request carries the SAME idempotency key.
|
|
890
|
+
request_headers.setdefault(IDEMPOTENCY_HEADER, str(uuid.uuid4()))
|
|
891
|
+
if params:
|
|
892
|
+
url += "?" + urllib.parse.urlencode(params, doseq=True)
|
|
893
|
+
attempt = 0
|
|
894
|
+
while True:
|
|
895
|
+
request = urllib.request.Request(url, data=data, method=method, headers=request_headers)
|
|
896
|
+
try:
|
|
897
|
+
with urllib.request.urlopen(request, timeout=self.timeout) as response:
|
|
898
|
+
content = response.read()
|
|
899
|
+
except urllib.error.HTTPError as error:
|
|
900
|
+
error_headers = dict(error.headers.items())
|
|
901
|
+
error_body = error.read()
|
|
902
|
+
if attempt < MAX_RETRIES and error.code in RETRYABLE_STATUS_CODES:
|
|
903
|
+
time.sleep(_retry_delay(attempt, error_headers))
|
|
904
|
+
attempt += 1
|
|
905
|
+
continue
|
|
906
|
+
raise _error_for_status(error.code, error_headers, error_body) from None
|
|
907
|
+
except OSError:
|
|
908
|
+
# Connection/timeout errors (URLError, reset, DNS failure, socket timeout).
|
|
909
|
+
if RETRY_CONNECTION_ERRORS and attempt < MAX_RETRIES:
|
|
910
|
+
time.sleep(_retry_delay(attempt, None))
|
|
911
|
+
attempt += 1
|
|
912
|
+
continue
|
|
913
|
+
raise
|
|
914
|
+
if raw:
|
|
915
|
+
return content
|
|
916
|
+
return json.loads(content.decode("utf-8")) if content else None
|
|
917
|
+
`;
|
|
918
|
+
}
|
|
919
|
+
function paginationPy() {
|
|
920
|
+
return `from __future__ import annotations
|
|
921
|
+
|
|
922
|
+
from dataclasses import dataclass, field
|
|
923
|
+
from typing import Any, Generic, Iterator, TypeVar
|
|
924
|
+
|
|
925
|
+
from ._transport import decode
|
|
926
|
+
|
|
927
|
+
T = TypeVar("T")
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
@dataclass
|
|
931
|
+
class CursorPage(Generic[T]):
|
|
932
|
+
"""One page of a cursor-paginated list: \`data\` plus a \`has_more\` marker."""
|
|
933
|
+
|
|
934
|
+
data: list[T] = field(default_factory=list)
|
|
935
|
+
has_more: bool = False
|
|
936
|
+
|
|
937
|
+
def __iter__(self) -> Iterator[T]:
|
|
938
|
+
return iter(self.data)
|
|
939
|
+
|
|
940
|
+
@classmethod
|
|
941
|
+
def from_response(cls, item_type: Any, raw: Any) -> CursorPage[T]:
|
|
942
|
+
payload = raw if isinstance(raw, dict) else {}
|
|
943
|
+
data = [decode(item_type, item) for item in payload.get("data") or []]
|
|
944
|
+
return cls(data=data, has_more=bool(payload.get("has_more") or False))
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
@dataclass
|
|
948
|
+
class Page(Generic[T]):
|
|
949
|
+
"""One page of a marker-less list: the whole collection in one \`data\` envelope."""
|
|
950
|
+
|
|
951
|
+
data: list[T] = field(default_factory=list)
|
|
952
|
+
|
|
953
|
+
def __iter__(self) -> Iterator[T]:
|
|
954
|
+
return iter(self.data)
|
|
955
|
+
|
|
956
|
+
@classmethod
|
|
957
|
+
def from_response(cls, item_type: Any, raw: Any) -> Page[T]:
|
|
958
|
+
payload = raw if isinstance(raw, dict) else {}
|
|
959
|
+
return cls(data=[decode(item_type, item) for item in payload.get("data") or []])
|
|
960
|
+
`;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// src/tests-py.ts
|
|
964
|
+
import { planMethodExample, planOperation as planOperation2 } from "@xyd-js/opensdk-framework";
|
|
965
|
+
|
|
966
|
+
// src/example-py.ts
|
|
967
|
+
function renderPyExample(value) {
|
|
968
|
+
switch (value.kind) {
|
|
969
|
+
case "string":
|
|
970
|
+
return pyStr2(value.value);
|
|
971
|
+
case "integer":
|
|
972
|
+
return String(value.value);
|
|
973
|
+
case "number":
|
|
974
|
+
return String(value.value);
|
|
975
|
+
case "boolean":
|
|
976
|
+
return value.value ? "True" : "False";
|
|
977
|
+
case "null":
|
|
978
|
+
return "None";
|
|
979
|
+
case "binary":
|
|
980
|
+
return 'b"Example data"';
|
|
981
|
+
case "enum":
|
|
982
|
+
return pyLiteral(value.value);
|
|
983
|
+
case "const":
|
|
984
|
+
return pyLiteral(value.value);
|
|
985
|
+
case "array":
|
|
986
|
+
return `[${renderPyExample(value.item)}]`;
|
|
987
|
+
case "map":
|
|
988
|
+
return `{"key": ${renderPyExample(value.value)}}`;
|
|
989
|
+
case "object":
|
|
990
|
+
return value.fields.length === 0 ? "{}" : `{${value.fields.map((f) => `${pyStr2(f.name)}: ${renderPyExample(f.value)}`).join(", ")}}`;
|
|
991
|
+
case "union":
|
|
992
|
+
return renderPyExample(value.variant);
|
|
993
|
+
default:
|
|
994
|
+
return "None";
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
function pyLiteral(v) {
|
|
998
|
+
if (v === null || v === void 0) return "None";
|
|
999
|
+
if (typeof v === "boolean") return v ? "True" : "False";
|
|
1000
|
+
if (typeof v === "number") return String(v);
|
|
1001
|
+
return pyStr2(String(v));
|
|
1002
|
+
}
|
|
1003
|
+
function pyStr2(s) {
|
|
1004
|
+
return JSON.stringify(s);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// src/tests-py.ts
|
|
1008
|
+
var DEFAULT_BASE_URL = "http://127.0.0.1:4010";
|
|
1009
|
+
function testUtilsPy() {
|
|
1010
|
+
return `from __future__ import annotations
|
|
1011
|
+
|
|
1012
|
+
import typing
|
|
1013
|
+
from typing import Any
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
def assert_matches_type(expected_type: Any, value: Any, *, path: Any = None) -> None:
|
|
1017
|
+
"""Pragmatic structural check for the generated test suite.
|
|
1018
|
+
|
|
1019
|
+
Verifies the SHAPE of a response without being strict about deep generics:
|
|
1020
|
+
dataclass instances, the vendored pagination containers, primitives, lists
|
|
1021
|
+
and dicts are all accepted. A parameterized generic (e.g. CursorPage[Pet],
|
|
1022
|
+
list[str]) is matched against its ORIGIN only; Any / object / typing
|
|
1023
|
+
constructs (Optional, Union, ...) always match.
|
|
1024
|
+
"""
|
|
1025
|
+
origin = typing.get_origin(expected_type)
|
|
1026
|
+
if origin is not None:
|
|
1027
|
+
expected_type = origin
|
|
1028
|
+
if expected_type is Any or expected_type is object or expected_type is None:
|
|
1029
|
+
return
|
|
1030
|
+
if not isinstance(expected_type, type):
|
|
1031
|
+
return
|
|
1032
|
+
assert isinstance(value, expected_type), (
|
|
1033
|
+
f"expected {getattr(expected_type, '__name__', expected_type)!r}, "
|
|
1034
|
+
f"got {type(value).__name__!r} (path={path})"
|
|
1035
|
+
)
|
|
1036
|
+
`;
|
|
1037
|
+
}
|
|
1038
|
+
function testConftestPy(pkg) {
|
|
1039
|
+
return `from __future__ import annotations
|
|
1040
|
+
|
|
1041
|
+
import os
|
|
1042
|
+
|
|
1043
|
+
import pytest
|
|
1044
|
+
|
|
1045
|
+
from ${pkg} import Client
|
|
1046
|
+
|
|
1047
|
+
base_url = os.environ.get("TEST_API_BASE_URL", ${JSON.stringify(DEFAULT_BASE_URL)})
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
@pytest.fixture
|
|
1051
|
+
def client() -> Client:
|
|
1052
|
+
return Client(api_key="My API Key", base_url=base_url)
|
|
1053
|
+
`;
|
|
1054
|
+
}
|
|
1055
|
+
function collectMethods(resource, chain, namePrefix, out) {
|
|
1056
|
+
for (const method of resource.methods || []) out.push({ method, chain, namePrefix });
|
|
1057
|
+
for (const sub of resource.resources || []) {
|
|
1058
|
+
const attr = snakeCase(sub.name);
|
|
1059
|
+
collectMethods(sub, [...chain, attr], `${namePrefix}${attr}_`, out);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
function firstStringPathParam(method) {
|
|
1063
|
+
var _a;
|
|
1064
|
+
for (const p of method.pathParams || []) {
|
|
1065
|
+
if (((_a = p.type) == null ? void 0 : _a.kind) === "scalar" && p.type.scalar === "string" && p.required !== false) return p;
|
|
1066
|
+
}
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
1069
|
+
function responseTypeExpr(method, types, uses, pages) {
|
|
1070
|
+
var _a;
|
|
1071
|
+
const plan = planOperation2(method, types);
|
|
1072
|
+
if (plan.binaryContentType) return "bytes";
|
|
1073
|
+
const page = pyPageName(plan);
|
|
1074
|
+
if (page) {
|
|
1075
|
+
pages.add(page);
|
|
1076
|
+
return `${page}[${pyType((_a = method.pagination) == null ? void 0 : _a.itemType, uses)}]`;
|
|
1077
|
+
}
|
|
1078
|
+
const primary = method.primaryResponse;
|
|
1079
|
+
if (!primary) return null;
|
|
1080
|
+
return pyType(primary, uses);
|
|
1081
|
+
}
|
|
1082
|
+
function renderCallArgs(ex) {
|
|
1083
|
+
const parts = ex.pathArgs.map((pa) => renderPyExample(pa.value));
|
|
1084
|
+
for (const f of ex.fields) parts.push(`${snakeCase(f.name)}=${renderPyExample(f.value)}`);
|
|
1085
|
+
return parts.join(", ");
|
|
1086
|
+
}
|
|
1087
|
+
function renderMethodTest(name, call, responseType) {
|
|
1088
|
+
const lines = [` def ${name}(self, client: Client) -> None:`];
|
|
1089
|
+
if (responseType) {
|
|
1090
|
+
lines.push(` result = ${call}`);
|
|
1091
|
+
lines.push(` assert_matches_type(${responseType}, result, path=["response"])`);
|
|
1092
|
+
} else {
|
|
1093
|
+
lines.push(` ${call}`);
|
|
1094
|
+
}
|
|
1095
|
+
return lines.join("\n");
|
|
1096
|
+
}
|
|
1097
|
+
function renderPathParamsTest(name, callChain, ex, target) {
|
|
1098
|
+
const n = snakeCase(target.name);
|
|
1099
|
+
const parts = [];
|
|
1100
|
+
for (const pa of ex.pathArgs) parts.push(pa.param === target ? '""' : renderPyExample(pa.value));
|
|
1101
|
+
for (const f of ex.fields) parts.push(`${snakeCase(f.name)}=${renderPyExample(f.value)}`);
|
|
1102
|
+
return [
|
|
1103
|
+
` def ${name}(self, client: Client) -> None:`,
|
|
1104
|
+
` with pytest.raises(ValueError, match=r"Expected a non-empty value for \`${n}\` but received ''"):`,
|
|
1105
|
+
` ${callChain}(${parts.join(", ")})`
|
|
1106
|
+
].join("\n");
|
|
1107
|
+
}
|
|
1108
|
+
function resourceTestPy(resource, pkg, types) {
|
|
1109
|
+
const uses = new PyUses();
|
|
1110
|
+
const pages = /* @__PURE__ */ new Set();
|
|
1111
|
+
let usesPytest = false;
|
|
1112
|
+
const collected = [];
|
|
1113
|
+
collectMethods(resource, [snakeCase(resource.name)], "", collected);
|
|
1114
|
+
const blocks = [];
|
|
1115
|
+
for (const { method, chain, namePrefix } of collected) {
|
|
1116
|
+
const action = snakeCase(method.action);
|
|
1117
|
+
const base = `${namePrefix}${action}`;
|
|
1118
|
+
const callChain = `client.${[...chain, action].join(".")}`;
|
|
1119
|
+
const responseType = responseTypeExpr(method, types, uses, pages);
|
|
1120
|
+
const required = planMethodExample(method, types);
|
|
1121
|
+
blocks.push(renderMethodTest(`test_method_${base}`, `${callChain}(${renderCallArgs(required)})`, responseType));
|
|
1122
|
+
if (required.hasOptional) {
|
|
1123
|
+
const all = planMethodExample(method, types, { withOptional: true });
|
|
1124
|
+
blocks.push(
|
|
1125
|
+
renderMethodTest(`test_method_${base}_with_all_params`, `${callChain}(${renderCallArgs(all)})`, responseType)
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
const target = firstStringPathParam(method);
|
|
1129
|
+
if (target) {
|
|
1130
|
+
usesPytest = true;
|
|
1131
|
+
blocks.push(renderPathParamsTest(`test_path_params_${base}`, callChain, required, target));
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
const groups = [["from __future__ import annotations"]];
|
|
1135
|
+
const typingLine = uses.typingImport();
|
|
1136
|
+
if (typingLine) groups.push([typingLine]);
|
|
1137
|
+
if (usesPytest) groups.push(["import pytest"]);
|
|
1138
|
+
const local = ["from tests.utils import assert_matches_type", `from ${pkg} import Client`, `from ${pkg}.models import * # noqa: F401,F403`];
|
|
1139
|
+
if (pages.size > 0) {
|
|
1140
|
+
const names = ["CursorPage", "Page"].filter((n) => pages.has(n));
|
|
1141
|
+
local.push(`from ${pkg}._pagination import ${names.join(", ")}`);
|
|
1142
|
+
}
|
|
1143
|
+
groups.push(local);
|
|
1144
|
+
const imports = groups.map((g) => g.join("\n")).join("\n\n");
|
|
1145
|
+
const body = blocks.length ? blocks.join("\n\n") : " pass";
|
|
1146
|
+
return `${imports}
|
|
1147
|
+
|
|
1148
|
+
|
|
1149
|
+
class Test${pascalCase(resource.name)}:
|
|
1150
|
+
${body}
|
|
1151
|
+
`;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// src/emitter.ts
|
|
1155
|
+
var resolve = (spec, ctx) => resolvePythonOptions(spec, ctx.emitterOptions);
|
|
1156
|
+
var pythonEmitter = {
|
|
1157
|
+
language: "python",
|
|
1158
|
+
fileHeader() {
|
|
1159
|
+
return "Code generated by opensdk. DO NOT EDIT.";
|
|
1160
|
+
},
|
|
1161
|
+
generateProject(spec, ctx) {
|
|
1162
|
+
const { pkg } = resolve(spec, ctx);
|
|
1163
|
+
return [{ path: "pyproject.toml", content: pyproject(pkg, spec), writeMode: "skipIfExists" }];
|
|
1164
|
+
},
|
|
1165
|
+
generateClient(spec, ctx) {
|
|
1166
|
+
const { pkg, envVar } = resolve(spec, ctx);
|
|
1167
|
+
const errors = ["APIError", ...errorClassNames(spec)];
|
|
1168
|
+
const all = ["Client", ...errors].sort();
|
|
1169
|
+
const init = `from ._client import Client
|
|
1170
|
+
from ._transport import ${errors.join(", ")}
|
|
1171
|
+
|
|
1172
|
+
__all__ = [${all.map((n) => JSON.stringify(n)).join(", ")}]
|
|
1173
|
+
`;
|
|
1174
|
+
return [
|
|
1175
|
+
{ path: `${pkg}/__init__.py`, content: init },
|
|
1176
|
+
{ path: `${pkg}/_client.py`, content: clientPy(spec, envVar) }
|
|
1177
|
+
];
|
|
1178
|
+
},
|
|
1179
|
+
// models.py is emitted even for an empty symbol table: resources.py
|
|
1180
|
+
// star-imports it, so the module must always exist.
|
|
1181
|
+
generateTypes(_types, ctx) {
|
|
1182
|
+
const { pkg } = resolve(ctx.spec, ctx);
|
|
1183
|
+
return [{ path: `${pkg}/models.py`, content: modelsPy(ctx.spec) }];
|
|
1184
|
+
},
|
|
1185
|
+
generateResources(_resources, ctx) {
|
|
1186
|
+
const { pkg } = resolve(ctx.spec, ctx);
|
|
1187
|
+
return [{ path: `${pkg}/resources.py`, content: resourcesPy(ctx.spec, ctx.types) }];
|
|
1188
|
+
},
|
|
1189
|
+
generateRuntime(spec, ctx) {
|
|
1190
|
+
const { pkg, baseURL } = resolve(spec, ctx);
|
|
1191
|
+
const files = [{ path: `${pkg}/_transport.py`, content: transportPy(spec, pkg, baseURL) }];
|
|
1192
|
+
if (walkMethods(spec).some(({ method }) => pyPageName(planOperation3(method, ctx.types)) !== null)) {
|
|
1193
|
+
files.push({ path: `${pkg}/_pagination.py`, content: paginationPy() });
|
|
1194
|
+
}
|
|
1195
|
+
return files;
|
|
1196
|
+
},
|
|
1197
|
+
// The SDK's own pytest suite (openai-python's tests/api_resources/*). SYNC
|
|
1198
|
+
// only — no async/raw/streaming client yet (follow-ups). Off via
|
|
1199
|
+
// emitterOptions.tests === false; default ON. One test file per top-level
|
|
1200
|
+
// resource plus the shared conftest fixture + assert_matches_type helper.
|
|
1201
|
+
generateTests(spec, ctx) {
|
|
1202
|
+
if (ctx.emitterOptions.tests === false) return [];
|
|
1203
|
+
const { pkg } = resolve(spec, ctx);
|
|
1204
|
+
const resources = spec.resources || [];
|
|
1205
|
+
if (resources.length === 0) return [];
|
|
1206
|
+
const files = [
|
|
1207
|
+
{ path: "tests/utils.py", content: testUtilsPy() },
|
|
1208
|
+
{ path: "tests/conftest.py", content: testConftestPy(pkg) }
|
|
1209
|
+
];
|
|
1210
|
+
for (const r of resources) {
|
|
1211
|
+
files.push({ path: `tests/test_${snakeCase(r.name)}.py`, content: resourceTestPy(r, pkg, ctx.types) });
|
|
1212
|
+
}
|
|
1213
|
+
return files;
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
function opensdkPython(spec, options = {}) {
|
|
1217
|
+
return generate(spec, pythonEmitter, options);
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// src/publish.ts
|
|
1221
|
+
import { runCommand } from "@xyd-js/opensdk-framework";
|
|
1222
|
+
function publishPython(dir, opts = {}) {
|
|
1223
|
+
runCommand("python3", ["-m", "build"], { cwd: dir });
|
|
1224
|
+
if (opts.dryRun) return;
|
|
1225
|
+
const args = ["upload"];
|
|
1226
|
+
if (opts.registry) args.push("--repository-url", opts.registry);
|
|
1227
|
+
args.push("dist/*");
|
|
1228
|
+
runCommand("twine", args, {
|
|
1229
|
+
cwd: dir,
|
|
1230
|
+
env: {
|
|
1231
|
+
...process.env,
|
|
1232
|
+
TWINE_USERNAME: process.env.TWINE_USERNAME ?? "__token__",
|
|
1233
|
+
TWINE_PASSWORD: opts.token ?? process.env.TWINE_PASSWORD ?? "opensdk"
|
|
1234
|
+
}
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
// src/index.ts
|
|
1239
|
+
import { writeProject } from "@xyd-js/opensdk-framework";
|
|
1240
|
+
export {
|
|
1241
|
+
opensdkPython,
|
|
1242
|
+
publishPython,
|
|
1243
|
+
pythonEmitter,
|
|
1244
|
+
writeProject
|
|
1245
|
+
};
|
|
1246
|
+
//# sourceMappingURL=index.js.map
|