mplang-nightly 0.1.dev151__py3-none-any.whl → 0.1.dev153__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.
@@ -0,0 +1,285 @@
1
+ # Copyright 2025 Ant Group Co., Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Core Session model (pure, no global registries).
16
+
17
+ Contents:
18
+ * SessionState dataclass
19
+ * LinkCommFactory (SPU link reuse cache)
20
+ * Session (topology derivation, runtime init, SPU env seeding, local symbol/computation storage)
21
+
22
+ Process-wide registries (sessions, global symbols) live in the server layer
23
+ (`server.py`) so this module remains portable and easy to unit test.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import logging
29
+ import time
30
+ from dataclasses import dataclass, field
31
+ from functools import cached_property
32
+ from typing import TYPE_CHECKING, Any, cast
33
+ from urllib.parse import urlparse
34
+
35
+ import spu.libspu as libspu
36
+
37
+ from mplang.core.expr.ast import Expr
38
+ from mplang.core.expr.evaluator import IEvaluator, create_evaluator
39
+ from mplang.core.mask import Mask
40
+ from mplang.kernels.context import RuntimeContext
41
+ from mplang.kernels.spu import PFunction # type: ignore
42
+ from mplang.runtime.communicator import HttpCommunicator
43
+ from mplang.runtime.exceptions import ResourceNotFound
44
+ from mplang.runtime.link_comm import LinkCommunicator
45
+ from mplang.utils.spu_utils import parse_field, parse_protocol
46
+
47
+ if TYPE_CHECKING: # pragma: no cover - import only for type checking
48
+ from mplang.core.cluster import ClusterSpec, Node, RuntimeInfo
49
+
50
+
51
+ class LinkCommFactory:
52
+ """Factory for creating and caching link communicators."""
53
+
54
+ def __init__(self) -> None:
55
+ self._cache: dict[tuple[int, tuple[str, ...]], LinkCommunicator] = {}
56
+
57
+ def create_link(self, rel_rank: int, addrs: list[str]) -> LinkCommunicator:
58
+ key = (rel_rank, tuple(addrs))
59
+ link = self._cache.get(key)
60
+ if link is not None:
61
+ return link
62
+ logging.info(f"LinkCommunicator created: rel_rank={rel_rank} addrs={addrs}")
63
+ link = LinkCommunicator(rel_rank, addrs)
64
+ self._cache[key] = link
65
+ return link
66
+
67
+
68
+ # Shared link factory (module-local, not global registry of sessions)
69
+ g_link_factory = LinkCommFactory()
70
+
71
+
72
+ @dataclass
73
+ class Symbol:
74
+ name: str
75
+ mptype: Any
76
+ data: Any
77
+
78
+
79
+ @dataclass
80
+ class Computation:
81
+ name: str
82
+ expr: Expr
83
+
84
+
85
+ @dataclass
86
+ class SessionState:
87
+ runtime: RuntimeContext | None = None
88
+ computations: dict[str, Computation] = field(default_factory=dict)
89
+ symbols: dict[str, Symbol] = field(default_factory=dict)
90
+ spu_seeded: bool = False
91
+ created_ts: float = field(default_factory=time.time)
92
+ last_access_ts: float = field(default_factory=time.time)
93
+
94
+
95
+ class Session:
96
+ """Represents the per-rank execution context.
97
+
98
+ Immutable config: name, rank, cluster_spec.
99
+ Derived: node, runtime_info, endpoints, spu_device, spu_mask, protocol/field, is_spu_party.
100
+ Mutable: state (runtime object, symbols, computations, seeded flag).
101
+ """
102
+
103
+ def __init__(self, name: str, rank: int, cluster_spec: ClusterSpec):
104
+ self.name = name
105
+ self.rank = rank
106
+ self.cluster_spec = cluster_spec
107
+ self.state = SessionState()
108
+ self.communicator = HttpCommunicator(
109
+ session_name=name, rank=rank, endpoints=self.endpoints
110
+ )
111
+
112
+ # --- Derived topology ---
113
+ @cached_property
114
+ def node(self) -> Node:
115
+ return self.cluster_spec.get_node_by_rank(self.rank)
116
+
117
+ @property
118
+ def runtime_info(self) -> RuntimeInfo:
119
+ return self.node.runtime_info
120
+
121
+ @cached_property
122
+ def endpoints(self) -> list[str]:
123
+ eps: list[str] = []
124
+ for n in sorted(
125
+ self.cluster_spec.nodes.values(),
126
+ key=lambda x: x.rank, # type: ignore[attr-defined]
127
+ ):
128
+ ep = n.endpoint
129
+ if not ep.startswith(("http://", "https://")):
130
+ ep = f"http://{ep}"
131
+ eps.append(ep)
132
+ return eps
133
+
134
+ @cached_property
135
+ def spu_device(self): # type: ignore
136
+ devs = self.cluster_spec.get_devices_by_kind("SPU")
137
+ if len(devs) != 1:
138
+ raise RuntimeError(
139
+ f"Expected exactly one SPU device, got {len(devs)} (session={self.name})"
140
+ )
141
+ return devs[0]
142
+
143
+ @cached_property
144
+ def spu_mask(self) -> Mask:
145
+ return Mask.from_ranks([m.rank for m in self.spu_device.members])
146
+
147
+ @property
148
+ def spu_protocol(self) -> str:
149
+ return cast(str, self.spu_device.config.get("protocol", "SEMI2K"))
150
+
151
+ @property
152
+ def spu_field(self) -> str:
153
+ return cast(str, self.spu_device.config.get("field", "FM64"))
154
+
155
+ @property
156
+ def is_spu_party(self) -> bool:
157
+ return self.rank in self.spu_mask
158
+
159
+ # --- Runtime helpers ---
160
+ def ensure_runtime(self) -> RuntimeContext:
161
+ if self.state.runtime is None:
162
+ self.state.runtime = RuntimeContext(
163
+ rank=self.rank,
164
+ world_size=len(self.cluster_spec.nodes), # type: ignore[attr-defined]
165
+ initial_bindings=(
166
+ self.runtime_info.op_bindings if self.runtime_info else {}
167
+ ),
168
+ )
169
+ return self.state.runtime
170
+
171
+ def ensure_spu_env(self) -> None:
172
+ """Ensure SPU kernel env (config/world[/link]) registered on this runtime.
173
+
174
+ Previous logic only seeded SPU parties; non-participating ranks then raised
175
+ a hard error when the evaluator encountered SPU ops in the global program,
176
+ because the kernel pocket lacked config/world. For now we register the
177
+ config/world on ALL parties (idempotent) and only attach a link context for
178
+ participating SPU ranks. Non-parties will still error later if they try to
179
+ execute a link-dependent SPU kernel (which should be guarded by masks in the
180
+ IR), but they will no longer fail early with a misleading
181
+ "SPU kernel state not initialized" message.
182
+ """
183
+ if self.state.spu_seeded:
184
+ return
185
+
186
+ link_ctx = None
187
+ # Fixed port offset for SPU runtime link services (legacy value retained).
188
+ # TODO: make configurable if future deployments require dynamic offset.
189
+ SPU_PORT_OFFSET = 100
190
+
191
+ if self.is_spu_party:
192
+ # Build SPU address list across all endpoints for ranks in mask
193
+ spu_addrs: list[str] = []
194
+ for r, addr in enumerate(self.communicator.endpoints):
195
+ if r in self.spu_mask:
196
+ if "//" not in addr:
197
+ addr = f"//{addr}"
198
+ parsed = urlparse(addr)
199
+ assert isinstance(parsed.port, int)
200
+ new_addr = f"{parsed.hostname}:{parsed.port + SPU_PORT_OFFSET}"
201
+ spu_addrs.append(new_addr)
202
+ rel_index = sum(1 for r in range(self.rank) if r in self.spu_mask)
203
+ link_ctx = g_link_factory.create_link(rel_index, spu_addrs)
204
+
205
+ spu_config = libspu.RuntimeConfig(
206
+ protocol=parse_protocol(self.spu_protocol),
207
+ field=parse_field(self.spu_field),
208
+ fxp_fraction_bits=18,
209
+ )
210
+ seed_pfunc = PFunction(
211
+ fn_type="spu.seed_env",
212
+ ins_info=(),
213
+ outs_info=(),
214
+ config=spu_config,
215
+ world=self.spu_mask.num_parties(),
216
+ link=link_ctx,
217
+ )
218
+ self.ensure_runtime().run_kernel(seed_pfunc, [])
219
+ self.state.spu_seeded = True
220
+
221
+ # --- Computations & Symbols (instance-local) ---
222
+ def add_computation(self, computation: Computation) -> None:
223
+ self.state.computations[computation.name] = computation
224
+
225
+ def get_computation(self, name: str) -> Computation | None:
226
+ return self.state.computations.get(name)
227
+
228
+ def add_symbol(self, symbol: Symbol) -> None:
229
+ self.state.symbols[symbol.name] = symbol
230
+
231
+ def get_symbol(self, name: str) -> Symbol | None:
232
+ return self.state.symbols.get(name)
233
+
234
+ def list_symbols(self) -> list[str]: # pragma: no cover - trivial
235
+ return list(self.state.symbols.keys())
236
+
237
+ def delete_symbol(self, name: str) -> bool:
238
+ if name in self.state.symbols:
239
+ del self.state.symbols[name]
240
+ return True
241
+ return False
242
+
243
+ def list_computations(self) -> list[str]: # pragma: no cover - trivial
244
+ return list(self.state.computations.keys())
245
+
246
+ def delete_computation(self, name: str) -> bool:
247
+ if name in self.state.computations:
248
+ del self.state.computations[name]
249
+ return True
250
+ return False
251
+
252
+ # --- Execution ---
253
+ def execute(
254
+ self, computation: Computation, input_names: list[str], output_names: list[str]
255
+ ) -> None:
256
+ env: dict[str, Any] = {}
257
+ for in_name in input_names:
258
+ sym = self.get_symbol(in_name)
259
+ if sym is None:
260
+ raise ResourceNotFound(
261
+ f"Input symbol '{in_name}' not found in session '{self.name}'"
262
+ )
263
+ env[in_name] = sym.data
264
+ rt = self.ensure_runtime()
265
+ self.ensure_spu_env()
266
+ evaluator: IEvaluator = create_evaluator(
267
+ rank=self.rank, env=env, comm=self.communicator, runtime=rt
268
+ )
269
+ results = evaluator.evaluate(computation.expr)
270
+ if results and len(results) != len(output_names):
271
+ raise RuntimeError(
272
+ f"Expected {len(output_names)} results, got {len(results)}"
273
+ )
274
+ for name, val in zip(output_names, results, strict=True):
275
+ self.add_symbol(Symbol(name=name, mptype={}, data=val))
276
+
277
+ # --- Convenience constructor ---
278
+ @classmethod
279
+ def from_cluster_spec_dict(cls, name: str, rank: int, spec_dict: dict) -> Session:
280
+ from mplang.core.cluster import ClusterSpec # local import to avoid cycles
281
+
282
+ spec = ClusterSpec.from_dict(spec_dict)
283
+ if len(spec.get_devices_by_kind("SPU")) == 0:
284
+ raise RuntimeError("No SPU device found in cluster_spec")
285
+ return cls(name=name, rank=rank, cluster_spec=spec)
@@ -86,20 +86,17 @@ class Simulator(InterpContext):
86
86
  cluster_spec: ClusterSpec,
87
87
  *,
88
88
  trace_ranks: list[int] | None = None,
89
- op_bindings: dict[str, str] | None = None,
90
89
  ) -> None:
91
90
  """Initialize a simulator with the given cluster specification.
92
91
 
93
92
  Args:
94
93
  cluster_spec: The cluster specification defining the simulation environment.
95
94
  trace_ranks: List of ranks to trace execution for debugging.
96
- op_bindings: Optional op->kernel binding template applied to all
97
- RuntimeContexts. These are static dispatch overrides (merged
98
- with project defaults) and are orthogonal to the per-evaluate
99
- variable ``bindings`` dict passed into ``evaluate``.
95
+ Per-node op binding overrides should now be provided via
96
+ each node's `runtime_info.op_bindings` in the supplied
97
+ `cluster_spec`.
100
98
  """
101
99
  super().__init__(cluster_spec)
102
- self._op_bindings_template = op_bindings or {}
103
100
  self._trace_ranks = trace_ranks or []
104
101
 
105
102
  spu_devices = cluster_spec.get_devices_by_kind("SPU")
@@ -145,21 +142,22 @@ class Simulator(InterpContext):
145
142
 
146
143
  # Persistent per-rank RuntimeContext instances (reused across evaluates).
147
144
  # We no longer pre-create evaluators since each evaluate has different env bindings.
