horus-runtime 0.1.0__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.
Files changed (100) hide show
  1. horus_builtin/__init__.py +17 -0
  2. horus_builtin/artifact/__init__.py +17 -0
  3. horus_builtin/artifact/file.py +51 -0
  4. horus_builtin/artifact/folder.py +153 -0
  5. horus_builtin/artifact/json.py +59 -0
  6. horus_builtin/artifact/pickle.py +56 -0
  7. horus_builtin/event/__init__.py +17 -0
  8. horus_builtin/event/artifact_event.py +48 -0
  9. horus_builtin/event/log_subscriber.py +54 -0
  10. horus_builtin/event/task_event.py +33 -0
  11. horus_builtin/event/workflow_event.py +32 -0
  12. horus_builtin/executor/__init__.py +17 -0
  13. horus_builtin/executor/python_exec.py +64 -0
  14. horus_builtin/executor/python_fn.py +57 -0
  15. horus_builtin/executor/shell.py +99 -0
  16. horus_builtin/interaction/__init__.py +17 -0
  17. horus_builtin/interaction/cli.py +202 -0
  18. horus_builtin/interaction/common/__init__.py +17 -0
  19. horus_builtin/interaction/common/confirm.py +55 -0
  20. horus_builtin/interaction/common/dropdown.py +65 -0
  21. horus_builtin/interaction/common/file.py +62 -0
  22. horus_builtin/interaction/common/string.py +43 -0
  23. horus_builtin/middleware/task_time.py +63 -0
  24. horus_builtin/middleware/workflow_time.py +68 -0
  25. horus_builtin/py.typed +0 -0
  26. horus_builtin/runtime/__init__.py +17 -0
  27. horus_builtin/runtime/command.py +95 -0
  28. horus_builtin/runtime/python.py +125 -0
  29. horus_builtin/runtime/python_string.py +52 -0
  30. horus_builtin/target/__init__.py +17 -0
  31. horus_builtin/target/local.py +129 -0
  32. horus_builtin/task/__init__.py +17 -0
  33. horus_builtin/task/function.py +101 -0
  34. horus_builtin/task/horus_task.py +114 -0
  35. horus_builtin/transfer/__init__.py +17 -0
  36. horus_builtin/transfer/local_noop.py +45 -0
  37. horus_builtin/workflow/__init__.py +17 -0
  38. horus_builtin/workflow/horus_workflow.py +98 -0
  39. horus_runtime/__init__.py +17 -0
  40. horus_runtime/cli.py +45 -0
  41. horus_runtime/context.py +145 -0
  42. horus_runtime/core/__init__.py +17 -0
  43. horus_runtime/core/artifact/__init__.py +17 -0
  44. horus_runtime/core/artifact/base.py +186 -0
  45. horus_runtime/core/artifact/exceptions.py +32 -0
  46. horus_runtime/core/executor/__init__.py +17 -0
  47. horus_runtime/core/executor/base.py +92 -0
  48. horus_runtime/core/executor/exceptions.py +32 -0
  49. horus_runtime/core/interaction/__init__.py +17 -0
  50. horus_runtime/core/interaction/base.py +47 -0
  51. horus_runtime/core/interaction/exceptions.py +133 -0
  52. horus_runtime/core/interaction/renderer.py +65 -0
  53. horus_runtime/core/interaction/transport.py +309 -0
  54. horus_runtime/core/runtime/__init__.py +17 -0
  55. horus_runtime/core/runtime/base.py +81 -0
  56. horus_runtime/core/runtime/events.py +33 -0
  57. horus_runtime/core/target/__init__.py +17 -0
  58. horus_runtime/core/target/base.py +151 -0
  59. horus_runtime/core/task/__init__.py +17 -0
  60. horus_runtime/core/task/base.py +250 -0
  61. horus_runtime/core/task/exceptions.py +40 -0
  62. horus_runtime/core/task/status.py +58 -0
  63. horus_runtime/core/transfer/__init__.py +17 -0
  64. horus_runtime/core/transfer/exceptions.py +74 -0
  65. horus_runtime/core/transfer/strategy.py +96 -0
  66. horus_runtime/core/workflow/__init__.py +17 -0
  67. horus_runtime/core/workflow/base.py +296 -0
  68. horus_runtime/core/workflow/exceptions.py +43 -0
  69. horus_runtime/core/workflow/status.py +68 -0
  70. horus_runtime/event/__init__.py +17 -0
  71. horus_runtime/event/async_loop.py +75 -0
  72. horus_runtime/event/base.py +106 -0
  73. horus_runtime/event/bus.py +188 -0
  74. horus_runtime/event/subscriber.py +64 -0
  75. horus_runtime/event/transport.py +59 -0
  76. horus_runtime/i18n.py +96 -0
  77. horus_runtime/locale/es/LC_MESSAGES/horus_runtime.mo +0 -0
  78. horus_runtime/locale/es/LC_MESSAGES/horus_runtime.po +59 -0
  79. horus_runtime/locale/messages.pot +50 -0
  80. horus_runtime/logging.py +110 -0
  81. horus_runtime/middleware/__init__.py +17 -0
  82. horus_runtime/middleware/auto_middleware.py +154 -0
  83. horus_runtime/middleware/executor.py +49 -0
  84. horus_runtime/middleware/interaction.py +54 -0
  85. horus_runtime/middleware/runtime.py +49 -0
  86. horus_runtime/middleware/target.py +49 -0
  87. horus_runtime/middleware/task.py +47 -0
  88. horus_runtime/middleware/transfer.py +52 -0
  89. horus_runtime/middleware/workflow.py +47 -0
  90. horus_runtime/py.typed +0 -0
  91. horus_runtime/registry/__init__.py +17 -0
  92. horus_runtime/registry/auto_registry.py +429 -0
  93. horus_runtime/registry/auto_registry_product.py +179 -0
  94. horus_runtime/registry/exceptions.py +61 -0
  95. horus_runtime/version.py +36 -0
  96. horus_runtime-0.1.0.dist-info/METADATA +13 -0
  97. horus_runtime-0.1.0.dist-info/RECORD +100 -0
  98. horus_runtime-0.1.0.dist-info/WHEEL +4 -0
  99. horus_runtime-0.1.0.dist-info/entry_points.txt +48 -0
  100. horus_runtime-0.1.0.dist-info/licenses/LICENSE +661 -0
