runwayml 3.4.0__py3-none-any.whl → 3.6.0__py3-none-any.whl

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.
runwayml/__init__.py CHANGED
@@ -36,7 +36,8 @@ from ._exceptions import (
36
36
  UnprocessableEntityError,
37
37
  APIResponseValidationError,
38
38
  )
39
- from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient
39
+ from .lib.polling import TaskFailedError, TaskTimeoutError
40
+ from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient
40
41
  from ._utils._logs import setup_logging as _setup_logging
41
42
 
42
43
  __all__ = [
@@ -78,6 +79,9 @@ __all__ = [
78
79
  "DEFAULT_CONNECTION_LIMITS",
79
80
  "DefaultHttpxClient",
80
81
  "DefaultAsyncHttpxClient",
82
+ "DefaultAioHttpClient",
83
+ "TaskFailedError",
84
+ "TaskTimeoutError",
81
85
  ]
82
86
 
83
87
  if not _t.TYPE_CHECKING:
runwayml/_base_client.py CHANGED
@@ -1071,7 +1071,14 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
1071
1071
  ) -> ResponseT:
1072
1072
  origin = get_origin(cast_to) or cast_to
1073
1073
 
1074
- if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
1074
+ if (
1075
+ inspect.isclass(origin)
1076
+ and issubclass(origin, BaseAPIResponse)
1077
+ # we only want to actually return the custom BaseAPIResponse class if we're
1078
+ # returning the raw response, or if we're not streaming SSE, as if we're streaming
1079
+ # SSE then `cast_to` doesn't actively reflect the type we need to parse into
1080
+ and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
1081
+ ):
1075
1082
  if not issubclass(origin, APIResponse):
1076
1083
  raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}")
1077
1084
 
@@ -1282,6 +1289,24 @@ class _DefaultAsyncHttpxClient(httpx.AsyncClient):
1282
1289
  super().__init__(**kwargs)
1283
1290
 
1284
1291
 
1292
+ try:
1293
+ import httpx_aiohttp
1294
+ except ImportError:
1295
+
1296
+ class _DefaultAioHttpClient(httpx.AsyncClient):
1297
+ def __init__(self, **_kwargs: Any) -> None:
1298
+ raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra")
1299
+ else:
1300
+
1301
+ class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore
1302
+ def __init__(self, **kwargs: Any) -> None:
1303
+ kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
1304
+ kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
1305
+ kwargs.setdefault("follow_redirects", True)
1306
+
1307
+ super().__init__(**kwargs)
1308
+
1309
+
1285
1310
  if TYPE_CHECKING:
1286
1311
  DefaultAsyncHttpxClient = httpx.AsyncClient
1287
1312
  """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK
@@ -1290,8 +1315,12 @@ if TYPE_CHECKING:
1290
1315
  This is useful because overriding the `http_client` with your own instance of
1291
1316
  `httpx.AsyncClient` will result in httpx's defaults being used, not ours.
1292
1317
  """
1318
+
1319
+ DefaultAioHttpClient = httpx.AsyncClient
1320
+ """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`."""
1293
1321
  else:
1294
1322
  DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient
1323
+ DefaultAioHttpClient = _DefaultAioHttpClient
1295
1324
 
1296
1325
 
1297
1326
  class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
@@ -1574,7 +1603,14 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1574
1603
  ) -> ResponseT:
1575
1604
  origin = get_origin(cast_to) or cast_to
1576
1605
 
1577
- if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
1606
+ if (
1607
+ inspect.isclass(origin)
1608
+ and issubclass(origin, BaseAPIResponse)
1609
+ # we only want to actually return the custom BaseAPIResponse class if we're
1610
+ # returning the raw response, or if we're not streaming SSE, as if we're streaming
1611
+ # SSE then `cast_to` doesn't actively reflect the type we need to parse into
1612
+ and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
1613
+ ):
1578
1614
  if not issubclass(origin, AsyncAPIResponse):
1579
1615
  raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}")
1580
1616
 
