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.
Files changed (94) hide show
  1. xoscar/__init__.py +61 -0
  2. xoscar/_utils.cpython-312-darwin.so +0 -0
  3. xoscar/_utils.pxd +36 -0
  4. xoscar/_utils.pyx +246 -0
  5. xoscar/_version.py +693 -0
  6. xoscar/aio/__init__.py +16 -0
  7. xoscar/aio/base.py +86 -0
  8. xoscar/aio/file.py +59 -0
  9. xoscar/aio/lru.py +228 -0
  10. xoscar/aio/parallelism.py +39 -0
  11. xoscar/api.py +527 -0
  12. xoscar/backend.py +67 -0
  13. xoscar/backends/__init__.py +14 -0
  14. xoscar/backends/allocate_strategy.py +160 -0
  15. xoscar/backends/communication/__init__.py +30 -0
  16. xoscar/backends/communication/base.py +315 -0
  17. xoscar/backends/communication/core.py +69 -0
  18. xoscar/backends/communication/dummy.py +253 -0
  19. xoscar/backends/communication/errors.py +20 -0
  20. xoscar/backends/communication/socket.py +444 -0
  21. xoscar/backends/communication/ucx.py +538 -0
  22. xoscar/backends/communication/utils.py +97 -0
  23. xoscar/backends/config.py +157 -0
  24. xoscar/backends/context.py +437 -0
  25. xoscar/backends/core.py +352 -0
  26. xoscar/backends/indigen/__init__.py +16 -0
  27. xoscar/backends/indigen/__main__.py +19 -0
  28. xoscar/backends/indigen/backend.py +51 -0
  29. xoscar/backends/indigen/driver.py +26 -0
  30. xoscar/backends/indigen/fate_sharing.py +221 -0
  31. xoscar/backends/indigen/pool.py +515 -0
  32. xoscar/backends/indigen/shared_memory.py +548 -0
  33. xoscar/backends/message.cpython-312-darwin.so +0 -0
  34. xoscar/backends/message.pyi +255 -0
  35. xoscar/backends/message.pyx +646 -0
  36. xoscar/backends/pool.py +1630 -0
  37. xoscar/backends/router.py +285 -0
  38. xoscar/backends/test/__init__.py +16 -0
  39. xoscar/backends/test/backend.py +38 -0
  40. xoscar/backends/test/pool.py +233 -0
  41. xoscar/batch.py +256 -0
  42. xoscar/collective/__init__.py +27 -0
  43. xoscar/collective/backend/__init__.py +13 -0
  44. xoscar/collective/backend/nccl_backend.py +160 -0
  45. xoscar/collective/common.py +102 -0
  46. xoscar/collective/core.py +737 -0
  47. xoscar/collective/process_group.py +687 -0
  48. xoscar/collective/utils.py +41 -0
  49. xoscar/collective/xoscar_pygloo.cpython-312-darwin.so +0 -0
  50. xoscar/collective/xoscar_pygloo.pyi +239 -0
  51. xoscar/constants.py +23 -0
  52. xoscar/context.cpython-312-darwin.so +0 -0
  53. xoscar/context.pxd +21 -0
  54. xoscar/context.pyx +368 -0
  55. xoscar/core.cpython-312-darwin.so +0 -0
  56. xoscar/core.pxd +51 -0
  57. xoscar/core.pyx +664 -0
  58. xoscar/debug.py +188 -0
  59. xoscar/driver.py +42 -0
  60. xoscar/errors.py +63 -0
  61. xoscar/libcpp.pxd +31 -0
  62. xoscar/metrics/__init__.py +21 -0
  63. xoscar/metrics/api.py +288 -0
  64. xoscar/metrics/backends/__init__.py +13 -0
  65. xoscar/metrics/backends/console/__init__.py +13 -0
  66. xoscar/metrics/backends/console/console_metric.py +82 -0
  67. xoscar/metrics/backends/metric.py +149 -0
  68. xoscar/metrics/backends/prometheus/__init__.py +13 -0
  69. xoscar/metrics/backends/prometheus/prometheus_metric.py +70 -0
  70. xoscar/nvutils.py +717 -0
  71. xoscar/profiling.py +260 -0
  72. xoscar/serialization/__init__.py +20 -0
  73. xoscar/serialization/aio.py +141 -0
  74. xoscar/serialization/core.cpython-312-darwin.so +0 -0
  75. xoscar/serialization/core.pxd +28 -0
  76. xoscar/serialization/core.pyi +57 -0
  77. xoscar/serialization/core.pyx +944 -0
  78. xoscar/serialization/cuda.py +111 -0
  79. xoscar/serialization/exception.py +48 -0
  80. xoscar/serialization/mlx.py +67 -0
  81. xoscar/serialization/numpy.py +82 -0
  82. xoscar/serialization/pyfury.py +37 -0
  83. xoscar/serialization/scipy.py +72 -0
  84. xoscar/serialization/torch.py +180 -0
  85. xoscar/utils.py +522 -0
  86. xoscar/virtualenv/__init__.py +34 -0
  87. xoscar/virtualenv/core.py +268 -0
  88. xoscar/virtualenv/platform.py +56 -0
  89. xoscar/virtualenv/utils.py +100 -0
  90. xoscar/virtualenv/uv.py +321 -0
  91. xoscar-0.9.0.dist-info/METADATA +230 -0
  92. xoscar-0.9.0.dist-info/RECORD +94 -0
  93. xoscar-0.9.0.dist-info/WHEEL +6 -0
  94. xoscar-0.9.0.dist-info/top_level.txt +2 -0
@@ -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
+ [![PyPI Latest Release](https://img.shields.io/pypi/v/xoscar.svg?style=for-the-badge)](https://pypi.org/project/xoscar/)
68
+ [![Coverage](https://img.shields.io/codecov/c/github/xorbitsai/xoscar?style=for-the-badge)](https://codecov.io/gh/xorbitsai/xoscar)
69
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/xorbitsai/xoscar/python.yaml?branch=main&style=for-the-badge&label=GITHUB%20ACTIONS&logo=github)](https://actions-badge.atrox.dev/xorbitsai/xoscar/goto?ref=main)
70
+ [![License](https://img.shields.io/pypi/l/xoscar.svg?style=for-the-badge)](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
+ ![architecture.png](doc/source/_static/architecture.png)
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
@@ -0,0 +1,6 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp312-cp312-macosx_10_13_x86_64
5
+ Generator: delocate 0.13.0
6
+
@@ -0,0 +1,2 @@
1
+ xoscar
2
+ xoscar_pygloo