modal 1.1.1.dev38__tar.gz → 1.1.1.dev39__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.

Potentially problematic release.


This version of modal might be problematic. Click here for more details.

Files changed (189) hide show
  1. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/PKG-INFO +1 -1
  2. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_output.py +2 -2
  3. modal-1.1.1.dev39/modal/_utils/time_utils.py +19 -0
  4. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/app.py +4 -4
  5. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/cluster.py +2 -2
  6. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/container.py +2 -2
  7. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/dict.py +2 -2
  8. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/network_file_system.py +2 -2
  9. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/queues.py +2 -2
  10. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/secret.py +3 -3
  11. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/volume.py +3 -3
  12. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/client.pyi +2 -2
  13. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/dict.py +2 -1
  14. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/functions.pyi +6 -6
  15. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/queue.py +2 -1
  16. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/secret.py +2 -1
  17. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/volume.py +2 -1
  18. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal.egg-info/PKG-INFO +1 -1
  19. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_version/__init__.py +1 -1
  20. modal-1.1.1.dev38/modal/_utils/time_utils.py +0 -15
  21. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/LICENSE +0 -0
  22. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/README.md +0 -0
  23. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/__init__.py +0 -0
  24. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/__main__.py +0 -0
  25. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_clustered_functions.py +0 -0
  26. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_clustered_functions.pyi +0 -0
  27. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_container_entrypoint.py +0 -0
  28. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_functions.py +0 -0
  29. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_ipython.py +0 -0
  30. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_location.py +0 -0
  31. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_object.py +0 -0
  32. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_partial_function.py +0 -0
  33. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_pty.py +0 -0
  34. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_resolver.py +0 -0
  35. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_resources.py +0 -0
  36. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_runtime/__init__.py +0 -0
  37. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_runtime/asgi.py +0 -0
  38. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_runtime/container_io_manager.py +0 -0
  39. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_runtime/container_io_manager.pyi +0 -0
  40. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_runtime/execution_context.py +0 -0
  41. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_runtime/execution_context.pyi +0 -0
  42. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  43. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_runtime/telemetry.py +0 -0
  44. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_runtime/user_code_imports.py +0 -0
  45. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_serialization.py +0 -0
  46. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_traceback.py +0 -0
  47. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_tunnel.py +0 -0
  48. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_tunnel.pyi +0 -0
  49. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_type_manager.py +0 -0
  50. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/__init__.py +0 -0
  51. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/app_utils.py +0 -0
  52. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/async_utils.py +0 -0
  53. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/auth_token_manager.py +0 -0
  54. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/blob_utils.py +0 -0
  55. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/bytes_io_segment_payload.py +0 -0
  56. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/deprecation.py +0 -0
  57. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/docker_utils.py +0 -0
  58. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/function_utils.py +0 -0
  59. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/git_utils.py +0 -0
  60. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/grpc_testing.py +0 -0
  61. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/grpc_utils.py +0 -0
  62. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/hash_utils.py +0 -0
  63. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/http_utils.py +0 -0
  64. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/jwt_utils.py +0 -0
  65. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/logger.py +0 -0
  66. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/mount_utils.py +0 -0
  67. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/name_utils.py +0 -0
  68. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/package_utils.py +0 -0
  69. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/pattern_utils.py +0 -0
  70. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/rand_pb_testing.py +0 -0
  71. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_utils/shell_utils.py +0 -0
  72. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_vendor/__init__.py +0 -0
  73. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  74. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_vendor/cloudpickle.py +0 -0
  75. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_vendor/tblib.py +0 -0
  76. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/_watcher.py +0 -0
  77. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/app.py +0 -0
  78. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/app.pyi +0 -0
  79. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/builder/2023.12.312.txt +0 -0
  80. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/builder/2023.12.txt +0 -0
  81. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/builder/2024.04.txt +0 -0
  82. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/builder/2024.10.txt +0 -0
  83. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/builder/2025.06.txt +0 -0
  84. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/builder/PREVIEW.txt +0 -0
  85. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/builder/README.md +0 -0
  86. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/builder/base-images.json +0 -0
  87. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/call_graph.py +0 -0
  88. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/__init__.py +0 -0
  89. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/_download.py +0 -0
  90. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/_traceback.py +0 -0
  91. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/config.py +0 -0
  92. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/entry_point.py +0 -0
  93. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/environment.py +0 -0
  94. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/import_refs.py +0 -0
  95. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/launch.py +0 -0
  96. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/profile.py +0 -0
  97. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/programs/__init__.py +0 -0
  98. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/programs/run_jupyter.py +0 -0
  99. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/programs/vscode.py +0 -0
  100. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/run.py +0 -0
  101. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/token.py +0 -0
  102. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cli/utils.py +0 -0
  103. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/client.py +0 -0
  104. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cloud_bucket_mount.py +0 -0
  105. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cloud_bucket_mount.pyi +0 -0
  106. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cls.py +0 -0
  107. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/cls.pyi +0 -0
  108. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/config.py +0 -0
  109. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/container_process.py +0 -0
  110. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/container_process.pyi +0 -0
  111. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/dict.pyi +0 -0
  112. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/environments.py +0 -0
  113. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/environments.pyi +0 -0
  114. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/exception.py +0 -0
  115. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/experimental/__init__.py +0 -0
  116. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/experimental/flash.py +0 -0
  117. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/experimental/flash.pyi +0 -0
  118. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/experimental/ipython.py +0 -0
  119. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/file_io.py +0 -0
  120. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/file_io.pyi +0 -0
  121. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/file_pattern_matcher.py +0 -0
  122. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/functions.py +0 -0
  123. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/gpu.py +0 -0
  124. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/image.py +0 -0
  125. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/image.pyi +0 -0
  126. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/io_streams.py +0 -0
  127. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/io_streams.pyi +0 -0
  128. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/mount.py +0 -0
  129. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/mount.pyi +0 -0
  130. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/network_file_system.py +0 -0
  131. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/network_file_system.pyi +0 -0
  132. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/object.py +0 -0
  133. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/object.pyi +0 -0
  134. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/output.py +0 -0
  135. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/parallel_map.py +0 -0
  136. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/parallel_map.pyi +0 -0
  137. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/partial_function.py +0 -0
  138. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/partial_function.pyi +0 -0
  139. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/proxy.py +0 -0
  140. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/proxy.pyi +0 -0
  141. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/py.typed +0 -0
  142. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/queue.pyi +0 -0
  143. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/retries.py +0 -0
  144. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/runner.py +0 -0
  145. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/runner.pyi +0 -0
  146. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/running_app.py +0 -0
  147. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/sandbox.py +0 -0
  148. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/sandbox.pyi +0 -0
  149. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/schedule.py +0 -0
  150. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/scheduler_placement.py +0 -0
  151. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/secret.pyi +0 -0
  152. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/serving.py +0 -0
  153. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/serving.pyi +0 -0
  154. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/snapshot.py +0 -0
  155. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/snapshot.pyi +0 -0
  156. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/stream_type.py +0 -0
  157. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/token_flow.py +0 -0
  158. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/token_flow.pyi +0 -0
  159. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal/volume.pyi +0 -0
  160. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal.egg-info/SOURCES.txt +0 -0
  161. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal.egg-info/dependency_links.txt +0 -0
  162. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal.egg-info/entry_points.txt +0 -0
  163. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal.egg-info/requires.txt +0 -0
  164. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal.egg-info/top_level.txt +0 -0
  165. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_docs/__init__.py +0 -0
  166. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_docs/gen_cli_docs.py +0 -0
  167. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_docs/gen_reference_docs.py +0 -0
  168. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_docs/mdmd/__init__.py +0 -0
  169. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_docs/mdmd/mdmd.py +0 -0
  170. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_docs/mdmd/signatures.py +0 -0
  171. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/__init__.py +0 -0
  172. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/api.proto +0 -0
  173. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/api_grpc.py +0 -0
  174. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/api_pb2.py +0 -0
  175. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/api_pb2.pyi +0 -0
  176. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/api_pb2_grpc.py +0 -0
  177. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/api_pb2_grpc.pyi +0 -0
  178. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/modal_api_grpc.py +0 -0
  179. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/modal_options_grpc.py +0 -0
  180. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/options.proto +0 -0
  181. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/options_grpc.py +0 -0
  182. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/options_pb2.py +0 -0
  183. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/options_pb2.pyi +0 -0
  184. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/options_pb2_grpc.py +0 -0
  185. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/options_pb2_grpc.pyi +0 -0
  186. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_proto/py.typed +0 -0
  187. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/modal_version/__main__.py +0 -0
  188. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/pyproject.toml +0 -0
  189. {modal-1.1.1.dev38 → modal-1.1.1.dev39}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.1.dev38