runwayml/_version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "runwayml"
4
- __version__ = "3.4.0" # x-release-please-version
4
+ __version__ = "3.6.0" # x-release-please-version
@@ -0,0 +1,127 @@
1
+ import time
2
+ import random
3
+ from typing import TYPE_CHECKING, Type, Union, TypeVar, cast
4
+ from typing_extensions import ParamSpec
5
+
6
+ import anyio
7
+
8
+ from .._models import BaseModel
9
+ from ..types.task_retrieve_response import TaskRetrieveResponse
10
+
11
+ if TYPE_CHECKING:
12
+ from .._client import RunwayML, AsyncRunwayML
13
+
14
+ P = ParamSpec("P")
15
+ T = TypeVar("T")
16
+
17
+ POLL_TIME = 6
18
+ POLL_JITTER = 3
19
+
20
+
21
+ class AwaitableTaskResponseMixin:
22
+ def wait_for_task_output(self, timeout: Union[float, None] = 60 * 10) -> TaskRetrieveResponse: # type: ignore[empty-body]
23
+ """
24
+ When called, this will block until the task is complete.
25
+
26
+ If the task fails or is cancelled, a `TaskFailedError` will be raised.
27
+
28
+ Args:
29
+ timeout: The maximum amount of time to wait for the task to complete in seconds. If not
30
+ specified, the default timeout is 10 minutes. Will raise a `TaskTimeoutError` if the
31
+ task does not complete within the timeout.
32
+
33
+ Returns:
34
+ The task details, equivalent to calling `client.tasks.retrieve(task_id)`.
35
+ """
36
+ ...
37
+
38
+
39
+ class NewTaskCreatedResponse(AwaitableTaskResponseMixin, BaseModel):
40
+ id: str
41
+
42
+
43
+ class AwaitableTaskRetrieveResponse(AwaitableTaskResponseMixin, TaskRetrieveResponse):
44
+ pass
45
+
46
+
47
+ class AsyncAwaitableTaskResponseMixin:
48
+ async def wait_for_task_output(self, timeout: Union[float, None] = 60 * 10) -> TaskRetrieveResponse: # type: ignore[empty-body]
49
+ """
50
+ When called, this will wait until the task is complete.
51
+
52
+ If the task fails or is cancelled, a `TaskFailedError` will be raised.
53
+
54
+ Args:
55
+ timeout: The maximum amount of time to wait for the task to complete in seconds. If not
56
+ specified, the default timeout is 10 minutes. Will raise a `TaskTimeoutError` if the
57
+ task does not complete within the timeout. Setting this to `None` will wait
58
+ indefinitely (disabling the timeout).
59
+
60
+ Returns:
61
+ The task details, equivalent to awaiting `client.tasks.retrieve(task_id)`.
62
+ """
63
+ ...
64
+
65
+
66
+ class AsyncNewTaskCreatedResponse(AsyncAwaitableTaskResponseMixin, BaseModel):
67
+ id: str
68
+
69
+
70
+ class AsyncAwaitableTaskRetrieveResponse(AsyncAwaitableTaskResponseMixin, TaskRetrieveResponse):
71
+ pass
72
+
73
+
74
+ def create_waitable_resource(base_class: Type[T], client: "RunwayML") -> Type[NewTaskCreatedResponse]:
75
+ class WithClient(base_class): # type: ignore[valid-type,misc]
76
+ id: str
77
+
78
+ def wait_for_task_output(self, timeout: Union[float, None] = 60 * 10) -> TaskRetrieveResponse:
79
+ start_time = time.time()
80
+ while True:
81
+ time.sleep(POLL_TIME + random.random() * POLL_JITTER - POLL_JITTER / 2)
82
+ task_details = client.tasks.retrieve(self.id)
83
+ if task_details.status == "SUCCEEDED":
84
+ return task_details
85
+ if task_details.status == "FAILED":
86
+ raise TaskFailedError(task_details)
87
+ if timeout is not None and time.time() - start_time > timeout:
88
+ raise TaskTimeoutError(task_details)
89
+
90
+ WithClient.__name__ = base_class.__name__
91
+ WithClient.__qualname__ = base_class.__qualname__
92
+
93
+ return cast(Type[NewTaskCreatedResponse], WithClient)
94
+
95
+
96
+ def create_async_waitable_resource(base_class: Type[T], client: "AsyncRunwayML") -> Type[AsyncNewTaskCreatedResponse]:
97
+ class WithClient(base_class): # type: ignore[valid-type,misc]
98
+ id: str
99
+
100
+ async def wait_for_task_output(self, timeout: Union[float, None] = 60 * 10) -> TaskRetrieveResponse:
101
+ start_time = anyio.current_time()
102
+ while True:
103
+ await anyio.sleep(POLL_TIME + random.random() * POLL_JITTER - POLL_JITTER / 2)
104
+ task_details = await client.tasks.retrieve(self.id)
105
+ if task_details.status == "SUCCEEDED":
106
+ return task_details
107
+ if task_details.status == "FAILED" or task_details.status == "CANCELLED":
108
+ raise TaskFailedError(task_details)
109
+ if timeout is not None and anyio.current_time() - start_time > timeout:
110
+ raise TaskTimeoutError(task_details)
111
+
112
+ WithClient.__name__ = base_class.__name__
113
+ WithClient.__qualname__ = base_class.__qualname__
114
+
115
+ return cast(Type[AsyncNewTaskCreatedResponse], WithClient)
116
+
117
+
118
+ class TaskFailedError(Exception):
119
+ def __init__(self, task_details: TaskRetrieveResponse):
120
+ self.task_details = task_details
121
+ super().__init__(f"Task failed")
122
+
123
+
124
+ class TaskTimeoutError(Exception):
125
+ def __init__(self, task_details: TaskRetrieveResponse):
126
+ self.task_details = task_details
127
+ super().__init__(f"Task timed out")
@@ -18,6 +18,12 @@ from .._response import (
18
18
  async_to_raw_response_wrapper,
19
19
  async_to_streamed_response_wrapper,
20
20
  )
