modAL 1.3.1.dev24__tar.gz → 1.3.1.dev25__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 (194) hide show
  1. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/PKG-INFO +1 -1
  2. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/run.py +53 -7
  3. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/client.pyi +2 -2
  4. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal.egg-info/PKG-INFO +1 -1
  5. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_version/__init__.py +1 -1
  6. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/LICENSE +0 -0
  7. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/README.md +0 -0
  8. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/__init__.py +0 -0
  9. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/__main__.py +0 -0
  10. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_billing.py +0 -0
  11. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_clustered_functions.py +0 -0
  12. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_clustered_functions.pyi +0 -0
  13. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_container_entrypoint.py +0 -0
  14. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_functions.py +0 -0
  15. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_grpc_client.py +0 -0
  16. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_ipython.py +0 -0
  17. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_load_context.py +0 -0
  18. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_location.py +0 -0
  19. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_object.py +0 -0
  20. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_output.py +0 -0
  21. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_partial_function.py +0 -0
  22. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_pty.py +0 -0
  23. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_resolver.py +0 -0
  24. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_resources.py +0 -0
  25. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_runtime/__init__.py +0 -0
  26. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_runtime/asgi.py +0 -0
  27. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_runtime/container_io_manager.py +0 -0
  28. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_runtime/container_io_manager.pyi +0 -0
  29. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_runtime/execution_context.py +0 -0
  30. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_runtime/execution_context.pyi +0 -0
  31. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  32. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_runtime/telemetry.py +0 -0
  33. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_runtime/user_code_event_loop.py +0 -0
  34. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_runtime/user_code_imports.py +0 -0
  35. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_serialization.py +0 -0
  36. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_traceback.py +0 -0
  37. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_tunnel.py +0 -0
  38. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_tunnel.pyi +0 -0
  39. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_type_manager.py +0 -0
  40. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/__init__.py +0 -0
  41. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/app_utils.py +0 -0
  42. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/async_utils.py +0 -0
  43. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/auth_token_manager.py +0 -0
  44. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/blob_utils.py +0 -0
  45. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/bytes_io_segment_payload.py +0 -0
  46. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/deprecation.py +0 -0
  47. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/docker_utils.py +0 -0
  48. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/function_utils.py +0 -0
  49. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/git_utils.py +0 -0
  50. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/grpc_testing.py +0 -0
  51. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/grpc_utils.py +0 -0
  52. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/hash_utils.py +0 -0
  53. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/http_utils.py +0 -0
  54. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/jwt_utils.py +0 -0
  55. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/logger.py +0 -0
  56. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/mount_utils.py +0 -0
  57. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/name_utils.py +0 -0
  58. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/package_utils.py +0 -0
  59. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/pattern_utils.py +0 -0
  60. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/rand_pb_testing.py +0 -0
  61. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/shell_utils.py +0 -0
  62. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/task_command_router_client.py +0 -0
  63. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_utils/time_utils.py +0 -0
  64. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_vendor/__init__.py +0 -0
  65. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  66. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_vendor/cloudpickle.py +0 -0
  67. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_vendor/tblib.py +0 -0
  68. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/_watcher.py +0 -0
  69. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/app.py +0 -0
  70. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/app.pyi +0 -0
  71. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/billing.py +0 -0
  72. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/builder/2023.12.312.txt +0 -0
  73. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/builder/2023.12.txt +0 -0
  74. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/builder/2024.04.txt +0 -0
  75. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/builder/2024.10.txt +0 -0
  76. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/builder/2025.06.txt +0 -0
  77. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/builder/PREVIEW.txt +0 -0
  78. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/builder/README.md +0 -0
  79. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/builder/base-images.json +0 -0
  80. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/call_graph.py +0 -0
  81. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/__init__.py +0 -0
  82. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/_download.py +0 -0
  83. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/_traceback.py +0 -0
  84. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/app.py +0 -0
  85. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/cluster.py +0 -0
  86. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/config.py +0 -0
  87. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/container.py +0 -0
  88. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/dict.py +0 -0
  89. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/entry_point.py +0 -0
  90. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/environment.py +0 -0
  91. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/import_refs.py +0 -0
  92. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/launch.py +0 -0
  93. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/network_file_system.py +0 -0
  94. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/profile.py +0 -0
  95. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/programs/__init__.py +0 -0
  96. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/programs/run_jupyter.py +0 -0
  97. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/programs/vscode.py +0 -0
  98. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/queues.py +0 -0
  99. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/secret.py +0 -0
  100. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/shell.py +0 -0
  101. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/token.py +0 -0
  102. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/utils.py +0 -0
  103. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cli/volume.py +0 -0
  104. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/client.py +0 -0
  105. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cloud_bucket_mount.py +0 -0
  106. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cloud_bucket_mount.pyi +0 -0
  107. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cls.py +0 -0
  108. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/cls.pyi +0 -0
  109. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/config.py +0 -0
  110. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/container_process.py +0 -0
  111. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/container_process.pyi +0 -0
  112. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/dict.py +0 -0
  113. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/dict.pyi +0 -0
  114. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/environments.py +0 -0
  115. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/environments.pyi +0 -0
  116. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/exception.py +0 -0
  117. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/experimental/__init__.py +0 -0
  118. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/experimental/flash.py +0 -0
  119. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/experimental/flash.pyi +0 -0
  120. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/experimental/ipython.py +0 -0
  121. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/file_io.py +0 -0
  122. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/file_io.pyi +0 -0
  123. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/file_pattern_matcher.py +0 -0
  124. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/functions.py +0 -0
  125. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/functions.pyi +0 -0
  126. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/gpu.py +0 -0
  127. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/image.py +0 -0
  128. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/image.pyi +0 -0
  129. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/io_streams.py +0 -0
  130. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/io_streams.pyi +0 -0
  131. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/mount.py +0 -0
  132. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/mount.pyi +0 -0
  133. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/network_file_system.py +0 -0
  134. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/network_file_system.pyi +0 -0
  135. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/object.py +0 -0
  136. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/object.pyi +0 -0
  137. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/output.py +0 -0
  138. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/parallel_map.py +0 -0
  139. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/parallel_map.pyi +0 -0
  140. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/partial_function.py +0 -0
  141. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/partial_function.pyi +0 -0
  142. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/proxy.py +0 -0
  143. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/proxy.pyi +0 -0
  144. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/py.typed +0 -0
  145. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/queue.py +0 -0
  146. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/queue.pyi +0 -0
  147. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/retries.py +0 -0
  148. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/runner.py +0 -0
  149. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/runner.pyi +0 -0
  150. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/running_app.py +0 -0
  151. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/sandbox.py +0 -0
  152. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/sandbox.pyi +0 -0
  153. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/schedule.py +0 -0
  154. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/scheduler_placement.py +0 -0
  155. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/secret.py +0 -0
  156. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/secret.pyi +0 -0
  157. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/serving.py +0 -0
  158. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/serving.pyi +0 -0
  159. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/snapshot.py +0 -0
  160. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/snapshot.pyi +0 -0
  161. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/stream_type.py +0 -0
  162. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/token_flow.py +0 -0
  163. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/token_flow.pyi +0 -0
  164. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/volume.py +0 -0
  165. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal/volume.pyi +0 -0
  166. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal.egg-info/SOURCES.txt +0 -0
  167. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal.egg-info/dependency_links.txt +0 -0
  168. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal.egg-info/entry_points.txt +0 -0
  169. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal.egg-info/requires.txt +0 -0
  170. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal.egg-info/top_level.txt +0 -0
  171. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_docs/__init__.py +0 -0
  172. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_docs/gen_cli_docs.py +0 -0
  173. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_docs/gen_reference_docs.py +0 -0
  174. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_docs/mdmd/__init__.py +0 -0
  175. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_docs/mdmd/mdmd.py +0 -0
  176. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_docs/mdmd/signatures.py +0 -0
  177. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/__init__.py +0 -0
  178. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/api.proto +0 -0
  179. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/api_grpc.py +0 -0
  180. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/api_pb2.py +0 -0
  181. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/api_pb2.pyi +0 -0
  182. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/api_pb2_grpc.py +0 -0
  183. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/api_pb2_grpc.pyi +0 -0
  184. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/modal_api_grpc.py +0 -0
  185. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/py.typed +0 -0
  186. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/task_command_router.proto +0 -0
  187. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/task_command_router_grpc.py +0 -0
  188. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/task_command_router_pb2.py +0 -0
  189. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/task_command_router_pb2.pyi +0 -0
  190. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  191. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  192. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/modal_version/__main__.py +0 -0
  193. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/pyproject.toml +0 -0
  194. {modal-1.3.1.dev24 → modal-1.3.1.dev25}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.3.1.dev24