3
+ Version: 1.1.1.dev39
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -31,7 +31,7 @@ from rich.progress import (
31
31
  from rich.spinner import Spinner
32
32
  from rich.text import Text
33
33
 
34
- from modal._utils.time_utils import timestamp_to_local
34
+ from modal._utils.time_utils import timestamp_to_localized_str
35
35
  from modal_proto import api_pb2
36
36
 
37
37
  from ._utils.grpc_utils import RETRYABLE_GRPC_STATUS_CODES, retry_transient_errors
@@ -91,7 +91,7 @@ class LineBufferedOutput:
91
91
 
92
92
  if self._show_timestamps:
93
93
  for i in range(0, len(chunks) - 1, 2):
94
- chunks[i] = f"{timestamp_to_local(log.timestamp)} {chunks[i]}"
94
+ chunks[i] = f"{timestamp_to_localized_str(log.timestamp)} {chunks[i]}"
95
95
 
96
96
  completed_lines = "".join(chunks[:-1])
97
97
  remainder = chunks[-1]
@@ -0,0 +1,19 @@
1
+ # Copyright Modal Labs 2025
2
+ from datetime import datetime
3
+ from typing import Optional
4
+
5
+
6
+ def timestamp_to_localized_dt(ts: float) -> datetime:
7
+ locale_tz = datetime.now().astimezone().tzinfo
8
+ return datetime.fromtimestamp(ts, tz=locale_tz)
9
+
10
+
11
+ def timestamp_to_localized_str(ts: float, isotz: bool = True) -> Optional[str]:
12
+ if ts > 0:
13
+ dt = timestamp_to_localized_dt(ts)
14
+ if isotz:
15
+ return dt.isoformat(sep=" ", timespec="seconds")
16
+ else:
17
+ return f"{dt:%Y-%m-%d %H:%M %Z}"
18
+ else:
19
+ return None
@@ -15,7 +15,7 @@ from modal.client import _Client
15
15
  from modal.environments import ensure_env
16
16
  from modal_proto import api_pb2
17
17
 
18
- from .._utils.time_utils import timestamp_to_local
18
+ from .._utils.time_utils import timestamp_to_localized_str
19
19
  from .utils import ENV_OPTION, display_table, get_app_id_from_name, stream_app_logs
20
20
 
21
21
  APP_IDENTIFIER = Argument("", help="App name or ID")
@@ -71,8 +71,8 @@ async def list_(env: Optional[str] = ENV_OPTION, json: bool = False):
71
71
  app_stats.description,
72
72
  state,
73
73
  str(app_stats.n_running_tasks),
74
- timestamp_to_local(app_stats.created_at, json),
75
- timestamp_to_local(app_stats.stopped_at, json),
74
+ timestamp_to_localized_str(app_stats.created_at, json),
75
+ timestamp_to_localized_str(app_stats.stopped_at, json),
76
76
  ]