21
+ from ..lib.polling import (
22
+ NewTaskCreatedResponse,
23
+ AsyncNewTaskCreatedResponse,
24
+ create_waitable_resource,
25
+ create_async_waitable_resource,
26
+ )
21
27
  from .._base_client import make_request_options
22
28
  from ..types.image_to_video_create_response import ImageToVideoCreateResponse
23
29
 
@@ -47,9 +53,10 @@ class ImageToVideoResource(SyncAPIResource):
47
53
  def create(
48
54
  self,
49
55
  *,
50
- model: Literal["gen4_turbo", "gen3a_turbo"],
56
+ model: Literal["gen3a_turbo", "gen4_turbo"],
51
57
  prompt_image: Union[str, Iterable[image_to_video_create_params.PromptImagePromptImage]],
52
58
  ratio: Literal["1280:720", "720:1280", "1104:832", "832:1104", "960:960", "1584:672", "1280:768", "768:1280"],
59
+ content_moderation: image_to_video_create_params.ContentModeration | NotGiven = NOT_GIVEN,
53
60
  duration: Literal[5, 10] | NotGiven = NOT_GIVEN,
54
61
  prompt_text: str | NotGiven = NOT_GIVEN,
55
62
  seed: int | NotGiven = NOT_GIVEN,
@@ -59,7 +66,7 @@ class ImageToVideoResource(SyncAPIResource):
59
66
  extra_query: Query | None = None,
60
67
  extra_body: Body | None = None,
61
68
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
62
- ) -> ImageToVideoCreateResponse:
69
+ ) -> NewTaskCreatedResponse:
63
70
  """
64
71
  This endpoint will start a new task to generate a video from an image prompt.
65
72
 
@@ -86,6 +93,8 @@ class ImageToVideoResource(SyncAPIResource):
86
93
  - `1280:768`
87
94
  - `768:1280`
88
95
 
96
+ content_moderation: Settings that affect the behavior of the content moderation system.
97
+
89
98
  duration: The number of seconds of duration for the output video.
90
99
 
91
100
  prompt_text: A non-empty string up to 1000 characters (measured in UTF-16 code units). This
@@ -110,6 +119,7 @@ class ImageToVideoResource(SyncAPIResource):
110
119
  "model": model,
111
120
  "prompt_image": prompt_image,
112
121
  "ratio": ratio,
122
+ "content_moderation": content_moderation,
113
123
  "duration": duration,
114
124
  "prompt_text": prompt_text,
115
125
  "seed": seed,
@@ -119,7 +129,7 @@ class ImageToVideoResource(SyncAPIResource):
119
129
  options=make_request_options(
120
130
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
121
131
  ),
122
- cast_to=ImageToVideoCreateResponse,
132
+ cast_to=create_waitable_resource(ImageToVideoCreateResponse, self._client),
123
133
  )
124
134
 
125
135
 
@@ -146,9 +156,10 @@ class AsyncImageToVideoResource(AsyncAPIResource):
146
156
  async def create(
147
157
  self,
148
158
  *,
149
- model: Literal["gen4_turbo", "gen3a_turbo"],
159
+ model: Literal["gen3a_turbo", "gen4_turbo"],
150
160
  prompt_image: Union[str, Iterable[image_to_video_create_params.PromptImagePromptImage]],
151
161
  ratio: Literal["1280:720", "720:1280", "1104:832", "832:1104", "960:960", "1584:672", "1280:768", "768:1280"],
162
+ content_moderation: image_to_video_create_params.ContentModeration | NotGiven = NOT_GIVEN,
152
163
  duration: Literal[5, 10] | NotGiven = NOT_GIVEN,
153
164
  prompt_text: str | NotGiven = NOT_GIVEN,
154
165
  seed: int | NotGiven = NOT_GIVEN,
@@ -158,7 +169,7 @@ class AsyncImageToVideoResource(AsyncAPIResource):
158
169
  extra_query: Query | None = None,
159
170
  extra_body: Body | None = None,
160
171
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
161
- ) -> ImageToVideoCreateResponse:
172
+ ) -> AsyncNewTaskCreatedResponse:
162
173
  """
