arkitekt-next 0.8.60__py3-none-any.whl → 0.8.62__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.
Potentially problematic release.
This version of arkitekt-next might be problematic. Click here for more details.
- arkitekt_next/__blok__.py +3 -0
- arkitekt_next/__init__.py +5 -1
- arkitekt_next/base_models.py +2 -4
- arkitekt_next/bloks/arkitekt.py +15 -13
- arkitekt_next/bloks/base.py +6 -4
- arkitekt_next/bloks/gateway.py +10 -6
- arkitekt_next/bloks/kraph.py +4 -1
- arkitekt_next/bloks/local_sign.py +261 -0
- arkitekt_next/bloks/lok.py +5 -3
- arkitekt_next/bloks/ollama.py +1 -4
- arkitekt_next/bloks/orkestrator.py +4 -6
- arkitekt_next/bloks/self_signed.py +1 -8
- arkitekt_next/bloks/services/certer.py +2 -2
- arkitekt_next/cli/commands/gen/init.py +2 -2
- arkitekt_next/cli/commands/inspect/templates.py +0 -2
- arkitekt_next/cli/commands/kabinet/build.py +28 -9
- arkitekt_next/cli/commands/kabinet/init.py +1 -1
- arkitekt_next/cli/commands/kabinet/io.py +206 -0
- arkitekt_next/cli/commands/kabinet/main.py +27 -15
- arkitekt_next/cli/commands/kabinet/publish.py +2 -2
- arkitekt_next/cli/commands/kabinet/stage.py +1 -1
- arkitekt_next/cli/commands/kabinet/types.py +139 -0
- arkitekt_next/cli/commands/kabinet/utils.py +1 -1
- arkitekt_next/cli/commands/kabinet/validate.py +1 -1
- arkitekt_next/cli/commands/manifest/inspect.py +2 -7
- arkitekt_next/cli/commands/manifest/main.py +0 -2
- arkitekt_next/cli/io.py +0 -192
- arkitekt_next/cli/types.py +2 -147
- arkitekt_next/cli/ui.py +1 -1
- arkitekt_next/init_registry.py +2 -11
- arkitekt_next/qt/builders.py +2 -3
- arkitekt_next/service_registry.py +5 -87
- arkitekt_next/utils.py +3 -2
- {arkitekt_next-0.8.60.dist-info → arkitekt_next-0.8.62.dist-info}/METADATA +19 -9
- {arkitekt_next-0.8.60.dist-info → arkitekt_next-0.8.62.dist-info}/RECORD +38 -37
- arkitekt_next/cli/commands/kabinet/wizard.py +0 -329
- arkitekt_next/cli/commands/manifest/wizard.py +0 -94
- {arkitekt_next-0.8.60.dist-info → arkitekt_next-0.8.62.dist-info}/LICENSE +0 -0
- {arkitekt_next-0.8.60.dist-info → arkitekt_next-0.8.62.dist-info}/WHEEL +0 -0
- {arkitekt_next-0.8.60.dist-info → arkitekt_next-0.8.62.dist-info}/entry_points.txt +0 -0
arkitekt_next/cli/io.py
CHANGED
|
@@ -5,18 +5,7 @@ import os
|
|
|
5
5
|
from typing import Optional, List, Dict
|
|
6
6
|
from arkitekt_next.cli.types import (
|
|
7
7
|
Manifest,
|
|
8
|
-
Build,
|
|
9
|
-
BuildsConfigFile,
|
|
10
|
-
Flavour,
|
|
11
|
-
DeploymentsConfigFile,
|
|
12
8
|
)
|
|
13
|
-
from kabinet.api.schema import (
|
|
14
|
-
InspectionInput,
|
|
15
|
-
AppImageInput,
|
|
16
|
-
DockerImageInput,
|
|
17
|
-
ManifestInput,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
9
|
import yaml
|
|
21
10
|
import json
|
|
22
11
|
import rich_click as click
|
|
@@ -83,184 +72,3 @@ def write_manifest(manifest: Manifest):
|
|
|
83
72
|
file,
|
|
84
73
|
sort_keys=True,
|
|
85
74
|
)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def get_builds(selected_run: Optional[str] = None) -> Dict[str, Build]:
|
|
89
|
-
"""Will load the builds.yaml file and return a dictionary of builds
|
|
90
|
-
|
|
91
|
-
Will load the builds.yaml file and return a dictionary of builds
|
|
92
|
-
where the key is the build_id and the value is the build object.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
Returns
|
|
96
|
-
-------
|
|
97
|
-
Dict[str, Build]
|
|
98
|
-
The loaded builds
|
|
99
|
-
"""
|
|
100
|
-
path = create_arkitekt_next_folder()
|
|
101
|
-
config_file = os.path.join(path, "builds.yaml")
|
|
102
|
-
|
|
103
|
-
builds = {}
|
|
104
|
-
|
|
105
|
-
if os.path.exists(config_file):
|
|
106
|
-
with open(config_file, "r") as file:
|
|
107
|
-
config = BuildsConfigFile(**yaml.safe_load(file))
|
|
108
|
-
|
|
109
|
-
# We will only return the builds from the selected run
|
|
110
|
-
selected_run = selected_run or config.latest_build_run
|
|
111
|
-
|
|
112
|
-
builds = {
|
|
113
|
-
build.build_id: build
|
|
114
|
-
for build in config.builds
|
|
115
|
-
if build.build_run == selected_run
|
|
116
|
-
}
|
|
117
|
-
return builds
|
|
118
|
-
else:
|
|
119
|
-
raise click.ClickException(
|
|
120
|
-
"Could not find any builds. Please run `arkitekt_next port build` first"
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
def manifest_to_input(manifest: Manifest) -> ManifestInput:
|
|
125
|
-
|
|
126
|
-
return ManifestInput(**manifest.model_dump(by_alias=True))
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def generate_build(
|
|
130
|
-
build_run: str,
|
|
131
|
-
build_id: str,
|
|
132
|
-
flavour_name: str,
|
|
133
|
-
flavour: Flavour,
|
|
134
|
-
manifest: Manifest,
|
|
135
|
-
inspection: Optional[InspectionInput],
|
|
136
|
-
) -> Build:
|
|
137
|
-
"""Generates a build from a builder, build_id and manifest
|
|
138
|
-
|
|
139
|
-
Will generate a build from a builder, build_id and manifest,
|
|
140
|
-
and write it to the builds.yaml file in the arkitekt_next folder.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
Parameters
|
|
144
|
-
----------
|
|
145
|
-
builder : str
|
|
146
|
-
The builder that was used to build the build
|
|
147
|
-
build_id : str
|
|
148
|
-
The build_id of the build
|
|
149
|
-
manifest : Manifest
|
|
150
|
-
The manifest of the build
|
|
151
|
-
|
|
152
|
-
Returns
|
|
153
|
-
-------
|
|
154
|
-
Build
|
|
155
|
-
The generated build
|
|
156
|
-
"""
|
|
157
|
-
path = create_arkitekt_next_folder()
|
|
158
|
-
|
|
159
|
-
config_file = os.path.join(path, "builds.yaml")
|
|
160
|
-
|
|
161
|
-
build = Build(
|
|
162
|
-
manifest=manifest_to_input(manifest),
|
|
163
|
-
flavour=flavour_name,
|
|
164
|
-
selectors=flavour.selectors,
|
|
165
|
-
build_id=build_id,
|
|
166
|
-
build_run=build_run,
|
|
167
|
-
description=flavour.description,
|
|
168
|
-
inspection=inspection,
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
if os.path.exists(config_file):
|
|
172
|
-
with open(config_file, "r") as file:
|
|
173
|
-
config = BuildsConfigFile(**yaml.safe_load(file))
|
|
174
|
-
config.builds.append(build)
|
|
175
|
-
config.latest_build_run = build_run
|
|
176
|
-
else:
|
|
177
|
-
config = BuildsConfigFile(builds=[build], latest_build_run=build_run)
|
|
178
|
-
|
|
179
|
-
with open(config_file, "w") as file:
|
|
180
|
-
yaml.safe_dump(
|
|
181
|
-
json.loads(
|
|
182
|
-
config.json(exclude_none=True, exclude_unset=True, by_alias=True)
|
|
183
|
-
),
|
|
184
|
-
file,
|
|
185
|
-
sort_keys=True,
|
|
186
|
-
)
|
|
187
|
-
|
|
188
|
-
return build
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def get_deployments() -> DeploymentsConfigFile:
|
|
192
|
-
"""Loads the deployments.yaml file and returns the deployments
|
|
193
|
-
|
|
194
|
-
Will load the deployments.yaml file and return the deployments
|
|
195
|
-
as a DeploymentsConfigFile object. If no deployments.yaml file
|
|
196
|
-
exists, it will return an empty DeploymentsConfigFile object.
|
|
197
|
-
|
|
198
|
-
Returns
|
|
199
|
-
-------
|
|
200
|
-
DeploymentsConfigFile
|
|
201
|
-
The deployments as a DeploymentsConfigFile object
|
|
202
|
-
"""
|
|
203
|
-
path = create_arkitekt_next_folder()
|
|
204
|
-
config_file = os.path.join(path, "deployments.yaml")
|
|
205
|
-
if os.path.exists(config_file):
|
|
206
|
-
with open(config_file, "r") as file:
|
|
207
|
-
return DeploymentsConfigFile(**yaml.safe_load(file))
|
|
208
|
-
else:
|
|
209
|
-
return DeploymentsConfigFile()
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
def generate_deployment(
|
|
213
|
-
deployment_run: str,
|
|
214
|
-
build: Build,
|
|
215
|
-
image: str,
|
|
216
|
-
) -> AppImageInput:
|
|
217
|
-
"""Generates a deployment from a build and an image
|
|
218
|
-
|
|
219
|
-
Parameters
|
|
220
|
-
----------
|
|
221
|
-
|
|
222
|
-
build : Build
|
|
223
|
-
The build that should be deployed
|
|
224
|
-
image: str
|
|
225
|
-
The image that is the actuall deployment of the build
|
|
226
|
-
with_definitions: bool:
|
|
227
|
-
Should we generated and inspect definitions to bundle with
|
|
228
|
-
the deployment?
|
|
229
|
-
|
|
230
|
-
Returns:
|
|
231
|
-
------
|
|
232
|
-
Deployment: The created deployment
|
|
233
|
-
|
|
234
|
-
"""
|
|
235
|
-
|
|
236
|
-
path = create_arkitekt_next_folder()
|
|
237
|
-
|
|
238
|
-
config_file = os.path.join(path, "deployments.yaml")
|
|
239
|
-
|
|
240
|
-
app_image = AppImageInput(
|
|
241
|
-
appImageId=uuid.uuid4().hex,
|
|
242
|
-
manifest=build.manifest,
|
|
243
|
-
flavourName=build.flavour,
|
|
244
|
-
selectors=build.selectors,
|
|
245
|
-
inspection=build.inspection,
|
|
246
|
-
image=DockerImageInput(imageString=image, buildAt=datetime.datetime.now()),
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
if os.path.exists(config_file):
|
|
250
|
-
with open(config_file, "r") as file:
|
|
251
|
-
config = DeploymentsConfigFile(**yaml.safe_load(file))
|
|
252
|
-
config.app_images.append(app_image)
|
|
253
|
-
config.latest_app_image = app_image.app_image_id
|
|
254
|
-
else:
|
|
255
|
-
config = DeploymentsConfigFile(
|
|
256
|
-
app_images=[app_image], latest_app_image=app_image.app_image_id
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
with open(config_file, "w") as file:
|
|
260
|
-
yaml.safe_dump(
|
|
261
|
-
json.loads(config.model_dump_json(exclude_none=True, by_alias=True)),
|
|
262
|
-
file,
|
|
263
|
-
sort_keys=True,
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
return app_image
|
arkitekt_next/cli/types.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from importlib.metadata import version
|
|
2
|
-
from pydantic import BaseModel, Field, field_validator
|
|
2
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
3
3
|
import datetime
|
|
4
4
|
from typing import List, Optional, Union, Literal, Dict
|
|
5
5
|
from enum import Enum
|
|
@@ -9,34 +9,6 @@ from arkitekt_next.base_models import Requirement
|
|
|
9
9
|
from string import Formatter
|
|
10
10
|
import os
|
|
11
11
|
|
|
12
|
-
from kabinet.api.schema import (
|
|
13
|
-
AppImageInput,
|
|
14
|
-
InspectionInput,
|
|
15
|
-
SelectorInput,
|
|
16
|
-
ManifestInput,
|
|
17
|
-
)
|
|
18
|
-
from rekuest_next.api.schema import TemplateInput
|
|
19
|
-
|
|
20
|
-
ALLOWED_BUILDER_KEYS = [
|
|
21
|
-
"tag",
|
|
22
|
-
"dockerfile",
|
|
23
|
-
"package_version",
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class Framework(str, Enum):
|
|
28
|
-
"""Do we support other frameworks?"""
|
|
29
|
-
|
|
30
|
-
VANILLA = "vanilla"
|
|
31
|
-
TENSORFLOW = "tensorflow"
|
|
32
|
-
PYTORCH = "pytorch"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class Packager(str, Enum):
|
|
36
|
-
CONDA = "conda"
|
|
37
|
-
POETRY = "poetry"
|
|
38
|
-
PIP = "pip"
|
|
39
|
-
|
|
40
12
|
|
|
41
13
|
class Manifest(BaseModel):
|
|
42
14
|
identifier: str
|
|
@@ -45,6 +17,7 @@ class Manifest(BaseModel):
|
|
|
45
17
|
logo: Optional[str] = None
|
|
46
18
|
entrypoint: str
|
|
47
19
|
scopes: List[str]
|
|
20
|
+
model_config = ConfigDict(extra="forbid", validate_assignment=True)
|
|
48
21
|
|
|
49
22
|
@field_validator("version", mode="before")
|
|
50
23
|
def version_must_be_semver(cls, v) -> str:
|
|
@@ -67,121 +40,3 @@ class Manifest(BaseModel):
|
|
|
67
40
|
"scopes": self.scopes,
|
|
68
41
|
}
|
|
69
42
|
|
|
70
|
-
class Config:
|
|
71
|
-
validate_assignment = True
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
class SelectorType(str, Enum):
|
|
75
|
-
RAM = "ram"
|
|
76
|
-
CPU = "cpu"
|
|
77
|
-
GPU = "gpu"
|
|
78
|
-
LABEL = "label"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
class Flavour(BaseModel):
|
|
82
|
-
selectors: List[SelectorInput]
|
|
83
|
-
description: str = Field(default="")
|
|
84
|
-
dockerfile: str = Field(default="Dockerfile")
|
|
85
|
-
build_command: List[str] = Field(
|
|
86
|
-
default_factory=lambda: [
|
|
87
|
-
"docker",
|
|
88
|
-
"build",
|
|
89
|
-
"-t",
|
|
90
|
-
"{tag}",
|
|
91
|
-
"-f",
|
|
92
|
-
"{dockerfile}",
|
|
93
|
-
".",
|
|
94
|
-
]
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
@field_validator("build_command", mode="before")
|
|
98
|
-
def check_valid_template_name(cls, value):
|
|
99
|
-
"""Checks that the build_command templates are valid"""
|
|
100
|
-
|
|
101
|
-
for v in value:
|
|
102
|
-
for literal_text, field_name, format_spec, conversion in Formatter().parse(
|
|
103
|
-
v
|
|
104
|
-
):
|
|
105
|
-
if field_name is not None:
|
|
106
|
-
assert (
|
|
107
|
-
field_name in ALLOWED_BUILDER_KEYS
|
|
108
|
-
), f"Invalid template key {field_name}. Allowed keys are {ALLOWED_BUILDER_KEYS}"
|
|
109
|
-
|
|
110
|
-
return value
|
|
111
|
-
|
|
112
|
-
def generate_build_command(self, tag: str, relative_dir: str):
|
|
113
|
-
"""Generates the build command for this flavour"""
|
|
114
|
-
|
|
115
|
-
dockerfile = os.path.join(relative_dir, self.dockerfile)
|
|
116
|
-
|
|
117
|
-
return [v.format(tag=tag, dockerfile=dockerfile) for v in self.build_command]
|
|
118
|
-
|
|
119
|
-
def check_relative_paths(self, flavour_folder: str):
|
|
120
|
-
"""Checks that the paths are relative to the flavour folder"""
|
|
121
|
-
|
|
122
|
-
dockerfile_path = os.path.join(flavour_folder, self.dockerfile)
|
|
123
|
-
|
|
124
|
-
if not os.path.exists(dockerfile_path):
|
|
125
|
-
raise Exception(
|
|
126
|
-
f"Could not find Dockerfile {self.dockerfile} in flavour {flavour_folder}"
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
class DeploymentsConfigFile(BaseModel):
|
|
131
|
-
"""The ConfigFile is a pydantic model that represents the deployments.yaml file
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
Parameters
|
|
135
|
-
----------
|
|
136
|
-
BaseModel : _type_
|
|
137
|
-
_description_
|
|
138
|
-
"""
|
|
139
|
-
|
|
140
|
-
app_images: List[AppImageInput] = []
|
|
141
|
-
latest_app_image: Optional[str] = None
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
class Build(BaseModel):
|
|
145
|
-
build_run: str
|
|
146
|
-
build_id: str
|
|
147
|
-
inspection: Optional[InspectionInput] = None
|
|
148
|
-
description: str = Field(default="")
|
|
149
|
-
selectors: List[SelectorInput] = Field(default_factory=list)
|
|
150
|
-
flavour: str = Field(default="vanilla")
|
|
151
|
-
manifest: ManifestInput
|
|
152
|
-
build_at: datetime.datetime = Field(default_factory=datetime.datetime.now)
|
|
153
|
-
base_docker_command: List[str] = Field(
|
|
154
|
-
default_factory=lambda: ["docker", "run", "-it", "--net", "host"]
|
|
155
|
-
)
|
|
156
|
-
base_arkitekt_next_command: List[str] = Field(
|
|
157
|
-
default_factory=lambda: ["arkitekt-next", "run", "prod", "--headless"]
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
def build_docker_command(self) -> List[str]:
|
|
161
|
-
"""Builds the docker command for this build"""
|
|
162
|
-
|
|
163
|
-
base_command = self.base_docker_command
|
|
164
|
-
|
|
165
|
-
for selector in self.selectors:
|
|
166
|
-
base_command = base_command + selector.build_docker_params()
|
|
167
|
-
|
|
168
|
-
base_command = base_command + [self.build_id]
|
|
169
|
-
|
|
170
|
-
return base_command
|
|
171
|
-
|
|
172
|
-
def build_arkitekt_next_command(self, fakts_next_url: str):
|
|
173
|
-
"""Builds the arkitekt_next command for this build"""
|
|
174
|
-
|
|
175
|
-
base_command = self.base_arkitekt_next_command
|
|
176
|
-
|
|
177
|
-
for selector in self.selectors:
|
|
178
|
-
base_command = base_command + selector.build_arkitekt_next_params()
|
|
179
|
-
|
|
180
|
-
base_command = base_command + ["--url", fakts_next_url]
|
|
181
|
-
|
|
182
|
-
return base_command
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
class BuildsConfigFile(BaseModel):
|
|
186
|
-
builds: List[Build] = Field(default_factory=list)
|
|
187
|
-
latest_build_run: Optional[str] = None
|
arkitekt_next/cli/ui.py
CHANGED
|
@@ -65,7 +65,7 @@ def construct_app_group(app: App) -> Group:
|
|
|
65
65
|
if rekuest is None:
|
|
66
66
|
return Group(panel_header, service_tree)
|
|
67
67
|
|
|
68
|
-
for key, extension in rekuest.agent.
|
|
68
|
+
for key, extension in rekuest.agent.extension_registry.agent_extensions.items():
|
|
69
69
|
tree = actor_tree.add(key)
|
|
70
70
|
for template in extension.definition_registry.templates.values():
|
|
71
71
|
tree.add(template.interface + "-" + template.definition.name)
|
arkitekt_next/init_registry.py
CHANGED
|
@@ -102,20 +102,17 @@ class InitHookRegisty:
|
|
|
102
102
|
|
|
103
103
|
def __init__(self):
|
|
104
104
|
self.init_hooks: Dict[str, InitHook] = {}
|
|
105
|
-
|
|
106
105
|
|
|
107
106
|
def register(
|
|
108
107
|
self,
|
|
109
108
|
function: InitHook,
|
|
110
109
|
name: Optional[str] = None,
|
|
111
110
|
only_cli: bool = False,
|
|
112
|
-
|
|
113
111
|
):
|
|
114
|
-
|
|
112
|
+
|
|
115
113
|
if name is None:
|
|
116
114
|
name = function.__name__
|
|
117
115
|
|
|
118
|
-
|
|
119
116
|
if name not in self.init_hooks:
|
|
120
117
|
self.init_hooks[name] = function
|
|
121
118
|
else:
|
|
@@ -126,12 +123,9 @@ class InitHookRegisty:
|
|
|
126
123
|
hook(app)
|
|
127
124
|
|
|
128
125
|
|
|
129
|
-
|
|
130
126
|
T = TypeVar("T")
|
|
131
127
|
|
|
132
128
|
|
|
133
|
-
|
|
134
|
-
|
|
135
129
|
@overload
|
|
136
130
|
def init(
|
|
137
131
|
function_or_actor: T,
|
|
@@ -149,9 +143,7 @@ def init(
|
|
|
149
143
|
only_cli: bool = False,
|
|
150
144
|
init_hook_registry: InitHookRegisty = None,
|
|
151
145
|
):
|
|
152
|
-
"""Register a function as an init hook. This function will be called when the app is initialized.
|
|
153
|
-
|
|
154
|
-
"""
|
|
146
|
+
"""Register a function as an init hook. This function will be called when the app is initialized."""
|
|
155
147
|
init_hook_registry = init_hook_registry or get_current_init_hook_registry()
|
|
156
148
|
|
|
157
149
|
if len(func) > 1:
|
|
@@ -181,7 +173,6 @@ def init(
|
|
|
181
173
|
|
|
182
174
|
wrapped_function.__is_init_hook__ = True
|
|
183
175
|
|
|
184
|
-
|
|
185
176
|
return wrapped_function
|
|
186
177
|
|
|
187
178
|
return real_decorator
|
arkitekt_next/qt/builders.py
CHANGED
|
@@ -8,7 +8,7 @@ from arkitekt_next.base_models import Manifest
|
|
|
8
8
|
from arkitekt_next.apps.types import App
|
|
9
9
|
from arkitekt_next.service_registry import (
|
|
10
10
|
ServiceBuilderRegistry,
|
|
11
|
-
|
|
11
|
+
get_default_service_registry,
|
|
12
12
|
)
|
|
13
13
|
from arkitekt_next.constants import DEFAULT_ARKITEKT_URL
|
|
14
14
|
from qtpy import QtWidgets, QtCore
|
|
@@ -30,7 +30,6 @@ from arkitekt_next.base_models import Manifest
|
|
|
30
30
|
from arkitekt_next.apps.types import App
|
|
31
31
|
from arkitekt_next.service_registry import (
|
|
32
32
|
ServiceBuilderRegistry,
|
|
33
|
-
check_and_import_services,
|
|
34
33
|
)
|
|
35
34
|
from arkitekt_next.constants import DEFAULT_ARKITEKT_URL
|
|
36
35
|
|
|
@@ -117,7 +116,7 @@ def devqt(
|
|
|
117
116
|
NextApp
|
|
118
117
|
A built app, that can be used to interact with the ArkitektNext server
|
|
119
118
|
"""
|
|
120
|
-
registry = registry or
|
|
119
|
+
registry = registry or get_default_service_registry()
|
|
121
120
|
|
|
122
121
|
url = os.getenv("FAKTS_URL", url)
|
|
123
122
|
token = os.getenv("FAKTS_TOKEN", token)
|
|
@@ -5,12 +5,6 @@ from herre_next import Herre
|
|
|
5
5
|
from fakts_next import Fakts
|
|
6
6
|
from .base_models import Manifest, Requirement
|
|
7
7
|
from typing import Callable, Dict, Optional, Protocol, TypeVar, overload
|
|
8
|
-
import importlib
|
|
9
|
-
import sys
|
|
10
|
-
import os
|
|
11
|
-
import traceback
|
|
12
|
-
import logging
|
|
13
|
-
import pkgutil
|
|
14
8
|
from typing import runtime_checkable
|
|
15
9
|
|
|
16
10
|
Params = Dict[str, str]
|
|
@@ -93,10 +87,7 @@ basic_requirements = [
|
|
|
93
87
|
class ServiceBuilderRegistry:
|
|
94
88
|
def __init__(self, import_services=True):
|
|
95
89
|
self.service_builders: Dict[str, ArkitektService] = {}
|
|
96
|
-
self.additional_requirements: Dict[str, Requirement]= {}
|
|
97
|
-
if import_services:
|
|
98
|
-
check_and_import_services(self)
|
|
99
|
-
|
|
90
|
+
self.additional_requirements: Dict[str, Requirement] = {}
|
|
100
91
|
|
|
101
92
|
def register(
|
|
102
93
|
self,
|
|
@@ -109,13 +100,11 @@ class ServiceBuilderRegistry:
|
|
|
109
100
|
self.service_builders[name] = service
|
|
110
101
|
else:
|
|
111
102
|
raise ValueError(f"Service {name} already registered")
|
|
112
|
-
|
|
113
103
|
|
|
114
104
|
def register_requirement(self, requirement: Requirement):
|
|
115
105
|
if requirement.key in self.additional_requirements:
|
|
116
106
|
raise ValueError(f"Requirement {requirement.key} already registered)")
|
|
117
107
|
self.additional_requirements[requirement.key] = requirement
|
|
118
|
-
|
|
119
108
|
|
|
120
109
|
def get(self, name):
|
|
121
110
|
return self.services.get(name)
|
|
@@ -151,7 +140,6 @@ class ServiceBuilderRegistry:
|
|
|
151
140
|
taken_requirements.add(requirement.key)
|
|
152
141
|
requirements.append(requirement)
|
|
153
142
|
|
|
154
|
-
|
|
155
143
|
for requirement in self.additional_requirements.values():
|
|
156
144
|
if requirement.key not in taken_requirements:
|
|
157
145
|
taken_requirements.add(requirement.key)
|
|
@@ -172,73 +160,12 @@ import pkgutil
|
|
|
172
160
|
import traceback
|
|
173
161
|
import logging
|
|
174
162
|
|
|
175
|
-
|
|
176
|
-
def check_and_import_services(service_registry: ServiceBuilderRegistry) -> ServiceBuilderRegistry:
|
|
177
|
-
processed_modules = set() # Track modules that have already been processed
|
|
178
|
-
|
|
179
|
-
# Function to load and call init_extensions from __rekuest__.py
|
|
180
|
-
def load_and_call_init_extensions(module_name, rekuest_path):
|
|
181
|
-
if module_name in processed_modules:
|
|
182
|
-
return # Skip if module has already been processed
|
|
183
|
-
try:
|
|
184
|
-
spec = importlib.util.spec_from_file_location(
|
|
185
|
-
f"{module_name}.__arkitekt__", rekuest_path
|
|
186
|
-
)
|
|
187
|
-
rekuest_module = importlib.util.module_from_spec(spec)
|
|
188
|
-
spec.loader.exec_module(rekuest_module)
|
|
189
|
-
if hasattr(rekuest_module, "build_services"):
|
|
190
|
-
for service in rekuest_module.build_services():
|
|
191
|
-
try:
|
|
192
|
-
service_registry.register(service)
|
|
193
|
-
except ValueError as e:
|
|
194
|
-
print(
|
|
195
|
-
f"Failed to register service {service}: Another service with the same name is already registered {service_registry.service_builders}"
|
|
196
|
-
)
|
|
197
|
-
logging.info(f"Called build_services function from {module_name}")
|
|
198
|
-
else:
|
|
199
|
-
print(
|
|
200
|
-
f"Discovered Arkitekt-like module (containing __arkitekt__) that doesn't conform with the __arkitekt__ spec. No build_services function in {module_name}.__arkitekt__"
|
|
201
|
-
)
|
|
202
|
-
processed_modules.add(module_name) # Mark this module as processed
|
|
203
|
-
except Exception as e:
|
|
204
|
-
print(f"Failed to call init_services for {module_name}: {e}")
|
|
205
|
-
traceback.print_exc()
|
|
206
|
-
|
|
207
|
-
# Check local modules in the current working directory
|
|
208
|
-
current_directory = os.getcwd()
|
|
209
|
-
for item in os.listdir(current_directory):
|
|
210
|
-
item_path = os.path.join(current_directory, item)
|
|
211
|
-
if os.path.isdir(item_path) and os.path.isfile(
|
|
212
|
-
os.path.join(item_path, "__init__.py")
|
|
213
|
-
):
|
|
214
|
-
rekuest_path = os.path.join(item_path, "__arkitekt__.py")
|
|
215
|
-
if os.path.isfile(rekuest_path):
|
|
216
|
-
load_and_call_init_extensions(item, rekuest_path)
|
|
217
|
-
|
|
218
|
-
# Check installed packages
|
|
219
|
-
for _, module_name, _ in pkgutil.iter_modules():
|
|
220
|
-
try:
|
|
221
|
-
module_spec = importlib.util.find_spec(module_name)
|
|
222
|
-
if module_spec and module_spec.origin:
|
|
223
|
-
rekuest_path = os.path.join(
|
|
224
|
-
os.path.dirname(module_spec.origin), "__arkitekt__.py"
|
|
225
|
-
)
|
|
226
|
-
if os.path.isfile(rekuest_path):
|
|
227
|
-
load_and_call_init_extensions(module_name, rekuest_path)
|
|
228
|
-
except Exception as e:
|
|
229
|
-
print(
|
|
230
|
-
f"Failed to call init_extensions for installed package {module_name}: {e}"
|
|
231
|
-
)
|
|
232
|
-
traceback.print_exc()
|
|
233
|
-
|
|
234
|
-
return service_registry
|
|
235
|
-
|
|
236
|
-
|
|
237
163
|
T = TypeVar("T")
|
|
238
164
|
|
|
165
|
+
|
|
239
166
|
@overload
|
|
240
167
|
def require(
|
|
241
|
-
key: str
|
|
168
|
+
key: str,
|
|
242
169
|
service: str = None,
|
|
243
170
|
description: str = None,
|
|
244
171
|
) -> Callable[[T], T]: ...
|
|
@@ -249,20 +176,11 @@ def require(
|
|
|
249
176
|
service: str = None,
|
|
250
177
|
description: str = None,
|
|
251
178
|
service_registry: Optional[ServiceBuilderRegistry] = None,
|
|
252
|
-
|
|
253
179
|
):
|
|
254
|
-
"""Register a requirement with the service registry
|
|
255
|
-
|
|
256
|
-
"""
|
|
180
|
+
"""Register a requirement with the service registry"""
|
|
257
181
|
service_hook_registry = service_registry or get_current_service_registry()
|
|
258
182
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
requirement = Requirement(
|
|
262
|
-
key=key,
|
|
263
|
-
service=service,
|
|
264
|
-
description=description
|
|
265
|
-
)
|
|
183
|
+
requirement = Requirement(key=key, service=service, description=description)
|
|
266
184
|
service_hook_registry.register_requirement(requirement)
|
|
267
185
|
|
|
268
186
|
return requirement
|
arkitekt_next/utils.py
CHANGED
|
@@ -61,11 +61,12 @@ def create_devcontainer_file(
|
|
|
61
61
|
|
|
62
62
|
devcontainer_file = os.path.join(flavour_container, "devcontainer.json")
|
|
63
63
|
|
|
64
|
-
|
|
65
64
|
devcontainer_content = {}
|
|
66
65
|
devcontainer_content["name"] = f"{manifest.identifier} {flavour} Devcontainer"
|
|
67
66
|
devcontainer_content["build"] = {}
|
|
68
|
-
devcontainer_content["build"]["dockerfile"] = os.path.relpath(
|
|
67
|
+
devcontainer_content["build"]["dockerfile"] = os.path.relpath(
|
|
68
|
+
docker_file_path, flavour_container
|
|
69
|
+
)
|
|
69
70
|
devcontainer_content["build"][
|
|
70
71
|
"context"
|
|
71
72
|
] = "../.." # This is the root of the project
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: arkitekt-next
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.62
|
|
4
4
|
Summary: client for the arkitekt_next platform
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: jhnnsrs
|
|
@@ -14,29 +14,39 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Provides-Extra: all
|
|
17
|
+
Provides-Extra: alpaka
|
|
17
18
|
Provides-Extra: blok
|
|
18
19
|
Provides-Extra: cli
|
|
19
20
|
Provides-Extra: extended
|
|
21
|
+
Provides-Extra: fluss
|
|
22
|
+
Provides-Extra: kabinet
|
|
23
|
+
Provides-Extra: kraph
|
|
24
|
+
Provides-Extra: lovekit
|
|
25
|
+
Provides-Extra: mikro
|
|
26
|
+
Provides-Extra: reaktion
|
|
27
|
+
Provides-Extra: rekuest
|
|
20
28
|
Provides-Extra: stream
|
|
29
|
+
Provides-Extra: unlok
|
|
30
|
+
Requires-Dist: alpaka (>=0.1.17) ; (python_version >= "3.10" and python_version < "4.0") and (extra == "alpaka" or extra == "extended")
|
|
21
31
|
Requires-Dist: blok (>=0.0.22) ; (python_version >= "3.9" and python_version < "4.0") and (extra == "blok")
|
|
22
32
|
Requires-Dist: cryptography (>=40.0.8) ; (python_version >= "3.8" and python_version < "4.0") and (extra == "blok")
|
|
23
33
|
Requires-Dist: dokker (>=1.0.0)
|
|
24
34
|
Requires-Dist: fakts-next (>=1.0.4)
|
|
25
|
-
Requires-Dist: fluss-next (>=0.1.
|
|
35
|
+
Requires-Dist: fluss-next (>=0.1.96) ; extra == "fluss" or extra == "all"
|
|
26
36
|
Requires-Dist: herre-next (>=1.0.2)
|
|
27
|
-
Requires-Dist: kabinet (>=0.1.
|
|
37
|
+
Requires-Dist: kabinet (>=0.1.46) ; (python_version >= "3.9" and python_version < "4.0") and (extra == "kabinet" or extra == "all")
|
|
28
38
|
Requires-Dist: koil (>=1.0.3)
|
|
29
|
-
Requires-Dist: kraph (>=0.1.
|
|
30
|
-
Requires-Dist: lovekit (>=0.1.
|
|
31
|
-
Requires-Dist: mikro-next (>=0.1.
|
|
39
|
+
Requires-Dist: kraph (>=0.1.101) ; (python_version >= "3.8" and python_version < "4.0") and (extra == "kraph" or extra == "extended")
|
|
40
|
+
Requires-Dist: lovekit (>=0.1.19) ; (python_version >= "3.10" and python_version < "4.0") and (extra == "lovekit" or extra == "stream")
|
|
41
|
+
Requires-Dist: mikro-next (>=0.1.55) ; (python_version >= "3.10" and python_version < "4.0") and (extra == "mikro" or extra == "all")
|
|
32
42
|
Requires-Dist: namegenerator (>=1.0.6) ; (python_version >= "3.8" and python_version < "4.0") and (extra == "blok")
|
|
33
43
|
Requires-Dist: netifaces (>=0.11.0) ; (python_version >= "3.8" and python_version < "4.0") and (extra == "blok")
|
|
34
|
-
Requires-Dist: reaktion-next (>=0.1.
|
|
35
|
-
Requires-Dist: rekuest-next (>=0.2.
|
|
44
|
+
Requires-Dist: reaktion-next (>=0.1.87) ; (python_version >= "3.8" and python_version < "4.0") and (extra == "reaktion" or extra == "all")
|
|
45
|
+
Requires-Dist: rekuest-next (>=0.2.62) ; (python_version >= "3.8" and python_version < "4.0") and (extra == "cli" or extra == "rekuest" or extra == "all")
|
|
36
46
|
Requires-Dist: rich-click (>=1.6.1) ; extra == "cli" or extra == "all" or extra == "blok"
|
|
37
47
|
Requires-Dist: semver (>=3.0.1) ; extra == "cli" or extra == "all"
|
|
38
48
|
Requires-Dist: turms (>=0.8.2) ; (python_version >= "3.9" and python_version < "4.0") and (extra == "cli" or extra == "all")
|
|
39
|
-
Requires-Dist: unlok-next (>=0.1.
|
|
49
|
+
Requires-Dist: unlok-next (>=0.1.89) ; (python_version >= "3.8" and python_version < "4.0") and (extra == "unlok")
|
|
40
50
|
Requires-Dist: watchfiles (>=0.18.1) ; extra == "cli" or extra == "all"
|
|
41
51
|
Description-Content-Type: text/markdown
|
|
42
52
|
|