set_html error : TypeError: html must be a bytes type
martinlombana opened this issue · 12 comments
This error is probably on my side, as I am unaware of the correct transformation to apply to a single string. What I am trying to do is to inject pure HTML (as I will be injecting generated jinja2 templates)
I am trying to do a simple test in a simple frame:
def on_event(self, source, target, code, phase, reason):
# events from html controls (behaviors)
he = sciter.Element(source)
if code == sciter.event.BEHAVIOR_EVENTS.DOCUMENT_READY:
main_content = frame.get_root()
main_content.set_html("<b>hello</b>")
I get:
TypeError: html must be a bytes type
I tried encoding the string, or passing it as
b"<b>hello</b>"
or even:
"<b>hello</b>".encode('utf-8')
But it is not working.
Is there any special transformation that must be done that I am unaware of?
Thanks for the help,
As an extended test, I did:
main_content.set_html(bytes("<b>hello</b>", 'utf8'))
But then I get:
ctypes.ArgumentError: argument 2: <class 'TypeError'>: expected LP_c_byte instance instead of bytes
@pravic , you can easily reproduce like this, this is a self contained example that you can just run. No files needed. Thanks!
PS: I also realized that the Document_Ready event gets picked twice. Is that normal somehow?:
Thanks!
(Edited, and copied the right example!)
import sciter
from sciter import SCITER_RT_OPTIONS, Element
class RootEventHandler(sciter.EventHandler):
def __init__(self, el, frame):
super().__init__(element=el)
self.parent = frame
pass
def on_event(self, source, target, code, phase, reason):
he = sciter.Element(source)
if code == sciter.event.BEHAVIOR_EVENTS.DOCUMENT_READY:
print('sciter.event.BEHAVIOR_EVENTS.DOCUMENT_READY', flush=True)
main_content = frame.get_root()
element: Element = main_content.find_first('p')
current_html = element.get_html()
# This works
print('current_html-> ', current_html, flush=True)
# What is unexpected????? :(
element.set_text('Oh, just the text')
# This fails
element.set_html(b"<b>I did</b>")
#element.set_html("<b>I did</b>".encode())
pass
class Frame(sciter.Window):
def __init__(self):
super().__init__(ismain=True, uni_theme=True, debug=False, size=(500, 500), resizeable=False)
self.set_dispatch_options(enable=True, require_attribute=False)
pass
if __name__ == "__main__":
print("Sciter version:", sciter.version(as_str=True))
sciter.set_option(SCITER_RT_OPTIONS.SCITER_SET_DEBUG_MODE, True)
frame = Frame()
frame.setup_debug()
# frame.load_file("index.html")
frame.load_html(b"<html><body><p>I want to be substituted</p></body></html>")
ev2 = RootEventHandler(frame.get_root(), frame)
frame.run_app()
Ok, I found the bug in the DOM, @pravic
The thing is in dom.py, line 469, you pass the bytes html object to the C api, while, I think, what we need to pass is the raw bytes:
Before (not working):
def set_html(self, html: bytes, where=SET_ELEMENT_HTML.SIH_REPLACE_CONTENT):
"""Set inner or outer html of the element."""
if not html:
self.clear()
return self
if not isinstance(html, bytes):
raise TypeError("html must be a bytes type")
ok = _api.SciterSetElementHtml(self, html, len(html), where)
self._throw_if(ok)
return self
After (working well):
def set_html(self, html: bytes, where=SET_ELEMENT_HTML.SIH_REPLACE_CONTENT):
"""Set inner or outer html of the element."""
if not html:
self.clear()
return self
if not isinstance(html, bytes):
raise TypeError("html must be a bytes type")
raw_html = (ctypes.c_byte * len(html)).from_buffer_copy(html)
ok = _api.SciterSetElementHtml(self, raw_html, len(raw_html), where)
self._throw_if(ok)
return self
Do you (@pravic or @c-smile) want me to submit a pull request in the future for other bugs like this?
@martinlombana ctypes
has a number implicit conversions but there was a mistake in a function declaration, see the fix.
Document_Ready event gets picked twice.
Since you're overloading a self.on_event
, check the phase
for events - it can be SINKING
, BUBBLING
, HANDLED
.
I believe, the fix resolves this issue. Feel free to add more comments if need.
Thanks.
Where can I see the an explanation of the phases, and all the possible events?
And thanks for the fix. Are you going to release a new version (i tried the upgrade but no new version was found) or should I install from GIT from now now?
Events are listed in the header include/sciter-x-behavior.h , in particular here are all mouse events:
https://github.com/c-smile/sciter-sdk/blob/master/include/sciter-x-behavior.h#L135
Thanks,
I was interested in the KEY events as well.
But when I do this, the program does not register any key events, at all. Is there any other way that this should be done? I want to access the KEY_DOWN and KEY_UP events and the KEY_CODE.
(I shall note, that I am getting other events, like clicks, etc)
class RootEventHandler(sciter.EventHandler):
def __init__(self, el, frame):
super().__init__(element=el)
self.parent = frame
pass
def on_event(self, source, target, code, phase, reason):
he = sciter.Element(source)
print('he-> ', he, flush=True)
if code == sciter.event.KEY_EVENTS.KEY_DOWN:
print ('KEY DOWN')
if code == sciter.event.BEHAVIOR_EVENTS.DOCUMENT_READY:
print('sciter.event.BEHAVIOR_EVENTS.DOCUMENT_READY', flush=True)
main_content = frame.get_root()
element: Element = main_content.find_first('p')
current_html = element.get_html()
# This works
print('current_html-> ', current_html, flush=True)
# What is unexpected????? :(
element.set_text('Oh, just the text')
# This fails
string_bytes = b"<b>now!</b>"
element.set_html(string_bytes)
# element.get_expando('what', True)
pass
@martinlombana I'll make a new release, yes.
Please, ask other questions in a different issue if they are not related to set_html
.
But the answer is here: https://github.com/sciter-sdk/pysciter/blob/master/sciter/event.py#L16. Pass a proper combination of EVENT_GROUPS
to the EventHandler
constructor.