robotcode-repl-server 0.100.2__py3-none-any.whl → 0.101.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.
@@ -1 +1 @@
1
- __version__ = "0.100.2"
1
+ __version__ = "0.101.0"
@@ -1,16 +1,17 @@
1
+ import textwrap
1
2
  from dataclasses import dataclass, field
2
- from datetime import datetime
3
+ from datetime import datetime, timedelta
3
4
  from pathlib import Path
4
5
  from threading import Event
5
6
  from typing import TYPE_CHECKING, Iterator, List, Optional, Protocol, Union, runtime_checkable
6
- from uuid import uuid4
7
7
 
8
8
  from robot.running import Keyword
9
+ from robot.utils.markuputils import html_format
10
+ from robot.utils.robottime import elapsed_time_to_string
9
11
 
10
12
  from robotcode.core.utils.dataclasses import as_json
11
13
  from robotcode.repl.base_interpreter import BaseInterpreter, is_true
12
-
13
- from .html_writer import Element, create_keyword_html, create_message_html
14
+ from robotcode.robot.utils import get_robot_version
14
15
 
15
16
  if TYPE_CHECKING:
16
17
  from robot import result, running
@@ -76,13 +77,28 @@ class KeywordResultData(ResultData):
76
77
  message: str
77
78
  start_time: Optional[str]
78
79
  end_time: Optional[str]
79
- elapsed_time: Optional[float]
80
+ elapsed_time: Optional[str]
80
81
 
81
82
  items: List[ResultData] = field(default_factory=list)
82
83
 
83
84
  node_type: str = "keyword"
84
85
 
85
86
 
87
+ if get_robot_version() < (7, 0):
88
+
89
+ def make_elapsed_time_str(elapsed_time: Union[timedelta, int, float, None]) -> Optional[str]:
90
+ if elapsed_time is None:
91
+ return None
92
+ return str(elapsed_time_to_string(elapsed_time))
93
+
94
+ else:
95
+
96
+ def make_elapsed_time_str(elapsed_time: Union[timedelta, int, float, None]) -> Optional[str]:
97
+ if elapsed_time is None:
98
+ return None
99
+ return str(elapsed_time_to_string(elapsed_time, seconds=True))
100
+
101
+
86
102
  class Interpreter(BaseInterpreter):
87
103
  def __init__(
88
104
  self,
@@ -93,45 +109,24 @@ class Interpreter(BaseInterpreter):
93
109
  self.has_input = Event()
94
110
  self.executed = Event()
95
111
  self._code: List[str] = []
96
- self._html_result: Optional[Element] = None
97
- self._result_stack: List[Element] = []
98
- self._output_stack: List[Element] = []
99
- self._shadow_marker: Optional[str] = None
100
112
  self._success: Optional[bool] = None
101
113
  self._result_data: Optional[ResultData] = None
102
114
  self._result_data_stack: List[ResultData] = []
103
115
  self.collect_messages: bool = False
104
116
  self._has_shutdown = False
117
+ self._cell_errors: List[str] = []
105
118
 
106
119
  def shutdown(self) -> None:
107
120
  self._code = []
108
121
  self._has_shutdown = True
109
122
  self.has_input.set()
110
- # self.executed.set()
111
123
 
112
124
  def execute(self, source: str) -> ExecutionResult:
113
- self._result_stack = []
114
125
  self._result_data_stack = []
115
126
 
116
127
  self._success = None
117
128
  try:
118
- self._shadow_marker = str(uuid4())
119
-
120
- html_result = Element("div", classes=["robot-results"])
121
-
122
- with html_result.tag(
123
- "div", attributes={"data-shadow-marker": self._shadow_marker}, styles={"display": "none"}
124
- ):
125
- pass
126
-
127
- outer_test: Optional[Element] = None
128
- with html_result.tag("div", classes=["result_body"]) as body:
129
- with body.tag("div", classes=["test"]) as test:
130
- with test.tag("div", classes=["children"], styles={"display": "block"}):
131
- pass
132
- outer_test = test
133
-
134
- self._html_result = outer_test
129
+ self._cell_errors = []
135
130
  self._result_data = RootResultData()
136
131
 
137
132
  self.executed.clear()
@@ -148,12 +143,18 @@ class Interpreter(BaseInterpreter):
148
143
  ExecutionOutput(
149
144
  "x-application/robotframework-repl-log", as_json(self._result_data, compact=True)
150
145
  ),
151
- ExecutionOutput(
152
- "x-application/robotframework-repl-html", html_result.as_str(only_children=True)
146
+ *(
147
+ [ExecutionOutput("application/vnd.code.notebook.stderr", "\n".join(self._cell_errors))]
148
+ if self._cell_errors
149
+ else []
153
150
  ),
154
151
  ]
155
152
  if self._success is not None
156
- else []
153
+ else (
154
+ [ExecutionOutput("application/vnd.code.notebook.stderr", "\n".join(self._cell_errors))]
155
+ if self._cell_errors
156
+ else []
157
+ )
157
158
  ),
