示例#1
0
async def setup_script(hass, notify_q, now, source):
    """Initialize and load the given pyscript."""
    scripts = [
        "/hello.py",
    ]

    with patch(
            "custom_components.pyscript.os.path.isdir", return_value=True
    ), patch("custom_components.pyscript.glob.iglob",
             return_value=scripts), patch(
                 "custom_components.pyscript.global_ctx.open",
                 mock_open(read_data=source)
             ), patch(
                 "custom_components.pyscript.trigger.dt_now", return_value=now
             ), patch(
                 "homeassistant.config.load_yaml_config_file", return_value={}
             ), patch(
                 "custom_components.pyscript.open", mock_open(read_data=source)
             ), patch(
                 "custom_components.pyscript.watchdog_start",
                 return_value=None), patch(
                     "custom_components.pyscript.os.path.getmtime",
                     return_value=1000
                 ), patch(
                     "custom_components.pyscript.global_ctx.os.path.getmtime",
                     return_value=1000), patch(
                         "custom_components.pyscript.install_requirements",
                         return_value=None,
                     ):
        assert await async_setup_component(hass, "pyscript", {DOMAIN: {}})

    #
    # I'm not sure how to run the mock all the time, so just force the dt_now()
    # trigger function to return the given list of times in now.
    #
    def return_next_time():
        nonlocal now
        if isinstance(now, list):
            if len(now) > 1:
                return now.pop(0)
            return now[0]
        return now

    trigger.__dict__["dt_now"] = return_next_time

    if notify_q:

        async def state_changed(event):
            var_name = event.data["entity_id"]
            if var_name != "pyscript.done":
                return
            value = event.data["new_state"].state
            await notify_q.put(value)

        hass.bus.async_listen(EVENT_STATE_CHANGED, state_changed)
示例#2
0
async def setup_script(hass, notify_q, now, source):
    """Initialize and load the given pyscript."""
    scripts = [
        "/some/config/dir/pyscripts/hello.py",
    ]

    with patch("custom_components.pyscript.os.path.isdir",
               return_value=True), patch(
                   "custom_components.pyscript.glob.iglob",
                   return_value=scripts), patch(
                       "custom_components.pyscript.global_ctx.open",
                       mock_open(read_data=source),
                       create=True,
                   ), patch("custom_components.pyscript.trigger.dt_now",
                            return_value=now):
        assert await async_setup_component(hass, "pyscript", {DOMAIN: {}})

    #
    # I'm not sure how to run the mock all the time, so just force the dt_now()
    # trigger function to return the fixed time, now.
    #
    trigger.__dict__["dt_now"] = lambda: now

    if notify_q:

        async def state_changed(event):
            var_name = event.data["entity_id"]
            if var_name != "pyscript.done":
                return
            value = event.data["new_state"].state
            await notify_q.put(value)

        hass.bus.async_listen(EVENT_STATE_CHANGED, state_changed)
示例#3
0
async def setup_script(hass, now, source, no_connect=False):
    """Initialize and load the given pyscript."""

    scripts = [
        "/some/config/dir/pyscripts/hello.py",
    ]

    with patch(
            "custom_components.pyscript.os.path.isdir",
            return_value=True), patch(
                "custom_components.pyscript.glob.iglob",
                return_value=scripts), patch(
                    "custom_components.pyscript.global_ctx.open",
                    mock_open(read_data=source),
                    create=True,
                ), patch(
                    "custom_components.pyscript.trigger.dt_now",
                    return_value=now), patch(
                        "homeassistant.config.load_yaml_config_file",
                        return_value={}), patch(
                            "custom_components.pyscript.install_requirements",
                            return_value=None,
                        ):
        assert await async_setup_component(hass, "pyscript", {DOMAIN: {}})

    #
    # I'm not sure how to run the mock all the time, so just force the dt_now()
    # trigger function to return the given list of times in now.
    #
    def return_next_time():
        nonlocal now
        if isinstance(now, list):
            if len(now) > 1:
                return now.pop(0)
            return now[0]
        return now

    trigger.__dict__["dt_now"] = return_next_time

    kernel_state_var = "pyscript.jupyter_ports_1234"
    kernel_cfg = {
        "ip": "127.0.0.1",
        "key": SECRET_KEY.decode("utf-8"),
        "signature_scheme": "hmac-sha256",
        "state_var": kernel_state_var,
    }
    if no_connect:
        kernel_cfg["no_connect_timeout"] = 0.0
    await hass.services.async_call("pyscript", "jupyter_kernel_start",
                                   kernel_cfg)

    while True:
        ports_state = hass.states.get(kernel_state_var)
        if ports_state is not None:
            break
        await asyncio.sleep(2e-3)

    port_nums = json.loads(ports_state.state)

    sock = {}

    if no_connect:
        return sock, port_nums

    for name in PORT_NAMES:
        kernel_reader, kernel_writer = await asyncio.open_connection(
            "127.0.0.1", port_nums[name])
        sock[name] = ZmqSocket(kernel_reader, kernel_writer, "ROUTER")
        await sock[name].handshake()

    return sock, port_nums
