xoscar 0.9.0__cp312-cp312-macosx_10_13_x86_64.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.
- xoscar/__init__.py +61 -0
- xoscar/_utils.cpython-312-darwin.so +0 -0
- xoscar/_utils.pxd +36 -0
- xoscar/_utils.pyx +246 -0
- xoscar/_version.py +693 -0
- xoscar/aio/__init__.py +16 -0
- xoscar/aio/base.py +86 -0
- xoscar/aio/file.py +59 -0
- xoscar/aio/lru.py +228 -0
- xoscar/aio/parallelism.py +39 -0
- xoscar/api.py +527 -0
- xoscar/backend.py +67 -0
- xoscar/backends/__init__.py +14 -0
- xoscar/backends/allocate_strategy.py +160 -0
- xoscar/backends/communication/__init__.py +30 -0
- xoscar/backends/communication/base.py +315 -0
- xoscar/backends/communication/core.py +69 -0
- xoscar/backends/communication/dummy.py +253 -0
- xoscar/backends/communication/errors.py +20 -0
- xoscar/backends/communication/socket.py +444 -0
- xoscar/backends/communication/ucx.py +538 -0
- xoscar/backends/communication/utils.py +97 -0
- xoscar/backends/config.py +157 -0
- xoscar/backends/context.py +437 -0
- xoscar/backends/core.py +352 -0
- xoscar/backends/indigen/__init__.py +16 -0
- xoscar/backends/indigen/__main__.py +19 -0
- xoscar/backends/indigen/backend.py +51 -0
- xoscar/backends/indigen/driver.py +26 -0
- xoscar/backends/indigen/fate_sharing.py +221 -0
- xoscar/backends/indigen/pool.py +515 -0
- xoscar/backends/indigen/shared_memory.py +548 -0
- xoscar/backends/message.cpython-312-darwin.so +0 -0
- xoscar/backends/message.pyi +255 -0
- xoscar/backends/message.pyx +646 -0
- xoscar/backends/pool.py +1630 -0
- xoscar/backends/router.py +285 -0
- xoscar/backends/test/__init__.py +16 -0
- xoscar/backends/test/backend.py +38 -0
- xoscar/backends/test/pool.py +233 -0
- xoscar/batch.py +256 -0
- xoscar/collective/__init__.py +27 -0
- xoscar/collective/backend/__init__.py +13 -0
- xoscar/collective/backend/nccl_backend.py +160 -0
- xoscar/collective/common.py +102 -0
- xoscar/collective/core.py +737 -0
- xoscar/collective/process_group.py +687 -0
- xoscar/collective/utils.py +41 -0
- xoscar/collective/xoscar_pygloo.cpython-312-darwin.so +0 -0
- xoscar/collective/xoscar_pygloo.pyi +239 -0
- xoscar/constants.py +23 -0
- xoscar/context.cpython-312-darwin.so +0 -0
- xoscar/context.pxd +21 -0
- xoscar/context.pyx +368 -0
- xoscar/core.cpython-312-darwin.so +0 -0
- xoscar/core.pxd +51 -0
- xoscar/core.pyx +664 -0
- xoscar/debug.py +188 -0
- xoscar/driver.py +42 -0
- xoscar/errors.py +63 -0
- xoscar/libcpp.pxd +31 -0
- xoscar/metrics/__init__.py +21 -0
- xoscar/metrics/api.py +288 -0
- xoscar/metrics/backends/__init__.py +13 -0
- xoscar/metrics/backends/console/__init__.py +13 -0
- xoscar/metrics/backends/console/console_metric.py +82 -0
- xoscar/metrics/backends/metric.py +149 -0
- xoscar/metrics/backends/prometheus/__init__.py +13 -0
- xoscar/metrics/backends/prometheus/prometheus_metric.py +70 -0
- xoscar/nvutils.py +717 -0
- xoscar/profiling.py +260 -0
- xoscar/serialization/__init__.py +20 -0
- xoscar/serialization/aio.py +141 -0
- xoscar/serialization/core.cpython-312-darwin.so +0 -0
- xoscar/serialization/core.pxd +28 -0
- xoscar/serialization/core.pyi +57 -0
- xoscar/serialization/core.pyx +944 -0
- xoscar/serialization/cuda.py +111 -0
- xoscar/serialization/exception.py +48 -0
- xoscar/serialization/mlx.py +67 -0
- xoscar/serialization/numpy.py +82 -0
- xoscar/serialization/pyfury.py +37 -0
- xoscar/serialization/scipy.py +72 -0
- xoscar/serialization/torch.py +180 -0
- xoscar/utils.py +522 -0
- xoscar/virtualenv/__init__.py +34 -0
- xoscar/virtualenv/core.py +268 -0
- xoscar/virtualenv/platform.py +56 -0
- xoscar/virtualenv/utils.py +100 -0
- xoscar/virtualenv/uv.py +321 -0
- xoscar-0.9.0.dist-info/METADATA +230 -0
- xoscar-0.9.0.dist-info/RECORD +94 -0
- xoscar-0.9.0.dist-info/WHEEL +6 -0
- xoscar-0.9.0.dist-info/top_level.txt +2 -0
xoscar/virtualenv/uv.py
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# Copyright 2022-2025 XProbe Inc.
|
|
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
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
import os
|
|
19
|
+
import re
|
|
20
|
+
import shutil
|
|
21
|
+
import subprocess
|
|
22
|
+
import sys
|
|
23
|
+
import sysconfig
|
|
24
|
+
import tempfile
|
|
25
|
+
from importlib.metadata import distributions
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
from typing import Optional
|
|
28
|
+
|
|
29
|
+
from packaging.requirements import Requirement
|
|
30
|
+
from packaging.version import Version
|
|
31
|
+
|
|
32
|
+
from .core import VirtualEnvManager
|
|
33
|
+
from .utils import is_vcs_url, run_subprocess_with_logger
|
|
34
|
+
|
|
35
|
+
UV_PATH = os.getenv("XOSCAR_UV_PATH")
|
|
36
|
+
SKIP_INSTALLED = bool(int(os.getenv("XOSCAR_VIRTUAL_ENV_SKIP_INSTALLED", "0")))
|
|
37
|
+
logger = logging.getLogger(__name__)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _is_in_pyinstaller():
|
|
41
|
+
return hasattr(sys, "_MEIPASS")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class UVVirtualEnvManager(VirtualEnvManager):
|
|
45
|
+
def __init__(self, env_path: Path):
|
|
46
|
+
super().__init__(env_path)
|
|
47
|
+
self._install_process: Optional[subprocess.Popen] = None
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def is_available(cls):
|
|
51
|
+
if UV_PATH is not None:
|
|
52
|
+
# user specified uv, just treat it as existed
|
|
53
|
+
return True
|
|
54
|
+
return shutil.which("uv") is not None
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def _get_uv_path() -> str:
|
|
58
|
+
if (uv_path := UV_PATH) is None:
|
|
59
|
+
try:
|
|
60
|
+
from uv import find_uv_bin
|
|
61
|
+
|
|
62
|
+
uv_path = find_uv_bin()
|
|
63
|
+
except (ImportError, FileNotFoundError):
|
|
64
|
+
logger.warning("Fail to find uv bin, use system one")
|
|
65
|
+
uv_path = "uv"
|
|
66
|
+
return uv_path
|
|
67
|
+
|
|
68
|
+
def exists_env(self) -> bool:
|
|
69
|
+
"""Check if virtual environment already exists."""
|
|
70
|
+
return self.env_path.exists() and (self.env_path / "pyvenv.cfg").exists()
|
|
71
|
+
|
|
72
|
+
def create_env(
|
|
73
|
+
self, python_path: Path | None = None, exists: str = "ignore"
|
|
74
|
+
) -> None:
|
|
75
|
+
"""
|
|
76
|
+
Create virtual environment.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
python_path: Path to Python interpreter to use
|
|
80
|
+
exists: How to handle existing environment:
|
|
81
|
+
- "ignore": Skip creation if environment already exists (default)
|
|
82
|
+
- "error": Raise error if environment exists
|
|
83
|
+
- "clear": Remove existing environment and create new one
|
|
84
|
+
"""
|
|
85
|
+
if self.exists_env():
|
|
86
|
+
if exists == "error":
|
|
87
|
+
raise FileExistsError(
|
|
88
|
+
f"Virtual environment already exists at {self.env_path}"
|
|
89
|
+
)
|
|
90
|
+
elif exists == "ignore":
|
|
91
|
+
logger.info(
|
|
92
|
+
f"Virtual environment already exists at {self.env_path}, skipping creation"
|
|
93
|
+
)
|
|
94
|
+
return
|
|
95
|
+
elif exists == "clear":
|
|
96
|
+
logger.info(f"Removing existing virtual environment at {self.env_path}")
|
|
97
|
+
self.remove_env()
|
|
98
|
+
else:
|
|
99
|
+
raise ValueError(
|
|
100
|
+
f"Invalid exists option: {exists}. Must be one of: error, clear, ignore"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
uv_path = self._get_uv_path()
|
|
104
|
+
cmd = [uv_path, "venv", str(self.env_path), "--system-site-packages"]
|
|
105
|
+
|
|
106
|
+
if python_path:
|
|
107
|
+
cmd += ["--python", str(python_path)]
|
|
108
|
+
elif _is_in_pyinstaller():
|
|
109
|
+
# in pyinstaller, uv would find the system python
|
|
110
|
+
# in this case we'd better specify the same python version
|
|
111
|
+
python_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
|
112
|
+
cmd += ["--python", python_version]
|
|
113
|
+
|
|
114
|
+
logger.info("Creating virtualenv via command: %s", cmd)
|
|
115
|
+
subprocess.run(cmd, check=True)
|
|
116
|
+
|
|
117
|
+
def _resolve_install_plan(
|
|
118
|
+
self, specs: list[str], pinned: dict[str, str]
|
|
119
|
+
) -> list[str]:
|
|
120
|
+
"""
|
|
121
|
+
Run uv --dry-run with pinned constraints and return
|
|
122
|
+
a list like ['package==version', ...].
|
|
123
|
+
"""
|
|
124
|
+
with tempfile.NamedTemporaryFile("w+", delete=True) as f:
|
|
125
|
+
for name, ver in pinned.items():
|
|
126
|
+
f.write(f"{name}=={ver}\n")
|
|
127
|
+
f.flush() # make sure content is on disk
|
|
128
|
+
|
|
129
|
+
cmd = [
|
|
130
|
+
self._get_uv_path(),
|
|
131
|
+
"pip",
|
|
132
|
+
"install",
|
|
133
|
+
"-p",
|
|
134
|
+
str(self.env_path),
|
|
135
|
+
"--dry-run",
|
|
136
|
+
"--constraint",
|
|
137
|
+
f.name,
|
|
138
|
+
*specs,
|
|
139
|
+
]
|
|
140
|
+
result = subprocess.run(cmd, check=True, text=True, capture_output=True)
|
|
141
|
+
|
|
142
|
+
# the temp file is automatically deleted here
|
|
143
|
+
deps = [
|
|
144
|
+
f"{m.group(1)}=={m.group(2)}"
|
|
145
|
+
for line in result.stderr.splitlines()
|
|
146
|
+
if (m := re.match(r"^\+ (\S+)==(\S+)$", line.strip()))
|
|
147
|
+
]
|
|
148
|
+
return deps
|
|
149
|
+
|
|
150
|
+
@staticmethod
|
|
151
|
+
def _split_specs(
|
|
152
|
+
specs: list[str], installed: dict[str, str]
|
|
153
|
+
) -> tuple[list[str], list[str], dict[str, str]]:
|
|
154
|
+
"""
|
|
155
|
+
Split the given requirement specs into:
|
|
156
|
+
- keep: specs that need to be kept, e.g. git+github://xxx
|
|
157
|
+
- to_resolve: specs that need to be passed to the resolver (unsatisfied ones)
|
|
158
|
+
- pinned: already satisfied specs, used for constraint to lock their versions
|
|
159
|
+
"""
|
|
160
|
+
keep: list[str] = []
|
|
161
|
+
to_resolve: list[str] = []
|
|
162
|
+
pinned: dict[str, str] = {}
|
|
163
|
+
|
|
164
|
+
for spec_str in specs:
|
|
165
|
+
# skip git+xxx
|
|
166
|
+
if is_vcs_url(spec_str):
|
|
167
|
+
keep.append(spec_str)
|
|
168
|
+
continue
|
|
169
|
+
|
|
170
|
+
req = Requirement(spec_str)
|
|
171
|
+
name = req.name.lower()
|
|
172
|
+
cur_ver = installed.get(name)
|
|
173
|
+
|
|
174
|
+
if cur_ver is None:
|
|
175
|
+
# Package not installed, needs resolution
|
|
176
|
+
to_resolve.append(spec_str)
|
|
177
|
+
continue
|
|
178
|
+
|
|
179
|
+
if not req.specifier:
|
|
180
|
+
# No version constraint, already satisfied
|
|
181
|
+
pinned[name] = cur_ver
|
|
182
|
+
continue
|
|
183
|
+
|
|
184
|
+
try:
|
|
185
|
+
if Version(cur_ver) in req.specifier:
|
|
186
|
+
# Version satisfies the specifier, pin it
|
|
187
|
+
pinned[name] = cur_ver
|
|
188
|
+
else:
|
|
189
|
+
# Version does not satisfy, needs resolution
|
|
190
|
+
to_resolve.append(spec_str)
|
|
191
|
+
except Exception:
|
|
192
|
+
# Parsing error, be conservative and resolve it
|
|
193
|
+
to_resolve.append(spec_str)
|
|
194
|
+
|
|
195
|
+
return keep, to_resolve, pinned
|
|
196
|
+
|
|
197
|
+
def _filter_packages_not_installed(self, packages: list[str]) -> list[str]:
|
|
198
|
+
"""
|
|
199
|
+
Filter out packages that are already installed with the same version.
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
# all the installed packages in system site packages
|
|
203
|
+
installed = {
|
|
204
|
+
dist.metadata["Name"].lower(): dist.version
|
|
205
|
+
for dist in distributions()
|
|
206
|
+
if dist.metadata and "Name" in dist.metadata
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
# exclude those packages that satisfied in system site packages
|
|
210
|
+
keep, to_resolve, pinned = self._split_specs(packages, installed)
|
|
211
|
+
if not keep and not to_resolve:
|
|
212
|
+
logger.debug("All requirement specifiers satisfied by system packages.")
|
|
213
|
+
return []
|
|
214
|
+
|
|
215
|
+
if to_resolve:
|
|
216
|
+
resolved = self._resolve_install_plan(to_resolve, pinned)
|
|
217
|
+
logger.debug(f"Resolved install list: {resolved}")
|
|
218
|
+
if not keep and not resolved:
|
|
219
|
+
# no packages to install
|
|
220
|
+
return []
|
|
221
|
+
else:
|
|
222
|
+
resolved = []
|
|
223
|
+
|
|
224
|
+
final = keep.copy()
|
|
225
|
+
for item in resolved:
|
|
226
|
+
name, version = item.split("==")
|
|
227
|
+
key = name.lower()
|
|
228
|
+
if key not in installed or installed[key] != version:
|
|
229
|
+
final.append(item)
|
|
230
|
+
logger.debug(f"Filtered install list: {final}")
|
|
231
|
+
return final
|
|
232
|
+
|
|
233
|
+
def install_packages(self, packages: list[str], **kwargs):
|
|
234
|
+
"""
|
|
235
|
+
Install packages into the virtual environment using uv.
|
|
236
|
+
Supports pip-compatible kwargs: index_url, extra_index_url, find_links.
|
|
237
|
+
"""
|
|
238
|
+
if not packages:
|
|
239
|
+
return
|
|
240
|
+
|
|
241
|
+
packages = self.process_packages(packages)
|
|
242
|
+
if not packages:
|
|
243
|
+
return
|
|
244
|
+
|
|
245
|
+
log = kwargs.pop("log", False)
|
|
246
|
+
skip_installed = kwargs.pop("skip_installed", SKIP_INSTALLED)
|
|
247
|
+
uv_path = self._get_uv_path()
|
|
248
|
+
|
|
249
|
+
if skip_installed:
|
|
250
|
+
packages = self._filter_packages_not_installed(packages)
|
|
251
|
+
if not packages:
|
|
252
|
+
logger.info("All required packages are already installed.")
|
|
253
|
+
return
|
|
254
|
+
|
|
255
|
+
cmd = [
|
|
256
|
+
uv_path,
|
|
257
|
+
"pip",
|
|
258
|
+
"install",
|
|
259
|
+
"-p",
|
|
260
|
+
str(self.env_path),
|
|
261
|
+
"--color=always",
|
|
262
|
+
"--no-deps",
|
|
263
|
+
] + packages
|
|
264
|
+
else:
|
|
265
|
+
cmd = [
|
|
266
|
+
uv_path,
|
|
267
|
+
"pip",
|
|
268
|
+
"install",
|
|
269
|
+
"-p",
|
|
270
|
+
str(self.env_path),
|
|
271
|
+
"--color=always",
|
|
272
|
+
] + packages
|
|
273
|
+
|
|
274
|
+
if "index_url" in kwargs and kwargs["index_url"]:
|
|
275
|
+
cmd += ["-i", kwargs["index_url"]]
|
|
276
|
+
param_and_option = [
|
|
277
|
+
("extra_index_url", "--extra-index-url"),
|
|
278
|
+
("find_links", "-f"),
|
|
279
|
+
("trusted_host", "--trusted-host"),
|
|
280
|
+
]
|
|
281
|
+
for param, option in param_and_option:
|
|
282
|
+
if param in kwargs and kwargs[param]:
|
|
283
|
+
val = kwargs[param]
|
|
284
|
+
cmd += (
|
|
285
|
+
[option, val]
|
|
286
|
+
if isinstance(val, str)
|
|
287
|
+
else [opt for v in val for opt in (option, v)]
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
if kwargs.get("no_build_isolation", False):
|
|
291
|
+
cmd += ["--no-build-isolation"]
|
|
292
|
+
|
|
293
|
+
logger.info("Installing packages via command: %s", cmd)
|
|
294
|
+
if not log:
|
|
295
|
+
self._install_process = process = subprocess.Popen(cmd)
|
|
296
|
+
returncode = process.wait()
|
|
297
|
+
else:
|
|
298
|
+
with run_subprocess_with_logger(cmd) as process:
|
|
299
|
+
self._install_process = process
|
|
300
|
+
returncode = process.returncode
|
|
301
|
+
|
|
302
|
+
self._install_process = None
|
|
303
|
+
if returncode != 0:
|
|
304
|
+
raise subprocess.CalledProcessError(returncode, cmd)
|
|
305
|
+
|
|
306
|
+
def cancel_install(self):
|
|
307
|
+
if self._install_process and self._install_process.poll() is None:
|
|
308
|
+
self._install_process.terminate()
|
|
309
|
+
self._install_process.wait()
|
|
310
|
+
|
|
311
|
+
def get_python_path(self) -> str | None:
|
|
312
|
+
if self.env_path.exists():
|
|
313
|
+
return str(self.env_path.joinpath("bin/python"))
|
|
314
|
+
return None
|
|
315
|
+
|
|
316
|
+
def get_lib_path(self) -> str:
|
|
317
|
+
return sysconfig.get_path("purelib", vars={"base": str(self.env_path)})
|
|
318
|
+
|
|
319
|
+
def remove_env(self):
|
|
320
|
+
if self.env_path.exists():
|
|
321
|
+
shutil.rmtree(self.env_path, ignore_errors=True)
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xoscar
|
|
3
|
+
Version: 0.9.0
|
|
4
|
+
Summary: Python actor framework for heterogeneous computing.
|
|
5
|
+
Home-page: http://github.com/xorbitsai/xoscar
|
|
6
|
+
Author: Qin Xuye
|
|
7
|
+
Author-email: qinxuye@xprobe.io
|
|
8
|
+
Maintainer: Qin Xuye
|
|
9
|
+
Maintainer-email: qinxuye@xprobe.io
|
|
10
|
+
License: Apache License 2.0
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: numpy>=1.14.0
|
|
23
|
+
Requires-Dist: pandas>=1.0.0
|
|
24
|
+
Requires-Dist: scipy>=1.0.0; sys_platform != "win32" or python_version >= "3.10"
|
|
25
|
+
Requires-Dist: scipy<=1.9.1,>=1.0.0; sys_platform == "win32" and python_version < "3.10"
|
|
26
|
+
Requires-Dist: cloudpickle>=1.5.0
|
|
27
|
+
Requires-Dist: psutil>=5.9.0
|
|
28
|
+
Requires-Dist: tblib>=1.7.0
|
|
29
|
+
Requires-Dist: uvloop>=0.14.0; sys_platform != "win32"
|
|
30
|
+
Requires-Dist: packaging
|
|
31
|
+
Requires-Dist: click
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: cython>=0.29; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest>=3.5.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-cov>=2.5.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-timeout>=1.2.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-forked>=1.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-asyncio>=0.14.0; extra == "dev"
|
|
39
|
+
Requires-Dist: ipython>=6.5.0; extra == "dev"
|
|
40
|
+
Requires-Dist: sphinx; extra == "dev"
|
|
41
|
+
Requires-Dist: pydata-sphinx-theme>=0.3.0; extra == "dev"
|
|
42
|
+
Requires-Dist: sphinx-intl>=0.9.9; extra == "dev"
|
|
43
|
+
Requires-Dist: flake8>=3.8.0; extra == "dev"
|
|
44
|
+
Requires-Dist: black; extra == "dev"
|
|
45
|
+
Requires-Dist: uv; extra == "dev"
|
|
46
|
+
Requires-Dist: click; extra == "dev"
|
|
47
|
+
Provides-Extra: doc
|
|
48
|
+
Requires-Dist: ipython>=6.5.0; extra == "doc"
|
|
49
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
50
|
+
Requires-Dist: pydata-sphinx-theme>=0.3.0; extra == "doc"
|
|
51
|
+
Requires-Dist: sphinx-intl>=0.9.9; extra == "doc"
|
|
52
|
+
Provides-Extra: extra
|
|
53
|
+
Requires-Dist: pyarrow>=5.0.0; extra == "extra"
|
|
54
|
+
Requires-Dist: torch; extra == "extra"
|
|
55
|
+
Provides-Extra: kubernetes
|
|
56
|
+
Requires-Dist: kubernetes>=10.0.0; extra == "kubernetes"
|
|
57
|
+
Provides-Extra: ray
|
|
58
|
+
Requires-Dist: xoscar_ray>=0.0.1; extra == "ray"
|
|
59
|
+
Dynamic: description
|
|
60
|
+
Dynamic: description-content-type
|
|
61
|
+
|
|
62
|
+
<div align="center">
|
|
63
|
+
<img width="77%" alt="" src="https://raw.githubusercontent.com/xprobe-inc/xoscar/main/doc/source/_static/Xoscar.svg"><br>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
# Python actor framework for heterogeneous computing.
|
|
67
|
+
[](https://pypi.org/project/xoscar/)
|
|
68
|
+
[](https://codecov.io/gh/xorbitsai/xoscar)
|
|
69
|
+
[](https://actions-badge.atrox.dev/xorbitsai/xoscar/goto?ref=main)
|
|
70
|
+
[](https://github.com/xorbitsai/xoscar/blob/main/LICENSE)
|
|
71
|
+
|
|
72
|
+
## What is actor
|
|
73
|
+
Writing parallel and distributed programs is often challenging and requires a lot of time to deal with concurrency
|
|
74
|
+
issues. Actor model provides a high-level, scalable and robust abstraction for building distributed applications.
|
|
75
|
+
It provides several benefits:
|
|
76
|
+
- Scalability: Actors easily scale across nodes. The asynchronous, non-blocking nature of actors allows them to handle huge volumes of concurrent tasks efficiently.
|
|
77
|
+
- Concurrency: The actor model abstracts over concurrency, allowing developers to avoid raw threads and locks.
|
|
78
|
+
- Modularity: An actor system decomposes naturally into a collection of actors that can be understood independently. Actor logic is encapsulated within the actor itself.
|
|
79
|
+
|
|
80
|
+
## Why Xoscar
|
|
81
|
+
Xoscar implements the actor model in Python and provides user-friendly APIs that offer significant benefits for building
|
|
82
|
+
applications on heterogeneous hardware:
|
|
83
|
+
- **Abstraction over low-level communication details**: Xoscar handles all communication between actors transparently,
|
|
84
|
+
whether on CPUs, GPUs, or across nodes. Developers focus on application logic rather than managing hardware resources
|
|
85
|
+
and optimizing data transfer.
|
|
86
|
+
- **Flexible actor models**: Xoscar supports both stateful and stateless actors. Stateful actors ensure thread safety for
|
|
87
|
+
concurrent systems while stateless actors can handle massive volumes of concurrent messages. Developers choose the
|
|
88
|
+
appropriate actor model for their needs.
|
|
89
|
+
- **Batch method**: Xoscar provides a batch interface to significantly improve call efficiency when an actor interface is
|
|
90
|
+
invoked a large number of times.
|
|
91
|
+
- **Advanced debugging support**: Xoscar can detect potential issues like deadlocks, long-running calls, and performance
|
|
92
|
+
bottlenecks that would otherwise be nearly impossible to troubleshoot in a heterogeneous environment.
|
|
93
|
+
- **Automated recovery**: If an actor fails for any reason, Xoscar will automatically restart it if you want. It can monitor
|
|
94
|
+
actors and restart them upon failure, enabling fault-tolerant systems.
|
|
95
|
+
|
|
96
|
+
## Overview
|
|
97
|
+

|
|
98
|
+
Xoscar allows you to create multiple actor pools on each worker node, typically binding an actor pool to a CPU core or
|
|
99
|
+
a GPU card. Xoscar provides allocation policies so that whenever an actor is created, it will be instantiated in the
|
|
100
|
+
appropriate pool based on the specified policy.
|
|
101
|
+
|
|
102
|
+
When actors communicate, Xoscar will choose the optimal communication mechanism based on which pools the actors
|
|
103
|
+
belong to. This allows Xoscar to optimize communication in heterogeneous environments with multiple processing
|
|
104
|
+
units and accelerators.
|
|
105
|
+
|
|
106
|
+
## Where to get it
|
|
107
|
+
|
|
108
|
+
### PyPI
|
|
109
|
+
Binary installers for the latest released version are available at the [Python
|
|
110
|
+
Package Index (PyPI)](https://pypi.org/project/xoscar).
|
|
111
|
+
|
|
112
|
+
```shell
|
|
113
|
+
# PyPI
|
|
114
|
+
pip install xoscar
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Build from source
|
|
118
|
+
The source code is currently hosted on GitHub at: https://github.com/xorbitsai/xoscar .
|
|
119
|
+
|
|
120
|
+
Building from source requires that you have cmake and gcc installed on your system.
|
|
121
|
+
|
|
122
|
+
- cmake >= 3.11
|
|
123
|
+
- gcc >= 8
|
|
124
|
+
|
|
125
|
+
```shell
|
|
126
|
+
# If you have never cloned xoscar before
|
|
127
|
+
git clone --recursive https://github.com/xorbitsai/xoscar.git
|
|
128
|
+
cd xoscar/python
|
|
129
|
+
pip install -e .
|
|
130
|
+
|
|
131
|
+
# If you have already cloned xoscar before
|
|
132
|
+
cd xoscar
|
|
133
|
+
git submodule init
|
|
134
|
+
git submodule update
|
|
135
|
+
cd python && pip install -e .
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## APIs
|
|
139
|
+
Here are basic APIs for Xoscar.
|
|
140
|
+
#### Define an actor
|
|
141
|
+
```python
|
|
142
|
+
import xoscar as xo
|
|
143
|
+
|
|
144
|
+
# stateful actor, for stateless actor, inherit from xo.StatelessActor
|
|
145
|
+
class MyActor(xo.Actor):
|
|
146
|
+
def __init__(self, *args, **kwargs):
|
|
147
|
+
pass
|
|
148
|
+
|
|
149
|
+
async def __post_create__(self):
|
|
150
|
+
# called after created
|
|
151
|
+
pass
|
|
152
|
+
|
|
153
|
+
async def __pre_destroy__(self):
|
|
154
|
+
# called before destroy
|
|
155
|
+
pass
|
|
156
|
+
|
|
157
|
+
def method_a(self, arg_1, arg_2, **kw_1): # user-defined function
|
|
158
|
+
pass
|
|
159
|
+
|
|
160
|
+
async def method_b(self, arg_1, arg_2, **kw_1): # user-defined async function
|
|
161
|
+
pass
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### Create an actor
|
|
165
|
+
```python
|
|
166
|
+
import xoscar as xo
|
|
167
|
+
|
|
168
|
+
actor_ref = await xo.create_actor(
|
|
169
|
+
MyActor, 1, 2, a=1, b=2,
|
|
170
|
+
address='<ip>:<port>', uid='UniqueActorName')
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### Get an actor reference
|
|
174
|
+
```python
|
|
175
|
+
import xoscar as xo
|
|
176
|
+
|
|
177
|
+
actor_ref = await xo.actor_ref(address, actor_id)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### Invoke a method
|
|
181
|
+
```python
|
|
182
|
+
# send
|
|
183
|
+
await actor_ref.method_a.send(1, 2, a=1, b=2)
|
|
184
|
+
# equivalent to actor_ref.method_a.send
|
|
185
|
+
await actor_ref.method_a(1, 2, a=1, b=2)
|
|
186
|
+
# tell, it sends a message asynchronously and does not wait for a response.
|
|
187
|
+
await actor_ref.method_a.tell(1, 2, a=1, b=2)
|
|
188
|
+
```
|
|
189
|
+
### Batch method
|
|
190
|
+
Xoscar provides a set of APIs to write batch methods. You can simply add a `@extensible` decorator to your actor method
|
|
191
|
+
and create a batch version. All calls wrapped in a batch will be sent together, reducing possible RPC cost.
|
|
192
|
+
#### Define a batch method
|
|
193
|
+
```python
|
|
194
|
+
import xoscar as xo
|
|
195
|
+
|
|
196
|
+
class ExampleActor(xo.Actor):
|
|
197
|
+
@xo.extensible
|
|
198
|
+
async def batch_method(self, a, b=None):
|
|
199
|
+
pass
|
|
200
|
+
```
|
|
201
|
+
Xoscar also supports creating a batch version of the method:
|
|
202
|
+
```python
|
|
203
|
+
class ExampleActor(xo.Actor):
|
|
204
|
+
@xo.extensible
|
|
205
|
+
async def batch_method(self, a, b=None):
|
|
206
|
+
raise NotImplementedError # this will redirect all requests to the batch version
|
|
207
|
+
|
|
208
|
+
@batch_method.batch
|
|
209
|
+
async def batch_method(self, args_list, kwargs_list):
|
|
210
|
+
results = []
|
|
211
|
+
for args, kwargs in zip(args_list, kwargs_list):
|
|
212
|
+
a, b = self.batch_method.bind(*args, **kwargs)
|
|
213
|
+
# process the request
|
|
214
|
+
results.append(result)
|
|
215
|
+
return results # return a list of results
|
|
216
|
+
```
|
|
217
|
+
In a batch method, users can define how to more efficiently process a batch of requests.
|
|
218
|
+
|
|
219
|
+
#### Invoke a batch method
|
|
220
|
+
Calling batch methods is easy. You can use `<method_name>.delay` to make a batched call and use `<method_name>.batch` to send them:
|
|
221
|
+
```python
|
|
222
|
+
ref = await xo.actor_ref(uid='ExampleActor', address='127.0.0.1:13425')
|
|
223
|
+
results = await ref.batch_method.batch(
|
|
224
|
+
ref.batch_method.delay(10, b=20),
|
|
225
|
+
ref.batch_method.delay(20),
|
|
226
|
+
)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## License
|
|
230
|
+
[Apache 2](LICENSE)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
xoscar-0.9.0.dist-info/RECORD,,
|
|
2
|
+
xoscar-0.9.0.dist-info/WHEEL,sha256=mer8vOuI-KlBtJIdzgyZALHdls6RZGRaE6RPt7dfKrk,138
|
|
3
|
+
xoscar-0.9.0.dist-info/top_level.txt,sha256=vYlqqY4Nys8Thm1hePIuUv8eQePdULVWMmt7lXtX_ZA,21
|
|
4
|
+
xoscar-0.9.0.dist-info/METADATA,sha256=xzzaQpcpPXVpWMxFc48xrtP_K8ibyXPtjWD__xu8ics,9279
|
|
5
|
+
xoscar/_utils.pyx,sha256=frgVQ5xGp92jBKc4PsPmjOlVsXlKeHWtTOAMfHmBaII,7380
|
|
6
|
+
xoscar/backend.py,sha256=is436OPkZfSpQXaoqTRVta5eoye_pp45RFgCstAk2hU,1850
|
|
7
|
+
xoscar/core.pxd,sha256=I_C2ka7XryyGnnAVXUVm8xfS1gtIrCs6X-9rswgOcUU,1317
|
|
8
|
+
xoscar/_version.py,sha256=ClSPrUjgGRGHIkVMQV9XQnkQ-n0akJMnq_rh819nqFE,23719
|
|
9
|
+
xoscar/context.pxd,sha256=qKa0OyDPZtVymftSh447m-RzFZgmz8rGqQBa7qlauvc,725
|
|
10
|
+
xoscar/batch.py,sha256=DpArS0L3WYJ_HVPG-6hSYEwoAFY1mY2-mlC4Jp5M_Dw,7872
|
|
11
|
+
xoscar/nvutils.py,sha256=qmW4mKLU0WB2yCs198ccQOgLL02zB7Fsa-AotO3NOmg,20412
|
|
12
|
+
xoscar/constants.py,sha256=QHHSREw6uWBBjQDCFqlNfTvBZgniJPGy42KSIsR8Fqw,787
|
|
13
|
+
xoscar/core.cpython-312-darwin.so,sha256=DbeW6zm4CI74eoIVEF7p7_l0rEKd3f1tMUzYksgR2PA,417800
|
|
14
|
+
xoscar/__init__.py,sha256=sy7Wtn2EuQZI0I4Az_MfsBVZm4G0DRj46qRyExgmnJk,1622
|
|
15
|
+
xoscar/context.cpython-312-darwin.so,sha256=5wqmKkQ9bNmKJmdQa5CpdD6QwNUkitKtGEZzBCK2_YU,204120
|
|
16
|
+
xoscar/api.py,sha256=zxNqOjGiTIKuAip9WJ0LOoM7yevD6P5rb-sLynpZ2Zo,14648
|
|
17
|
+
xoscar/utils.py,sha256=vo1DS6xHnvZ9jDS9qpGFFN4GCJDo6nyhMINWOna5dp8,16582
|
|
18
|
+
xoscar/debug.py,sha256=9Z8SgE2WaKYQcyDo-5-DxEJQ533v7kWjrvCd28pSx3E,5069
|
|
19
|
+
xoscar/libcpp.pxd,sha256=DJqBxLFOKL4iRr9Kale5UH3rbvPRD1x5bTSOPHFpz9I,1147
|
|
20
|
+
xoscar/context.pyx,sha256=8CdgPnWcE9eOp3N600WgDQ03MCi8P73eUOGcfV7Zksg,10942
|
|
21
|
+
xoscar/errors.py,sha256=wBlQOKsXf0Fc4skN39tDie0YZT-VIAuLNRgoDl2pZcA,1241
|
|
22
|
+
xoscar/_utils.cpython-312-darwin.so,sha256=myOia1O2KWOt9Ub_xdP2Qz9yh7YWbnBsbUgW7V5fSY0,140472
|
|
23
|
+
xoscar/core.pyx,sha256=phN-yYV0A0QI8WFi2jCu0nc4CnShTepfDi0V7ZrLYPY,22092
|
|
24
|
+
xoscar/driver.py,sha256=498fowtJr6b3FE8FIOA_Tc1Vwx88nfZw7p0FxrML0h4,1372
|
|
25
|
+
xoscar/profiling.py,sha256=BC5OF0HzSaXv8V7w-y-B8r5gV5DgxHFoTEIF6jCMioQ,8015
|
|
26
|
+
xoscar/_utils.pxd,sha256=5KYAL3jfPdejsHnrGGT2s--ZUX5SXznQWpHVSno429k,1157
|
|
27
|
+
xoscar/metrics/__init__.py,sha256=9Badi7rxYikGm2dQiNCrj9GgMRBxwuR3JaEKcFZmfak,705
|
|
28
|
+
xoscar/metrics/api.py,sha256=BBlMIFvVAGVfrtpeJ1YlH9Tqhy9OzGavwvGyeHcQ0Tk,8856
|
|
29
|
+
xoscar/metrics/backends/__init__.py,sha256=h_JgzSqV5lP6vQ6XX_17kE4IY4BRnvKta_7VLQAL1ms,581
|
|
30
|
+
xoscar/metrics/backends/metric.py,sha256=aPhyc8JgH22L3rcHP8IjsmgrhSODjg6B5TZVnre97y8,4446
|
|
31
|
+
xoscar/metrics/backends/prometheus/__init__.py,sha256=h_JgzSqV5lP6vQ6XX_17kE4IY4BRnvKta_7VLQAL1ms,581
|
|
32
|
+
xoscar/metrics/backends/prometheus/prometheus_metric.py,sha256=MxoMvVrg0pOkKpkjJ0PcAuEaaEJR2FZljmPrLjQ1-oc,2050
|
|
33
|
+
xoscar/metrics/backends/console/console_metric.py,sha256=y5CCtH33j3AqI5_Uhwi4mgOcAhyhb4cWv_YvR6fxcbQ,2082
|
|
34
|
+
xoscar/metrics/backends/console/__init__.py,sha256=h_JgzSqV5lP6vQ6XX_17kE4IY4BRnvKta_7VLQAL1ms,581
|
|
35
|
+
xoscar/collective/__init__.py,sha256=XsClIkO_3Jd8GDifYuAbZCmJLAo9ZqGvnjUn9iuogmU,774
|
|
36
|
+
xoscar/collective/core.py,sha256=NVR-7Iaq3aDPCN6fgXcq9Ew6uFEszRwxYqmUG9FLcws,23502
|
|
37
|
+
xoscar/collective/common.py,sha256=INAnISbfnRicbbbDHTqbSr9ITb89ZphH5BUkSpEdXXU,3561
|
|
38
|
+
xoscar/collective/utils.py,sha256=3S4qF4JEnAUD3RiWVBUj-ZptL83CBSwGYyVZyIasAsE,1178
|
|
39
|
+
xoscar/collective/xoscar_pygloo.cpython-312-darwin.so,sha256=vkMqFbgxW9NDS2gmPcIbQvPV62V_6C3KrpLOOCGXy30,1132944
|
|
40
|
+
xoscar/collective/process_group.py,sha256=zy7LcIFnEcmrcxuECI89v0bQlUbSqQMkVyBw468WBnk,22599
|
|
41
|
+
xoscar/collective/xoscar_pygloo.pyi,sha256=uM_jcyca3dpCZVQIdgj-KzMoXm-niL7mDu6HGS7kh1E,7377
|
|
42
|
+
xoscar/collective/backend/nccl_backend.py,sha256=7VvjAVTkr6qWJC1CztzJ5CN9USGJkstO-RAbaPKQA-Y,6280
|
|
43
|
+
xoscar/collective/backend/__init__.py,sha256=CyLLkbImZouAk4lePIgKXT4WQoqyauIEwdqea5IOUVU,581
|
|
44
|
+
xoscar/serialization/exception.py,sha256=Jy8Lsk0z-VJyEUaWeuZIwkmxqaoB-nLKMa1D15Cl4js,1634
|
|
45
|
+
xoscar/serialization/pyfury.py,sha256=sifOnVMYoS82PzZEkzkfxesmMHei23k5UAUUKUyoOYQ,1163
|
|
46
|
+
xoscar/serialization/core.pxd,sha256=k4RoJgX5E5LGs4jdCQ7vvcn26MabXbrWoWhkO49X6YI,985
|
|
47
|
+
xoscar/serialization/core.pyi,sha256=-pQARSj91rt3iU4ftWGFH6jYwsSKYCT_Ya7EJsaGEjg,1874
|
|
48
|
+
xoscar/serialization/core.cpython-312-darwin.so,sha256=flJjNs_Bx809aNpS0KDJKoQfaA2JGFHeXpn3yH4FYQs,406624
|
|
49
|
+
xoscar/serialization/__init__.py,sha256=Zz9E_Nydkph2iX7CW1bayqzFxerBLKxN6rsXV2u92GI,870
|
|
50
|
+
xoscar/serialization/numpy.py,sha256=5Kem87CvpJmzUMp3QHk4WeHU30FoQWTJJP2SwIcaQG0,2919
|
|
51
|
+
xoscar/serialization/cuda.py,sha256=iFUEnN4SiquBIhyieyOrfw3TnKnW-tU_vYgqOxO_DrA,3758
|
|
52
|
+
xoscar/serialization/scipy.py,sha256=yOEi0NB8cqQ6e2UnCZ1w006RsB7T725tIL-DM_hNcsU,2482
|
|
53
|
+
xoscar/serialization/aio.py,sha256=_DcJxf2aiQ4seO8oVKcMmoa8IiFBFTDEqH42P3tNc6k,4708
|
|
54
|
+
xoscar/serialization/core.pyx,sha256=bjR-zXGm9qersk7kYPzpjpMIxDl_Auur4BCubRfKmfA,29626
|
|
55
|
+
xoscar/serialization/torch.py,sha256=HyNt7RM7HKp69RWwbZY1PEL1Lj3Jc-T5YU_LDIFZM8Y,6739
|
|
56
|
+
xoscar/serialization/mlx.py,sha256=tRu_7o6RizdRhbr88EasHrZtShimAsLy3pIEO-by29o,2118
|
|
57
|
+
xoscar/backends/config.py,sha256=4tZMiXAMMS8qQ4SX_LjONLtSQVfZTx3m-IK3EqbkYdk,5375
|
|
58
|
+
xoscar/backends/message.pyi,sha256=DByZdNdZIMJhn1x4aE32deqi3vhU1bxfrTgzlQsaLpQ,6543
|
|
59
|
+
xoscar/backends/allocate_strategy.py,sha256=tC1Nbq2tJohahUwd-zoRYHEDX65wyuX8tmeY45uWj_w,4845
|
|
60
|
+
xoscar/backends/__init__.py,sha256=VHEBQcUWM5bj027W8EUf9PiJUAP7JoMrRw3Tsvy5ySw,643
|
|
61
|
+
xoscar/backends/core.py,sha256=hhowZJ1PmsmK1ap3IkIny-50cM3qawYbtUHVSBxzfPc,12845
|
|
62
|
+
xoscar/backends/context.py,sha256=XfDPG2eDhAhE6hWBEkEsHTnyyOYN9R3houlMjAL7BFw,16329
|
|
63
|
+
xoscar/backends/router.py,sha256=MVl5naz-FYf-Wla7XRn3kRxOpWV0SjKDsKNluifVA8M,10532
|
|
64
|
+
xoscar/backends/message.cpython-312-darwin.so,sha256=SweZE3qkIZdjJslIvXAv-Wz2pTWEOFlc1NRaeLNwXWQ,369888
|
|
65
|
+
xoscar/backends/message.pyx,sha256=krGVtZ1YDaZX8yWhaNHwZiudQooLvcGlw6x3Sq7jxjE,19685
|
|
66
|
+
xoscar/backends/pool.py,sha256=7yyU5EzU0Izf3j8ifGovpGbGR3KrCoYIU0L3JH_e9WM,60683
|
|
67
|
+
xoscar/backends/indigen/backend.py,sha256=znl_fZzWGEtLH8hZ9j9Kkf0fva25jEem2_KO7I1RVvc,1612
|
|
68
|
+
xoscar/backends/indigen/shared_memory.py,sha256=wqbckbgnd0qNm5KzlP_hklF3F_n8fKnCehSox5uMwNs,19082
|
|
69
|
+
xoscar/backends/indigen/__init__.py,sha256=tKHP5ClzedBRBpZsLRVErR3EUNbbDm4CY4u0rCFJr44,685
|
|
70
|
+
xoscar/backends/indigen/fate_sharing.py,sha256=3QUHwq5Cjk9oCKFUISvkqHaoxWZIaXcq8JNOetdBl-A,8655
|
|
71
|
+
xoscar/backends/indigen/driver.py,sha256=VGzkacYKykegW5qhCuhx01gdgBZEKJjNIyfNCnA6Nm8,952
|
|
72
|
+
xoscar/backends/indigen/pool.py,sha256=pt8B269wYTS4Rd0rpFoRdhfGkRt7qgeSZaGO0I9eQvI,18778
|
|
73
|
+
xoscar/backends/indigen/__main__.py,sha256=-pfio-Y4Ogbk6lBFksH-gRatp-N6sZ7wuNc-i2YsLJc,510
|
|
74
|
+
xoscar/backends/test/backend.py,sha256=nv9WFhH5Bbq4Q1HB9yfpciZBaeHT4IQAtzugBWESrUY,1263
|
|
75
|
+
xoscar/backends/test/__init__.py,sha256=j2ZfD6prD9WjUxRUDC7Eq5Z7N7TkL6fFr59oNyc_vY4,682
|
|
76
|
+
xoscar/backends/test/pool.py,sha256=tPq-MKHmiB9SOVo64y6Nv-U3evdxVQZuuWLYR-fj3ZA,8257
|
|
77
|
+
xoscar/backends/communication/ucx.py,sha256=_Dp9Ld2MWIa1txSGMnmfYwJDT0esxS-GOd2FQ4BdHiM,19960
|
|
78
|
+
xoscar/backends/communication/__init__.py,sha256=oFIg83Ga93-AhrG52TE85Z2LgpGZu1RCgQu1RWi62zQ,1063
|
|
79
|
+
xoscar/backends/communication/core.py,sha256=sJeE3foRIqVPXldzYpFKHDSsabfAIFBU4JuXY4OyklY,2130
|
|
80
|
+
xoscar/backends/communication/utils.py,sha256=AmovE-hmWLXNCPwHafYuaRjOk8m42BUyT3XBqfXQRVI,3664
|
|
81
|
+
xoscar/backends/communication/errors.py,sha256=V3CdBe2xX9Rwv32f2dH2Msc84yaUhlyerZ42-739o1Q,723
|
|
82
|
+
xoscar/backends/communication/socket.py,sha256=8GW-7HNnZE7tqvLyU6L9B75kaQvI4atc6AGwVHq1IGE,14482
|
|
83
|
+
xoscar/backends/communication/dummy.py,sha256=6kLkxjNk4xTQ-IlNZD6cftNCx5UsGOur2jk7ikrNUCg,8157
|
|
84
|
+
xoscar/backends/communication/base.py,sha256=0P4Tr35GSWpRp394e9jVWUUoKKa-gIk177eYPw1BnSU,7421
|
|
85
|
+
xoscar/aio/__init__.py,sha256=kViDKR_kJe59VQViHITKEfBcIgN4ZJblUyd8zl0E3ZI,675
|
|
86
|
+
xoscar/aio/file.py,sha256=PBtkLp-Q7XtYl-zk00s18TtgIrkNr60J3Itf66ctO1o,1486
|
|
87
|
+
xoscar/aio/lru.py,sha256=rpXCqSLtPV5xnWtd6uDwQQFGgIPEgvmWEQDkPNUx9cM,6311
|
|
88
|
+
xoscar/aio/parallelism.py,sha256=VSsjk8wP-Bw7tLeUsTyLVNgp91thjxEfE3pCrw_vF5Q,1293
|
|
89
|
+
xoscar/aio/base.py,sha256=9j0f1piwfE5R5GIvV212vSD03ixdaeSzSSsO2kxJZVE,2249
|
|
90
|
+
xoscar/virtualenv/__init__.py,sha256=65t9_X1DvbanNjFy366SiiWZrRTpa9SXWMXPmqayE-4,1117
|
|
91
|
+
xoscar/virtualenv/core.py,sha256=Ij36UQaej9fFaz1PfqkEtL1ss8yBribXHcWT115kH-o,8098
|
|
92
|
+
xoscar/virtualenv/platform.py,sha256=AhebqQL67C0i7Td3XaB7x82MMHPlB8frXs-LxxIgkgo,1555
|
|
93
|
+
xoscar/virtualenv/utils.py,sha256=qKHw7Gg0n3JuzKFjhBnftPq2QWlgNJLk1sGPr5GzamM,2875
|
|
94
|
+
xoscar/virtualenv/uv.py,sha256=VBw045LN8gYMLgjaazt7-tnwBveWr7YYE2zjDsL18h0,11091
|