reflex-dev / reflex

🕸️ Web apps in pure Python 🐍

Home Page:https://reflex.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[REF-2682] Foreach over dict gets incorrect arg type

masenf opened this issue · comments

Describe the bug
The arg var resulting from iterating over a Var of type dict should be a tuple of the key and value types. But it's actually just the same type as the Var itself.

To Reproduce

import reflex as rx


class MyState(rx.State):

    labels: dict[str, str] = {
        "A": "Alpha",
        "a": "alpha",
        "b": "beta",
    }
    some_values: dict[str, str] = {
        "A": "a",
    }
    some_values_dict: dict[str, list[str]] = {
        "A": ["a", "b"],
    }


def make_nice_label(entry: list[str, str]) -> rx.Component:
    key = entry[0]
    value = entry[1]
    print(repr(entry), repr(key), repr(value))
    labels = MyState.labels
    return rx.vstack(rx.heading(labels[key]), rx.text(labels[value]))


def make_nice_label_dict(entry: list[str, str]) -> rx.Component:
    key = entry[0]
    values = entry[1]
    print(repr(entry), repr(key), repr(values))
    labels = MyState.labels
    return rx.vstack(
        rx.heading(labels[key]),
        rx.foreach(
            values,
            lambda value: rx.text(labels[value]),
        ),
    )


@rx.page(route="/")
def index() -> rx.Component:
    return rx.foreach(
        MyState.some_values,
        make_nice_label,
    ), rx.foreach(
        MyState.some_values_dict,
        make_nice_label_dict,
    )


app = rx.App()

Expected behavior
Should display

Alpha
alpha

Alpha
alpha
beta

Should print

BaseVar(_var_name='entry', _var_type=typing.Tuple[str, str], _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None) BaseVar(_var_name='entry.at(0)', _var_type=<class 'str'>, _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None) BaseVar(_var_name='entry.at(1)', _var_type=<class 'str'>, _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None)
BaseVar(_var_name='entry', _var_type=typing.Tuple[str, list[str]], _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None) BaseVar(_var_name='entry.at(0)', _var_type=<class 'str'>, _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None) BaseVar(_var_name='entry.at(1)', _var_type=list[str], _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None)

Instead, it crashes:

BaseVar(_var_name='entry', _var_type=dict[str, str], _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None) BaseVar(_var_name='entry[0]', _var_type=<class 'str'>, _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None) BaseVar(_var_name='entry[1]', _var_type=<class 'str'>, _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None)
BaseVar(_var_name='entry', _var_type=dict[str, list[str]], _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None) BaseVar(_var_name='entry[0]', _var_type=list[str], _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None) BaseVar(_var_name='entry[1]', _var_type=list[str], _var_is_local=False, _var_is_string=False, _var_full_name_needs_state_prefix=False, _var_data=None)
Traceback (most recent call last):
  File "/Users/masen/code/reflex-dev/VENV-dev311/bin/reflex", line 8, in <module>
    sys.exit(cli())
             ^^^^^
  File "/Users/masen/code/reflex-dev/VENV-dev311/lib/python3.11/site-packages/typer/main.py", line 326, in __call__
    raise e
  File "/Users/masen/code/reflex-dev/VENV-dev311/lib/python3.11/site-packages/typer/main.py", line 309, in __call__
    return get_command(self)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/masen/code/reflex-dev/VENV-dev311/lib/python3.11/site-packages/click/core.py", line 1157, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/masen/code/reflex-dev/VENV-dev311/lib/python3.11/site-packages/typer/core.py", line 723, in main
    return _main(
           ^^^^^^
  File "/Users/masen/code/reflex-dev/VENV-dev311/lib/python3.11/site-packages/typer/core.py", line 193, in _main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/Users/masen/code/reflex-dev/VENV-dev311/lib/python3.11/site-packages/click/core.py", line 1688, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/masen/code/reflex-dev/VENV-dev311/lib/python3.11/site-packages/click/core.py", line 1434, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/masen/code/reflex-dev/VENV-dev311/lib/python3.11/site-packages/click/core.py", line 783, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/masen/code/reflex-dev/VENV-dev311/lib/python3.11/site-packages/typer/main.py", line 688, in wrapper
    return callback(**use_params)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/masen/code/reflex-dev/reflex/reflex/reflex.py", line 256, in run
    _run(env, frontend, backend, frontend_port, backend_port, backend_host, loglevel)
  File "/Users/masen/code/reflex-dev/reflex/reflex/reflex.py", line 182, in _run
    prerequisites.get_compiled_app()
  File "/Users/masen/code/reflex-dev/reflex/reflex/utils/prerequisites.py", line 242, in get_compiled_app
    app._apply_decorated_pages()
  File "/Users/masen/code/reflex-dev/reflex/reflex/app.py", line 735, in _apply_decorated_pages
    self.add_page(render, **kwargs)
  File "/Users/masen/code/reflex-dev/reflex/reflex/app.py", line 455, in add_page
    component = self._generate_component(component)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/masen/code/reflex-dev/reflex/reflex/app.py", line 406, in _generate_component
    raise e
  File "/Users/masen/code/reflex-dev/reflex/reflex/app.py", line 395, in _generate_component
    return component if isinstance(component, Component) else component()
                                                              ^^^^^^^^^^^
  File "/Users/masen/code/reflex-dev/repro-complex-indexing/repro_complex_indexing/repro_complex_indexing.py", line 46, in index
    ), rx.foreach(
       ^^^^^^^^^^^
  File "/Users/masen/code/reflex-dev/reflex/reflex/components/core/foreach.py", line 64, in create
    component._render(props=dict(index_var_name="i")).render_component()
  File "/Users/masen/code/reflex-dev/reflex/reflex/components/tags/iter_tag.py", line 117, in render_component
    component = self.render_fn(arg)
                ^^^^^^^^^^^^^^^^^^^
  File "/Users/masen/code/reflex-dev/repro-complex-indexing/repro_complex_indexing/repro_complex_indexing.py", line 33, in make_nice_label_dict
    rx.heading(labels[key]),
               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
  File "/Users/masen/code/reflex-dev/reflex/reflex/vars.py", line 661, in __getitem__
    raise TypeError(
TypeError: Index must be one of the following types: int, str, int or str Var

Specifics (please complete the following information):

  • Python Version: 3.11.8
  • Reflex Version: 0.4.9
  • OS: macOS 14
  • Browser (Optional):

Additional context
In IterTag.get_iterable_var_type, we could use Tuple[self.iterable._var_type.__args__[0], self.iterable._var_type.__args__[1]] if the _var_type is dict

From SyncLinear.com | REF-2682