Repository: xonsh/xonsh

Issue:
f-string with env vars raises syntxc error in 0.9.23 under Python 3.9
f-strings with env vars in expressions give an error. When you type into the repl

    f"hallo {$PATH}" 

you get an error:

_SyntaxError: <xonsh-code>:1:0: f-string: invalid syntax_

### xonfig

<details>

```
+------------------+-----------------+
| xonsh            | 0.9.23          |
| Python           | 3.9.0           |
| PLY              | 3.11            |
| have readline    | True            |
| prompt toolkit   | None            |
| shell type       | prompt_toolkit  |
| pygments         | None            |
| on posix         | True            |
| on linux         | False           |
| on darwin        | True            |
| on windows       | False           |
| on cygwin        | False           |
| on msys2         | False           |
| is superuser     | False           |
| default encoding | utf-8           |
| xonsh encoding   | utf-8           |
| encoding errors  | surrogateescape |
| on jupyter       | False           |
| jupyter kernel   | None            |
+------------------+-----------------+

```

</details>



Discussion:
Interesting!

For me, both lines give a Syntax Error...

Any other way to debug this?
hmmm very strange, this works for me...
I can repeat. The key is:
> | Python           | 3.9.0           |

```bash
docker run --rm -it python:3.9-slim /bin/bash -c "pip install xonsh && xonsh"
$XONSH_SHOW_TRACEBACK = $XONSH_DEBUG = 1
f"hallo {$PATH}" 
```
```
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/xonsh/ptk_shell/shell.py", line 238, in _push
    code = self.execer.compile(src, mode="single", glbs=self.ctx, locs=None)
  File "/usr/local/lib/python3.9/site-packages/xonsh/execer.py", line 135, in compile
    tree = self.parse(input, ctx, mode=mode, filename=filename, transform=transform)
  File "/usr/local/lib/python3.9/site-packages/xonsh/execer.py", line 95, in parse
    tree, input = self._parse_ctx_free(input, mode=mode, filename=filename)
  File "/usr/local/lib/python3.9/site-packages/xonsh/execer.py", line 238, in _parse_ctx_free
    raise original_error from None
  File "/usr/local/lib/python3.9/site-packages/xonsh/execer.py", line 219, in _parse_ctx_free
    tree = self.parser.parse(
  File "/usr/local/lib/python3.9/site-packages/xonsh/parsers/base.py", line 499, in parse
    self._parse_error(self._error[0], self._error[1])
  File "/usr/local/lib/python3.9/site-packages/xonsh/parsers/base.py", line 639, in _parse_error
    raise err
  File "<string>", line None
SyntaxError: <xonsh-code>:1:0: f-string: invalid syntax (<unknown>, line 1)
f"hallo {$PATH}"
^
```
@scopatz  I think you need random choice not only for the shell type but for the python version too ;)
> @scopatz I think you need random choice not only for the shell type but for the python version too ;)

haha :laughing: 

Yeah this might be a 3.9 issue
Yes, I had xonsh running under 3.9.0 on that machine! (Had forgotten to pin the old Python version in Homebrew, so it got silently upgraded...)
Python 3.9 enables new parser by default. Can you try setting `PYTHONOLDPARSER=1` as environment variable to see if it helps?
I have had downgraded to Python 3.8.

So to test this I  needed to installed Python3.9. separately. Then I created a new venv with it in which I installed xonsh. However I cannot reproduce the issue anymore!

Now f-strings in xonsh 0.9.23 under Python 3.9 behave correctly. (Maybe because there _is_ a Python 3.8 still on the system?)
What does `xonfig` say in the xonsh session where it works?

Resolving patch:
diff --git a/xonsh/parsers/fstring_adaptor.py b/xonsh/parsers/fstring_adaptor.py
--- a/xonsh/parsers/fstring_adaptor.py
+++ b/xonsh/parsers/fstring_adaptor.py
@@ -67,7 +67,7 @@ def _patch_special_syntax(self):
                 # expression, e.g. "($HOME)" for f"{$HOME}" string.
                 if e.text is None or e.text[0] != "(":
                     raise
-                error_expr = e.text[1:-1]
+                error_expr = e.text.strip()[1:-1]
                 epos = template.find(error_expr)
                 if epos < 0:
                     raise


Test patch: