runwayml 3.4.0__tar.gz → 3.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. runwayml-3.5.0/.release-please-manifest.json +3 -0
  2. {runwayml-3.4.0 → runwayml-3.5.0}/CHANGELOG.md +22 -0
  3. {runwayml-3.4.0 → runwayml-3.5.0}/PKG-INFO +1 -1
  4. runwayml-3.5.0/examples/generate_image.py +16 -0
  5. {runwayml-3.4.0 → runwayml-3.5.0}/pyproject.toml +3 -2
  6. {runwayml-3.4.0 → runwayml-3.5.0}/requirements-dev.lock +4 -0
  7. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/__init__.py +3 -0
  8. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_base_client.py +16 -2
  9. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_version.py +1 -1
  10. runwayml-3.5.0/src/runwayml/lib/polling.py +127 -0
  11. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/resources/image_to_video.py +20 -6
  12. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/resources/tasks.py +17 -4
  13. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/resources/text_to_image.py +10 -4
  14. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/resources/video_upscale.py +10 -4
  15. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/types/image_to_video_create_params.py +13 -2
  16. {runwayml-3.4.0 → runwayml-3.5.0}/tests/api_resources/test_image_to_video.py +10 -8
  17. {runwayml-3.4.0 → runwayml-3.5.0}/tests/conftest.py +2 -0
  18. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_client.py +52 -6
  19. runwayml-3.4.0/.release-please-manifest.json +0 -3
  20. {runwayml-3.4.0 → runwayml-3.5.0}/.gitignore +0 -0
  21. {runwayml-3.4.0 → runwayml-3.5.0}/CONTRIBUTING.md +0 -0
  22. {runwayml-3.4.0 → runwayml-3.5.0}/LICENSE +0 -0
  23. {runwayml-3.4.0 → runwayml-3.5.0}/README.md +0 -0
  24. {runwayml-3.4.0 → runwayml-3.5.0}/SECURITY.md +0 -0
  25. {runwayml-3.4.0 → runwayml-3.5.0}/api.md +0 -0
  26. {runwayml-3.4.0 → runwayml-3.5.0}/bin/check-release-environment +0 -0
  27. {runwayml-3.4.0 → runwayml-3.5.0}/bin/publish-pypi +0 -0
  28. {runwayml-3.4.0 → runwayml-3.5.0}/examples/.keep +0 -0
  29. {runwayml-3.4.0 → runwayml-3.5.0}/mypy.ini +0 -0
  30. {runwayml-3.4.0 → runwayml-3.5.0}/noxfile.py +0 -0
  31. {runwayml-3.4.0 → runwayml-3.5.0}/release-please-config.json +0 -0
  32. {runwayml-3.4.0 → runwayml-3.5.0}/requirements.lock +0 -0
  33. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_client.py +0 -0
  34. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_compat.py +0 -0
  35. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_constants.py +0 -0
  36. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_exceptions.py +0 -0
  37. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_files.py +0 -0
  38. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_models.py +0 -0
  39. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_qs.py +0 -0
  40. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_resource.py +0 -0
  41. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_response.py +0 -0
  42. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_streaming.py +0 -0
  43. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_types.py +0 -0
  44. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_utils/__init__.py +0 -0
  45. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_utils/_logs.py +0 -0
  46. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_utils/_proxy.py +0 -0
  47. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_utils/_reflection.py +0 -0
  48. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_utils/_resources_proxy.py +0 -0
  49. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_utils/_streams.py +0 -0
  50. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_utils/_sync.py +0 -0
  51. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_utils/_transform.py +0 -0
  52. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_utils/_typing.py +0 -0
  53. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/_utils/_utils.py +0 -0
  54. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/lib/.keep +0 -0
  55. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/py.typed +0 -0
  56. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/resources/__init__.py +0 -0
  57. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/resources/organization.py +0 -0
  58. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/types/__init__.py +0 -0
  59. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/types/image_to_video_create_response.py +0 -0
  60. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/types/organization_retrieve_response.py +0 -0
  61. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/types/task_retrieve_response.py +0 -0
  62. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/types/text_to_image_create_params.py +0 -0
  63. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/types/text_to_image_create_response.py +0 -0
  64. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/types/video_upscale_create_params.py +0 -0
  65. {runwayml-3.4.0 → runwayml-3.5.0}/src/runwayml/types/video_upscale_create_response.py +0 -0
  66. {runwayml-3.4.0 → runwayml-3.5.0}/tests/__init__.py +0 -0
  67. {runwayml-3.4.0 → runwayml-3.5.0}/tests/api_resources/__init__.py +0 -0
  68. {runwayml-3.4.0 → runwayml-3.5.0}/tests/api_resources/test_organization.py +0 -0
  69. {runwayml-3.4.0 → runwayml-3.5.0}/tests/api_resources/test_tasks.py +0 -0
  70. {runwayml-3.4.0 → runwayml-3.5.0}/tests/api_resources/test_text_to_image.py +0 -0
  71. {runwayml-3.4.0 → runwayml-3.5.0}/tests/api_resources/test_video_upscale.py +0 -0
  72. {runwayml-3.4.0 → runwayml-3.5.0}/tests/sample_file.txt +0 -0
  73. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_deepcopy.py +0 -0
  74. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_extract_files.py +0 -0
  75. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_files.py +0 -0
  76. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_models.py +0 -0
  77. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_qs.py +0 -0
  78. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_required_args.py +0 -0
  79. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_response.py +0 -0
  80. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_streaming.py +0 -0
  81. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_transform.py +0 -0
  82. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_utils/test_proxy.py +0 -0
  83. {runwayml-3.4.0 → runwayml-3.5.0}/tests/test_utils/test_typing.py +0 -0
  84. {runwayml-3.4.0 → runwayml-3.5.0}/tests/utils.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "3.5.0"
3
+ }
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.5.0 (2025-06-17)
4
+
5
+ Full Changelog: [v3.4.0...v3.5.0](https://github.com/runwayml/sdk-python/compare/v3.4.0...v3.5.0)
6
+
7
+ ### Features
8
+
9
+ * **api:** SDK updates, contentModeration for i2v ([1286e32](https://github.com/runwayml/sdk-python/commit/1286e3239f388143404c4b0a61816f5f6282fe1c))
10
+ * **api:** SDK updates, contentModeration for i2v ([8ff202e](https://github.com/runwayml/sdk-python/commit/8ff202ee39dc5856118bf1f3f5537e459a120967))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **client:** correctly parse binary response | stream ([fc9bedb](https://github.com/runwayml/sdk-python/commit/fc9bedb3cbb47849e83a5982ed92a694796e80c7))
16
+
17
+
18
+ ### Chores
19
+
20
+ * **ci:** enable for pull requests ([4b439c9](https://github.com/runwayml/sdk-python/commit/4b439c99012918849be4fa64b1ab8d1802cee6e6))
21
+ * **internal:** update conftest.py ([0ff71fd](https://github.com/runwayml/sdk-python/commit/0ff71fd67a421dbff729e98418b6cd72ed0e57b3))
22
+ * **tests:** add tests for httpx client instantiation & proxies ([89e5fbe](https://github.com/runwayml/sdk-python/commit/89e5fbef9e8a64d050252f489b2d76e4c510c663))
23
+ * **tests:** run tests in parallel ([7edbcd1](https://github.com/runwayml/sdk-python/commit/7edbcd1db04ed139e026701fe24501199b4eaffd))
24
+
3
25
  ## 3.4.0 (2025-06-04)
4
26
 
5
27
  Full Changelog: [v3.3.0...v3.4.0](https://github.com/runwayml/sdk-python/compare/v3.3.0...v3.4.0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: runwayml
3
- Version: 3.4.0
3
+ Version: 3.5.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
@@ -0,0 +1,16 @@
1
+ from runwayml import RunwayML, TaskFailedError
2
+
3
+ client = RunwayML()
4
+
5
+ image_task = client.text_to_image.create(
6
+ model="gen4_image",
7
+ prompt_text="A beautiful sunset over a calm ocean",
8
+ ratio="1920:1080",
9
+ )
10
+ try:
11
+ output = image_task.wait_for_task_output()
12
+ except TaskFailedError as e:
13
+ print('The image failed to generate.')
14
+ print(e.task_details)
15
+ else:
16
+ print(output.output[0]) # type: ignore
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "runwayml"
3
- version = "3.4.0"
3
+ version = "3.5.0"
4
4
  description = "The official Python library for the runwayml API"
5
5
  dynamic = ["readme"]
6
6
  license = "Apache-2.0"
@@ -54,6 +54,7 @@ dev-dependencies = [
54
54
  "importlib-metadata>=6.7.0",
55
55
  "rich>=13.7.1",
56
56
  "nest_asyncio==1.6.0",
57
+ "pytest-xdist>=3.6.1",
57
58
  ]
58
59
 
59
60
  [tool.rye.scripts]
@@ -125,7 +126,7 @@ replacement = '[\1](https://github.com/runwayml/sdk-python/tree/main/\g<2>)'
125
126
 
126
127
  [tool.pytest.ini_options]
127
128
  testpaths = ["tests"]
128
- addopts = "--tb=short"
129
+ addopts = "--tb=short -n auto"
129
130
  xfail_strict = true
130
131
  asyncio_mode = "auto"
131
132
  asyncio_default_fixture_loop_scope = "session"
@@ -30,6 +30,8 @@ distro==1.8.0
30
30
  exceptiongroup==1.2.2
31
31
  # via anyio
32
32
  # via pytest
33
+ execnet==2.1.1
34
+ # via pytest-xdist
33
35
  filelock==3.12.4
34
36
  # via virtualenv
35
37
  h11==0.14.0
@@ -72,7 +74,9 @@ pygments==2.18.0
72
74
  pyright==1.1.399
73
75
  pytest==8.3.3
74
76
  # via pytest-asyncio
77
+ # via pytest-xdist
75
78
  pytest-asyncio==0.24.0
79
+ pytest-xdist==3.7.0
76
80
  python-dateutil==2.8.2
77
81
  # via time-machine
78
82
  pytz==2023.3.post1
@@ -36,6 +36,7 @@ from ._exceptions import (
36
36
  UnprocessableEntityError,
37
37
  APIResponseValidationError,
38
38
  )
39
+ from .lib.polling import TaskFailedError, TaskTimeoutError
39
40
  from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient
40
41
  from ._utils._logs import setup_logging as _setup_logging
41
42
 
@@ -78,6 +79,8 @@ __all__ = [
78
79
  "DEFAULT_CONNECTION_LIMITS",
79
80
  "DefaultHttpxClient",
80
81
  "DefaultAsyncHttpxClient",
82
+ "TaskFailedError",
83
+ "TaskTimeoutError",
81
84
  ]
82
85
 
83
86
  if not _t.TYPE_CHECKING:
@@ -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
 
@@ -1574,7 +1581,14 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1574
1581
  ) -> ResponseT:
1575
1582
  origin = get_origin(cast_to) or cast_to
1576
1583
 
1577
- if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
1584
+ if (
1585
+ inspect.isclass(origin)
1586
+ and issubclass(origin, BaseAPIResponse)
1587
+ # we only want to actually return the custom BaseAPIResponse class if we're
1588
+ # returning the raw response, or if we're not streaming SSE, as if we're streaming
1589
+ # SSE then `cast_to` doesn't actively reflect the type we need to parse into
1590
+ and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
1591
+ ):
1578
1592
  if not issubclass(origin, AsyncAPIResponse):
1579
1593
  raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}")
1580
1594
 
@@ -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.5.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
+ """
@@ -20,7 +20,7 @@ class TestImageToVideo:
20
20
  @parametrize
21
21
  def test_method_create(self, client: RunwayML) -> None:
22
22
  image_to_video = client.image_to_video.create(
23
- model="gen4_turbo",
23
+ model="gen3a_turbo",
24
24
  prompt_image="https://example.com",
25
25
  ratio="1280:720",
26
26
  )
@@ -29,9 +29,10 @@ class TestImageToVideo:
29
29
  @parametrize
30
30
  def test_method_create_with_all_params(self, client: RunwayML) -> None:
31
31
  image_to_video = client.image_to_video.create(
32
- model="gen4_turbo",
32
+ model="gen3a_turbo",
33
33
  prompt_image="https://example.com",
34
34
  ratio="1280:720",
35
+ content_moderation={"public_figure_threshold": "auto"},
35
36
  duration=5,
36
37
  prompt_text="promptText",
37
38
  seed=0,
@@ -41,7 +42,7 @@ class TestImageToVideo:
41
42
  @parametrize
42
43
  def test_raw_response_create(self, client: RunwayML) -> None:
43
44
  response = client.image_to_video.with_raw_response.create(
44
- model="gen4_turbo",
45
+ model="gen3a_turbo",
45
46
  prompt_image="https://example.com",
46
47
  ratio="1280:720",
47
48
  )
@@ -54,7 +55,7 @@ class TestImageToVideo:
54
55
  @parametrize
55
56
  def test_streaming_response_create(self, client: RunwayML) -> None:
56
57
  with client.image_to_video.with_streaming_response.create(
57
- model="gen4_turbo",
58
+ model="gen3a_turbo",
58
59
  prompt_image="https://example.com",
59
60
  ratio="1280:720",
60
61
  ) as response:
@@ -73,7 +74,7 @@ class TestAsyncImageToVideo:
73
74
  @parametrize
74
75
  async def test_method_create(self, async_client: AsyncRunwayML) -> None:
75
76
  image_to_video = await async_client.image_to_video.create(
76
- model="gen4_turbo",
77
+ model="gen3a_turbo",
77
78
  prompt_image="https://example.com",
78
79
  ratio="1280:720",
79
80
  )
@@ -82,9 +83,10 @@ class TestAsyncImageToVideo:
82
83
  @parametrize
83
84
  async def test_method_create_with_all_params(self, async_client: AsyncRunwayML) -> None:
84
85
  image_to_video = await async_client.image_to_video.create(
85
- model="gen4_turbo",
86
+ model="gen3a_turbo",
86
87
  prompt_image="https://example.com",
87
88
  ratio="1280:720",
89
+ content_moderation={"public_figure_threshold": "auto"},
88
90
  duration=5,
89
91
  prompt_text="promptText",
90
92
  seed=0,
@@ -94,7 +96,7 @@ class TestAsyncImageToVideo:
94
96
  @parametrize
95
97
  async def test_raw_response_create(self, async_client: AsyncRunwayML) -> None:
96
98
  response = await async_client.image_to_video.with_raw_response.create(
97
- model="gen4_turbo",
99
+ model="gen3a_turbo",
98
100
  prompt_image="https://example.com",
99
101
  ratio="1280:720",
100
102
  )
@@ -107,7 +109,7 @@ class TestAsyncImageToVideo:
107
109
  @parametrize
108
110
  async def test_streaming_response_create(self, async_client: AsyncRunwayML) -> None:
109
111
  async with async_client.image_to_video.with_streaming_response.create(
110
- model="gen4_turbo",
112
+ model="gen3a_turbo",
111
113
  prompt_image="https://example.com",
112
114
  ratio="1280:720",
113
115
  ) as response:
@@ -1,3 +1,5 @@
1
+ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+
1
3
  from __future__ import annotations
2
4
 
3
5
  import os
@@ -31,6 +31,8 @@ from runwayml._base_client import (
31
31
  DEFAULT_TIMEOUT,
32
32
  HTTPX_DEFAULT_TIMEOUT,
33
33
  BaseClient,
34
+ DefaultHttpxClient,
35
+ DefaultAsyncHttpxClient,
34
36
  make_request_options,
35
37
  )
36
38
  from runwayml.types.image_to_video_create_params import ImageToVideoCreateParams
@@ -790,7 +792,7 @@ class TestRunwayML:
790
792
  respx_mock.post("/v1/image_to_video").mock(side_effect=retry_handler)
791
793
 
792
794
  response = client.image_to_video.with_raw_response.create(
793
- model="gen4_turbo", prompt_image="https://example.com", ratio="1280:720"
795
+ model="gen3a_turbo", prompt_image="https://example.com", ratio="1280:720"
794
796
  )
795
797
 
796
798
  assert response.retries_taken == failures_before_success
@@ -816,7 +818,7 @@ class TestRunwayML:
816
818
  respx_mock.post("/v1/image_to_video").mock(side_effect=retry_handler)
817
819
 
818
820
  response = client.image_to_video.with_raw_response.create(
819
- model="gen4_turbo",
821
+ model="gen3a_turbo",
820
822
  prompt_image="https://example.com",
821
823
  ratio="1280:720",
822
824
  extra_headers={"x-stainless-retry-count": Omit()},
@@ -844,7 +846,7 @@ class TestRunwayML:
844
846
  respx_mock.post("/v1/image_to_video").mock(side_effect=retry_handler)
845
847
 
846
848
  response = client.image_to_video.with_raw_response.create(
847
- model="gen4_turbo",
849
+ model="gen3a_turbo",
848
850
  prompt_image="https://example.com",
849
851
  ratio="1280:720",
850
852
  extra_headers={"x-stainless-retry-count": "42"},
@@ -852,6 +854,28 @@ class TestRunwayML:
852
854
 
853
855
  assert response.http_request.headers.get("x-stainless-retry-count") == "42"
854
856
 
857
+ def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None:
858
+ # Test that the proxy environment variables are set correctly
859
+ monkeypatch.setenv("HTTPS_PROXY", "https://example.org")
860
+
861
+ client = DefaultHttpxClient()
862
+
863
+ mounts = tuple(client._mounts.items())
864
+ assert len(mounts) == 1
865
+ assert mounts[0][0].pattern == "https://"
866
+
867
+ @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning")
868
+ def test_default_client_creation(self) -> None:
869
+ # Ensure that the client can be initialized without any exceptions
870
+ DefaultHttpxClient(
871
+ verify=True,
872
+ cert=None,
873
+ trust_env=True,
874
+ http1=True,
875
+ http2=False,
876
+ limits=httpx.Limits(max_connections=100, max_keepalive_connections=20),
877
+ )
878
+
855
879
  @pytest.mark.respx(base_url=base_url)
856
880
  def test_follow_redirects(self, respx_mock: MockRouter) -> None:
857
881
  # Test that the default follow_redirects=True allows following redirects
@@ -1628,7 +1652,7 @@ class TestAsyncRunwayML:
1628
1652
  respx_mock.post("/v1/image_to_video").mock(side_effect=retry_handler)
1629
1653
 
1630
1654
  response = await client.image_to_video.with_raw_response.create(
1631
- model="gen4_turbo", prompt_image="https://example.com", ratio="1280:720"
1655
+ model="gen3a_turbo", prompt_image="https://example.com", ratio="1280:720"
1632
1656
  )
1633
1657
 
1634
1658
  assert response.retries_taken == failures_before_success
@@ -1655,7 +1679,7 @@ class TestAsyncRunwayML:
1655
1679
  respx_mock.post("/v1/image_to_video").mock(side_effect=retry_handler)
1656
1680
 
1657
1681
  response = await client.image_to_video.with_raw_response.create(
1658
- model="gen4_turbo",
1682
+ model="gen3a_turbo",
1659
1683
  prompt_image="https://example.com",
1660
1684
  ratio="1280:720",
1661
1685
  extra_headers={"x-stainless-retry-count": Omit()},
@@ -1684,7 +1708,7 @@ class TestAsyncRunwayML:
1684
1708
  respx_mock.post("/v1/image_to_video").mock(side_effect=retry_handler)
1685
1709
 
1686
1710
  response = await client.image_to_video.with_raw_response.create(
1687
- model="gen4_turbo",
1711
+ model="gen3a_turbo",
1688
1712
  prompt_image="https://example.com",
1689
1713
  ratio="1280:720",
1690
1714
  extra_headers={"x-stainless-retry-count": "42"},
@@ -1737,6 +1761,28 @@ class TestAsyncRunwayML:
1737
1761
 
1738
1762
  time.sleep(0.1)
1739
1763
 
1764
+ async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None:
1765
+ # Test that the proxy environment variables are set correctly
1766
+ monkeypatch.setenv("HTTPS_PROXY", "https://example.org")
1767
+
1768
+ client = DefaultAsyncHttpxClient()
1769
+
1770
+ mounts = tuple(client._mounts.items())
1771
+ assert len(mounts) == 1
1772
+ assert mounts[0][0].pattern == "https://"
1773
+
1774
+ @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning")
1775
+ async def test_default_client_creation(self) -> None:
1776
+ # Ensure that the client can be initialized without any exceptions
1777
+ DefaultAsyncHttpxClient(
1778
+ verify=True,
1779
+ cert=None,
1780
+ trust_env=True,
1781
+ http1=True,
1782
+ http2=False,
1783
+ limits=httpx.Limits(max_connections=100, max_keepalive_connections=20),
1784
+ )
1785
+
1740
1786
  @pytest.mark.respx(base_url=base_url)
1741
1787
  async def test_follow_redirects(self, respx_mock: MockRouter) -> None:
1742
1788
  # Test that the default follow_redirects=True allows following redirects
@@ -1,3 +0,0 @@
1
- {
2
- ".": "3.4.0"
3
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes