modAL 1.3.1.dev12__py3-none-any.whl → 1.3.1.dev14__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -92,8 +92,7 @@ class ConnectionManager:
92
92
 
93
93
  def __init__(self, client: "modal.client._Client", metadata: dict[str, str] = {}):
94
94
  self._client = client
95
- # Warning: This metadata is shared across all channels! If the metadata is mutated
96
- # in one `create_channel` call, the mutation will be reflected in all channels.
95
+ # This metadata is injected into all requests on all channels created by this manager.
97
96
  self._metadata = metadata
98
97
  self._channels: dict[str, grpclib.client.Channel] = {}
99
98
 
@@ -168,8 +167,7 @@ def create_channel(
168
167
  ) -> grpclib.client.Channel:
169
168
  """Creates a grpclib.Channel to be used by a GRPC stub.
170
169
 
171
- Note that this function mutates the given metadata argument by adding an x-modal-auth-token
172
- if one is present in the trailing metadata of any response.
170
+ The given metadata dict is injected into all outgoing requests on this channel.
173
171
  """
174
172
  o = urllib.parse.urlparse(server_url)
175
173
 
modal/client.pyi CHANGED
@@ -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.dev12",
36
+ version: str = "1.3.1.dev14",
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.dev12",
166
+ version: str = "1.3.1.dev14",
167
167
  ):
168
168
  """mdmd:hidden
169
169
  The Modal client object is not intended to be instantiated directly by users.
modal/image.py CHANGED
@@ -74,8 +74,8 @@ ImageBuilderVersion = Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVI
74
74
  # Python versions in mount.py where we specify the "standalone Python versions" we create mounts for.
75
75
  # Consider consolidating these multiple sources of truth?
76
76
  SUPPORTED_PYTHON_SERIES: dict[ImageBuilderVersion, list[str]] = {
77
- "PREVIEW": ["3.10", "3.11", "3.12", "3.13", "3.14"],
78
- "2025.06": ["3.10", "3.11", "3.12", "3.13", "3.14"],
77
+ "PREVIEW": ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"],
78
+ "2025.06": ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"],
79
79
  "2024.10": ["3.10", "3.11", "3.12", "3.13"],
80
80
  "2024.04": ["3.10", "3.11", "3.12"],
81
81
  "2023.12": ["3.10", "3.11", "3.12"],
@@ -104,15 +104,22 @@ See https://modal.com/docs/guide/modal-1-0-migration for more details.
104
104
 
105
105
 
106
106
  def _validate_python_version(
107
- python_version: Optional[str], builder_version: ImageBuilderVersion, allow_micro_granularity: bool = True
107
+ python_version: Optional[str],
108
+ builder_version: ImageBuilderVersion,
109
+ allow_micro_granularity: bool = True,
110
+ allow_free_threading: bool = False,
111
+ caller_name: str = "",
108
112
  ) -> str:
109
113
  if python_version is None:
110
114
  # If Python version is unspecified, match the local version, up to the minor component
111
115
  python_version = series_version = "{}.{}".format(*sys.version_info)
112
116
  elif not isinstance(python_version, str):
113
117
  raise InvalidError(f"Python version must be specified as a string, not {type(python_version).__name__}")
114
- elif not re.match(r"^3(?:\.\d{1,2}){1,2}(rc\d*)?$", python_version):
118
+ elif not re.match(r"^3(?:\.\d{1,2}){1,2}(rc\d*)?t?$", python_version):
115
119
  raise InvalidError(f"Invalid Python version: {python_version!r}")
120
+ elif not allow_free_threading and python_version.endswith("t"):
121
+ context = f"with {caller_name}" if caller_name else ""
122
+ raise InvalidError(f"Free threaded Python is not supported {context}")
116
123
  else:
117
124
  components = python_version.split(".")
118
125
  if len(components) == 3 and not allow_micro_granularity:
@@ -120,7 +127,8 @@ def _validate_python_version(
120
127
  "Python version must be specified as 'major.minor' for this interface;"
121
128
  f" micro-level specification ({python_version!r}) is not valid."
122
129
  )
123
- series_version = "{}.{}".format(*components)
130
+ suffix = "t" if len(components) == 3 and python_version.endswith("t") else ""
131
+ series_version = f"{components[0]}.{components[1]}{suffix}"
124
132
 
125
133
  supported_series = SUPPORTED_PYTHON_SERIES[builder_version]
126
134
  if series_version not in supported_series:
@@ -132,8 +140,15 @@ def _validate_python_version(
132
140
  return python_version
133
141
 
134
142
 
135
- def _dockerhub_python_version(builder_version: ImageBuilderVersion, python_version: Optional[str] = None) -> str:
136
- python_version = _validate_python_version(python_version, builder_version)
143
+ def _dockerhub_python_version(
144
+ builder_version: ImageBuilderVersion,
145
+ python_version: Optional[str] = None,
146
+ allow_free_threading: bool = False,
147
+ caller_name: str = "",
148
+ ) -> str:
149
+ python_version = _validate_python_version(
150
+ python_version, builder_version, allow_free_threading=allow_free_threading, caller_name=caller_name
151
+ )
137
152
  version_components = python_version.split(".")
138
153
 
139
154
  # When user specifies a full Python version, use that
@@ -1753,7 +1768,9 @@ class _Image(_Object, type_prefix="im"):
1753
1768
  """A Micromamba base image. Micromamba allows for fast building of small Conda-based containers."""
1754
1769
 
1755
1770
  def build_dockerfile(version: ImageBuilderVersion) -> DockerfileSpec:
1756
- validated_python_version = _validate_python_version(python_version, version)
1771
+ validated_python_version = _validate_python_version(
1772
+ python_version, version, allow_free_threading=False, caller_name="Image.micromamba"
1773
+ )
1757
1774
  micromamba_version = _base_image_config("micromamba", version)
1758
1775
  tag = f"mambaorg/micromamba:{micromamba_version}"
1759
1776
  setup_commands = [
@@ -1833,12 +1850,16 @@ class _Image(_Object, type_prefix="im"):
1833
1850
  ) -> list[str]:
1834
1851
  add_python_commands: list[str] = []
1835
1852
  if add_python:
1836
- _validate_python_version(add_python, builder_version, allow_micro_granularity=False)
1853
+ _validate_python_version(
1854
+ add_python, builder_version, allow_micro_granularity=False, allow_free_threading=True
1855
+ )
1837
1856
  add_python_commands = [
1838
1857
  "COPY /python/. /usr/local",
1839
1858
  "ENV TERMINFO_DIRS=/etc/terminfo:/lib/terminfo:/usr/share/terminfo:/usr/lib/terminfo",
1840
1859
  ]
1841
1860
  python_minor = add_python.split(".")[1]
1861
+ if python_minor.endswith("t"):
1862
+ python_minor = python_minor[:-1]
1842
1863
  if int(python_minor) < 13:
1843
1864
  # Previous versions did not include the `python` binary, but later ones do.
1844
1865
  # (The important factor is not the Python version itself, but the standalone dist version.)
@@ -2160,7 +2181,9 @@ class _Image(_Object, type_prefix="im"):
2160
2181
  if version <= "2024.10":
2161
2182
  requirements_path = _get_modal_requirements_path(version, python_version)
2162
2183
  context_files = {CONTAINER_REQUIREMENTS_PATH: requirements_path}
2163
- full_python_version = _dockerhub_python_version(version, python_version)
2184
+ full_python_version = _dockerhub_python_version(
2185
+ version, python_version, allow_free_threading=False, caller_name="Image.debian_slim"
2186
+ )
2164
2187
  debian_codename = _base_image_config("debian", version)
2165
2188
 
2166
2189
  commands = [
modal/image.pyi CHANGED
@@ -34,10 +34,14 @@ def _validate_python_version(
34
34
  python_version: typing.Optional[str],
35
35
  builder_version: typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVIEW"],
36
36
  allow_micro_granularity: bool = True,
37
+ allow_free_threading: bool = False,
38
+ caller_name: str = "",
37
39
  ) -> str: ...
38
40
  def _dockerhub_python_version(
39
41
  builder_version: typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVIEW"],
40
42
  python_version: typing.Optional[str] = None,
43
+ allow_free_threading: bool = False,
44
+ caller_name: str = "",
41
45
  ) -> str: ...
42
46
  def _base_image_config(
43
47
  group: str, builder_version: typing.Literal["2023.12", "2024.04", "2024.10", "2025.06", "PREVIEW"]
modal/mount.py CHANGED
@@ -23,7 +23,11 @@ from ._load_context import LoadContext
23
23
  from ._object import _Object
24
24
  from ._resolver import Resolver
25
25
  from ._utils.async_utils import TaskContext, aclosing, async_map, synchronize_api
26
- from ._utils.blob_utils import FileUploadSpec, blob_upload_file, get_file_upload_spec_from_path
26
+ from ._utils.blob_utils import (
27
+ FileUploadSpec,
28
+ blob_upload_file,
29
+ get_file_upload_spec_from_path,
30
+ )
27
31
  from ._utils.grpc_utils import Retry
28
32
  from ._utils.name_utils import check_object_name
29
33
  from ._utils.package_utils import get_module_mount_info
@@ -45,6 +49,7 @@ PYTHON_STANDALONE_VERSIONS: dict[str, tuple[str, str]] = {
45
49
  "3.12": ("20240107", "3.12.1"),
46
50
  "3.13": ("20241008", "3.13.0"),
47
51
  "3.14": ("20251205", "3.14.2"),
52
+ "3.14t": ("20251209", "3.14.2t"),
48
53
  }
49
54
 
50
55
  MOUNT_DEPRECATION_MESSAGE_PATTERN = """modal.Mount usage will soon be deprecated.
@@ -797,7 +802,7 @@ async def _create_single_client_dependency_mount(
797
802
  tmpd,
798
803
  "--python-platform",
799
804
  uv_python_platform,
800
- "--python-version",
805
+ "--python",
801
806
  python_version,
802
807
  ]
803
808
  )
modal/mount.pyi CHANGED
@@ -426,7 +426,7 @@ async def _create_single_client_dependency_mount(
426
426
  ): ...
427
427
  async def _create_client_dependency_mounts(
428
428
  client=None,
429
- python_versions: list[str] = ["3.10", "3.11", "3.12", "3.13", "3.14"],
429
+ python_versions: list[str] = ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"],
430
430
  builder_versions: list[str] = ["2025.06"],
431
431
  check_if_exists=True,
432
432
  dry_run=False,
@@ -437,7 +437,7 @@ class __create_client_dependency_mounts_spec(typing_extensions.Protocol):
437
437
  self,
438
438
  /,
439
439
  client=None,
440
- python_versions: list[str] = ["3.10", "3.11", "3.12", "3.13", "3.14"],
440
+ python_versions: list[str] = ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"],
441
441
  builder_versions: list[str] = ["2025.06"],
442
442
  check_if_exists=True,
443
443
  dry_run=False,
@@ -446,7 +446,7 @@ class __create_client_dependency_mounts_spec(typing_extensions.Protocol):
446
446
  self,
447
447
  /,
448
448
  client=None,
449
- python_versions: list[str] = ["3.10", "3.11", "3.12", "3.13", "3.14"],
449
+ python_versions: list[str] = ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"],
450
450
  builder_versions: list[str] = ["2025.06"],
451
451
  check_if_exists=True,
452
452
  dry_run=False,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.3.1.dev12
3
+ Version: 1.3.1.dev14
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -26,7 +26,7 @@ modal/app.pyi,sha256=WR0nGSUh8-8OYRHFqEnijGoPp_IbawNY1JW_0pozXsE,50857
26
26
  modal/billing.py,sha256=zmQ3bcCJlwa4KD1IA_QgdWpm1pn13c-7qfy79iEauYI,195
27
27
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
28
28
  modal/client.py,sha256=CXnyJYLhY--xaCkjv3tpjYDca8AuXGQG1IiaXQVX4y4,14436
29
- modal/client.pyi,sha256=18zSEWajEhEpaTNF1oSeELgXY9sTCoeDRv2bLLlNGPM,14473
29
+ modal/client.pyi,sha256=UeAqC6dYlTsxTXkl7RWvxcHUwTH00jWqtb2Xv7bpJzI,14473
30
30
  modal/cloud_bucket_mount.py,sha256=cvVj5Rt4nDHoQbTneoJPTaAcnl_Ab_mrsjnnzd0v9OI,6013
31
31
  modal/cloud_bucket_mount.pyi,sha256=vXusGMOUk9HjCs4lhxteuCK4xLQclPfugGWKo7LECEA,7539
32
32
  modal/cls.py,sha256=DNXcOrd9l2DoX-nLGdpwXm-N9V0BbQEvWA7d2UwFf44,41510
@@ -45,12 +45,12 @@ modal/file_pattern_matcher.py,sha256=A_Kdkej6q7YQyhM_2-BvpFmPqJ0oHb54B6yf9VqvPVE
45
45
  modal/functions.py,sha256=kcNHvqeGBxPI7Cgd57NIBBghkfbeFJzXO44WW0jSmao,325
46
46
  modal/functions.pyi,sha256=fkjxeYAqh6sX9C84gjUGoLVgHT1IfNB_07h0fpmIyWw,36465
47
47
  modal/gpu.py,sha256=Fe5ORvVPDIstSq1xjmM6OoNgLYFWvogP9r5BgmD3hYg,6769
48
- modal/image.py,sha256=sPaYxx4Dwdod1FjVooDaDDcPbcyyBXY4ChpbQvWe5mc,108197
49
- modal/image.pyi,sha256=UMwAaYu4feSDzJS9l-5xKYP_yaJm18bY_s3pREOQF6A,78249
48
+ modal/image.py,sha256=HKPUQwdXCwuP7d_KZyEYXMVvtyIQH1_H3_BslQEk6ck,109094
49
+ modal/image.pyi,sha256=x8a6gohK9XD35z8MejOmKHauOnI7JwbQcZhp3bVfB5I,78383
50
50
  modal/io_streams.py,sha256=g6H6QAl48qZtN5OY6WIIVwF9TXBj3jMNYCgn7RYYrVg,30697
51
51
  modal/io_streams.pyi,sha256=aBxCcbHTprL08FLvPlkzu4bypCTT7xUdelNe5kc7OZY,18506
52
- modal/mount.py,sha256=5ps0p8dik2McxetRfHakLouzOvBrQPYBFCUCrgNlXik,33856
53
- modal/mount.pyi,sha256=ISBxzudOyLvw5r2LtzYm6Bh_wMUHrVAans8-u33k8cY,15721
52
+ modal/mount.py,sha256=cw5Goi3rLIUHlRESSMj60TYYO9dyskUGMbXjcCBbgq8,33903
53
+ modal/mount.pyi,sha256=HVNPL8po23Hulaj7Kdl5goakZbirN0ADv2nkLc8Hpn4,15748
54
54
  modal/network_file_system.py,sha256=23GUYz2DZ5kCzlUrdWBq1siBse6fP_CeGt2Lo9xHkR8,13598
55
55
  modal/network_file_system.pyi,sha256=oRQzPxSF3ZmY8BDtBFU3CCyGwPLl5jkobtN6ekexLog,16161
56
56
  modal/object.py,sha256=bTeskuY8JFrESjU4_UL_nTwYlBQdOLmVaOX3X6EMxsg,164
@@ -105,7 +105,7 @@ modal/_utils/docker_utils.py,sha256=h1uETghR40mp_y3fSWuZAfbIASH1HMzuphJHghAL6DU,
105
105
  modal/_utils/function_utils.py,sha256=uoOcn_pyl6fOVHr_Q6ci1_5eJqo90so7G9izfs-T-As,28272
106
106
  modal/_utils/git_utils.py,sha256=qtUU6JAttF55ZxYq51y55OR58B0tDPZsZWK5dJe6W5g,3182
107
107
  modal/_utils/grpc_testing.py,sha256=fZLyfMA5VYmIo-dUCcKQrVCH3ZKPT7K4_6ww373jt0Y,8697
108
- modal/_utils/grpc_utils.py,sha256=8KxNd8M8ziVTc-FB2mkmesBG9hscJScjjL0VIUB4T8k,16270
108
+ modal/_utils/grpc_utils.py,sha256=1imvFLM9jx2QyHGld0exIQL-LxGYNsMwlTZBblqeVPM,16110
109
109
  modal/_utils/hash_utils.py,sha256=zg3J6OGxTFGSFri1qQ12giDz90lWk8bzaxCTUCRtiX4,3034
110
110
  modal/_utils/http_utils.py,sha256=yeTFsXYr0rYMEhB7vBP7audG9Uc7OLhzKBANFDZWVt0,2451
111
111
  modal/_utils/jwt_utils.py,sha256=fxH9plyrbAemTbjSsQtzIdDXE9QXxvMC4DiUZ16G0aA,1360
@@ -158,7 +158,7 @@ modal/experimental/__init__.py,sha256=GOuo3t4-Le0ZVddiHIOw0MQxkdTJge-bVbhDvgnblm
158
158
  modal/experimental/flash.py,sha256=GJZwSr-4OHlP6gCIZdcbsSb8D8WX9xJwMphjwcfsRoU,31262
159
159
  modal/experimental/flash.pyi,sha256=W62a0AhmLUuH9a0n8Y3-DYhyEEFH3-bRUQFphOQfKHg,16418
160
160
  modal/experimental/ipython.py,sha256=TrCfmol9LGsRZMeDoeMPx3Hv3BFqQhYnmD_iH0pqdhk,2904
161
- modal-1.3.1.dev12.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
161
+ modal-1.3.1.dev14.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
162
162
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
163
163
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
164
164
  modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
@@ -180,10 +180,10 @@ modal_proto/task_command_router_pb2.py,sha256=2Y8wRvnq4_7RiQ-5ZAPIgXaxrHv_MXzgS5
180
180
  modal_proto/task_command_router_pb2.pyi,sha256=yI4tFteErLlonFA2HyaWtONfhY_VGSe7KCWFIspvmkE,16323
181
181
  modal_proto/task_command_router_pb2_grpc.py,sha256=q2VWfK2-4uDcPaPLhAqPZkgxhuQRYnWmwUcnEbPbGuk,13895
182
182
  modal_proto/task_command_router_pb2_grpc.pyi,sha256=e1MM10VGUgDkm041v53QeTglGQPzTpA0FUsFtezjp74,4536
183
- modal_version/__init__.py,sha256=p7Kr6XTekZbafGsmwVCctfFFERuDp3kC2yy1OupdiMQ,121
183
+ modal_version/__init__.py,sha256=v_VLCokNOucn6yuP8lDIQDFS91B5blQUVMFdqW8Mw0I,121
184
184
  modal_version/__main__.py,sha256=nLUbubxKx7GXNzJIkTB7M7_u8080LyLM0IS0rzFkC_c,119
185
- modal-1.3.1.dev12.dist-info/METADATA,sha256=uyQENlqNQddQ3Iq0c4B7WuLAqla8v_vdlrOiptChEVA,2582
186
- modal-1.3.1.dev12.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
187
- modal-1.3.1.dev12.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
188
- modal-1.3.1.dev12.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
189
- modal-1.3.1.dev12.dist-info/RECORD,,
185
+ modal-1.3.1.dev14.dist-info/METADATA,sha256=c_Gv4po5uosH8YHYd_Q0rm6pbiMtrOe7LQZJTfZBBbE,2582
186
+ modal-1.3.1.dev14.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
187
+ modal-1.3.1.dev14.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
188
+ modal-1.3.1.dev14.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
189
+ modal-1.3.1.dev14.dist-info/RECORD,,
modal_version/__init__.py CHANGED
@@ -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.dev12"
4
+ __version__ = "1.3.1.dev14"