158
159
  )
159
160
  except BaseException as e:
@@ -164,7 +165,12 @@ class Interpreter(BaseInterpreter):
164
165
  s = self._code.pop(0)
165
166
  test, errors = self.get_test_body_from_string(s)
166
167
  if errors:
167
- raise CellInputError(errors)
168
+ self._cell_errors.append(
169
+ "CellInputError: " + ("\n" + textwrap.indent("\n".join(errors), " "))
170
+ if len(errors) > 1
171
+ else errors[0]
172
+ )
173
+ # raise CellInputError(errors)
168
174
 
169
175
  for kw in test.body:
170
176
  yield kw
@@ -183,29 +189,6 @@ class Interpreter(BaseInterpreter):
183
189
  )
184
190
  )
185
191
 
186
- if level in ("DEBUG", "TRACE"):
187
- return
188
-
189
- if self._html_result is None:
190
- return
191
-
192
- items = next(
193
- (
194
- i
195
- for i in self._html_result.children
196
- if isinstance(i, Element) and i.tag_name == "div" and i.classes is not None and "children" in i.classes
197
- ),
198
- None,
199
- )
200
- if items is None:
201
- items = Element("div", classes=["children"])
202
- self._html_result.add_element(items)
203
-
204
- id = f"message-{len(items.children)}"
205
-
206
- message_data = create_message_html(id, message, level, html, timestamp, shadow_root_id=self._shadow_marker)
207
- items.add_element(message_data)
208
-
209
192
  def message(
210
193
  self, message: str, level: str, html: Union[str, bool] = False, timestamp: Union[datetime, str, None] = None
211
194
  ) -> None:
@@ -232,7 +215,7 @@ class Interpreter(BaseInterpreter):
232
215
  name=result.name if getattr(result, "name", None) else "",
233
216
  owner=result.owner if getattr(result, "owner", None) else "",
234
217
  source_name=result.source_name if getattr(result, "source_name", None) else "",
235
- doc=result.doc if getattr(result, "doc", None) else "",
218
+ doc=html_format(result.doc) if getattr(result, "doc", None) else "",
236
219
  args=list(result.args) if getattr(result, "args", None) else [],
237
220
  assign=list(result.assign) if getattr(result, "assign", None) else [],
238
221
  tags=list(result.tags) if getattr(result, "tags", None) else [],
@@ -242,43 +225,29 @@ class Interpreter(BaseInterpreter):
242
225
  message=result.message,
243
226
  start_time=result.starttime,
244
227
  end_time=result.endtime,
245
- elapsed_time=result.elapsedtime,
228
+ elapsed_time=(
229
+ make_elapsed_time_str(result.elapsedtime)
230
+ if get_robot_version() < (7, 0)
231
+ else make_elapsed_time_str(result.elapsed_time)
232
+ ),
246
233
  )
247
234
  if self._result_data is not None and isinstance(self._result_data, ResultDataWithChildren):
248
235
  self._result_data.items.append(kw_data)
249
236
  self._result_data_stack.append(self._result_data)
250
237
  self._result_data = kw_data
251
238
 
