moru 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 (152) hide show
  1. moru/__init__.py +174 -0
  2. moru/api/__init__.py +164 -0
  3. moru/api/client/__init__.py +8 -0
  4. moru/api/client/api/__init__.py +1 -0
  5. moru/api/client/api/sandboxes/__init__.py +1 -0
  6. moru/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py +161 -0
  7. moru/api/client/api/sandboxes/get_sandboxes.py +176 -0
  8. moru/api/client/api/sandboxes/get_sandboxes_metrics.py +173 -0
  9. moru/api/client/api/sandboxes/get_sandboxes_sandbox_id.py +163 -0
  10. moru/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py +199 -0
  11. moru/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +212 -0
  12. moru/api/client/api/sandboxes/get_v2_sandboxes.py +230 -0
  13. moru/api/client/api/sandboxes/post_sandboxes.py +172 -0
  14. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
  15. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py +165 -0
  16. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py +181 -0
  17. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py +189 -0
  18. moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py +193 -0
  19. moru/api/client/api/templates/__init__.py +1 -0
  20. moru/api/client/api/templates/delete_templates_template_id.py +157 -0
  21. moru/api/client/api/templates/get_templates.py +172 -0
  22. moru/api/client/api/templates/get_templates_template_id.py +195 -0
  23. moru/api/client/api/templates/get_templates_template_id_builds_build_id_status.py +217 -0
  24. moru/api/client/api/templates/get_templates_template_id_files_hash.py +180 -0
  25. moru/api/client/api/templates/patch_templates_template_id.py +183 -0
  26. moru/api/client/api/templates/post_templates.py +172 -0
  27. moru/api/client/api/templates/post_templates_template_id.py +181 -0
  28. moru/api/client/api/templates/post_templates_template_id_builds_build_id.py +170 -0
  29. moru/api/client/api/templates/post_v2_templates.py +172 -0
  30. moru/api/client/api/templates/post_v3_templates.py +172 -0
  31. moru/api/client/api/templates/post_v_2_templates_template_id_builds_build_id.py +192 -0
  32. moru/api/client/client.py +286 -0
  33. moru/api/client/errors.py +16 -0
  34. moru/api/client/models/__init__.py +123 -0
  35. moru/api/client/models/aws_registry.py +85 -0
  36. moru/api/client/models/aws_registry_type.py +8 -0
  37. moru/api/client/models/build_log_entry.py +89 -0
  38. moru/api/client/models/build_status_reason.py +95 -0
  39. moru/api/client/models/connect_sandbox.py +59 -0
  40. moru/api/client/models/created_access_token.py +100 -0
  41. moru/api/client/models/created_team_api_key.py +166 -0
  42. moru/api/client/models/disk_metrics.py +91 -0
  43. moru/api/client/models/error.py +67 -0
  44. moru/api/client/models/gcp_registry.py +69 -0
  45. moru/api/client/models/gcp_registry_type.py +8 -0
  46. moru/api/client/models/general_registry.py +77 -0
  47. moru/api/client/models/general_registry_type.py +8 -0
  48. moru/api/client/models/identifier_masking_details.py +83 -0
  49. moru/api/client/models/listed_sandbox.py +154 -0
  50. moru/api/client/models/log_level.py +11 -0
  51. moru/api/client/models/max_team_metric.py +78 -0
  52. moru/api/client/models/mcp_type_0.py +44 -0
  53. moru/api/client/models/new_access_token.py +59 -0
  54. moru/api/client/models/new_sandbox.py +172 -0
  55. moru/api/client/models/new_team_api_key.py +59 -0
  56. moru/api/client/models/node.py +155 -0
  57. moru/api/client/models/node_detail.py +165 -0
  58. moru/api/client/models/node_metrics.py +122 -0
  59. moru/api/client/models/node_status.py +11 -0
  60. moru/api/client/models/node_status_change.py +79 -0
  61. moru/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py +59 -0
  62. moru/api/client/models/post_sandboxes_sandbox_id_timeout_body.py +59 -0
  63. moru/api/client/models/resumed_sandbox.py +68 -0
  64. moru/api/client/models/sandbox.py +145 -0
  65. moru/api/client/models/sandbox_detail.py +183 -0
  66. moru/api/client/models/sandbox_log.py +70 -0
  67. moru/api/client/models/sandbox_log_entry.py +93 -0
  68. moru/api/client/models/sandbox_log_entry_fields.py +44 -0
  69. moru/api/client/models/sandbox_logs.py +91 -0
  70. moru/api/client/models/sandbox_metric.py +118 -0
  71. moru/api/client/models/sandbox_network_config.py +92 -0
  72. moru/api/client/models/sandbox_state.py +9 -0
  73. moru/api/client/models/sandboxes_with_metrics.py +59 -0
  74. moru/api/client/models/team.py +83 -0
  75. moru/api/client/models/team_api_key.py +158 -0
  76. moru/api/client/models/team_metric.py +86 -0
  77. moru/api/client/models/team_user.py +68 -0
  78. moru/api/client/models/template.py +217 -0
  79. moru/api/client/models/template_build.py +139 -0
  80. moru/api/client/models/template_build_file_upload.py +70 -0
  81. moru/api/client/models/template_build_info.py +126 -0
  82. moru/api/client/models/template_build_request.py +115 -0
  83. moru/api/client/models/template_build_request_v2.py +88 -0
  84. moru/api/client/models/template_build_request_v3.py +88 -0
  85. moru/api/client/models/template_build_start_v2.py +184 -0
  86. moru/api/client/models/template_build_status.py +11 -0
  87. moru/api/client/models/template_legacy.py +207 -0
  88. moru/api/client/models/template_request_response_v3.py +83 -0
  89. moru/api/client/models/template_step.py +91 -0
  90. moru/api/client/models/template_update_request.py +59 -0
  91. moru/api/client/models/template_with_builds.py +148 -0
  92. moru/api/client/models/update_team_api_key.py +59 -0
  93. moru/api/client/py.typed +1 -0
  94. moru/api/client/types.py +54 -0
  95. moru/api/client_async/__init__.py +50 -0
  96. moru/api/client_sync/__init__.py +52 -0
  97. moru/api/metadata.py +14 -0
  98. moru/connection_config.py +217 -0
  99. moru/envd/api.py +59 -0
  100. moru/envd/filesystem/filesystem_connect.py +193 -0
  101. moru/envd/filesystem/filesystem_pb2.py +76 -0
  102. moru/envd/filesystem/filesystem_pb2.pyi +233 -0
  103. moru/envd/process/process_connect.py +155 -0
  104. moru/envd/process/process_pb2.py +92 -0
  105. moru/envd/process/process_pb2.pyi +304 -0
  106. moru/envd/rpc.py +61 -0
  107. moru/envd/versions.py +6 -0
  108. moru/exceptions.py +95 -0
  109. moru/sandbox/commands/command_handle.py +69 -0
  110. moru/sandbox/commands/main.py +39 -0
  111. moru/sandbox/filesystem/filesystem.py +94 -0
  112. moru/sandbox/filesystem/watch_handle.py +60 -0
  113. moru/sandbox/main.py +210 -0
  114. moru/sandbox/mcp.py +1120 -0
  115. moru/sandbox/network.py +8 -0
  116. moru/sandbox/sandbox_api.py +210 -0
  117. moru/sandbox/signature.py +45 -0
  118. moru/sandbox/utils.py +34 -0
  119. moru/sandbox_async/commands/command.py +336 -0
  120. moru/sandbox_async/commands/command_handle.py +196 -0
  121. moru/sandbox_async/commands/pty.py +240 -0
  122. moru/sandbox_async/filesystem/filesystem.py +531 -0
  123. moru/sandbox_async/filesystem/watch_handle.py +62 -0
  124. moru/sandbox_async/main.py +734 -0
  125. moru/sandbox_async/paginator.py +69 -0
  126. moru/sandbox_async/sandbox_api.py +325 -0
  127. moru/sandbox_async/utils.py +7 -0
  128. moru/sandbox_sync/commands/command.py +328 -0
  129. moru/sandbox_sync/commands/command_handle.py +150 -0
  130. moru/sandbox_sync/commands/pty.py +230 -0
  131. moru/sandbox_sync/filesystem/filesystem.py +518 -0
  132. moru/sandbox_sync/filesystem/watch_handle.py +69 -0
  133. moru/sandbox_sync/main.py +726 -0
  134. moru/sandbox_sync/paginator.py +69 -0
  135. moru/sandbox_sync/sandbox_api.py +308 -0
  136. moru/template/consts.py +30 -0
  137. moru/template/dockerfile_parser.py +275 -0
  138. moru/template/logger.py +232 -0
  139. moru/template/main.py +1360 -0
  140. moru/template/readycmd.py +138 -0
  141. moru/template/types.py +105 -0
  142. moru/template/utils.py +320 -0
  143. moru/template_async/build_api.py +202 -0
  144. moru/template_async/main.py +366 -0
  145. moru/template_sync/build_api.py +199 -0
  146. moru/template_sync/main.py +371 -0
  147. moru-0.1.0.dist-info/METADATA +63 -0
  148. moru-0.1.0.dist-info/RECORD +152 -0
  149. moru-0.1.0.dist-info/WHEEL +4 -0
  150. moru-0.1.0.dist-info/licenses/LICENSE +9 -0
  151. moru_connect/__init__.py +1 -0
  152. moru_connect/client.py +493 -0