77
77
  )
78
78
 
@@ -217,7 +217,7 @@ async def history(
217
217
 
218
218
  row = [
219
219
  Text(f"v{app_stats.version}", style=style),
220
- Text(timestamp_to_local(app_stats.deployed_at, json), style=style),
220
+ Text(timestamp_to_localized_str(app_stats.deployed_at, json), style=style),
221
221
  Text(app_stats.client_version, style=style),
222
222
  Text(app_stats.deployed_by, style=style),
223
223
  ]
@@ -8,7 +8,7 @@ from modal._object import _get_environment_name
8
8
  from modal._output import make_console
9
9
  from modal._pty import get_pty_info
10
10
  from modal._utils.async_utils import synchronizer
11
- from modal._utils.time_utils import timestamp_to_local
11
+ from modal._utils.time_utils import timestamp_to_localized_str
12
12
  from modal.cli.utils import ENV_OPTION, display_table, is_tty
13
13
  from modal.client import _Client
14
14
  from modal.config import config
@@ -42,7 +42,7 @@ async def list_(env: Optional[str] = ENV_OPTION, json: bool = False):
42
42
  [
43
43
  c.cluster_id,
44
44
  c.app_id,
45
- timestamp_to_local(c.started_at, json) if c.started_at else "Pending",
45
+ timestamp_to_localized_str(c.started_at, json) if c.started_at else "Pending",
46
46
  str(len(c.task_ids)),
47
47
  ]
48
48
  )
@@ -8,7 +8,7 @@ from modal._object import _get_environment_name
8
8
  from modal._pty import get_pty_info
9
9
  from modal._utils.async_utils import synchronizer
10
10
  from modal._utils.grpc_utils import retry_transient_errors
11
- from modal._utils.time_utils import timestamp_to_local
11
+ from modal._utils.time_utils import timestamp_to_localized_str
12
12
  from modal.cli.utils import ENV_OPTION, display_table, is_tty, stream_app_logs
13
13
  from modal.client import _Client
14
14
  from modal.config import config
@@ -40,7 +40,7 @@ async def list_(env: Optional[str] = ENV_OPTION, json: bool = False):
40
40
  task_stats.task_id,
41
41
  task_stats.app_id,
42
42
  task_stats.app_description,
43
- timestamp_to_local(task_stats.started_at, json) if task_stats.started_at else "Pending",
43
+ timestamp_to_localized_str(task_stats.started_at, json) if task_stats.started_at else "Pending",
44
44
  ]
45
45
  )
46
46
 
@@ -8,7 +8,7 @@ from modal._output import make_console
8
8
  from modal._resolver import Resolver
9
9
  from modal._utils.async_utils import synchronizer
10
10
  from modal._utils.grpc_utils import retry_transient_errors
11
- from modal._utils.time_utils import timestamp_to_local
11
+ from modal._utils.time_utils import timestamp_to_localized_str
12
12
  from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
13
13
  from modal.client import _Client
14
14
  from modal.dict import _Dict
@@ -44,7 +44,7 @@ async def list_(*, json: bool = False, env: Optional[str] = ENV_OPTION):
44
44
  request = api_pb2.DictListRequest(environment_name=env)
45
45
  response = await retry_transient_errors(client.stub.DictList, request)
46
46
 
47
- rows = [(d.name, timestamp_to_local(d.created_at, json)) for d in response.dicts]
47
+ rows = [(d.name, timestamp_to_localized_str(d.created_at, json)) for d in response.dicts]
48
48
  display_table(["Name", "Created at"], rows, json)
49
49
 
50
50
 
@@ -16,7 +16,7 @@ from modal._location import display_location
16
16
  from modal._output import OutputManager, ProgressHandler, make_console
17
17
  from modal._utils.async_utils import synchronizer
18
18
  from modal._utils.grpc_utils import retry_transient_errors
19
- from modal._utils.time_utils import timestamp_to_local
19
+ from modal._utils.time_utils import timestamp_to_localized_str
20
20
  from modal.cli._download import _volume_download
21
21
  from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
22
22
  from modal.client import _Client
@@ -44,7 +44,7 @@ async def list_(env: Optional[str] = ENV_OPTION, json: Optional[bool] = False):
44
44
  [
45
45
  item.label,
46
46
  display_location(item.cloud_provider),
47
- timestamp_to_local(item.created_at, json),
47
+ timestamp_to_localized_str(item.created_at, json),
48
48
  ]
49
49
  )
50
50
  display_table(column_names, rows, json, title=f"Shared Volumes{env_part}")
@@ -8,7 +8,7 @@ from modal._output import make_console
8
8
  from modal._resolver import Resolver
9
9
  from modal._utils.async_utils import synchronizer
10
10
  from modal._utils.grpc_utils import retry_transient_errors
11
- from modal._utils.time_utils import timestamp_to_local
11
+ from modal._utils.time_utils import timestamp_to_localized_str
12
12
  from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
13
13
  from modal.client import _Client
14
14
  from modal.environments import ensure_env
@@ -71,7 +71,7 @@ async def list_(*, json: bool = False, env: Optional[str] = ENV_OPTION):
71
71
  rows = [
72
72
  (
73
73
  q.name,
74
- timestamp_to_local(q.created_at, json),
74
+ timestamp_to_localized_str(q.created_at, json),
75
75
  str(q.num_partitions),
76
76
  str(q.total_size) if q.total_size <= max_total_size else f">{max_total_size}",
77
77
  )
@@ -15,7 +15,7 @@ from typer import Argument
15
15
  from modal._output import make_console
16
16
  from modal._utils.async_utils import synchronizer
17
17
  from modal._utils.grpc_utils import retry_transient_errors
18
- from modal._utils.time_utils import timestamp_to_local
18
+ from modal._utils.time_utils import timestamp_to_localized_str
19
19
  from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
20
20
  from modal.client import _Client
21
21
  from modal.environments import ensure_env
@@ -38,8 +38,8 @@ async def list_(env: Optional[str] = ENV_OPTION, json: bool = False):
38
38
  rows.append(
39
39
  [
40
40
  item.label,
41
- timestamp_to_local(item.created_at, json),
42
- timestamp_to_local(item.last_used_at, json) if item.last_used_at else "-",
41
+ timestamp_to_localized_str(item.created_at, json),
42
+ timestamp_to_localized_str(item.last_used_at, json) if item.last_used_at else "-",
43
43
  ]
44
44
  )
45
45
 
@@ -14,7 +14,7 @@ import modal
14
14
  from modal._output import OutputManager, ProgressHandler, make_console
15
15
  from modal._utils.async_utils import synchronizer
16
16
  from modal._utils.grpc_utils import retry_transient_errors
17
- from modal._utils.time_utils import timestamp_to_local
17
+ from modal._utils.time_utils import timestamp_to_localized_str
18
18
  from modal.cli._download import _volume_download
19
19
  from modal.cli.utils import ENV_OPTION, YES_OPTION, display_table
20
20
  from modal.client import _Client
@@ -116,7 +116,7 @@ async def list_(env: Optional[str] = ENV_OPTION, json: Optional[bool] = False):
116
116
  column_names = ["Name", "Created at"]
117
117
  rows = []
118
118
  for item in response.items:
119
- rows.append([item.label, timestamp_to_local(item.created_at, json)])
119
+ rows.append([item.label, timestamp_to_localized_str(item.created_at, json)])
120
120
  display_table(column_names, rows, json, title=f"Volumes{env_part}")
121
121
 
122
122
 
@@ -163,7 +163,7 @@ async def ls(
163
163
  (
164
164
  entry.path.encode("unicode_escape").decode("utf-8"),
165
165
  filetype,
166
- timestamp_to_local(entry.mtime, False),
166
+ timestamp_to_localized_str(entry.mtime, False),
167
167
  humanize_filesize(entry.size),
168
168
  )
169
169
  )
@@ -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.1.1.dev38",
36
+ version: str = "1.1.1.dev39",
37
37
  ):
38
38
  """mdmd:hidden
39
39
  The Modal client object is not intended to be instantiated directly by users.
@@ -164,7 +164,7 @@ class Client:
164
164
  server_url: str,
165
165
  client_type: int,
166
166
  credentials: typing.Optional[tuple[str, str]],
167
- version: str = "1.1.1.dev38",
167
+ version: str = "1.1.1.dev39",
168
168
  ):
169
169
  """mdmd:hidden
170
170
  The Modal client object is not intended to be instantiated directly by users.
@@ -17,6 +17,7 @@ from ._utils.async_utils import TaskContext, synchronize_api
17
17
  from ._utils.deprecation import deprecation_warning, warn_if_passing_namespace
18
18
  from ._utils.grpc_utils import retry_transient_errors
19
19
  from ._utils.name_utils import check_object_name
20
+ from ._utils.time_utils import timestamp_to_localized_dt
20
21
  from .client import _Client
21
22
  from .config import logger
22
23
  from .exception import RequestSizeError
@@ -248,7 +249,7 @@ class _Dict(_Object, type_prefix="di"):
248
249
  creation_info = metadata.creation_info
249
250
  return DictInfo(
250
251
  name=metadata.name or None,
251
- created_at=datetime.fromtimestamp(creation_info.created_at),
252
+ created_at=timestamp_to_localized_dt(creation_info.created_at),
252
253
  created_by=creation_info.created_by or None,
253
254
  )
254
255
 