163
174
  This endpoint will start a new task to generate a video from an image prompt.
164
175
 
@@ -185,6 +196,8 @@ class AsyncImageToVideoResource(AsyncAPIResource):
185
196
  - `1280:768`
186
197
  - `768:1280`
187
198
 
199
+ content_moderation: Settings that affect the behavior of the content moderation system.
200
+
188
201
  duration: The number of seconds of duration for the output video.
189
202
 
190
203
  prompt_text: A non-empty string up to 1000 characters (measured in UTF-16 code units). This
@@ -209,6 +222,7 @@ class AsyncImageToVideoResource(AsyncAPIResource):
209
222
  "model": model,
210
223
  "prompt_image": prompt_image,
211
224
  "ratio": ratio,
225
+ "content_moderation": content_moderation,
212
226
  "duration": duration,
213
227
  "prompt_text": prompt_text,
214
228
  "seed": seed,
@@ -218,7 +232,7 @@ class AsyncImageToVideoResource(AsyncAPIResource):
218
232
  options=make_request_options(
219
233
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
220
234
  ),
221
- cast_to=ImageToVideoCreateResponse,
235
+ cast_to=create_async_waitable_resource(ImageToVideoCreateResponse, self._client),
222
236
  )
223
237
 
224
238
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from typing import cast
6
+
5
7
  import httpx
6
8
 
7
9
  from .._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven
@@ -13,6 +15,12 @@ from .._response import (
13
15
  async_to_raw_response_wrapper,
14
16
  async_to_streamed_response_wrapper,
15
17
  )
18
+ from ..lib.polling import (
19
+ AwaitableTaskRetrieveResponse,
20
+ AsyncAwaitableTaskRetrieveResponse,
21
+ create_waitable_resource,
22
+ create_async_waitable_resource,
23
+ )
16
24
  from .._base_client import make_request_options
17
25
  from ..types.task_retrieve_response import TaskRetrieveResponse
18
26
 
@@ -49,7 +57,7 @@ class TasksResource(SyncAPIResource):
49
57
  extra_query: Query | None = None,
50
58
  extra_body: Body | None = None,
51
59
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
52
- ) -> TaskRetrieveResponse:
60
+ ) -> AwaitableTaskRetrieveResponse:
53
61
  """Return details about a task.
54
62
 
55
63
  Consumers of this API should not expect updates
@@ -71,7 +79,9 @@ class TasksResource(SyncAPIResource):
71
79
  options=make_request_options(
72
80
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
73
81
  ),
74
- cast_to=TaskRetrieveResponse,
82
+ cast_to=cast(
83
+ type[AwaitableTaskRetrieveResponse], create_waitable_resource(TaskRetrieveResponse, self._client)
84
+ ),
75
85
  )
76
86
 
77
87
  def delete(
@@ -144,7 +154,7 @@ class AsyncTasksResource(AsyncAPIResource):
144
154
  extra_query: Query | None = None,
145
155
  extra_body: Body | None = None,
146
156
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
147
- ) -> TaskRetrieveResponse:
157
+ ) -> AsyncAwaitableTaskRetrieveResponse:
148
158
  """Return details about a task.
149
159
 
150
160
  Consumers of this API should not expect updates
@@ -166,7 +176,10 @@ class AsyncTasksResource(AsyncAPIResource):
166
176
  options=make_request_options(
167
177
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
168
178
  ),
