kubetorch 0.2.5__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.
- kubetorch/__init__.py +59 -0
- kubetorch/cli.py +1939 -0
- kubetorch/cli_utils.py +967 -0
- kubetorch/config.py +453 -0
- kubetorch/constants.py +18 -0
- kubetorch/docs/Makefile +18 -0
- kubetorch/docs/__init__.py +0 -0
- kubetorch/docs/_ext/json_globaltoc.py +42 -0
- kubetorch/docs/api/cli.rst +10 -0
- kubetorch/docs/api/python/app.rst +21 -0
- kubetorch/docs/api/python/cls.rst +19 -0
- kubetorch/docs/api/python/compute.rst +25 -0
- kubetorch/docs/api/python/config.rst +11 -0
- kubetorch/docs/api/python/fn.rst +19 -0
- kubetorch/docs/api/python/image.rst +14 -0
- kubetorch/docs/api/python/secret.rst +18 -0
- kubetorch/docs/api/python/volumes.rst +13 -0
- kubetorch/docs/api/python.rst +101 -0
- kubetorch/docs/conf.py +69 -0
- kubetorch/docs/index.rst +20 -0
- kubetorch/docs/requirements.txt +5 -0
- kubetorch/globals.py +269 -0
- kubetorch/logger.py +59 -0
- kubetorch/resources/__init__.py +0 -0
- kubetorch/resources/callables/__init__.py +0 -0
- kubetorch/resources/callables/cls/__init__.py +0 -0
- kubetorch/resources/callables/cls/cls.py +159 -0
- kubetorch/resources/callables/fn/__init__.py +0 -0
- kubetorch/resources/callables/fn/fn.py +140 -0
- kubetorch/resources/callables/module.py +1315 -0
- kubetorch/resources/callables/utils.py +203 -0
- kubetorch/resources/compute/__init__.py +0 -0
- kubetorch/resources/compute/app.py +253 -0
- kubetorch/resources/compute/compute.py +2414 -0
- kubetorch/resources/compute/decorators.py +137 -0
- kubetorch/resources/compute/utils.py +1026 -0
- kubetorch/resources/compute/websocket.py +135 -0
- kubetorch/resources/images/__init__.py +1 -0
- kubetorch/resources/images/image.py +412 -0
- kubetorch/resources/images/images.py +64 -0
- kubetorch/resources/secrets/__init__.py +2 -0
- kubetorch/resources/secrets/kubernetes_secrets_client.py +377 -0
- kubetorch/resources/secrets/provider_secrets/__init__.py +0 -0
- kubetorch/resources/secrets/provider_secrets/anthropic_secret.py +12 -0
- kubetorch/resources/secrets/provider_secrets/aws_secret.py +16 -0
- kubetorch/resources/secrets/provider_secrets/azure_secret.py +14 -0
- kubetorch/resources/secrets/provider_secrets/cohere_secret.py +12 -0
- kubetorch/resources/secrets/provider_secrets/gcp_secret.py +16 -0
- kubetorch/resources/secrets/provider_secrets/github_secret.py +13 -0
- kubetorch/resources/secrets/provider_secrets/huggingface_secret.py +20 -0
- kubetorch/resources/secrets/provider_secrets/kubeconfig_secret.py +12 -0
- kubetorch/resources/secrets/provider_secrets/lambda_secret.py +13 -0
- kubetorch/resources/secrets/provider_secrets/langchain_secret.py +12 -0
- kubetorch/resources/secrets/provider_secrets/openai_secret.py +11 -0
- kubetorch/resources/secrets/provider_secrets/pinecone_secret.py +12 -0
- kubetorch/resources/secrets/provider_secrets/providers.py +92 -0
- kubetorch/resources/secrets/provider_secrets/ssh_secret.py +12 -0
- kubetorch/resources/secrets/provider_secrets/wandb_secret.py +11 -0
- kubetorch/resources/secrets/secret.py +224 -0
- kubetorch/resources/secrets/secret_factory.py +64 -0
- kubetorch/resources/secrets/utils.py +222 -0
- kubetorch/resources/volumes/__init__.py +0 -0
- kubetorch/resources/volumes/volume.py +340 -0
- kubetorch/servers/__init__.py +0 -0
- kubetorch/servers/http/__init__.py +0 -0
- kubetorch/servers/http/distributed_utils.py +2968 -0
- kubetorch/servers/http/http_client.py +802 -0
- kubetorch/servers/http/http_server.py +1622 -0
- kubetorch/servers/http/server_metrics.py +255 -0
- kubetorch/servers/http/utils.py +722 -0
- kubetorch/serving/__init__.py +0 -0
- kubetorch/serving/autoscaling.py +153 -0
- kubetorch/serving/base_service_manager.py +344 -0
- kubetorch/serving/constants.py +77 -0
- kubetorch/serving/deployment_service_manager.py +431 -0
- kubetorch/serving/knative_service_manager.py +487 -0
- kubetorch/serving/raycluster_service_manager.py +526 -0
- kubetorch/serving/service_manager.py +18 -0
- kubetorch/serving/templates/deployment_template.yaml +17 -0
- kubetorch/serving/templates/knative_service_template.yaml +19 -0
- kubetorch/serving/templates/kt_setup_template.sh.j2 +91 -0
- kubetorch/serving/templates/pod_template.yaml +198 -0
- kubetorch/serving/templates/raycluster_service_template.yaml +42 -0
- kubetorch/serving/templates/raycluster_template.yaml +35 -0
- kubetorch/serving/templates/service_template.yaml +21 -0
- kubetorch/serving/templates/workerset_template.yaml +36 -0
- kubetorch/serving/utils.py +344 -0
- kubetorch/utils.py +263 -0
- kubetorch-0.2.5.dist-info/METADATA +75 -0
- kubetorch-0.2.5.dist-info/RECORD +92 -0
- kubetorch-0.2.5.dist-info/WHEEL +4 -0
- kubetorch-0.2.5.dist-info/entry_points.txt +5 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
from kubetorch.logger import get_logger
|
|
2
|
+
from kubetorch.resources.callables.module import Module
|
|
3
|
+
from kubetorch.resources.callables.utils import extract_pointers, SHELL_COMMANDS
|
|
4
|
+
|
|
5
|
+
logger = get_logger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Cls(Module):
|
|
9
|
+
MODULE_TYPE = "cls"
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
name: str,
|
|
14
|
+
pointers: tuple = None,
|
|
15
|
+
init_args: dict = None,
|
|
16
|
+
):
|
|
17
|
+
"""
|
|
18
|
+
Initialize a Cls object for remote class execution.
|
|
19
|
+
|
|
20
|
+
.. note::
|
|
21
|
+
|
|
22
|
+
To create a Cls, please use the factory method :func:`cls`.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
name (str): The name of the class to be executed remotely.
|
|
26
|
+
pointers (tuple, optional): A tuple containing pointers/references needed to locate and execute
|
|
27
|
+
the class, typically including module path and class name.
|
|
28
|
+
init_args (dict, optional): Dictionary of arguments to pass to the class constructor.
|
|
29
|
+
Defaults to None.
|
|
30
|
+
"""
|
|
31
|
+
self._init_args = init_args
|
|
32
|
+
if not pointers:
|
|
33
|
+
# local to the class definition
|
|
34
|
+
pointers = extract_pointers(self.__class__)
|
|
35
|
+
|
|
36
|
+
super().__init__(name=name, pointers=pointers)
|
|
37
|
+
|
|
38
|
+
def __getattr__(self, attr_name):
|
|
39
|
+
if attr_name in SHELL_COMMANDS:
|
|
40
|
+
return getattr(self.compute, attr_name)
|
|
41
|
+
|
|
42
|
+
if not attr_name.startswith("_") and attr_name not in CLASS_METHODS:
|
|
43
|
+
|
|
44
|
+
def remote_method_wrapper(*args, **kwargs):
|
|
45
|
+
async_ = kwargs.pop("async_", self.async_)
|
|
46
|
+
|
|
47
|
+
if async_:
|
|
48
|
+
return self._call_async(attr_name, *args, **kwargs)
|
|
49
|
+
else:
|
|
50
|
+
return self._call_sync(attr_name, *args, **kwargs)
|
|
51
|
+
|
|
52
|
+
return remote_method_wrapper
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def init_args(self):
|
|
56
|
+
return self._init_args
|
|
57
|
+
|
|
58
|
+
@init_args.setter
|
|
59
|
+
def init_args(self, value):
|
|
60
|
+
self._init_args = value
|
|
61
|
+
|
|
62
|
+
def _call_sync(self, method_name, *args, **kwargs):
|
|
63
|
+
"""Synchronous call implementation."""
|
|
64
|
+
client = self._client(method_name=method_name)
|
|
65
|
+
stream_logs = kwargs.pop("stream_logs", None)
|
|
66
|
+
stream_metrics = kwargs.pop("stream_metrics", None)
|
|
67
|
+
pdb = kwargs.pop("pdb", None)
|
|
68
|
+
if pdb:
|
|
69
|
+
logger.info(f"Debugging remote cls {self.name}.{method_name}")
|
|
70
|
+
elif stream_logs:
|
|
71
|
+
logger.info(f"Calling remote cls {self.name}.{method_name}")
|
|
72
|
+
|
|
73
|
+
response = client.call_method(
|
|
74
|
+
self.endpoint(method_name),
|
|
75
|
+
stream_logs=stream_logs,
|
|
76
|
+
stream_metrics=stream_metrics,
|
|
77
|
+
headers=self.request_headers,
|
|
78
|
+
body={"args": list(args), "kwargs": kwargs},
|
|
79
|
+
pdb=pdb,
|
|
80
|
+
serialization=kwargs.pop("serialization", self.serialization),
|
|
81
|
+
)
|
|
82
|
+
return response
|
|
83
|
+
|
|
84
|
+
async def _call_async(self, method_name, *args, **kwargs):
|
|
85
|
+
"""Asynchronous call implementation."""
|
|
86
|
+
client = self._client(method_name=method_name)
|
|
87
|
+
stream_logs = kwargs.pop("stream_logs", None)
|
|
88
|
+
stream_metrics = kwargs.pop("stream_metrics", None)
|
|
89
|
+
pdb = kwargs.pop("pdb", None)
|
|
90
|
+
if pdb:
|
|
91
|
+
logger.info(f"Debugging remote cls {self.name}.{method_name} (async)")
|
|
92
|
+
elif stream_logs:
|
|
93
|
+
logger.info(f"Calling remote cls {self.name}.{method_name} (async)")
|
|
94
|
+
|
|
95
|
+
response = await client.call_method_async(
|
|
96
|
+
self.endpoint(method_name),
|
|
97
|
+
stream_logs=stream_logs,
|
|
98
|
+
stream_metrics=stream_metrics,
|
|
99
|
+
headers=self.request_headers,
|
|
100
|
+
body={"args": list(args), "kwargs": kwargs},
|
|
101
|
+
pdb=pdb,
|
|
102
|
+
serialization=kwargs.pop("serialization", self.serialization),
|
|
103
|
+
)
|
|
104
|
+
return response
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def cls(class_obj=None, name: str = None, get_if_exists=True, reload_prefixes=None):
|
|
108
|
+
"""
|
|
109
|
+
Builds an instance of :class:`Cls`.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
class_obj (Cls, optional): The class to be executed remotely. If not provided and name is
|
|
113
|
+
specified, will reload an existing cls object.
|
|
114
|
+
name (str, optional): The name to give the remote class. If not provided,
|
|
115
|
+
will use the class's name.
|
|
116
|
+
get_if_exists (bool, optional):
|
|
117
|
+
Controls how service lookup is performed when loading by name.
|
|
118
|
+
|
|
119
|
+
- If True (default): Attempt to find an existing service using a standard fallback order
|
|
120
|
+
(e.g., username, git branch, then prod).
|
|
121
|
+
- If False: Only look for an exact name match; do not attempt any fallback.
|
|
122
|
+
|
|
123
|
+
This allows you to control whether and how the loader should fall back to alternate
|
|
124
|
+
versions of a service (such as QA, prod, or CI versions) if the exact name is not found.
|
|
125
|
+
reload_prefixes (Union[str, List[str]], optional):
|
|
126
|
+
A list of prefixes to use when reloading the class (e.g., ["qa", "prod", "git-branch-name"]).
|
|
127
|
+
If not provided, will use the current username, git branch, and prod.
|
|
128
|
+
|
|
129
|
+
Example:
|
|
130
|
+
|
|
131
|
+
.. code-block:: python
|
|
132
|
+
|
|
133
|
+
import kubetorch as kt
|
|
134
|
+
|
|
135
|
+
remote_cls = kt.cls(MyClass, name="my-class").to(kt.Compute(cpus=".1"))
|
|
136
|
+
result = remote_cls.my_method(1, 2)
|
|
137
|
+
"""
|
|
138
|
+
if class_obj:
|
|
139
|
+
cls_pointers = extract_pointers(class_obj)
|
|
140
|
+
name = name or (cls_pointers[2] if cls_pointers else cls.__name__)
|
|
141
|
+
new_cls = Cls(
|
|
142
|
+
name=name,
|
|
143
|
+
pointers=cls_pointers,
|
|
144
|
+
)
|
|
145
|
+
new_cls.get_if_exists = get_if_exists
|
|
146
|
+
new_cls.reload_prefixes = reload_prefixes or []
|
|
147
|
+
return new_cls
|
|
148
|
+
|
|
149
|
+
if name is None:
|
|
150
|
+
raise ValueError("Name must be provided to reload an existing class")
|
|
151
|
+
|
|
152
|
+
if get_if_exists is False:
|
|
153
|
+
raise ValueError("Either provide a class object or a name with get_if_exists=True to reload an existing class")
|
|
154
|
+
|
|
155
|
+
reloaded_cls = Cls.from_name(name, reload_prefixes=reload_prefixes)
|
|
156
|
+
return reloaded_cls
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
CLASS_METHODS = dir(Cls)
|
|
File without changes
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from kubetorch.logger import get_logger
|
|
2
|
+
from kubetorch.resources.callables.module import Module
|
|
3
|
+
from kubetorch.resources.callables.utils import extract_pointers, prepare_notebook_fn
|
|
4
|
+
|
|
5
|
+
logger = get_logger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Fn(Module):
|
|
9
|
+
MODULE_TYPE = "fn"
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
name: str,
|
|
14
|
+
pointers: tuple = None,
|
|
15
|
+
):
|
|
16
|
+
"""
|
|
17
|
+
Initialize a Fn object for remote function execution.
|
|
18
|
+
|
|
19
|
+
.. note::
|
|
20
|
+
|
|
21
|
+
To create a Function, please use the factory method :func:`fn`.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
name (str): The name of the function to be executed remotely.
|
|
25
|
+
pointers (tuple, optional): A tuple containing pointers/references needed to locate and execute
|
|
26
|
+
the function, typically including module path, class name (if applicable), and
|
|
27
|
+
function name.
|
|
28
|
+
"""
|
|
29
|
+
super().__init__(name=name, pointers=pointers)
|
|
30
|
+
|
|
31
|
+
def __call__(self, *args, **kwargs):
|
|
32
|
+
async_ = kwargs.pop("async_", self.async_)
|
|
33
|
+
|
|
34
|
+
if async_:
|
|
35
|
+
return self._call_async(*args, **kwargs)
|
|
36
|
+
else:
|
|
37
|
+
return self._call_sync(*args, **kwargs)
|
|
38
|
+
|
|
39
|
+
def _call_sync(self, *args, **kwargs):
|
|
40
|
+
client = self._client()
|
|
41
|
+
stream_logs = kwargs.pop("stream_logs", None)
|
|
42
|
+
stream_metrics = kwargs.pop("stream_metrics", None)
|
|
43
|
+
pdb = kwargs.pop("pdb", None)
|
|
44
|
+
if pdb:
|
|
45
|
+
logger.info(f"Debugging remote function {self.name}")
|
|
46
|
+
elif stream_logs:
|
|
47
|
+
logger.info(f"Calling remote function {self.name}")
|
|
48
|
+
|
|
49
|
+
response = client.call_method(
|
|
50
|
+
self.endpoint(),
|
|
51
|
+
stream_logs=stream_logs,
|
|
52
|
+
stream_metrics=stream_metrics,
|
|
53
|
+
headers=self.request_headers,
|
|
54
|
+
body={"args": list(args), "kwargs": kwargs},
|
|
55
|
+
pdb=pdb,
|
|
56
|
+
serialization=kwargs.pop("serialization", self.serialization),
|
|
57
|
+
)
|
|
58
|
+
return response
|
|
59
|
+
|
|
60
|
+
async def _call_async(self, *args, **kwargs):
|
|
61
|
+
"""Asynchronous call implementation."""
|
|
62
|
+
client = self._client()
|
|
63
|
+
stream_logs = kwargs.pop("stream_logs", None)
|
|
64
|
+
stream_metrics = kwargs.pop("stream_metrics", None)
|
|
65
|
+
pdb = kwargs.pop("pdb", None)
|
|
66
|
+
if pdb:
|
|
67
|
+
logger.info(f"Debugging remote function {self.name}")
|
|
68
|
+
elif stream_logs:
|
|
69
|
+
logger.info(f"Calling remote function {self.name}")
|
|
70
|
+
|
|
71
|
+
response = await client.call_method_async(
|
|
72
|
+
self.endpoint(),
|
|
73
|
+
stream_logs=stream_logs,
|
|
74
|
+
stream_metrics=stream_metrics,
|
|
75
|
+
headers=self.request_headers,
|
|
76
|
+
body={"args": list(args), "kwargs": kwargs},
|
|
77
|
+
pdb=pdb,
|
|
78
|
+
serialization=kwargs.pop("serialization", self.serialization),
|
|
79
|
+
)
|
|
80
|
+
return response
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def fn(function_obj=None, name: str = None, get_if_exists=True, reload_prefixes=None):
|
|
84
|
+
"""
|
|
85
|
+
Builds an instance of :class:`Fn`.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
function_obj (Fn, optional): The function to be executed remotely. If not provided and name is
|
|
89
|
+
specified, will reload an existing fn object.
|
|
90
|
+
name (str, optional): The name to give the remote function. If not provided,
|
|
91
|
+
will use the function's name.
|
|
92
|
+
get_if_exists (bool, optional):
|
|
93
|
+
Controls how service lookup is performed when loading by name.
|
|
94
|
+
|
|
95
|
+
- If True (default): Attempt to find an existing service using a standard fallback order
|
|
96
|
+
(e.g., username, git branch, then prod).
|
|
97
|
+
- If False: Only look for an exact name match; do not attempt any fallback.
|
|
98
|
+
|
|
99
|
+
This allows you to control whether and how the loader should fall back to alternate
|
|
100
|
+
versions of a service (such as QA, prod, or CI versions) if the exact name is not found.
|
|
101
|
+
reload_prefixes (Union[str, List[str]], optional):
|
|
102
|
+
A list of prefixes to use when reloading the function (e.g., ["qa", "prod", "git-branch-name"]).
|
|
103
|
+
If not provided, will use the current username, git branch, and prod.
|
|
104
|
+
|
|
105
|
+
Example:
|
|
106
|
+
|
|
107
|
+
.. code-block:: python
|
|
108
|
+
|
|
109
|
+
import kubetorch as kt
|
|
110
|
+
|
|
111
|
+
remote_fn = kt.fn(my_func, name="some-func").to(kt.Compute(cpus=".1"))
|
|
112
|
+
result = remote_fn(1, 2)
|
|
113
|
+
"""
|
|
114
|
+
if function_obj:
|
|
115
|
+
fn_pointers = extract_pointers(function_obj)
|
|
116
|
+
if fn_pointers[1] == "notebook":
|
|
117
|
+
fn_pointers = prepare_notebook_fn(fn_pointers, name=fn_pointers[2] or name)
|
|
118
|
+
|
|
119
|
+
name = name or (fn_pointers[2] if fn_pointers else function_obj.__name__)
|
|
120
|
+
new_fn = Fn(
|
|
121
|
+
name=name,
|
|
122
|
+
pointers=fn_pointers,
|
|
123
|
+
)
|
|
124
|
+
new_fn.get_if_exists = get_if_exists
|
|
125
|
+
new_fn.reload_prefixes = reload_prefixes or []
|
|
126
|
+
return new_fn
|
|
127
|
+
|
|
128
|
+
if name is None:
|
|
129
|
+
raise ValueError("Name must be provided to reload an existing function")
|
|
130
|
+
|
|
131
|
+
if get_if_exists is False:
|
|
132
|
+
raise ValueError(
|
|
133
|
+
"Either provide a function object or a name with get_if_exists=True to reload an existing function"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
reloaded_fn = Fn.from_name(name, reload_prefixes=reload_prefixes)
|
|
137
|
+
return reloaded_fn
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
FN_METHODS = dir(Fn)
|