252
- if self._html_result is not None:
253
- self._result_stack.append(self._html_result)
254
- kw = self.create_keyword_html_element(result)
255
-
256
- children = next(
257
- (
258
- i
259
- for i in self._html_result.children
260
- if isinstance(i, Element)
261
- and i.tag_name == "div"
262
- and i.classes is not None
263
- and "children" in i.classes
264
- ),
265
- None,
266
- )
267
-
268
- if children is None:
269
- self._html_result.add_element(kw)
270
- else:
271
- children.add_element(kw)
272
-
273
- self._html_result = kw
274
-
275
239
  def end_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None:
276
240
  if data.type in ["IF/ELSE ROOT", "TRY/EXCEPT ROOT"]:
277
241
  return
242
+
278
243
  if self._result_data is not None:
279
244
  if isinstance(self._result_data, KeywordResultData):
280
245
  self._result_data.end_time = result.endtime
281
- self._result_data.elapsed_time = result.elapsedtime
246
+ self._result_data.elapsed_time = (
247
+ make_elapsed_time_str(result.elapsedtime)
248
+ if get_robot_version() < (7, 0)
249
+ else make_elapsed_time_str(result.elapsed_time)
250
+ )
282
251
  self._result_data.status = result.status
283
252
  self._result_data.message = result.message
284
253
 
@@ -289,69 +258,6 @@ class Interpreter(BaseInterpreter):
289
258
  elif result.status == "PASS" and self.last_result is not False:
290
259
  self._success = True
291
260
 
292
- if self._html_result is not None and isinstance(self._html_result, Element):
293
- kw = self.create_keyword_html_element(result)
294
-
295
- old_children = next(
296
- (
297
- i
298
- for i in self._html_result.children
299
- if isinstance(i, Element)
300
- and i.tag_name == "div"
301
- and i.classes is not None
302
- and "children" in i.classes
303
- ),
304
- None,
305
- )
306
- if old_children is not None:
307
- new_children = next(
308
- (
309
- i
310
- for i in kw.children
311
- if isinstance(i, Element)
312
- and i.tag_name == "div"
313
- and i.classes is not None
314
- and "children" in i.classes
315
- ),
316
- None,
317
- )
318
- if new_children is None:
319
- new_children = Element("div", classes=["children"])
320
- self._html_result.add_element(new_children)
321
-
322
- for old_child in old_children.children:
323
- if not (
324
- isinstance(old_child, Element)
325
- and old_child.tag_name == "table"
326
- and old_child.classes is not None
327
- and "metadata" in old_child.classes
328
- ):
329
- new_children.add_element(old_child)
330
-
331
- self._html_result.children = kw.children
332
-
333
- self._html_result = self._result_stack.pop()
334
-
335
- def create_keyword_html_element(self, result: "result.Keyword") -> Element:
336
- return create_keyword_html(
337
- id=result.id,
338
- name=result.name if getattr(result, "name", None) else None,
339
- owner=result.owner if getattr(result, "owner", None) else None,
340
- source_name=result.source_name if getattr(result, "source_name", None) else None,
341
- doc=result.doc if getattr(result, "doc", None) else None,
342
- args=result.args if getattr(result, "args", None) else (),
343
- assign=result.assign if getattr(result, "assign", None) else (),
344
- tags=result.tags if getattr(result, "tags", None) else (),
345
- timeout=result.timeout if getattr(result, "timeout", None) else None,
346
- type=result.type,
347
- status=result.status,
348
- message=result.message,
349
- start_time=result.starttime,
350
- end_time=result.endtime,
351
- elapsed_time=result.elapsedtime,
352
- shadow_root_id=self._shadow_marker,
353
- )
354
-
355
261
  def run_input(self) -> None:
356
262
  self.has_input.wait()
357
263
  if self._has_shutdown:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: robotcode-repl-server
3
- Version: 0.100.2
3
+ Version: 0.101.0
4
4
  Summary: RobotCode REPL Server for Robot Framework
5
5
  Project-URL: Homepage, https://robotcode.io