3
+ Version: 1.3.1.dev25
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -49,6 +49,26 @@ class AnyParamType(click.ParamType):
49
49
  return value
50
50
 
51
51
 
52
+ class LiteralIntParamType(click.Choice):
53
+ """A ParamType for Literal types containing only integers."""
54
+
55
+ def __init__(self, literal_values: tuple[int, ...]):
56
+ self.int_values = {str(v): v for v in literal_values}
57
+ super().__init__(list(self.int_values.keys()))
58
+
59
+ def convert(self, value, param, ctx):
60
+ # If value is already an int (e.g., from a default), validate and return it
61
+ # Exclude bools since they're a subclass of int but we don't support them
62
+ if isinstance(value, int) and not isinstance(value, bool):
63
+ if value in self.int_values.values():
64
+ return value
65
+ # Invalid int - convert to string so Choice can generate a nice error message
66
+ value = str(value)
67
+ # Use Choice's validation for string inputs, then convert back to int
68
+ str_value = super().convert(value, param, ctx)
69
+ return self.int_values[str_value]
70
+
71
+
52
72
  option_parsers = {
53
73
  "str": str,
54
74
  "int": int,
@@ -99,6 +119,20 @@ def _get_cli_runnable_signature(sig: inspect.Signature, type_hints: dict[str, ty
99
119
  return CliRunnableSignature(signature, has_variadic_args)
100
120
 
101
121
 
122
+ def _get_literal_values(type_hint: Any) -> Optional[tuple[Any, ...]]:
123
+ """Extract values from a Literal type annotation.
124
+
125
+ Returns None if not a Literal type, otherwise returns tuple of literal values.
126
+ """
127
+ try:
128
+ origin = typing.get_origin(type_hint)
129
+ if origin is typing.Literal:
130
+ return typing.get_args(type_hint)
131
+ except Exception:
132
+ pass
133
+ return None
134
+
135
+
102
136
  def _get_param_type_as_str(annot: Any) -> str:
103
137
  """Return annotation as a string, handling various spellings for optional types."""
104
138
  annot_str = str(annot)
@@ -121,16 +155,28 @@ def _add_click_options(func, parameters: dict[str, ParameterMetadata]):
121
155
  Kind of like typer, but using options instead of positional arguments
122
156
  """
123
157
  for param in parameters.values():
124
- param_type_str = _get_param_type_as_str(param["type_hint"])
125
158
  param_name = param["name"].replace("_", "-")
126
159
  cli_name = "--" + param_name
127
- if param_type_str == "bool":
128
- cli_name += "/--no-" + param_name
129
160
 
130
- parser = option_parsers.get(param_type_str)
131
- if parser is None:
132
- msg = f"Parameter `{param_name}` has unparseable annotation: {param['annotation']}"
133
- raise NoParserAvailable(msg)
161
+ parser: Any
162
+ if (literal_values := _get_literal_values(param["type_hint"])) is not None:
163
+ if all(isinstance(v, str) for v in literal_values):
164
+ parser = click.Choice(list(literal_values))
165
+ elif all(isinstance(v, int) and not isinstance(v, bool) for v in literal_values):
166
+ parser = LiteralIntParamType(literal_values)
167
+ else:
168
+ # Mixed types, booleans, or other unsupported types
169
+ msg = f"Parameter `{param_name}` has unparseable annotation: {param['annotation']}"
170
+ raise NoParserAvailable(msg)
171
+ else:
172
+ param_type_str = _get_param_type_as_str(param["type_hint"])
173
+ if param_type_str == "bool":
174
+ cli_name += "/--no-" + param_name
175
+
176
+ parser = option_parsers.get(param_type_str)
177
+ if parser is None:
178
+ msg = f"Parameter `{param_name}` has unparseable annotation: {param['annotation']}"
179
+ raise NoParserAvailable(msg)
134
180
  kwargs: Any = {
135
181
  "type": parser,
136
182
  }
@@ -33,7 +33,7 @@ class _Client:
33
33
  server_url: str,
34
34
  client_type: int,
35
35
  credentials: typing.Optional[tuple[str, str]],
36
- version: str = "1.3.1.dev24",
36
+ version: str = "1.3.1.dev25",
37
37
  ):
38
38
  """mdmd:hidden
39
39
  The Modal client object is not intended to be instantiated directly by users.
@@ -163,7 +163,7 @@ class Client:
163
163
  server_url: str,
164
164
  client_type: int,
165
165
  credentials: typing.Optional[tuple[str, str]],
166
- version: str = "1.3.1.dev24",
166
+ version: str = "1.3.1.dev25",
167
167
  ):
168
168
  """mdmd:hidden
169
169
  The Modal client object is not intended to be instantiated directly by users.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.3.1.dev24
3
+ Version: 1.3.1.dev25
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2025
2
2
  """Supplies the current version of the modal client library."""
3
3
 
4
- __version__ = "1.3.1.dev24"
4
+ __version__ = "1.3.1.dev25"
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
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