148
- self._runtimes: list[RuntimeContext] = [
149
- RuntimeContext(
145
+ # Build per-rank runtime contexts.
146
+ self._runtimes: list[RuntimeContext] = []
147
+ for rank in range(self.world_size()):
148
+ node = self.cluster_spec.get_node_by_rank(rank)
149
+ rt = RuntimeContext(
150
150
  rank=rank,
151
151
  world_size=self.world_size(),
152
- # Static op bindings template cloned into each runtime. These are kernel
153
- # dispatch mappings, not per-evaluate variable bindings.
154
- initial_bindings=self._op_bindings_template,
152
+ initial_bindings=node.runtime_info.op_bindings,
155
153
  )
156
- for rank in range(self.world_size())
157
- ]
154
+ self._runtimes.append(rt)
158
155
 
159
156
  @classmethod
160
157
  def simple(
161
158
  cls,
162
159
  world_size: int,
160
+ op_bindings: dict[str, str] | None = None,
163
161
  **kwargs: Any,
164
162
  ) -> Simulator:
165
163
  """Create a simple simulator with the given number of parties.
@@ -175,6 +173,10 @@ class Simulator(InterpContext):
175
173
  A Simulator instance with a simple cluster configuration.
176
174
  """
177
175
  cluster_spec = ClusterSpec.simple(world_size)
176
+ if op_bindings:
177
+ # Apply the same op_bindings to every node's runtime_info for convenience
178
+ for node in cluster_spec.nodes.values():
179
+ node.runtime_info.op_bindings.update(op_bindings)
178
180
  return cls(cluster_spec, **kwargs)
179
181
 
180
182
  def _do_evaluate(self, expr: Expr, evaluator_engine: IEvaluator) -> Any:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mplang-nightly
3
- Version: 0.1.dev151
3
+ Version: 0.1.dev153
4
4
  Summary: Multi-Party Programming Language
5
5
  Author-email: SecretFlow Team <secretflow-contact@service.alipay.com>
6
6
  License: Apache License
@@ -4,7 +4,7 @@ mplang/device.py,sha256=RmjnhzHxJkkNmtBKtYMEbpQYBZpuC43qlllkCOp-QD8,12548
4
4
  mplang/analysis/__init__.py,sha256=CTHFvRsi-nFngojqjn08UaR3RY9i7CJ7T2UdR95kCrk,1056
5
5
  mplang/analysis/diagram.py,sha256=ffwgD12gL1_KH1uJ_EYkjmIlDrfxYJJkWj-wHl09_Xk,19520
6
6
  mplang/core/__init__.py,sha256=lWxlEKfRwX7FNDzgyKZ1fiDMaCiqkyg0j5mKlZD_v7g,2244
7
- mplang/core/cluster.py,sha256=gqMJenvXUfHhE181Dd5JiUkD4nT07RLoicBnvsGmRkE,8598
7
+ mplang/core/cluster.py,sha256=IqXHLogetegUEEAzmD8cWRash-UID06Wo3OBeZFwatg,11800
8
8
  mplang/core/comm.py,sha256=MByyu3etlQh_TkP1vKCFLIAPPuJOpl9Kjs6hOj6m4Yc,8843
9
9
  mplang/core/context_mgr.py,sha256=R0QJAod-1nYduVoOknLfAsxZiy-RtmuQcp-07HABYZU,1541
10
10
  mplang/core/dtype.py,sha256=0rZqFaFikFu9RxtdO36JLEgFL-E-lo3hH10whwkTVVY,10213
@@ -34,33 +34,33 @@ mplang/kernels/crypto.py,sha256=TWixli1uRQ_7OjA49qQXUXa2ldHDEwaCMXXPSHdAPi8,3812
34
34
  mplang/kernels/mock_tee.py,sha256=ifVqb03FgQ5EDK8r14PMpZKMMaSeqMDorcpGLiy00mM,2233
35
35
  mplang/kernels/phe.py,sha256=8-_1IFPOaGECGj9mbYja8XoqbMYnYqfpDNVyMJd8J1Y,65247
36
36
  mplang/kernels/spu.py,sha256=Kkg1ZQbmklXl7YkIeBfxqs3o4wX7ygBE8hXLpx90L9Y,9307
37
- mplang/kernels/sql_duckdb.py,sha256=C2XdNLoE2Apma-Fs7OYzDzkBAXAVuShuROxhCWCHDG4,1502
37
+ mplang/kernels/sql_duckdb.py,sha256=UN1Ev6-MxF_-65zMExUsLScC9PlmEIEcN8YziIoX_rY,1724
38
38
  mplang/kernels/stablehlo.py,sha256=jDsu-lIHRAm94FcUcxZgK02c6BhFJpbO8cf2hP2DFgk,2937
39
39
  mplang/ops/__init__.py,sha256=dpe7WWiYapOFzJeGoKFYBr5mnd6P5SdOyvdYaM2Nhm0,1408
40
- mplang/ops/base.py,sha256=rGtfBejcDh9mTRxOdJK5VUlG5vYiVJSir8X72X0Huvc,18264
40
+ mplang/ops/base.py,sha256=h67_SHWNZGUuTCuMll-9kDgGvlPhlFov7WAQCHTmUvw,18258
41
41
  mplang/ops/builtin.py,sha256=D7T8rRF9g05VIw9T72lsncF5cDQqaT37eapBieRKvRI,9363
42
42
  mplang/ops/crypto.py,sha256=9CeFJrYmvjmgx-3WQl6jHXh8VafRpT4QBunbzsPF8Uc,3646
43
- mplang/ops/ibis_cc.py,sha256=bWKN1dL8Nluwvu5TLi8iUwytcnpXtWakZDCL793zBRA,4230
43
+ mplang/ops/ibis_cc.py,sha256=G8TobBlkyT_IxOWXmMm4APPUnj6sH9bJ-1STfw4kIcw,4256
44
44
  mplang/ops/jax_cc.py,sha256=42czYg3hNQbI_nUebXnshlU8ULwM-oBDe_TQoApLNVA,7802
45
45
  mplang/ops/phe.py,sha256=SatswExjZWPed8y3qA33BCwIWbvsgHCuCAz_pv2RLLw,6790
46
46
  mplang/ops/spu.py,sha256=UHr5DSoqG08xDYER_11OsMVjGGNXXxsvkFoVvXU8uik,4989
47
- mplang/ops/sql.py,sha256=p-u0wQPk9KlgveltYvQcF1UefScJoqBCqhzYPeLBB5Y,1994
47
+ mplang/ops/sql.py,sha256=HyY2i5aGC5W7r62JryFSjQCUDXH3kQz82YADwn4z5uc,2015
48
48
  mplang/ops/tee.py,sha256=gwzP81y2idH-d-Du84H6oNZpLaGD-3fEgm8G1uxWpUA,1388
49
49
  mplang/protos/v1alpha1/mpir_pb2.py,sha256=Bros37t-4LMJbuUYVSM65rImUYTtZDhNTIADGbZCKp0,7522
50
50
  mplang/protos/v1alpha1/mpir_pb2.pyi,sha256=GwXR4wPB_kB_36iYS9x-cGI9KDKFMq89KhdLhW_xmvE,19342
51
51
  mplang/protos/v1alpha1/mpir_pb2_grpc.py,sha256=xYOs94SXiNYAlFodACnsXW5QovLsHY5tCk3p76RH5Zc,158
52
52
  mplang/runtime/__init__.py,sha256=IRPP3TtpFC4iSt7_uaq-S4dL7CwrXL0XBMeaBoEYLlg,948
53
53
  mplang/runtime/cli.py,sha256=WehDodeVB4AukSWx1LJxxtKUqGmLPY4qjayrPlOg3bE,14438
54
- mplang/runtime/client.py,sha256=w8sPuQzqaJI5uS_3JHu2mf0tLaFmZH3f6-SeUBfMLMY,15737
54
+ mplang/runtime/client.py,sha256=vkJUFSDcKIdbKiGUM5AosCKTZygl9g8uZFEjw2xwKig,15249
55
55
  mplang/runtime/communicator.py,sha256=Lek6_h_Wmr_W-_JpT-vMxL3CHxcVZdtf7jdaLGuxPgQ,3199
56
56
  mplang/runtime/data_providers.py,sha256=hH2butEOYNGq2rRZjVBDfXLxe3YUin2ftAF6htbTfLA,8226
57
- mplang/runtime/driver.py,sha256=Ok1jY301ctN1_KTb4jwSxOdB0lI_xhx9AwhtEGJ-VLQ,11300
57
+ mplang/runtime/driver.py,sha256=pq2EQFZK9tH90Idops_yeF6fj0cfFVD_5mFcmy4Hzco,11089
58
58
  mplang/runtime/exceptions.py,sha256=c18U0xK20dRmgZo0ogTf5vXlkix9y3VAFuzkHxaXPEk,981
59
59
  mplang/runtime/http_api.md,sha256=-re1DhEqMplAkv_wnqEU-PSs8tTzf4-Ml0Gq0f3Go6s,4883
60
60
  mplang/runtime/link_comm.py,sha256=uNqTCGZVwWeuHAb7yXXQf0DUsMXLa8leHCkrcZdzYMU,4559
61
- mplang/runtime/resource.py,sha256=xNke4UpNDjsjWcr09oXWNBXsMfSZFOwsKD7FWdCVPbc,11688
62
- mplang/runtime/server.py,sha256=LQ5uJi95tYrKmgHwZaxUQi-aiqwSsT3W4z7pZ9dQaUQ,14716
63
- mplang/runtime/simulation.py,sha256=_cmUsYL58mvc6msHZ2fDjFAEHHLdJ-TRzJV8BxOP_WA,11473
61
+ mplang/runtime/server.py,sha256=vYjuWTWhhSLHUpsO8FDnOQ8kFzPhE-fXDDyL8GHVPj4,16673
62
+ mplang/runtime/session.py,sha256=4TQ_RPRmriv0H0S6rl_GSabxS7XrwMkdZIdcnyE8bHw,10374
63
+ mplang/runtime/simulation.py,sha256=WyIs8ta3ZM5o3RB0Bcb0MUu6Yh88Iujr27KvZFqGxig,11497
64
64
  mplang/simp/__init__.py,sha256=xNXnA8-jZAANa2A1W39b3lYO7D02zdCXl0TpivkTGS4,11579
65
65
  mplang/simp/mpi.py,sha256=Wv_Q16TQ3rdLam6OzqXiefIGSMmagGkso09ycyOkHEs,4774
66
66
  mplang/simp/random.py,sha256=7PVgWNL1j7Sf3MqT5PRiWplUu-0dyhF3Ub566iqX86M,3898
@@ -70,8 +70,8 @@ mplang/utils/crypto.py,sha256=rvPomBFtznRHc3RPi6Aip9lsU8zW2oxBqGv1K3vn7Rs,1052
70
70
  mplang/utils/func_utils.py,sha256=vCJcZmu0bEbqhOQKdpttV2_MBllIcPSN0b8U4WjNGGo,5164
71
71
  mplang/utils/spu_utils.py,sha256=S3L9RBkBe2AvSuMSQQ12cBY5Y1NPthubvErSX_7nj1A,4158
72
72
  mplang/utils/table_utils.py,sha256=aC-IZOKkSmFkpr3NZchLM0Wt0GOn-rg_xHBHREWBwAU,2202
73
- mplang_nightly-0.1.dev151.dist-info/METADATA,sha256=sCQECTJOQoKyr3XXAf8Kma7lrB5KEt6toJbQA9a5nEA,16547
74
- mplang_nightly-0.1.dev151.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
75
- mplang_nightly-0.1.dev151.dist-info/entry_points.txt,sha256=mG1oJT-GAjQR834a62_QIWb7litzWPPyVnwFqm-rWuY,55
76
- mplang_nightly-0.1.dev151.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
77
- mplang_nightly-0.1.dev151.dist-info/RECORD,,
73
+ mplang_nightly-0.1.dev153.dist-info/METADATA,sha256=4dEwwbuB0n0oRHxO09vuMY2Al57Ol8O8KdXGlDpEZqo,16547
74
+ mplang_nightly-0.1.dev153.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
75
+ mplang_nightly-0.1.dev153.dist-info/entry_points.txt,sha256=mG1oJT-GAjQR834a62_QIWb7litzWPPyVnwFqm-rWuY,55
76
+ mplang_nightly-0.1.dev153.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
77
+ mplang_nightly-0.1.dev153.dist-info/RECORD,,