6
6
  Project-URL: Donate, https://opencollective.com/robotcode
@@ -24,8 +24,8 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
24
24
  Classifier: Topic :: Utilities
25
25
  Classifier: Typing :: Typed
26
26
  Requires-Python: >=3.8
27
- Requires-Dist: robotcode-jsonrpc2==0.100.2
28
- Requires-Dist: robotcode-runner==0.100.2
27
+ Requires-Dist: robotcode-jsonrpc2==0.101.0
28
+ Requires-Dist: robotcode-runner==0.101.0
29
29
  Description-Content-Type: text/markdown
30
30
 
31
31
  # robotcode-repl-server
@@ -1,14 +1,13 @@
1
1
  robotcode/repl_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- robotcode/repl_server/__version__.py,sha256=KOSZwXxaWC5gV2MfDYCKF5EXztMoe69rJ4ys10pqYs4,24
2
+ robotcode/repl_server/__version__.py,sha256=tErTpFCmZUfGTNOXJztDNy6EvOoUJyR9YDFmyRr1HdE,24
3
3
  robotcode/repl_server/cli.py,sha256=yxgD_4QFwRD-BSGxto3MeimKess5_KZWkUJldERBsSk,5970
4
4
  robotcode/repl_server/hooks.py,sha256=4O9H8cefHc6T7erjPxzU941w3KWytTBB5gmvYb4bs_I,196
5
- robotcode/repl_server/html_writer.py,sha256=fr-6kSobkhqfYPGlOgBuAs-CSln-lkAwYsxc8_nb79Y,11647
6
- robotcode/repl_server/interpreter.py,sha256=5Xgr2bACjU2-hOvZYe2p4MP4c9K3XivsUpyFd6Vbrz4,12557
5
+ robotcode/repl_server/interpreter.py,sha256=gzCwKiYfzVuOl4FHC_lpt5HLH8WdKwMz2CKmgbATFKk,9053
7
6
  robotcode/repl_server/protocol.py,sha256=4Eeoz45DfkKuzMZ7NJed8x0m0SWJdKkeFbnuO3e6DgQ,980
8
7
  robotcode/repl_server/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
9
8
  robotcode/repl_server/server.py,sha256=zzFsD6ds56d4GQJKXoysVZP-oiS08AtMKeyLKXH9Fss,746