@@ -0,0 +1,232 @@
1
+ import sys
2
+ import threading
3
+ import time
4
+ from dataclasses import dataclass, field
5
+ from datetime import datetime
6
+ from typing import Optional, TypedDict, Callable, Dict, Literal
7
+
8
+ from rich.console import Console
9
+ from rich.style import Style
10
+ from rich.text import Text
11
+
12
+ from moru.template.utils import strip_ansi_escape_codes
13
+
14
+ """Log entry severity levels."""
15
+ LogEntryLevel = Literal["debug", "info", "warn", "error"]
16
+
17
+
18
+ @dataclass
19
+ class LogEntry:
20
+ """
21
+ Represents a single log entry from the template build process.
22
+ """
23
+
24
+ timestamp: datetime
25
+ level: LogEntryLevel
26
+ message: str
27
+
28
+ def __post_init__(self):
29
+ self.message = strip_ansi_escape_codes(self.message)
30
+
31
+ def __str__(self) -> str:
32
+ return f"[{self.timestamp.isoformat()}] [{self.level}] {self.message}"
33
+
34
+
35
+ @dataclass
36
+ class LogEntryStart(LogEntry):
37
+ """
38
+ Special log entry indicating the start of a build process.
39
+ """
40
+
41
+ level: LogEntryLevel = field(default="debug", init=False)
42
+
43
+
44
+ @dataclass
45
+ class LogEntryEnd(LogEntry):
46
+ """
47
+ Special log entry indicating the end of a build process.
48
+ """
49
+
50
+ level: LogEntryLevel = field(default="debug", init=False)
51
+
52
+
53
+ """
54
+ Interval in milliseconds for updating the build timer display.
55
+ """
56
+ TIMER_UPDATE_INTERVAL_MS = 150
57
+
58
+ """
59
+ Default minimum log level to display.
60
+ """
61
+ DEFAULT_LEVEL: LogEntryLevel = "info"
62
+
63
+ """
64
+ Colored labels for each log level.
65
+ """
66
+ levels: Dict[LogEntryLevel, tuple[str, Style]] = {
67
+ "error": ("ERROR", Style(color="red")),
68
+ "warn": ("WARN ", Style(color="#FF4400")),
69
+ "info": ("INFO ", Style(color="#FF8800")),
70
+ "debug": ("DEBUG", Style(color="bright_black")),
71
+ }
72
+
73
+ """
74
+ Numeric ordering of log levels for comparison (lower = less severe).
75
+ """
76
+ level_order = {
77
+ "debug": 0,
78
+ "info": 1,
79
+ "warn": 2,
80
+ "error": 3,
81
+ }
82
+
83
+
84
+ def set_interval(func, interval):
85
+ """
86
+ Returns a stop function that can be called to cancel the interval.
87
+
88
+ Similar to JavaScript's setInterval.
89
+
90
+ :param func: Function to execute at each interval
91
+ :param interval: Interval duration in **seconds**
92
+
93
+ :return: Stop function that can be called to cancel the interval
94
+ """
95
+ stopped = threading.Event()
96
+
97
+ def loop():
98
+ while not stopped.is_set():
99
+ if stopped.wait(interval): # wait returns True if stopped
100
+ break
101
+ if not stopped.is_set(): # Double-check before executing
102
+ func()
103
+
104
+ threading.Thread(target=loop, daemon=True).start()
105
+ return stopped.set # Return the stop function
106
+
107
+
108
+ class DefaultBuildLoggerInitialState(TypedDict):
109
+ start_time: float
110
+ animation_frame: int
111
+ timer: Optional[Callable[[], None]]
112
+
113
+
114
+ class DefaultBuildLogger:
115
+ __console = Console()
116
+
117
+ __min_level: LogEntryLevel
118
+ __state: DefaultBuildLoggerInitialState
119
+
120
+ def __init__(self, min_level: Optional[LogEntryLevel] = None):
121
+ self.__min_level = min_level if min_level is not None else DEFAULT_LEVEL
122
+ self.__reset_initial_state()
123
+
124
+ def logger(self, log):
125
+ if isinstance(log, LogEntryStart):
126
+ self.__start_timer()
127
+ return
128
+
129
+ if isinstance(log, LogEntryEnd):
130
+ if self.__state["timer"] is not None:
131
+ self.__state["timer"]()
132
+ return
133
+
134
+ # Filter by minimum level
135
+ if level_order[log.level] < level_order[self.__min_level]:
136
+ return
137
+
138
+ formatted_line = self.__format_log_line(log)
139
+ self.__console.print(formatted_line)
140
+
141
+ # Redraw the timer line
142
+ self.__update_timer()
143
+
144
+ def __reset_initial_state(self, timer: Optional[Callable[[], None]] = None):
145
+ self.__state = {
146
+ "start_time": time.time(),
147
+ "animation_frame": 0,
148
+ "timer": timer,
149
+ }
150
+
151
+ def __format_timer_line(self) -> str:
152
+ elapsed_seconds = time.time() - self.__state["start_time"]
153
+ return f"{elapsed_seconds:.1f}s"
154
+
155
+ def __animate_status(self) -> str:
156
+ frames = ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"]
157
+ idx = self.__state["animation_frame"] % len(frames)
158
+ return frames[idx]
159
+
160
+ def __format_log_line(self, line: LogEntry) -> Text:
161
+ timer = self.__format_timer_line().ljust(5)
162
+ timestamp = line.timestamp.strftime("%H:%M:%S")
163
+ level_text, level_style = levels.get(line.level, levels[DEFAULT_LEVEL])
164
+
165
+ # Build a rich Text object
166
+ text = Text.assemble(
167
+ timer,
168
+ " | ",
169
+ (timestamp, "dim"),
170
+ " ",
171
+ (level_text, level_style),
172
+ " ",
173
+ line.message,
174
+ )
175
+
176
+ return text
177
+
178
+ def __start_timer(self):
179
+ if not sys.stdout.isatty():
180
+ return
181
+
182
+ # Start the timer interval
183
+ stop_timer = set_interval(
184
+ self.__update_timer, TIMER_UPDATE_INTERVAL_MS / 1000.0
185
+ )
186
+
187
+ self.__reset_initial_state(stop_timer)
188
+
189
+ # Initial timer display
190
+ self.__update_timer()
191
+
192
+ def __update_timer(self):
193
+ if not sys.stdout.isatty():
194
+ return
195
+
196
+ self.__state["animation_frame"] += 1
197
+ jumping_squares = self.__animate_status()
198
+
199
+ timer_text = Text.assemble(
200
+ jumping_squares, " Building ", self.__format_timer_line()
201
+ )
202
+
203
+ # Print with carriage return
204
+ self.__console.print(timer_text, end="\r")
205
+
206
+
207
+ def default_build_logger(
208
+ min_level: Optional[LogEntryLevel] = None,
209
+ ) -> Callable[[LogEntry], None]:
210
+ """
211
+ Create a default build logger with animated timer display.
212
+
213
+ :param min_level: Minimum log level to display (default: 'info')
214
+
215
+ :return: Logger function that accepts LogEntry instances
216
+
217
+ Example
218
+ ```python
219
+ from moru import Template, default_build_logger
220
+
221
+ template = Template().from_python_image()
222
+
223
+ # Use with build - implementation would be in build_async module
224
+ # await Template.build(template,
225
+ # alias='my-template',
226
+ # on_build_logs=default_build_logger(min_level='debug')
227
+ # )
228
+ ```
229
+ """
230
+ build_logger = DefaultBuildLogger(min_level)
231
+
232
+ return build_logger.logger