Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TextArea should handle missing tree-sitter-languages binaries #4045

Closed
tconbeer opened this issue Jan 18, 2024 · 2 comments · Fixed by #4046
Closed

TextArea should handle missing tree-sitter-languages binaries #4045

tconbeer opened this issue Jan 18, 2024 · 2 comments · Fixed by #4046

Comments

@tconbeer
Copy link
Contributor

tconbeer commented Jan 18, 2024

I'm upstreaming tconbeer/harlequin#420 (ultimately from a Harlequin user).

When installed with the syntax extra, the TextArea assumes that all of the binaries for the "built-in" languages for tree-sitter will be present. However, this may not be the case; for example (in the lijnked issue), Conda (micromamba) seems to struggle with installing the language binaries, and they may be missing on some platforms.

In that case, initializing a TextArea with a built-in language name will raise an OSError, which is not handled by the widget. I think it would be better to handle this error and re-raise as a SyntaxAwareDocumentError, so the TextArea degrades instead of crashes.

I'll be opening a PR with a simple fix for this shortly.

Full trace from the linked issue:

╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /home/moritz/micromamba/envs/harlequin-issue/lib/python3.11/site-packages/textual/widget.py:3386 │
│ in _on_compose                                                                                   │
│                                                                                                  │
│   3383 │                                                                                         │
│   3384 │   async def _on_compose(self) -> None:                                                  │
│   3385 │   │   try:                                                                              │
│ ❱ 3386 │   │   │   widgets = [*self._nodes, *compose(self)]                                      │
│   3387 │   │   except TypeError as error:                                                        │
│   3388 │   │   │   raise TypeError(                                                              │
│   3389 │   │   │   │   f"{self!r} compose() method returned an invalid result; {error}"          │
│                                                                                                  │
│ /home/moritz/micromamba/envs/harlequin-issue/lib/python3.11/site-packages/textual_textarea/texta │
│ rea.py:950 in compose                                                                            │
│                                                                                                  │
│    947 │                                                                                         │
│    948 │   def compose(self) -> ComposeResult:                                                   │
│    949 │   │   with TextContainer():                                                             │
│ ❱  950 │   │   │   yield TextInput(language=self._language)                                      │
│    951 │   │   │   yield CompletionList()                                                        │
│    952 │   │   with FooterContainer():                                                           │
│    953 │   │   │   yield Label("", id="validation_label")                                        │
│                                                                                                  │
│ /home/moritz/micromamba/envs/harlequin-issue/lib/python3.11/site-packages/textual_textarea/texta │
│ rea.py:191 in __init__                                                                           │
│                                                                                                  │
│    188 │   │   classes: str | None = None,                                                       │
│    189 │   │   disabled: bool = False,                                                           │
│    190 │   ) -> None:                                                                            │
│ ❱  191 │   │   super().__init__(                                                                 │
│    192 │   │   │   text,                                                                         │
│    193 │   │   │   language=language,                                                            │
│    194 │   │   │   theme=theme,                                                                  │
│                                                                                                  │
│ /home/moritz/micromamba/envs/harlequin-issue/lib/python3.11/site-packages/textual/widgets/_text_ │
│ area.py:339 in __init__                                                                          │
│                                                                                                  │
│    336 │   │   reactive is set as a string, the watcher will update this attribute to the        │
│    337 │   │   corresponding `TextAreaTheme` object."""                                          │
│    338 │   │                                                                                     │
│ ❱  339 │   │   self.language = language                                                          │
│    340 │   │                                                                                     │
│    341 │   │   self.theme = theme                                                                │
│    342                                                                                           │
│                                                                                                  │
│ /home/moritz/micromamba/envs/harlequin-issue/lib/python3.11/site-packages/textual/widgets/_text_ │
│ area.py:479 in _watch_language                                                                   │
│                                                                                                  │
│    476 │   │   │   │   f"then switch to it by setting the `TextArea.language` attribute."        │
│    477 │   │   │   )                                                                             │
│    478 │   │                                                                                     │
│ ❱  479 │   │   self._set_document(                                                               │
│    480 │   │   │   self.document.text if self.document is not None else self._initial_text,      │
│    481 │   │   │   language,                                                                     │
│    482 │   │   )                                                                                 │
│                                                                                                  │
│ /home/moritz/micromamba/envs/harlequin-issue/lib/python3.11/site-packages/textual/widgets/_text_ │
│ area.py:637 in _set_document                                                                     │
│                                                                                                  │
│    634 │   │   │   │   highlight_query = self._get_builtin_highlight_query(language)             │
│    635 │   │   │   document: DocumentBase                                                        │
│    636 │   │   │   try:                                                                          │
│ ❱  637 │   │   │   │   document = SyntaxAwareDocument(text, document_language)                   │
│    638 │   │   │   except SyntaxAwareDocumentError:                                              │
│    639 │   │   │   │   document = Document(text)                                                 │
│    640 │   │   │   │   log.warning(                                                              │
│                                                                                                  │
│ /home/moritz/micromamba/envs/harlequin-issue/lib/python3.11/site-packages/textual/document/_synt │
│ ax_aware_document.py:61 in __init__                                                              │
│                                                                                                  │
│    58 │   │   if isinstance(language, str):                                                      │
│    59 │   │   │   if language not in BUILTIN_LANGUAGES:                                          │
│    60 │   │   │   │   raise SyntaxAwareDocumentError(f"Invalid language {language!r}")           │
│ ❱  61 │   │   │   self.language = get_language(language)                                         │
│    62 │   │   │   self._parser = get_parser(language)                                            │
│    63 │   │   else:                                                                              │
│    64 │   │   │   self.language = language                                                       │
│                                                                                                  │
│ in tree_sitter_languages.core.get_language:14                                                    │
│                                                                                                  │
│ /home/moritz/micromamba/envs/harlequin-issue/lib/python3.11/site-packages/tree_sitter/__init__.p │
│ y:131 in __init__                                                                                │
│                                                                                                  │
│   128 │   │   at the given path.                                                                 │
│   129 │   │   """                                                                                │
│   130 │   │   self.name = name                                                                   │
│ ❱ 131 │   │   self.lib = cdll.LoadLibrary(library_path)                                          │
│   132 │   │   language_function: Callable[[], c_void_p] = getattr(self.lib, "tree_sitter_%s" %   │
│   133 │   │   language_function.restype = c_void_p                                               │
│   134 │   │   self.language_id: c_void_p = language_function()                                   │
│                                                                                                  │
│ /home/moritz/micromamba/envs/harlequin-issue/lib/python3.11/ctypes/__init__.py:454 in            │
│ LoadLibrary                                                                                      │
│                                                                                                  │
│   451 │   │   return getattr(self, name)                                                         │
│   452 │                                                                                          │
│   453 │   def LoadLibrary(self, name):                                                           │
│ ❱ 454 │   │   return self._dlltype(name)                                                         │
│   455 │                                                                                          │
│   456 │   __class_getitem__ = classmethod(_types.GenericAlias)                                   │
│   457                                                                                            │
│                                                                                                  │
│ /home/moritz/micromamba/envs/harlequin-issue/lib/python3.11/ctypes/__init__.py:376 in __init__   │
│                                                                                                  │
│   373 │   │   self._FuncPtr = _FuncPtr                                                           │
│   374 │   │                                                                                      │
│   375 │   │   if handle is None:                                                                 │
│ ❱ 376 │   │   │   self._handle = _dlopen(self._name, mode)                                       │
│   377 │   │   else:                                                                              │
│   378 │   │   │   self._handle = handle                                                          │
│   379                                                                                            │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
Copy link

Thank you for your issue. Give us a little time to review it.

PS. You might want to check the FAQ if you haven't done so already.

This is an automated reply, generated by FAQtory

Copy link

Don't forget to star the repository!

Follow @textualizeio for Textual updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant