sciter-sdk/pysciter

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?:
image

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.