@@ -427,7 +427,7 @@ class Function(
427
427
 
428
428
  _call_generator: ___call_generator_spec[typing_extensions.Self]
429
429
 
430
- class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
430
+ class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
431
431
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
432
432
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
433
433
  ...
@@ -436,7 +436,7 @@ class Function(
436
436
  """Calls the function remotely, executing it with the given arguments and returning the execution's result."""
437
437
  ...
438
438
 
439
- remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
439
+ remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
440
440
 
441
441
  class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
442
442
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -463,7 +463,7 @@ class Function(
463
463
  """
464
464
  ...
465
465
 
466
- class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
466
+ class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
467
467
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
468
468
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
469
469
 
@@ -487,7 +487,7 @@ class Function(
487
487
  ...
488
488
 
489
489
  _experimental_spawn: ___experimental_spawn_spec[
490
- modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
490
+ modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
491
491
  ]
492
492
 
493
493
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
@@ -496,7 +496,7 @@ class Function(
496
496
 
497
497
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
498
498
 
499
- class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
499
+ class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
500
500
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
501
501
  """Calls the function with the given arguments, without waiting for the results.
502
502
 
@@ -517,7 +517,7 @@ class Function(
517
517
  """
518
518
  ...
519
519
 
520
- spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
520
+ spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
521
521
 
522
522
  def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
523
523
  """Return the inner Python object wrapped by this Modal Function."""
@@ -20,6 +20,7 @@ from ._utils.async_utils import TaskContext, synchronize_api, warn_if_generator_
20
20
  from ._utils.deprecation import deprecation_warning, warn_if_passing_namespace
21
21
  from ._utils.grpc_utils import retry_transient_errors
22
22
  from ._utils.name_utils import check_object_name
23
+ from ._utils.time_utils import timestamp_to_localized_dt
23
24
  from .client import _Client
24
25
  from .exception import InvalidError, RequestSizeError
25
26
 
@@ -260,7 +261,7 @@ class _Queue(_Object, type_prefix="qu"):
260
261
  creation_info = metadata.creation_info
261
262
  return QueueInfo(
262
263
  name=metadata.name or None,
263
- created_at=datetime.fromtimestamp(creation_info.created_at),
264
+ created_at=timestamp_to_localized_dt(creation_info.created_at),
264
265
  created_by=creation_info.created_by or None,
265
266
  )
266
267
 
@@ -16,6 +16,7 @@ from ._utils.async_utils import synchronize_api
16
16
  from ._utils.deprecation import deprecation_warning, warn_if_passing_namespace
17
17
  from ._utils.grpc_utils import retry_transient_errors
18
18
  from ._utils.name_utils import check_object_name
19
+ from ._utils.time_utils import timestamp_to_localized_dt
19
20
  from .client import _Client
20
21
  from .exception import InvalidError, NotFoundError
21
22
 
@@ -299,7 +300,7 @@ class _Secret(_Object, type_prefix="st"):
299
300
  creation_info = metadata.creation_info
300
301
  return SecretInfo(
301
302
  name=metadata.name or None,
302
- created_at=datetime.fromtimestamp(creation_info.created_at),
303
+ created_at=timestamp_to_localized_dt(creation_info.created_at),
303
304
  created_by=creation_info.created_by or None,
304
305
  )
305
306
 
@@ -55,6 +55,7 @@ from ._utils.deprecation import deprecation_warning, warn_if_passing_namespace
55
55
  from ._utils.grpc_utils import retry_transient_errors
56
56
  from ._utils.http_utils import ClientSessionRegistry
57
57
  from ._utils.name_utils import check_object_name
58
+ from ._utils.time_utils import timestamp_to_localized_dt
58
59
  from .client import _Client
59
60
  from .config import logger
60
61
 
@@ -364,7 +365,7 @@ class _Volume(_Object, type_prefix="vo"):
364
365
  creation_info = metadata.creation_info
365
366
  return VolumeInfo(
366
367
  name=metadata.name or None,
367
- created_at=datetime.fromtimestamp(creation_info.created_at) if creation_info.created_at else None,
368
+ created_at=timestamp_to_localized_dt(creation_info.created_at),
368
369
  created_by=creation_info.created_by or None,
369
370
  )
370
371
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.1.1.dev38
3
+ Version: 1.1.1.dev39
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.1.1.dev38"
4
+ __version__ = "1.1.1.dev39"
@@ -1,15 +0,0 @@
1
- # Copyright Modal Labs 2025
2
- from datetime import datetime
3
- from typing import Optional
4
-
5
-
6
- def timestamp_to_local(ts: float, isotz: bool = True) -> Optional[str]:
7
- if ts > 0:
8
- locale_tz = datetime.now().astimezone().tzinfo
9
- dt = datetime.fromtimestamp(ts, tz=locale_tz)
10
- if isotz:
11
- return dt.isoformat(sep=" ", timespec="seconds")
12
- else:
13
- return f"{datetime.strftime(dt, '%Y-%m-%d %H:%M')} {locale_tz.tzname(dt)}"
14
- else:
15
- return None
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