10
- robotcode_repl_server-0.100.2.dist-info/METADATA,sha256=_0b3C_7ooqfSfTkBSj-AaN5Q3LjaLfmqk6hnXrSLAo0,2112
11
- robotcode_repl_server-0.100.2.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
12
- robotcode_repl_server-0.100.2.dist-info/entry_points.txt,sha256=U_1iYu71VNyPq_epO0fXHki3B4BE4gR2mbZFAOWN1cg,54
13
- robotcode_repl_server-0.100.2.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
14
- robotcode_repl_server-0.100.2.dist-info/RECORD,,
9
+ robotcode_repl_server-0.101.0.dist-info/METADATA,sha256=c9BuRjQ0U2RsM6uTrSkiq_qdqLQSy65b9xFsPoLbMV8,2112
10
+ robotcode_repl_server-0.101.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
11
+ robotcode_repl_server-0.101.0.dist-info/entry_points.txt,sha256=U_1iYu71VNyPq_epO0fXHki3B4BE4gR2mbZFAOWN1cg,54
12
+ robotcode_repl_server-0.101.0.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
13
+ robotcode_repl_server-0.101.0.dist-info/RECORD,,
@@ -1,324 +0,0 @@
1
- from contextlib import contextmanager
2
- from datetime import datetime, timedelta
3
- from typing import Any, Dict, Generator, List, Optional, Sequence, TypeVar, Union
4
-
5
- from robot.utils.robottime import elapsed_time_to_string
6
-
7
- from robotcode.repl.base_interpreter import is_true
8
- from robotcode.robot.utils import get_robot_version
9
-
10
-
11
- class ElementDataBase:
12
- def as_str(self, indent: int = 0) -> str:
13
- raise NotImplementedError
14
-
15
- def __str__(self) -> str:
16
- return self.as_str(0)
17
-
18
-
19
- _T = TypeVar("_T", bound=ElementDataBase)
20
-
21
-
22
- class TextElement(ElementDataBase):
23
- def __init__(self, text: str) -> None:
24
- self.text = text
25
-
26
- def as_str(self, indent: int = 0) -> str:
27
- return f"{' '*indent}{self.text}"
28
-
29
-
30
- class RawElement(ElementDataBase):
31
- def __init__(self, text: str) -> None:
32
- self.text = text
33
-
34
- def as_str(self, indent: int = 0) -> str:
35
- return f"{' '*indent}{self.text}"
36
-
37
-
38
- class Element(ElementDataBase):
39
- def __init__(
40
- self,
41
- tag_name: str,
42
- text: Optional[str] = None,
43
- classes: Optional[List[str]] = None,
44
- styles: Optional[Dict[str, str]] = None,
45
- attributes: Optional[Dict[str, str]] = None,
46
- **kwargs: Any,
47
- ) -> None:
48
- self.tag_name = tag_name
49
- self.classes = classes
50
- self.styles = styles
51
- if attributes is None:
52
- attributes = {}
53
- attributes.update(kwargs)
54
- self.attributes = attributes
55
- self.children: List[ElementDataBase] = []
56
-
57
- if text is not None:
58
- self.add_element(TextElement(text))
59
-
60
- def add_element(self, child: _T) -> _T:
61
- self.children.append(child)
62
- return child
63
-
64
- @contextmanager
65
- def tag(
66
- self,
67
- tag_name: str,
68
- *,
69
- text: Optional[str] = None,
70
- classes: Optional[List[str]] = None,
71
- styles: Optional[Dict[str, str]] = None,
72
- attributes: Optional[Dict[str, str]] = None,
73
- **kwargs: Any,
74
- ) -> Generator["Element", None, None]:
75
- element = Element(tag_name, text=text, classes=classes, styles=styles, attributes=attributes, **kwargs)
76
-
77
- yield element
78
-
79
- self.add_element(element)
80
-
81
- def add_raw(self, text: Any) -> None:
82
- self.add_element(RawElement(str(text)))
83
-
84
- def add_text(self, text: Any) -> None:
85
- self.add_element(TextElement(str(text)))
86
-
87
- def _build_attributes(self) -> str:
88
- result = []
89
- if self.classes:
90
- result.append(f'class="{" ".join(s for s in self.classes if s)}"')
91
- if self.styles:
92
- result.append(f'style="{"; ".join(f"{k}: {v}" for k, v in self.styles.items() if v)}"')
93
- if self.attributes:
94
- result.extend(f'{k}="{v}"' for k, v in self.attributes.items())
95
-
96
- return " ".join(result)
97
-
98
- NON_BREAKABLE_TAGS = {"span", "a", "b", "i", "u", "strong", "em", "code", "pre", "tt", "samp", "kbd", "var", "td"}
99
-
100
- def as_str(self, indent: int = 0, *, only_children: bool = False) -> str:
101
- if not only_children:
102
- attributes = self._build_attributes()
103
-
104
- if attributes:
105
- start_tag = f"<{self.tag_name} {attributes}>"
106
- else:
107
- start_tag = f"<{self.tag_name}>"
108
-
109
- end_tag = f"</{self.tag_name}>"
110
-
111
- result = " " * indent + start_tag
112
- else:
113
- result = ""
114
- end_tag = None
115
-
116
- if self.children:
117
- result += "\n" if self.tag_name not in self.NON_BREAKABLE_TAGS else ""
118
- for child in self.children:
119
- result += child.as_str((indent + 1) if self.tag_name not in self.NON_BREAKABLE_TAGS else 0) + (
120
- "\n" if self.tag_name not in self.NON_BREAKABLE_TAGS else ""
121
- )
122
- result += (" " * indent) if self.tag_name not in self.NON_BREAKABLE_TAGS else ""
123
-
124
- if end_tag:
125
- result += end_tag
126
-
127
- return result
128
-
129
-
130
- def create_keyword_html(
131
- id: Optional[str] = None,
132
- name: Optional[str] = "",
133
- owner: Optional[str] = None,
134
- source_name: Optional[str] = None,
135
- doc: Optional[str] = "",
136
- args: Sequence[str] = (),
137
- assign: Sequence[str] = (),
138
- tags: Sequence[str] = (),
139
- timeout: Optional[str] = None,
140
- type: str = "KEYWORD",
141
- status: str = "FAIL",
142
- message: str = "",
143
- start_time: Union[datetime, str, None] = None,
144
- end_time: Union[datetime, str, None] = None,
145
- elapsed_time: Union[timedelta, int, float, None] = None,
146
- shadow_root_id: Optional[str] = None,
147
- ) -> Element:
148
- result = Element("div", classes=["keyword"], id=id)
149
-
150
- elapsed_time_str = (
151
- (
152
- elapsed_time_to_string(elapsed_time)
153
- if get_robot_version() < (7, 0)
154
- else elapsed_time_to_string(elapsed_time, seconds=True)
155
- )
156
- if elapsed_time is not None
157
- else ""
158
- )
159
-
160
- with result.tag(
161
- "div",
162
- classes=["element-header", "closed" if status not in ["FAIL"] else ""],
163
- onclick=f"toggleKeyword('{id}', '{shadow_root_id}')",
164
- ) as e_element_header:
165
- with e_element_header.tag(
166
- "div",
167
- classes=["element-header-left"],
168
- title=f"{type.upper()} {owner}.{name} [{status}]",
169
- ) as e_header_left:
170
- if elapsed_time is not None:
171
- with e_header_left.tag("span", classes=["elapsed"]) as e_elapsed:
172
- e_elapsed.add_text(elapsed_time_str)
173
- with e_header_left.tag("span", classes=["label", status.lower()]) as e_label:
174
- e_label.add_text(str(type).upper())
175
- with e_header_left.tag("span", classes=["assign"]) as e_assign:
176
- e_assign.add_text(" ".join(assign))
177
- with e_header_left.tag("span", classes=["name"]) as e_name:
178
- with e_name.tag("span", classes=["parent-name"]) as parent_name:
179
- parent_name.add_text((owner + " . ") if owner else "")
180
- e_name.add_text(name)
181
- e_header_left.add_raw("&nbsp;")
182
- with e_header_left.tag("span", classes=["arg"]) as args_tag:
183
- args_tag.add_text(" ".join(args))
184
- with e_element_header.tag("div", classes=["element-header-right"]) as e_header_right:
185
- with e_header_right.tag(
186
- "div",
187
- classes=["expand"],
188
- title="Expand all",
189
- onclick=f"expandAll(event, '{id}', '{shadow_root_id}')",
190
- ):
191
- pass
192
- with e_header_right.tag(
193
- "div",
194
- classes=["collapse"],
195
- title="Collapse all",
196
- onclick=f"collapseAll(event, '{id}', '{shadow_root_id}')",
197
- ):
198
- pass
199
- with e_header_right.tag(
200
- "div",
201
- classes=["link"],
202
- title="Highlight this item",
203
- onclick=f"makeElementVisible(event, '{id}', '{shadow_root_id}')",
204
- ):
205
- pass
206
- with e_element_header.tag("div", classes=["element-header-toggle"], title="Toggle visibility"):
207
- pass
208
-
209
- with result.tag(
210
- "div", classes=["children", "populated"], styles={"display": "none" if status not in ["FAIL"] else "block"}
211
- ) as e_children:
212
- with e_children.tag("table", classes=["metadata", "keyword-metadata"]) as e_body:
213
- if doc:
214
- with e_body.tag("tr") as tr:
215
- with tr.tag("th", text="Documentation:"):
216
- pass
217
- with tr.tag("td", classes=["doc"]) as td:
218
- td.add_text(doc)
219
- if tags:
220
- with e_body.tag("tr") as tr:
221
- with tr.tag("th", text="Tags:"):
222
- pass
223
- with tr.tag("td", classes=["tags"]) as td:
224
- td.add_text(", ".join(tags))
225
- if timeout:
226
- with e_body.tag("tr") as tr:
227
- with tr.tag("th", text="Timeout:"):
228
- pass
229
- with tr.tag("td", classes=["timeout"]) as td:
230
- td.add_text(timeout)
231
- if source_name:
232
- with e_body.tag("tr") as tr:
233
- with tr.tag("th", text="Source:"):
234
- pass
235
- with tr.tag("td", classes=["source"]) as td:
236
- td.add_text(source_name)
237
- with e_body.tag("tr") as tr:
238
- with tr.tag("th", text="Start / End / Elapsed:"):
239
- pass
240
- with tr.tag("td", classes=["message"]) as td:
241
- td.add_text(str(start_time) + " / " + str(end_time) + " / " + elapsed_time_str)
242
- if message:
243
- with e_body.tag("tr") as tr:
244
- with tr.tag("th", text="Message:"):
245
- pass
246
- with tr.tag("td", classes=["message"]) as td:
247
- td.add_text(message)
248
-
249
- return result
250
-
251
-
252
- def create_message_html(
253
- id: str,
254
- message: str,
255
- level: str,
256
- html: Union[str, bool] = False,
257
- timestamp: Union[datetime, str, None] = None,
258
- shadow_root_id: Optional[str] = None,
259
- ) -> Element:
260
- result = Element("table", classes=["messages", f"{level.lower()}-message"], id=id)
261
-
262
- with result.tag("tr", classes=["message-row"]) as tr:
263
- with tr.tag("td", classes=["time"]) as td:
264
- if isinstance(timestamp, datetime):
265
- td.add_text(timestamp.strftime("%H:%M:%S"))
266
- else:
267
- td.add_text(timestamp)
268
- with tr.tag("td", classes=["level", level.lower()]) as td:
269
- with td.tag("span", classes=["label", level.lower()]) as sp:
270
- sp.add_text(level.upper())
271
- with tr.tag("td", classes=["message"]) as td:
272
- if is_true(html):
273
- td.add_raw(message)
274
- else:
275
- td.add_text(message)
276
- with tr.tag(
277
- "td",
278
- classes=["select-message"],
279
- onclick=f"selectMessage('{id}', '{shadow_root_id}')",
280
- title="Select message text",
281
- ) as td:
282
- with td.tag("div"):
283
- pass
284
-
285
- return result
286
-
287
-
288
- if __name__ == "__main__":
289
- # div = Element("div", id="main", classes=["test", "test2"], styles={"color": "red", "font-size": "12px"})
290
- # p = div.add_element(Element("p", text="Hello, world!"))
291
- # p.add_element(Element("span", text="This is a test"))
292
- # print(div)
293
-
294
- # body = Element("body")
295
- # with body.tag("div", id="main", classes=["test", "test2"], styles={"color": "red"}) as div:
296
- # with div.tag("p") as p:
297
- # p.add_text("Hello, world!")
298
- # with p.tag("span") as span:
299
- # span.add_text("This is a test")
300
- # with span.tag("br"):
301
- # pass
302
- # span.add_text("This is a test")
303
- # with span.tag("br", id="test"):
304
- # pass
305
- # print(body)
306
-
307
- # r = create_keyword_html(
308
- # id="ts-1-2-3-4-5-6",
309
- # name="Test Keyword",
310
- # owner="Test Library",
311
- # doc="This is a test keyword",
312
- # args=("arg1", "arg2"),
313
- # assign=("${var1}", "${var2}"),
314
- # tags=("tag1", "tag2"),
315
- # timeout="10s",
316
- # type="KEYWORD",
317
- # status="PASS",
318
- # message="This is a test message",
319
- # start_time=datetime.now(timezone.utc),
320
- # end_time=datetime.now(timezone.utc),
321
- # elapsed_time=timedelta(seconds=5),
322
- # )
323
- r = create_message_html("ts-1-2-3-4-5-6", "This is a test message", "INFO", timestamp="2021-10-10 12:00:00")
324
- print(r)