169
- cast_to=TaskRetrieveResponse,
179
+ cast_to=cast(
180
+ type[AsyncAwaitableTaskRetrieveResponse],
181
+ create_async_waitable_resource(TaskRetrieveResponse, self._client),
182
+ ),
170
183
  )
171
184
 
172
185
  async def delete(
@@ -18,6 +18,12 @@ from .._response import (
18
18
  async_to_raw_response_wrapper,
19
19
  async_to_streamed_response_wrapper,
20
20
  )
21
+ from ..lib.polling import (
22
+ NewTaskCreatedResponse,
23
+ AsyncNewTaskCreatedResponse,
24
+ create_waitable_resource,
25
+ create_async_waitable_resource,
26
+ )
21
27
  from .._base_client import make_request_options
22
28
  from ..types.text_to_image_create_response import TextToImageCreateResponse
23
29
 
@@ -76,7 +82,7 @@ class TextToImageResource(SyncAPIResource):
76
82
  extra_query: Query | None = None,
77
83
  extra_body: Body | None = None,
78
84
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
79
- ) -> TextToImageCreateResponse:
85
+ ) -> NewTaskCreatedResponse:
80
86
  """
81
87
  This endpoint will start a new task to generate images from text.
82
88
 
@@ -121,7 +127,7 @@ class TextToImageResource(SyncAPIResource):
121
127
  options=make_request_options(
122
128
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
123
129
  ),
124
- cast_to=TextToImageCreateResponse,
130
+ cast_to=create_waitable_resource(TextToImageCreateResponse, self._client),
125
131
  )
126
132
 
127
133
 
@@ -177,7 +183,7 @@ class AsyncTextToImageResource(AsyncAPIResource):
177
183
  extra_query: Query | None = None,
178
184
  extra_body: Body | None = None,
179
185
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
180
- ) -> TextToImageCreateResponse:
186
+ ) -> AsyncNewTaskCreatedResponse:
181
187
  """
182
188
  This endpoint will start a new task to generate images from text.
183
189
 
@@ -222,7 +228,7 @@ class AsyncTextToImageResource(AsyncAPIResource):
222
228
  options=make_request_options(
223
229
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
224
230
  ),
225
- cast_to=TextToImageCreateResponse,
231
+ cast_to=create_async_waitable_resource(TextToImageCreateResponse, self._client),
226
232
  )
227
233
 
228
234
 
@@ -17,6 +17,12 @@ from .._response import (
17
17
  async_to_raw_response_wrapper,
18
18
  async_to_streamed_response_wrapper,
19
19
  )
20
+ from ..lib.polling import (
21
+ NewTaskCreatedResponse,
22
+ AsyncNewTaskCreatedResponse,
23
+ create_waitable_resource,
24
+ create_async_waitable_resource,
25
+ )
20
26
  from .._base_client import make_request_options
21
27
  from ..types.video_upscale_create_response import VideoUpscaleCreateResponse
22
28
 
@@ -54,7 +60,7 @@ class VideoUpscaleResource(SyncAPIResource):
54
60
  extra_query: Query | None = None,
55
61
  extra_body: Body | None = None,
56
62
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
57
- ) -> VideoUpscaleCreateResponse:
63
+ ) -> NewTaskCreatedResponse:
58
64
  """This endpoint will start a new task to upscale a video.
59
65
 
60
66
  Videos will be upscaled
@@ -87,7 +93,7 @@ class VideoUpscaleResource(SyncAPIResource):
87
93
  options=make_request_options(
88
94
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
89
95
  ),
90
- cast_to=VideoUpscaleCreateResponse,
96
+ cast_to=create_waitable_resource(VideoUpscaleCreateResponse, self._client),
91
97
  )
92
98
 
93
99
 
@@ -122,7 +128,7 @@ class AsyncVideoUpscaleResource(AsyncAPIResource):
122
128
  extra_query: Query | None = None,
123
129
  extra_body: Body | None = None,
124
130
  timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
125
- ) -> VideoUpscaleCreateResponse:
131
+ ) -> AsyncNewTaskCreatedResponse:
126
132
  """This endpoint will start a new task to upscale a video.
127
133
 
128
134
  Videos will be upscaled
@@ -155,7 +161,7 @@ class AsyncVideoUpscaleResource(AsyncAPIResource):
155
161
  options=make_request_options(
156
162
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
157
163
  ),