@@ -0,0 +1,17 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
@@ -0,0 +1,17 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
@@ -0,0 +1,51 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ """
19
+ Implementation of the FileArtifact class, which represents a local
20
+ file artifact in the Horus runtime.
21
+ """
22
+
23
+ from horus_builtin.event.artifact_event import ArtifactEventsEnum
24
+ from horus_runtime.core.artifact.base import BaseArtifact
25
+
26
+
27
+ class FileArtifact(BaseArtifact[str]):
28
+ """
29
+ Represents a local file artifact.
30
+ """
31
+
32
+ kind: str = "file"
33
+
34
+ def read(self) -> str:
35
+ """
36
+ Read and deserialize the contents of the file artifact.
37
+
38
+ Returns:
39
+ The full text content of the file.
40
+ """
41
+ txt = self.path.read_text()
42
+ self._emit_event(ArtifactEventsEnum.READ)
43
+ return txt
44
+
45
+ def write(self, value: str) -> None:
46
+ """
47
+ Write text content to the file artifact path.
48
+ """
49
+ self.path.parent.mkdir(parents=True, exist_ok=True)
50
+ self.path.write_text(value)
51
+ self._emit_event(ArtifactEventsEnum.WRITE)
@@ -0,0 +1,153 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ """
19
+ Implementation of the FolderArtifact class, which represents a local
20
+ folder/directory artifact in the Horus runtime.
21
+ """
22
+
23
+ import hashlib
24
+ import os
25
+ import shutil
26
+ import tempfile
27
+ from pathlib import Path
28
+
29
+ from horus_builtin.event.artifact_event import ArtifactEventsEnum
30
+ from horus_runtime.core.artifact.base import BaseArtifact
31
+ from horus_runtime.i18n import tr as _
32
+
33
+
34
+ class FolderArtifact(BaseArtifact[Path]):
35
+ """
36
+ Represents a local folder artifact.
37
+ """
38
+
39
+ kind: str = "folder"
40
+
41
+ def exists(self) -> bool:
42
+ """
43
+ Check if the folder specified by the path exists and is a directory.
44
+ """
45
+ return self.path.is_dir()
46
+
47
+ @property
48
+ def hash(self) -> str | None:
49
+ """
50
+ Computes the hash of the folder and its contents by recursively hashing
51
+ all files in the folder. The hash is computed by combining the relative
52
+ paths and contents of all files in the folder, ensuring that changes to
53
+ any file or the addition/removal of files will result in a different
54
+ hash.
55
+ """
56
+ if not self.exists():
57
+ return None
58
+
59
+ sha256 = hashlib.sha256()
60
+
61
+ # 1. Get all files and sort them by relative path for determinism
62
+ # We use rglob("*") to get everything, but only hash files
63
+ paths = sorted([p for p in self.path.rglob("*") if p.is_file()])
64
+
65
+ for path in paths:
66
+ relative_path = path.relative_to(self.path).as_posix()
67
+ sha256.update(relative_path.encode("utf-8"))
68
+
69
+ # Hash the file contents
70
+ sha256.update(self.hash_file(path))
71
+
72
+ return sha256.hexdigest()
73
+
74
+ def read(self) -> Path:
75
+ """
76
+ Return the canonical directory path for this artifact.
77
+ """
78
+ self._emit_event(ArtifactEventsEnum.READ)
79
+ return self.path
80
+
81
+ def write(self, value: Path) -> None:
82
+ """
83
+ Materialize this folder artifact from another local directory.
84
+
85
+ WARNING: THIS WILL OVERWRITE ANY EXISTING CONTENT AT THE ARTIFACT PATH.
86
+ """
87
+ source_path = Path(value).resolve()
88
+ if not source_path.is_dir():
89
+ raise ValueError(
90
+ _("Expected directory path, got %(source_path)s")
91
+ % {"source_path": source_path}
92
+ )
93
+
94
+ if self.path.exists():
95
+ shutil.rmtree(self.path)
96
+
97
+ self.path.parent.mkdir(parents=True, exist_ok=True)
98
+ shutil.copytree(source_path, self.path)
99
+ self._emit_event(ArtifactEventsEnum.WRITE)
100
+
101
+ def package(self) -> Path:
102
+ """
103
+ Archive the folder into a zip file and return the archive path.
104
+ """
105
+ if not self.exists():
106
+ raise FileNotFoundError(self.path)
107
+
108
+ # Create a temporary file to be used as the archive path.
109
+ # shutil.make_archive requires a base name without extension,
110
+ # so we create a temp file and then remove it after archiving.
111
+ fd, arch_p = tempfile.mkstemp()
112
+ os.close(fd)
113
+ archive_path = Path(arch_p)
114
+
115
+ shutil.make_archive(
116
+ base_name=str(archive_path),
117
+ format="zip",
118
+ root_dir=self.path,
119
+ )
120
+
121
+ # shutil.make_archive adds .zip, so remove the temp
122
+ # file and use the generated archive
123
+ archive_file = archive_path.with_suffix(".zip")
124
+ if archive_path.exists():
125
+ archive_path.unlink()
126
+
127
+ self._emit_event(ArtifactEventsEnum.PACKAGE)
128
+ return archive_file
129
+
130
+ def unpackage(self, package_path: Path) -> None:
131
+ """
132
+ Extract a packaged folder archive into the canonical directory path.
133
+ """
134
+ package_path = Path(package_path).resolve()
135
+
136
+ if self.path.exists():
137
+ shutil.rmtree(self.path)
138
+
139
+ self.path.mkdir(parents=True, exist_ok=True)
140
+ shutil.unpack_archive(
141
+ filename=str(package_path),
142
+ extract_dir=str(self.path),
143
+ )
144
+ self._emit_event(ArtifactEventsEnum.UNPACKAGE)
145
+
146
+ def delete(self) -> None:
147
+ """
148
+ Deletes the artifact from its location by deleting the folder at the
149
+ specified path.
150
+ """
151
+ if self.exists():
152
+ shutil.rmtree(self.path)
153
+ self._emit_event(ArtifactEventsEnum.DELETE)
@@ -0,0 +1,59 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ """
19
+ Implementation of the FolderArtifact class, which represents a local
20
+ folder/directory artifact in the Horus runtime.
21
+ """
22
+
23
+ import json
24
+ from typing import Any, cast
25
+
26
+ from horus_builtin.event.artifact_event import ArtifactEventsEnum
27
+ from horus_runtime.core.artifact.base import BaseArtifact
28
+
29
+
30
+ class JSONArtifact[T: Any = Any](BaseArtifact[T]):
31
+ """
32
+ Represents a JSON-serializable Python object artifact.
33
+ The artifact is materialized as a JSON file on disk.
34
+ """
35
+
36
+ kind: str = "json"
37
+
38
+ def read(self) -> T:
39
+ """
40
+ Read and deserialize the JSON artifact contents.
41
+
42
+ Warning: This method assumes that the JSON file is well-formed and that
43
+ the contents can be deserialized into the expected type `T`. For more
44
+ robust handling, consider using PydanticArtifact, which provides
45
+ validation and error handling for deserialization.
46
+ """
47
+ with open(self.path) as f:
48
+ j_contet = json.load(f)
49
+ self._emit_event(ArtifactEventsEnum.READ)
50
+
51
+ return cast(T, j_contet)
52
+
53
+ def write(self, value: T) -> None:
54
+ """
55
+ Serialize and write the JSON artifact contents.
56
+ """
57
+ with open(self.path, "w") as f:
58
+ json.dump(value, f)
59
+ self._emit_event(ArtifactEventsEnum.WRITE)
@@ -0,0 +1,56 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ """
19
+ Implementation of PickleArtifact, which serializes arbitrary Python objects
20
+ to disk using the pickle protocol.
21
+ """
22
+
23
+ import pickle
24
+ from typing import Any, cast
25
+
26
+ from horus_builtin.event.artifact_event import ArtifactEventsEnum
27
+ from horus_runtime.core.artifact.base import BaseArtifact
28
+
29
+
30
+ class PickleArtifact[T: Any = Any](BaseArtifact[T]):
31
+ """
32
+ Represents a pickled Python object artifact.
33
+ The artifact is materialized as a pickle file on disk.
34
+
35
+ Warning: pickle is not secure against malformed or maliciously crafted
36
+ data. Never unpickle data from untrusted sources.
37
+ """
38
+
39
+ kind: str = "pickle"
40
+
41
+ def read(self) -> T:
42
+ """
43
+ Deserialize the artifact from the pickle file.
44
+ """
45
+ with open(self.path, "rb") as f:
46
+ obj = pickle.load(f)
47
+ self._emit_event(ArtifactEventsEnum.READ)
48
+ return cast(T, obj)
49
+
50
+ def write(self, value: T) -> None:
51
+ """
52
+ Serialize and write the object to the pickle file.
53
+ """
54
+ with open(self.path, "wb") as f:
55
+ pickle.dump(value, f)
56
+ self._emit_event(ArtifactEventsEnum.WRITE)
@@ -0,0 +1,17 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
@@ -0,0 +1,48 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ """
19
+ ArtifactEvent. Emitted when an artifact is created, updated, or deleted.
20
+ """
21
+
22
+ from enum import Enum
23
+ from typing import ClassVar
24
+
25
+ from horus_runtime.event.base import BaseEvent
26
+
27
+
28
+ class ArtifactEventsEnum(Enum):
29
+ """
30
+ Standard artifact events.
31
+ """
32
+
33
+ DELETE = "deleted"
34
+ PACKAGE = "packaged"
35
+ UNPACKAGE = "unpackaged"
36
+ READ = "read"
37
+ WRITE = "written"
38
+
39
+
40
+ class ArtifactEvent(BaseEvent):
41
+ """
42
+ Event emitted when an artifact is created, updated, or deleted.
43
+ """
44
+
45
+ add_to_registry: ClassVar[bool] = True
46
+ event_type: str = "artifact_event"
47
+ event_name: ArtifactEventsEnum
48
+ artifact_id: str
@@ -0,0 +1,54 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ """
19
+ Logging subscriber for horus-runtime events.
20
+ """
21
+
22
+ from horus_runtime.event.base import BaseEvent
23
+ from horus_runtime.event.subscriber import BaseEventSubscriber
24
+ from horus_runtime.logging import horus_logger
25
+
26
+
27
+ class LogsSubscriber(BaseEventSubscriber):
28
+ """
29
+ A simple event subscriber that logs all events using loguru.
30
+ """
31
+
32
+ subscriber_type: str = "loguru"
33
+
34
+ def setup(self) -> None:
35
+ """
36
+ No setup needed for this subscriber.
37
+ """
38
+ pass
39
+
40
+ def handle(self, event: BaseEvent) -> None:
41
+ """
42
+ Handle an incoming event by logging it using loguru's bind.
43
+ """
44
+ # Secure the message by escaping any potential markup characters
45
+ safe_message = (event.message or "").replace("<", r"\<")
46
+
47
+ horus_logger.log.opt(colors=True).log(
48
+ event.level,
49
+ "<cyan>[{source}]</cyan> <yellow>[{event_type}]</yellow> "
50
+ "{safe_message}",
51
+ source=event.source,
52
+ event_type=event.event_type,
53
+ safe_message=safe_message,
54
+ )
@@ -0,0 +1,33 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ """
19
+ HorusTaskEvent. Emitted when a HorusTask is executed.
20
+ """
21
+
22
+ from horus_runtime.event.base import BaseEvent
23
+
24
+
25
+ class HorusTaskEvent(BaseEvent):
26
+ """
27
+ Event emitted when a HorusTask is executed.
28
+ """
29
+
30
+ event_type: str = "horus_task_event"
31
+
32
+ task_id: str | None = None
33
+ task_name: str
@@ -0,0 +1,32 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ """
19
+ HorusTaskEvent. Emitted when a HorusTask is executed.
20
+ """
21
+
22
+ from horus_runtime.event.base import BaseEvent
23
+
24
+
25
+ class HorusWorkflowEvent(BaseEvent):
26
+ """
27
+ Event emitted when a HorusWorkflow is executed.
28
+ """
29
+
30
+ event_type: str = "horus_workflow_event"
31
+
32
+ workflow_name: str
@@ -0,0 +1,17 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
@@ -0,0 +1,64 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ """
19
+ Defines the PythonExecExecutor class, which represents an executor that runs a
20
+ a Python code task in-process in the Horus runtime.
21
+ """
22
+
23
+ from typing import TYPE_CHECKING, ClassVar
24
+
25
+ from horus_builtin.runtime.python_string import PythonCodeStringRuntime
26
+ from horus_runtime.context import HorusContext
27
+ from horus_runtime.core.executor.base import BaseExecutor, RuntimeFilterType
28
+ from horus_runtime.i18n import tr as _
29
+
30
+ if TYPE_CHECKING:
31
+ from horus_runtime.core.task.base import BaseTask
32
+
33
+
34
+ class PythonExecExecutor(BaseExecutor):
35
+ """
36
+ Run the tasks locally in the horus-runtime instance.
37
+ """
38
+
39
+ kind: str = "python"
40
+ kind_name: ClassVar[str] = "Python Exec"
41
+ kind_description: ClassVar[str] = _(
42
+ "Executes a Python code snippet in-process within the Horus runtime."
43
+ )
44
+
45
+ runtimes: ClassVar[RuntimeFilterType] = (PythonCodeStringRuntime,)
46
+
47
+ async def _execute(self, task: "BaseTask") -> None:
48
+ """
49
+ Runs the task in-process by executing the Python code specified in the
50
+ task's runtime.
51
+ """
52
+ assert isinstance(task.runtime, PythonCodeStringRuntime)
53
+ code = await task.runtime.setup_runtime(task)
54
+
55
+ ctx = HorusContext.get_context()
56
+
57
+ scope = {
58
+ "ctx": ctx,
59
+ "task": task,
60
+ }
61
+
62
+ # Security Warning: using exec to execute arbitrary code can be
63
+ # dangerous and should be done with caution.
64
+ exec(code, scope)
@@ -0,0 +1,57 @@
1
+ #
2
+ # horus-runtime
3
+ # Copyright (C) 2026 Temple Compute
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ #
18
+ """
19
+ Python executor for in-memory workflows in horus-runtime. (Function
20
+ executor).
21
+ """
22
+
23
+ from inspect import isawaitable
24
+ from typing import ClassVar
25
+
26
+ from horus_builtin.runtime.python import PythonFunctionRuntime
27
+ from horus_runtime.core.executor.base import BaseExecutor, RuntimeFilterType
28
+ from horus_runtime.core.task.base import BaseTask
29
+ from horus_runtime.i18n import tr as _
30
+
31
+
32
+ class PythonFunctionExecutor(BaseExecutor):
33
+ """
34
+ Executor for running Python functions in-memory.
35
+ """
36
+
37
+ kind: str = "python_function"
38
+ kind_name: ClassVar[str] = "Python Function Executor"
39
+ kind_description: ClassVar[str] = _(
40
+ "Executes a Python function in-memory within the Horus runtime."
41
+ )
42
+
43
+ runtimes: ClassVar[RuntimeFilterType] = (PythonFunctionRuntime,)
44
+
45
+ async def _execute(self, task: "BaseTask") -> None:
46
+ """
47
+ Executes the Python function specified in the task's runtime.
48
+ """
49
+ assert isinstance(task.runtime, PythonFunctionRuntime)
50
+
51
+ # Get the function and resolved arguments from the runtime.
52
+ func, args = await task.runtime.setup_runtime(task)
53
+
54
+ result = func(**args)
55
+
56
+ if isawaitable(result):
57
+ await result