async def test_reload(hass, caplog):
    """Test reload."""
    notify_q = asyncio.Queue(0)
    now = dt(2020, 7, 1, 11, 59, 59, 999999)
    source0 = """
seq_num = 0

@time_trigger
def func_startup_sync():
    global seq_num

    seq_num += 1
    log.info(f"func_startup_sync setting pyscript.done = {seq_num}")
    pyscript.done = seq_num

@service
@state_trigger("pyscript.f1var1 == '1'")
def func9(var_name=None, value=None):
    global seq_num

    seq_num += 1
    log.info(f"func9 var = {var_name}, value = {value}")
    pyscript.done = [seq_num, var_name, int(value)]

"""
    source1 = """
seq_num = 10

@time_trigger("startup")
def func_startup_sync():
    global seq_num

    seq_num += 1
    log.info(f"func_startup_sync setting pyscript.done = {seq_num}")
    pyscript.done = seq_num

@service
@state_trigger("pyscript.f5var1 == '1'")
def func5(var_name=None, value=None):
    global seq_num

    seq_num += 1
    log.info(f"func5 var = {var_name}, value = {value}")
    pyscript.done = [seq_num, var_name, int(value)]

"""

    await setup_script(hass, notify_q, now, source0)

    #
    # run and reload 6 times with different source files to make sure seqNum
    # gets reset, autostart of func_startup_sync happens and triggers work each time
    #
    # first time: fire event to startup triggers and run func_startup_sync
    #
    hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
    for i in range(6):
        if i & 1:
            seq_num = 10

            assert not hass.services.has_service("pyscript", "func9")
            assert hass.services.has_service("pyscript", "reload")
            assert hass.services.has_service("pyscript", "func5")

            seq_num += 1
            assert literal_eval(await wait_until_done(notify_q)) == seq_num

            seq_num += 1
            # initialize the trigger and active variables
            hass.states.async_set("pyscript.f5var1", 0)

            # try some values that shouldn't work, then one that does
            hass.states.async_set("pyscript.f5var1", "string")
            hass.states.async_set("pyscript.f5var1", 1)
            assert literal_eval(await wait_until_done(notify_q)) == [
                seq_num,
                "pyscript.f5var1",
                1,
            ]
            assert "func5 var = pyscript.f5var1, value = 1" in caplog.text
            next_source = source0

        else:
            seq_num = 0

            assert hass.services.has_service("pyscript", "func9")
            assert hass.services.has_service("pyscript", "reload")
            assert not hass.services.has_service("pyscript", "func5")

            seq_num += 1
            assert literal_eval(await wait_until_done(notify_q)) == seq_num

            seq_num += 1
            # initialize the trigger and active variables
            hass.states.async_set("pyscript.f1var1", 0)

            # try some values that shouldn't work, then one that does
            hass.states.async_set("pyscript.f1var1", "string")
            hass.states.async_set("pyscript.f1var1", 1)
            assert literal_eval(await wait_until_done(notify_q)) == [
                seq_num,
                "pyscript.f1var1",
                1,
            ]
            assert "func9 var = pyscript.f1var1, value = 1" in caplog.text
            next_source = source1

        #
        # now reload the other source file
        #
        scripts = [
            "/hello.py",
        ]

        with patch(
                "custom_components.pyscript.os.path.isdir", return_value=True
        ), patch(
                "custom_components.pyscript.glob.iglob", return_value=scripts
        ), patch("custom_components.pyscript.global_ctx.open",
                 mock_open(read_data=next_source)), patch(
                     "custom_components.pyscript.open",
                     mock_open(read_data=next_source)
                 ), patch(
                     "custom_components.pyscript.trigger.dt_now",
                     return_value=now
                 ), patch(
                     "homeassistant.config.load_yaml_config_file",
                     return_value={}
                 ), patch(
                     "custom_components.pyscript.os.path.getmtime",
                     return_value=1000
                 ), patch(
                     "custom_components.pyscript.global_ctx.os.path.getmtime",
                     return_value=1000), patch(
                         "custom_components.pyscript.install_requirements",
                         return_value=None,
                     ):
            reload_param = {}
            if i % 2 == 1:
                #
                # on alternate times, just reload the specific file we are testing with
                #
                reload_param = {"global_ctx": "file.hello"}
            await hass.services.async_call("pyscript",
                                           "reload",
                                           reload_param,
                                           blocking=True)
            if i % 3 == 0:
                #
                # reload a file that doesn't exist; will log error and do nothing
                #
                await hass.services.async_call(
                    "pyscript",
                    "reload", {"global_ctx": "file.nosuchfile"},
                    blocking=True)

    assert "pyscript.reload: no global context 'file.nosuchfile' to reload" in caplog.text