Repository: Textualize/rich

Issue:
[BUG] rich.traceback: no lexer for filename X found
**Describe the bug**

The rich.traceback doesn't know how to render tracebacks originating from inside jinja2 templates.
The issue is twofold: (1) rich doesn't recognize the `.yaml.j2` extension as `jinja2+yaml`,  and (2) the fallback isn't to print the file contents without highlighting but instead to **simply not print it at all**.
As such this bug likely also affects other languages to compile to python bytecode, such as [dg](http://pyos.github.io/dg/), [Hylang](https://docs.hylang.org/en/stable/) and [hissp/hebigo](https://github.com/gilch/hissp).

Repro:

test.py:
```python
import jinja2, os
from rich.traceback import install
install()
def raiser():
    raise Exception
env = jinja2.Environment(
    loader = jinja2.FileSystemLoader([os.getcwd(), "/"], followlinks=True),
)
env.globals["raiser"] = raiser    
template = env.get_template("test.yaml.j2")
print(template.render())
```
test.yaml.j2:
```jinja2
foobar:
    something: {{ raiser() }}
    else: {{ 5 + 5 }}
```

Vanilla traceback:

```
Traceback (most recent call last):
  File "/home/pbsds/tmp/repro/test.py", line 13, in <module>
    print(template.render())
  File "/usr/lib/python3.10/site-packages/jinja2/environment.py", line 1291, in render
    self.environment.handle_exception()
  File "/usr/lib/python3.10/site-packages/jinja2/environment.py", line 925, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "/home/pbsds/tmp/repro/test.yaml.j2", line 2, in top-level template code
    something: {{ raiser() }}
  File "/home/pbsds/tmp/repro/test.py", line 4, in raiser
    raise Exception
Exception
```

rich.traceback:
```
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│                                                                                                  │
│ /home/pbsds/tmp/repro/test.py:15 in <module>                                                     │
│                                                                                                  │
│   12                                                                                             │
│   13 template = env.get_template("test.yaml.j2")                                                 │
│   14                                                                                             │
│ ❱ 15 print(template.render())                                                                    │
│   16                                                                                             │
│ /usr/lib/python3.10/site-packages/jinja2/environment.py:1291 in render                           │
│                                                                                                  │
│   1288 │   │   try:                                                                              │
│   1289 │   │   │   return concat(self.root_render_func(ctx))  # type: ignore                     │
│   1290 │   │   except Exception:                                                                 │
│ ❱ 1291 │   │   │   self.environment.handle_exception()                                           │
│   1292 │                                                                                         │
│   1293 │   async def render_async(self, *args: t.Any, **kwargs: t.Any) -> str:                   │
│   1294 │   │   """This works similar to :meth:`render` but returns a coroutine                   │
│                                                                                                  │
│ /usr/lib/python3.10/site-packages/jinja2/environment.py:925 in handle_exception                  │
│                                                                                                  │
│    922 │   │   """                                                                               │
│    923 │   │   from .debug import rewrite_traceback_stack                                        │
│    924 │   │                                                                                     │
│ ❱  925 │   │   raise rewrite_traceback_stack(source=source)                                      │
│    926 │                                                                                         │
│    927 │   def join_path(self, template: str, parent: str) -> str:                               │
│    928 │   │   """Join a template with the parent.  By default all the lookups are               │
│                                                                                                  │
│ /home/pbsds/tmp/repro/test.yaml.j2:2 in top-level template code                                  │
│                                                                                                  │
│ no lexer for filename 'test.yaml.j2' found                                                       │
│                                                                                                  │
│ /home/pbsds/tmp/repro/test.py:6 in raiser                                                        │
│                                                                                                  │
│    3 install()                                                                                   │
│    4                                                                                             │
│    5 def raiser():                                                                               │
│ ❱  6 │   raise Exception                                                                         │
│    7                                                                                             │
│    8 env = jinja2.Environment(                                                                   │
│    9 │   loader = jinja2.FileSystemLoader([os.getcwd(), "/"], followlinks=True),                 │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
```



**Platform**
<details>
<summary>Click to expand</summary>

What platform (Win/Linux/Mac) are you running on? What terminal software are you using?

Manjaro GNOME, python 3.10.2, lxterminal

I may ask you to copy and paste the output of the following commands. It may save some time if you do it now.

If you're using Rich in a terminal:

```
╭─────────────────────── <class 'rich.console.Console'> ───────────────────────╮
│ A high level console interface.                                              │
│                                                                              │
│ ╭──────────────────────────────────────────────────────────────────────────╮ │
│ │ <console width=80 ColorSystem.TRUECOLOR>                                 │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│     color_system = 'truecolor'                                               │
│         encoding = 'utf-8'                                                   │
│             file = <_io.TextIOWrapper name='<stdout>' mode='w'               │
│                    encoding='utf-8'>                                         │
│           height = 24                                                        │
│    is_alt_screen = False                                                     │
│ is_dumb_terminal = False                                                     │
│   is_interactive = True                                                      │
│       is_jupyter = False                                                     │
│      is_terminal = True                                                      │
│   legacy_windows = False                                                     │
│         no_color = False                                                     │
│          options = ConsoleOptions(                                           │
│                        size=ConsoleDimensions(width=80, height=24),          │
│                        legacy_windows=False,                                 │
│                        min_width=1,                                          │
│                        max_width=80,                                         │
│                        is_terminal=True,                                     │
│                        encoding='utf-8',                                     │
│                        max_height=24,                                        │
│                        justify=None,                                         │
│                        overflow=None,                                        │
│                        no_wrap=False,                                        │
│                        highlight=None,                                       │
│                        markup=None,                                          │
│                        height=None                                           │
│                    )                                                         │
│            quiet = False                                                     │
│           record = False                                                     │
│         safe_box = True                                                      │
│             size = ConsoleDimensions(width=80, height=24)                    │
│        soft_wrap = False                                                     │
│           stderr = False                                                     │
│            style = None                                                      │
│         tab_size = 8                                                         │
│            width = 80                                                        │
╰──────────────────────────────────────────────────────────────────────────────╯
rich==11.0.0
```

</details>



Discussion:

Resolving patch:
diff --git a/rich/traceback.py b/rich/traceback.py
--- a/rich/traceback.py
+++ b/rich/traceback.py
@@ -12,6 +12,7 @@
 from pygments.token import Comment, Keyword, Name, Number, Operator, String
 from pygments.token import Text as TextToken
 from pygments.token import Token
+from pygments.util import ClassNotFound
 
 from . import pretty
 from ._loop import loop_last
@@ -521,10 +522,10 @@ def _guess_lexer(cls, filename: str, code: str) -> str:
             first_line = code[:new_line_index] if new_line_index != -1 else code
             if first_line.startswith("#!") and "python" in first_line.lower():
                 return "python"
-        lexer_name = (
-            cls.LEXERS.get(ext) or guess_lexer_for_filename(filename, code).name
-        )
-        return lexer_name
+        try:
+            return cls.LEXERS.get(ext) or guess_lexer_for_filename(filename, code).name
+        except ClassNotFound:
+            return "text"
 
     @group()
     def _render_stack(self, stack: Stack) -> RenderResult:


Test patch:
diff --git a/tests/test_traceback.py b/tests/test_traceback.py
--- a/tests/test_traceback.py
+++ b/tests/test_traceback.py
@@ -237,6 +237,16 @@ def test_guess_lexer():
     assert Traceback._guess_lexer("foo", "foo\nbnar") == "text"
 
 
+def test_guess_lexer_yaml_j2():
+    # https://github.com/Textualize/rich/issues/2018
+    code = """\
+foobar:
+    something: {{ raiser() }}
+    else: {{ 5 + 5 }}
+    """
+    assert Traceback._guess_lexer("test.yaml.j2", code) == "text"
+
+
 def test_recursive():
     def foo(n):
         return bar(n)