solara icon indicating copy to clipboard operation
solara copied to clipboard

__future__ annotations import and dataclass in multipage projects gives AttributeError

Open langestefan opened this issue 1 year ago • 1 comments

This is #208, but the issue still appears in multi-page projects.

I am on the latest version 1.25.1.

log
(project-name-py3.12) vscode ➜ /workspaces/pvcast-frontend (solara) $ solara run test
Solara server is starting at http://localhost:8765
Traceback (most recent call last):
  File "/workspaces/pvcast-frontend/.venv/bin/solara", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/solara/__main__.py", line 706, in main
    cli()
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/click/core.py", line 1157, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/rich_click/rich_command.py", line 126, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/click/core.py", line 1688, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/click/core.py", line 1434, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/click/core.py", line 783, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/solara/__main__.py", line 428, in run
    start_server()
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/solara/__main__.py", line 400, in start_server
    server.run()
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/uvicorn/server.py", line 62, in run
    return asyncio.run(self.serve(sockets=sockets))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 684, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/uvicorn/server.py", line 69, in serve
    config.load()
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/uvicorn/config.py", line 458, in load
    self.loaded_app = import_from_string(self.app)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/uvicorn/importer.py", line 21, in import_from_string
    module = importlib.import_module(module_str)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/importlib/__init__.py", line 90, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 994, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/solara/server/starlette.py", line 47, in <module>
    from . import app as appmod
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/solara/server/app.py", line 407, in <module>
    apps["__default__"] = AppScript(os.environ.get("SOLARA_APP", "solara.website.pages:Page"))
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/solara/server/app.py", line 69, in __init__
    app = self._execute()
          ^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/solara/server/app.py", line 97, in _execute
    routes = solara.generate_routes_directory(self.path)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/solara/autorouting.py", line 475, in generate_routes_directory
    route = _generate_route_path(subpath, layout=layout, first=first, has_index=has_index)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/solara/autorouting.py", line 507, in _generate_route_path
    module = source_to_module(subpath, initial_namespace=initial_namespace)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/pvcast-frontend/.venv/lib/python3.12/site-packages/solara/autorouting.py", line 37, in source_to_module
    exec(ast, mod.__dict__)
  File "/workspaces/pvcast-frontend/test/sol.py", line 9, in <module>
    @dataclass(frozen=True)
     ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/dataclasses.py", line 1256, in wrap
    return _process_class(cls, init, repr, eq, order, unsafe_hash,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/dataclasses.py", line 983, in _process_class
    and _is_type(type, cls, dataclasses, dataclasses.KW_ONLY,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/dataclasses.py", line 749, in _is_type
    ns = sys.modules.get(cls.__module__).__dict__
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute '__dict__'. Did you mean: '__dir__'?

How to reproduce:

  1. Create a folder to hold your pages, for example test
  2. Create the file test/sol.py:
from __future__ import annotations
from typing import Optional

from dataclasses import dataclass, field
import solara


@dataclass(frozen=True)
class FilterItem:
    name: str
    min: Optional[float] = field(default=None)
    max: Optional[float] = field(default=None)


@solara.component
def Page():
    solara.Markdown("## Foobar")
  1. Run solara run test

langestefan avatar Jan 30 '24 11:01 langestefan

I am not sure we can fix this (but will keep this open). The workaround would be to run as a package. e.g.

solara run mypackage.pages

maartenbreddels avatar Feb 28 '24 10:02 maartenbreddels