158
- cast_to=VideoUpscaleCreateResponse,
164
+ cast_to=create_async_waitable_resource(VideoUpscaleCreateResponse, self._client),
159
165
  )
160
166
 
161
167
 
@@ -7,11 +7,11 @@ from typing_extensions import Literal, Required, Annotated, TypedDict
7
7
 
8
8
  from .._utils import PropertyInfo
9
9
 
10
- __all__ = ["ImageToVideoCreateParams", "PromptImagePromptImage"]
10
+ __all__ = ["ImageToVideoCreateParams", "PromptImagePromptImage", "ContentModeration"]
11
11
 
12
12
 
13
13
  class ImageToVideoCreateParams(TypedDict, total=False):
14
- model: Required[Literal["gen4_turbo", "gen3a_turbo"]]
14
+ model: Required[Literal["gen3a_turbo", "gen4_turbo"]]
15
15
  """The model variant to use."""
16
16
 
17
17
  prompt_image: Required[Annotated[Union[str, Iterable[PromptImagePromptImage]], PropertyInfo(alias="promptImage")]]
@@ -41,6 +41,9 @@ class ImageToVideoCreateParams(TypedDict, total=False):
41
41
  - `768:1280`
42
42
  """
43
43
 
44
+ content_moderation: Annotated[ContentModeration, PropertyInfo(alias="contentModeration")]
45
+ """Settings that affect the behavior of the content moderation system."""
46
+
44
47
  duration: Literal[5, 10]
45
48
  """The number of seconds of duration for the output video."""
46
49
 
@@ -74,3 +77,11 @@ class PromptImagePromptImage(TypedDict, total=False):
74
77
 
75
78
  See [our docs](/assets/inputs#images) on image inputs for more information.
76
79
  """
80
+
81
+
82
+ class ContentModeration(TypedDict, total=False):
83
+ public_figure_threshold: Annotated[Literal["auto", "low"], PropertyInfo(alias="publicFigureThreshold")]
84
+ """
85
+ When set to `low`, the content moderation system will be less strict about
86
+ preventing generations that include recognizable public figures.
87
+ """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: runwayml
3
- Version: 3.4.0
3
+ Version: 3.6.0
4
4
  Summary: The official Python library for the runwayml API
5
5
  Project-URL: Homepage, https://github.com/runwayml/sdk-python
6
6
  Project-URL: Repository, https://github.com/runwayml/sdk-python
@@ -27,11 +27,14 @@ Requires-Dist: httpx<1,>=0.23.0
27
27
  Requires-Dist: pydantic<3,>=1.9.0
28
28
  Requires-Dist: sniffio
29
29
  Requires-Dist: typing-extensions<5,>=4.10
30
+ Provides-Extra: aiohttp
31
+ Requires-Dist: aiohttp; extra == 'aiohttp'
32
+ Requires-Dist: httpx-aiohttp>=0.1.6; extra == 'aiohttp'
30
33
  Description-Content-Type: text/markdown
31
34
 
32
35
  # RunwayML Python API library
33
36
 
34
- [![PyPI version](https://img.shields.io/pypi/v/runwayml.svg)](https://pypi.org/project/runwayml/)
37
+ [![PyPI version](https://github.com/runwayml/sdk-python/tree/main/<https://img.shields.io/pypi/v/runwayml.svg?label=pypi%20(stable)>)](https://pypi.org/project/runwayml/)
35
38
 
36
39
  The RunwayML Python library provides convenient access to the RunwayML REST API from any Python 3.8+
37
40
  application. The library includes type definitions for all request params and response fields,
@@ -105,6 +108,43 @@ asyncio.run(main())
105
108
 
106
109
  Functionality between the synchronous and asynchronous clients is otherwise identical.
107
110
 
111
+ ### With aiohttp
112
+
113
+ By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
114
+
115
+ You can enable this by installing `aiohttp`:
116
+
117
+ ```sh
118
+ # install from PyPI
119
+ pip install runwayml[aiohttp]
120
+ ```
121
+
122
+ Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
123
+
124
+ ```python
125
+ import os
126
+ import asyncio
127
+ from runwayml import DefaultAioHttpClient
128
+ from runwayml import AsyncRunwayML
129
+
130
+
131
+ async def main() -> None:
132
+ async with AsyncRunwayML(
133
+ api_key=os.environ.get("RUNWAYML_API_SECRET"), # This is the default and can be omitted
134
+ http_client=DefaultAioHttpClient(),
135
+ ) as client:
136
+ image_to_video = await client.image_to_video.create(
137
+ model="gen4_turbo",
138
+ prompt_image="https://example.com/assets/bunny.jpg",
139
+ ratio="1280:720",
140
+ prompt_text="The bunny is eating a carrot",
141
+ )
142
+ print(image_to_video.id)
143
+
144
+
145
+ asyncio.run(main())
146
+ ```
147
+
108
148
  ## Using types
109
149
 
110
150
  Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:
@@ -206,7 +246,7 @@ client.with_options(max_retries=5).image_to_video.create(
206
246
  ### Timeouts
207
247
 
208
248
  By default requests time out after 1 minute. You can configure this with a `timeout` option,
209
- which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
249
+ which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
210
250
 
211
251
  ```python
212
252
  from runwayml import RunwayML
@@ -1,5 +1,5 @@
1
- runwayml/__init__.py,sha256=w7Il_Fc71HY9Ebs62Q5VLcsCQGraefXwcOmtzeg4r5I,2587
2
- runwayml/_base_client.py,sha256=C7nXQufaETXu-KXQeQtb6h6lEMCA-xWQUKWlIh9x0Ro,65094
1
+ runwayml/__init__.py,sha256=tr-n2Y4sH_wBv8t2F_jk7ku_rLT2erU3j61ONZJWUVs,2743
2
+ runwayml/_base_client.py,sha256=FH5ueSL8_ijbhXlcd6FG98sy_IMnFsAhVkBkCcv4ZjI,66717
3
3
  runwayml/_client.py,sha256=tEooz-jH6JGowMQwrTZE7CKcyqpILEHKfSFf7OevoIU,18513
4
4
  runwayml/_compat.py,sha256=VWemUKbj6DDkQ-O4baSpHVLJafotzeXmCQGJugfVTIw,6580
5
5
  runwayml/_constants.py,sha256=S14PFzyN9-I31wiV7SmIlL5Ga0MLHxdvegInGdXH7tM,462
@@ -11,7 +11,7 @@ runwayml/_resource.py,sha256=BF-j3xY5eRTKmuTxg8eDhLtLP4MLB1phDh_B6BKipKA,1112
11
11
  runwayml/_response.py,sha256=WxjSEXX-j01ZhlSxYyMCVSEKxo20pgy40RA7iyski8M,28800
12
12
  runwayml/_streaming.py,sha256=NSVuAgknVQWU1cgZEjQn01IdZKKynb5rOeYp5Lo-OEQ,10108
13
13
  runwayml/_types.py,sha256=YL6SdhLq5SHlT644GjzDwOJ_Slyr8QDRCoacOp4trhI,6199
14
- runwayml/_version.py,sha256=ewweQm0FzO6J6GFWJ5sAqxHCBDqFKEIYiPzmmxSjCF8,160
14
+ runwayml/_version.py,sha256=cTRo7ZS2XlFsYQnDltFU4mR3P69yxWhnj5GXcoaXxfM,160
15
15
  runwayml/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  runwayml/_utils/__init__.py,sha256=PNZ_QJuzZEgyYXqkO1HVhGkj5IU9bglVUcw7H-Knjzw,2062
17
17
  runwayml/_utils/_logs.py,sha256=ZfS5W59hdqEBVV86lNrk28PhvUxtHOzs9JqiLhSu0pI,780
@@ -24,14 +24,15 @@ runwayml/_utils/_transform.py,sha256=n7kskEWz6o__aoNvhFoGVyDoalNe6mJwp-g7BWkdj88
24
24
  runwayml/_utils/_typing.py,sha256=D0DbbNu8GnYQTSICnTSHDGsYXj8TcAKyhejb0XcnjtY,4602
25
25
  runwayml/_utils/_utils.py,sha256=ts4CiiuNpFiGB6YMdkQRh2SZvYvsl7mAF-JWHCcLDf4,12312
26
26
  runwayml/lib/.keep,sha256=wuNrz-5SXo3jJaJOJgz4vFHM41YH_g20F5cRQo0vLes,224
27
+ runwayml/lib/polling.py,sha256=4fF0gP-h4iR0jvxWifsqtR1iH9vRoKEgGykkaZNT9Ek,4743
27
28
  runwayml/resources/__init__.py,sha256=5XJIeBB9D2GqQU-9Ub5AuzRVgLYp1QdLr8Fjh6DCDxM,2643
28
- runwayml/resources/image_to_video.py,sha256=dS2yTuOx10xSUAhAZ0FmuAEDXqo-WLyWe41aVovR5yo,10120
29
+ runwayml/resources/image_to_video.py,sha256=O6YbnD7QEE_YK5UeRDq8RzWwiuS5nTQSAkCl9RvZe74,10880
29
30
  runwayml/resources/organization.py,sha256=XBg5nhkycPU3rllRvf9aaeHuZNtzGDKHlLPrPqDCAsw,5419
30
- runwayml/resources/tasks.py,sha256=-VT3qetYcaqn4FskekxhN_fCTozMl1GqxGpGwxV8M60,9673
31
- runwayml/resources/text_to_image.py,sha256=E-Fbu2fL96QFbp_j_hz7fw9iQTQwlqjpzH32K4HwoRg,9958
32
- runwayml/resources/video_upscale.py,sha256=OWr-oCJ4ovhw6YLELsCwIvGLRnRKj9E3STB5ofMStbw,7451
31
+ runwayml/resources/tasks.py,sha256=mjdBqB1G4u9v3xB_9yn6aIdvsDmawxSNcTENkMpKSms,10146
32
+ runwayml/resources/text_to_image.py,sha256=OJ9oD1Fc5NBGqci6Ox_-M9lFvsYG31fSwSzsr0pwPak,10200
33
+ runwayml/resources/video_upscale.py,sha256=8Mz_g5Swxmgp14jfcfexurUYpPi73q_iU-9D1jOddt0,7691
33
34
  runwayml/types/__init__.py,sha256=zXevA88F25dbdsjgpvdlKlvELiv9aamz1hS3xcLbe40,889
34
- runwayml/types/image_to_video_create_params.py,sha256=TgoNwKkz_PK_sFBeATqMFkXpBhdx8DSZTLA6hLbMhFM,2352
35
+ runwayml/types/image_to_video_create_params.py,sha256=6M_xJRx0ws8nQ0a3k3jEICDm-WXJUG9j-j1UIxAAg-s,2869
35
36
  runwayml/types/image_to_video_create_response.py,sha256=WvZHbZxxJz8KerRNogzb1RYBrxa1x0iCPDi9-LCpHyE,345
36
37
  runwayml/types/organization_retrieve_response.py,sha256=_7vny0YNmNmREe8jp58ldJbXDdzNAGzDT8V0kK9pbsA,4385
37
38
  runwayml/types/task_retrieve_response.py,sha256=v8y2bLxsW6srzScW-B3Akv72q_PI_NQmduGrGRQMHds,2139
@@ -39,7 +40,7 @@ runwayml/types/text_to_image_create_params.py,sha256=I8Dr4UG6VnciQ87zN6qp03FKwlQ
39
40
  runwayml/types/text_to_image_create_response.py,sha256=koMzUg82dYFQPp77wln3UR1z8WO2sHCNMWGgoQ9Id8M,262
40
41
  runwayml/types/video_upscale_create_params.py,sha256=Ta3BNQy9aeTUBU5Ui-CMJtF32HeNRqbNpqjAAOKXyks,743
41
42
  runwayml/types/video_upscale_create_response.py,sha256=zf-79HbJa68dUHltBiZjVtnW_U6HUI-htmkTm5URBSU,264
42
- runwayml-3.4.0.dist-info/METADATA,sha256=KQJ79S4lKQj3iKWmYi4-V__ryR9P89f9oqA5QwHBXDM,13986
43
- runwayml-3.4.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
44
- runwayml-3.4.0.dist-info/licenses/LICENSE,sha256=baeFj6izBWIm6A5_7N3-WAsy_VYpDF05Dd4zS1zsfZI,11338
45
- runwayml-3.4.0.dist-info/RECORD,,
43
+ runwayml-3.6.0.dist-info/METADATA,sha256=bR7BWijWXnNF3KexxAaHUaeUDjSgxAztRyUSEmFF19w,15209
44
+ runwayml-3.6.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
45
+ runwayml-3.6.0.dist-info/licenses/LICENSE,sha256=baeFj6izBWIm6A5_7N3-WAsy_VYpDF05Dd4zS1zsfZI,11338
46
+ runwayml-3.6.0.dist-info/RECORD,,