Merge branch 'main' into fix_callias_double_open

This commit is contained in:
Andy Kipp 2024-12-16 16:28:30 +06:00 committed by GitHub
commit 1850e14061
Failed to generate hash of commit
43 changed files with 774 additions and 212 deletions

View file

@ -64,7 +64,7 @@
- Gilbert.Forsyth@capitalone.com
- gforsyth@gwu.edu
- gil@forsyth.dev
num_commits: 665
num_commits: 680
first_commit: 2015-10-19 16:04:32
github: gforsyth
- name: Morten Enemark Lund
@ -1136,7 +1136,7 @@
github: marciomazza
- name: Noortheen Raja
email: jnoortheen@gmail.com
num_commits: 237
num_commits: 239
first_commit: 2020-03-15 10:13:56
github: jnoortheen
- name: Samuel Lotz
@ -1283,7 +1283,7 @@
first_commit: 2021-02-08 10:50:51
- name: Evgeny
email: eugenesvk@users.noreply.github.com
num_commits: 11
num_commits: 12
first_commit: 2021-02-22 09:32:34
- name: Adam Schwalm
email: adamschwalm@gmail.com
@ -1301,7 +1301,7 @@
email: 46109467+yaxollum@users.noreply.github.com
alternate_emails:
- yaxollum@gmail.com
num_commits: 34
num_commits: 36
first_commit: 2021-06-11 14:11:19
- name: Walter A. Boring IV
email: waboring@hemna.com
@ -1431,7 +1431,7 @@
first_commit: 2021-11-18 18:42:29
- name: doronz88
email: doron88@gmail.com
num_commits: 6
num_commits: 7
first_commit: 2022-04-27 12:41:13
- name: Stefano Rivera
email: github@rivera.za.net
@ -1465,7 +1465,7 @@
first_commit: 2022-06-27 22:21:34
- name: pre-commit-ci[bot]
email: 66853113+pre-commit-ci[bot]@users.noreply.github.com
num_commits: 66
num_commits: 78
first_commit: 2022-07-11 14:26:34
- name: jgart
email: 47760695+jgarte@users.noreply.github.com
@ -1571,7 +1571,7 @@
first_commit: 2024-01-15 05:25:23
- name: JamesParrott
email: 80779630+JamesParrott@users.noreply.github.com
num_commits: 1
num_commits: 2
first_commit: 2024-01-16 08:56:07
- name: Airat Makhmutov
email: 108220148+rautyrauty@users.noreply.github.com
@ -1613,3 +1613,31 @@
email: kulkarniniraj14@gmail.com
num_commits: 1
first_commit: 2024-07-04 04:37:55
- name: Aidan Courtney
email: aidanfc97@gmail.com
num_commits: 1
first_commit: 2024-07-27 11:33:35
- name: Max Nordlund
email: max.nordlund@gmail.com
num_commits: 1
first_commit: 2024-10-30 09:11:04
- name: Shawn Wallace
email: yungwallace@live.com
num_commits: 1
first_commit: 2024-10-31 05:33:45
- name: Faidon Liambotis
email: paravoid@debian.org
num_commits: 1
first_commit: 2024-09-17 06:47:59
- name: Jueun Lee
email: seirios0107@gmail.com
num_commits: 1
first_commit: 2024-11-18 18:04:24
- name: Simon Billinge
email: sbillinge@users.noreply.github.com
num_commits: 1
first_commit: 2024-12-08 03:28:31
- name: Bala
email: kumaran.4353@gmail.com
num_commits: 1
first_commit: 2024-12-02 07:01:09

View file

@ -22,6 +22,7 @@ jobs:
- "3.10"
- "3.11"
- "3.12"
- "3.13"
steps:
- uses: actions/checkout@v4
- name: setup-python

View file

@ -38,7 +38,7 @@ jobs:
- "3.10"
- "3.11"
- "3.12"
# - "3.13-dev"
- "3.13"
name: Test Python ${{ matrix.python-version }} ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
@ -76,11 +76,4 @@ jobs:
run: |
python -m pip install -e . --no-deps
python -m xonsh run-tests.xsh test --report-coverage -- --timeout=240
- name: Upload coverage to Codecov
if: ${{ startsWith(matrix.python-version, env.DEFAULT_PYTHON_VERSION) }}
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
verbose: true
flags: ${{ matrix.os }}

View file

@ -36,8 +36,8 @@ anki-code <anki-code@users.noreply.github.com> a <anki-code>
anki-code <anki-code@users.noreply.github.com> a <aaa@aaa.aaa>
anki-code <anki-code@users.noreply.github.com> a <1@1.1>
BlahGeek <i@BlahGeek.com>
Daniel Shimon <daniel.shimon22@gmail.com>
pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Daniel Shimon <daniel.shimon22@gmail.com>
Gyuri Horak <dyuri@horak.hu>
Jean-Benoist Leger <jb@leger.tf> Jean-Benoist Leger <jbleger@gertrude>
Jean-Benoist Leger <jb@leger.tf> Jean-Benoist Leger <jbleger@hds.utc.fr>
@ -47,9 +47,9 @@ Leonardo Santagada <santagada@gmail.com>
Burak Yiğit Kaya <ben@byk.im> Burak Yigit Kaya <ben@byk.im>
Matthias Bussonnier <bussonniermatthias@gmail.com>
Aaron Griffin <aig787@gmail.com>
Peter Ye <46109467+yaxollum@users.noreply.github.com> Peter Ye <yaxollum@gmail.com>
Rob Brewer <rwb123@gmail.com> Robert W. Brewer <rwb123@gmail.com>
virus <virusbb001a@gmail.com>
Peter Ye <46109467+yaxollum@users.noreply.github.com> Peter Ye <yaxollum@gmail.com>
Sagar Tewari <sagartewari01@gmail.com> Sagar Tewari <sagartewariym@yahoo.com>
Gordon Ball <gordon@chronitis.net>
Eadaen1 <eadaen@protonmail.com>
@ -95,6 +95,7 @@ Alessio Bogon <youtux@gmail.com> Alessio Bogon <youtux@users.noreply.github.com>
Yohei Tamura <tamuhey@gmail.com>
Maximilian Köhl <mail@koehlma.de>
Alexander Sosedkin <monk@unboiled.info>
doronz88 <doron88@gmail.com>
Cody Scott <cody.j.b.scott@gmail.com>
Jake Hedman <jake@hedman.email>
traverseda <traverse.da@gmail.com>
@ -107,7 +108,6 @@ Jared Crawford <jmcrawford45@gmail.com>
Mike Crowe <drmikecrowe@gmail.com> drmikecrowe <drmikecrowe@gmail.com>
Vasilis Gerakaris <vasilis.gerakaris@navarino.gr> Vasilis Gerakaris <vgerak@gmail.com>
Angus Hollands <goosey15@gmail.com>
doronz88 <doron88@gmail.com>
JuanPablo <jpabloaj@gmail.com>
Ollie Terrance <ollie.terrance@live.co.uk>
Marcel Bollmann <bollmann@linguistics.rub.de>
@ -214,6 +214,7 @@ cmidkiff87 <39914727+cmidkiff87@users.noreply.github.com>
jbw3 <jbw3@users.noreply.github.com>
Naveen <172697+naveensrinivasan@users.noreply.github.com>
Blake Ramsdell <blaker@gmail.com>
JamesParrott <80779630+JamesParrott@users.noreply.github.com>
jyn <github@jyn.dev>
Dan Allan <dallan@bnl.gov>
Ned Letcher <nletcher@gmail.com>
@ -345,7 +346,6 @@ Wilfried Pollan <gitwipo@users.noreply.github.com>
Jacqueline Leykam <me@jacqueline.id.au>
Joshix-1 <57299889+Joshix-1@users.noreply.github.com>
Nathan Monfils <nathanmonfils@gmail.com>
JamesParrott <80779630+JamesParrott@users.noreply.github.com>
Airat Makhmutov <108220148+rautyrauty@users.noreply.github.com>
Matthieu LAURENT <matthieu.laurent69@protonmail.com>
Daniel Saunders <dsaunders410@gmail.com>
@ -355,5 +355,12 @@ amacfie-tc <91503417+amacfie-tc@users.noreply.github.com>
lunrenyi <87307989+lunrenyi@users.noreply.github.com>
Spencer Bliven <spencer.bliven@gmail.com>
Niraj Kulkarni <kulkarniniraj14@gmail.com>
Aidan Courtney <aidanfc97@gmail.com>
Max Nordlund <max.nordlund@gmail.com>
Shawn Wallace <yungwallace@live.com>
Faidon Liambotis <paravoid@debian.org>
Jueun Lee <seirios0107@gmail.com>
Simon Billinge <sbillinge@users.noreply.github.com>
Bala <kumaran.4353@gmail.com>
goodboy <tgoodlet@users.noreply.github.com>
Atsushi Morimoto <atsushi.morimoto@dena.com>

View file

@ -1,6 +1,6 @@
default_language_version:
# force all unspecified python hooks to run python3
python: python3.10
python: python3.13
#ci:
# autofix_prs: false
@ -8,7 +8,7 @@ default_language_version:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: 'v0.5.6'
rev: 'v0.8.2'
hooks:
- id: ruff
args: [., --fix, --exit-non-zero-on-fix]
@ -18,14 +18,14 @@ repos:
pass_filenames: false
- repo: https://github.com/pre-commit/mirrors-mypy
rev: 'v1.11.1' # Use the sha / tag you want to point at
rev: 'v1.13.0' # Use the sha / tag you want to point at
hooks:
- id: mypy
pass_filenames: false
additional_dependencies:
- types-ujson
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
exclude: |

View file

@ -14,8 +14,8 @@ Authors are sorted by number of commits.
* Bob Hyman
* anki-code
* BlahGeek
* Daniel Shimon
* pre-commit-ci[bot]
* Daniel Shimon
* Gyuri Horak
* Jean-Benoist Leger
* christopher
@ -24,9 +24,9 @@ Authors are sorted by number of commits.
* Burak Yiğit Kaya
* Matthias Bussonnier
* Aaron Griffin
* Peter Ye
* Rob Brewer
* virus
* Peter Ye
* Sagar Tewari
* Gordon Ball
* Eadaen1
@ -70,6 +70,7 @@ Authors are sorted by number of commits.
* Yohei Tamura
* Maximilian Köhl
* Alexander Sosedkin
* doronz88
* Cody Scott
* Jake Hedman
* traverseda
@ -82,7 +83,6 @@ Authors are sorted by number of commits.
* Mike Crowe
* Vasilis Gerakaris
* Angus Hollands
* doronz88
* JuanPablo
* Ollie Terrance
* Marcel Bollmann
@ -189,6 +189,7 @@ Authors are sorted by number of commits.
* jbw3
* Naveen
* Blake Ramsdell
* JamesParrott
* jyn
* Dan Allan
* Ned Letcher
@ -320,7 +321,6 @@ Authors are sorted by number of commits.
* Jacqueline Leykam
* Joshix-1
* Nathan Monfils
* JamesParrott
* Airat Makhmutov
* Matthieu LAURENT
* Daniel Saunders
@ -330,5 +330,12 @@ Authors are sorted by number of commits.
* lunrenyi
* Spencer Bliven
* Niraj Kulkarni
* Aidan Courtney
* Max Nordlund
* Shawn Wallace
* Faidon Liambotis
* Jueun Lee
* Simon Billinge
* Bala
* goodboy
* Atsushi Morimoto

View file

@ -4,6 +4,88 @@ Xonsh Change Log
.. current developments
v0.19.0
====================
**Added:**
* env: Added ``$XONSH_SUPPRESS_WELCOME`` variable to suppress the welcome message.
**Changed:**
* replaced `case_insensitive_dictionary` dependency with local
`CaseInsensitiveDict` class
**Fixed:**
* parsers: fix deprecation warnings triggered on python3.13
* Fix DeprecationWarning while initializing Expression
**Authors:**
* Gil Forsyth
* pre-commit-ci[bot]
* Evgeny
* doronz88
* JamesParrott
* Jueun Lee
* Simon Billinge
* Bala
v0.18.4
====================
**Changed:**
* Now SystemExit that invoked from callable alias follows to exiting from callable alias instead of exiting the entire shell.
**Fixed:**
* Built-in commands such as `xonfig -h` and `xontrib -h` no longer cause the shell to exit.
* Fixed incorrect quoting behaviour in `activate.xsh` for virtualenv version 20.26.6.
**Authors:**
* anki-code
* pre-commit-ci[bot]
* Peter Ye
* Max Nordlund
* Shawn Wallace
* Faidon Liambotis
v0.18.3
====================
**Added:**
* executables: Added ``locate_relative_path`` functionality to ``locate_file``.
**Changed:**
* ``$MULTILINE_PROMPT`` changed from ``'.'`` to ``' '`` (space)
to have an ability to copy the multiline functions from shell history without deleting the dot manually (#5624 #5634).
**Fixed:**
* Fixed ``$AUTO_CD`` regress after previous refactoring.
* Partial fix for "Bad file descriptor" in case of callable alias with execx invocation inside e.g. ExecAlias (#5645).
* completer: Fixed exception when in python-only completion context (#5632).
* Fixed exception "object has no attribute readlines" in case of redirect callable alias output.
**Authors:**
* Gil Forsyth
* Noortheen Raja
* anki-code
* pre-commit-ci[bot]
* Aidan Courtney
v0.18.2
====================
@ -2692,7 +2774,7 @@ v0.8.6
* Exits after concatenating normal files which have a finite size
* Continues to run for special files which do not have a size,
such as ``/dev/random``
* Is interruptable in all cases with Crtl-C.
* Is interruptable in all cases with Ctrl-C.
* Callable aliases were not properly raising a ``CalledProcessError`` when they
returned a non-zero exist status when ``$RAISE_SUBPROC_ERROR = True``. This has
been fixed.
@ -4434,7 +4516,7 @@ v0.5.0
* Fixed many PEP8 violations that had gone unnoticed
* Fix failure to detect an Anaconda python distribution if the python was install from the conda-forge channel.
* current_branch will try and locate the vc binary once
* May now Crtl-C out of an infinite loop with a subprocess, such as
* May now Ctrl-C out of an infinite loop with a subprocess, such as
```while True: sleep 1``.
* Fix for stdin redirects.
* Backgrounding works with ``$XONSH_STORE_STDOUT``

View file

@ -131,7 +131,8 @@ The xonsh shell is developed by a community of volunteers. There are a few ways
- Solve a `popular issue <https://github.com/xonsh/xonsh/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc>`_ or `high priority issue <https://github.com/xonsh/xonsh/issues?q=is%3Aopen+is%3Aissue+label%3Apriority-high+sort%3Areactions-%2B1-desc>`_ or a `good first issue <https://github.com/xonsh/xonsh/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+sort%3Areactions-%2B1-desc>`_. You can start with the `Developer guide <https://xon.sh/devguide.html>`_.
- Take an `idea <https://github.com/xonsh/xontrib-template/issues?q=is%3Aopen+is%3Aissue+label%3Aidea+sort%3Areactions-%2B1-desc>`_ and `create a new xontrib <https://github.com/xonsh/xontrib-template#why-use-this-template>`_.
- Become xonsh core by deep diving into xonsh and improve the threading and subprocess logic.
- Contribute to `xonsh API <https://github.com/xonsh/xonsh/tree/main/xonsh/api>`_.
- Become xonsh core developer by deep diving into xonsh internals. E.g. we feel a lack of Windows support.
- `Become a sponsor to xonsh <https://github.com/sponsors/xonsh>`_.
- `Write a tweet`_, post or an article to spread the good word about xonsh in the world.
- Give a star to xonsh repository and to `xontribs <https://github.com/topics/xontrib>`_ you like.

View file

@ -123,7 +123,7 @@
<div class="d-table-cell align-middle" >
<h2 style="color:white;"><b>XONSH</b> is a Python-powered shell</h2>
<br>
<p style="font-size: 20px; font-weight: 1;">Xonsh is a modern, full-featured and cross-platform shell. The language is a superset of Python 3.6+ with additional shell primitives that you are used to from Bash and IPython.
<p style="font-size: 20px; font-weight: 1;">Xonsh is a modern, full-featured and cross-platform python shell. The language is a superset of Python 3.6+ with additional shell primitives that you are used to from Bash and IPython.
It works on all major systems including Linux, OSX, and Windows. Xonsh is meant for the daily use of experts and novices.</p>
<a href="#" data-scroll-nav="3"><i class="icofont-download"></i> Install</a>
<a href="https://xon.sh/contents.html" target="_blank"><i class="icofont-ui-note"></i> Docs</a>
@ -139,7 +139,7 @@
<section id="about-area" data-scroll-index="1">
<div class="container text-center section-heading">
<h2>What is Xonsh?</h2>
<p>The xonsh shell lets you easily mix Python and shell commands in a powerful and simplified approach to the command line.</p>
<p>The xonsh as a python shell lets you easily mix Python and shell commands in a powerful and simplified approach to the command line.</p>
</div>
<div class="container" style="margin-top: 30px">

View file

@ -70,7 +70,7 @@ independent of the setting of the $AUTO_CONTINUE option.
``EOF``, ``exit``, and ``quit``
===================================
The commands ``EOF``, ``exit``, and ``quit`` all alias the same action, which is to
leave xonsh in a safe manner. Typing ``Crtl-d`` is the same as typing ``EOF`` and
leave xonsh in a safe manner. Typing ``Ctrl-d`` is the same as typing ``EOF`` and
pressing enter.

View file

@ -135,6 +135,17 @@ variable in Python. The same is true for deleting them too.
Become the Lord of the Files
>>> del $GOAL
>>> $NUM = "123"
>>> $EXT = $NUM + "456"
>>> $EXT
'123456'
>>> $FNUM = f"{$NUM}456" # Not working with Python 3.12+ (https://github.com/xonsh/xonsh/issues/5166).
>>> $FNUM = "{FILLME}456".format(FILLME=$NUM)
>>> $FNUM
'123456'
>>> "%s456" % $NUM
'123456'
Very nice.
.. note::
@ -142,6 +153,7 @@ Very nice.
To update ``os.environ`` when the xonsh environment changes set
:ref:`$UPDATE_OS_ENVIRON <update_os_environ>` to ``True``.
The Environment Itself ``${...}``
---------------------------------
@ -543,12 +555,12 @@ For example, the ``echo`` command has no interaction with the user and is captur
However, some tools have mixed behavior and can be run for either interactive or non-interactive tasks.
The best example of this is ``ssh``, which allows for remote terminal sessions and executing commands.
To handle different types of tasks, xonsh has the ``xthread`` and ``xunthread`` built-in aliases.
If you need to capture the output from an interactive tool that has a capturable mode use ``xthread`` to run:
To handle different types of tasks, xonsh has the ``@thread`` and ``@unthread`` built-in decorator aliases.
If you need to capture the output from an interactive tool that has a capturable mode use ``@thread`` to run:
.. code-block:: xonshcon
@ !(xthread ssh host -T 'echo remote')
@ !(@thread ssh host -T 'echo remote')
CommandPipeline(output="remote")

View file

@ -44,8 +44,6 @@ from being consumed.
Other languages like Lisp, Forth, and Julia also provide their macro systems.
Even restructured text (rST) directives could be considered macros.
Haskell and other more purely functional languages do not need macros (since
evaluation is lazy anyway), and so do not have them.
If these seem unfamiliar to the Python world, note that Jupyter and IPython
magics ``%`` and ``%%`` are macros!

View file

@ -41,7 +41,7 @@ initializes your personal run control file (usually at ``~/.xonshrc``). To invo
.. code-block:: xonshcon
>>> xonfig web
Web config started at 'http://localhost:8421'. Hit Crtl+C to stop.
Web config started at 'http://localhost:8421'. Hit Ctrl+C to stop.
127.0.0.1 - - [23/Aug/2020 15:04:39] "GET / HTTP/1.1" 200 -
This will open your default browser on a page served from a local server. You can exit the server by typing ``Ctrl+c`` at any time.

View file

@ -1,23 +0,0 @@
**Added:**
* <news item>
**Changed:**
* <news item>
**Deprecated:**
* <news item>
**Removed:**
* <news item>
**Fixed:**
* Partial fix for "Bad file descriptor" in case of callable alias with execx invocation inside e.g. ExecAlias (#5645).
**Security:**
* <news item>

View file

@ -1,23 +0,0 @@
**Added:**
* <news item>
**Changed:**
* <news item>
**Deprecated:**
* <news item>
**Removed:**
* <news item>
**Fixed:**
* completer: Fixed exception when in python-only completion context (#5632).
**Security:**
* <news item>

View file

@ -1,23 +0,0 @@
**Added:**
* <news item>
**Changed:**
* <news item>
**Deprecated:**
* <news item>
**Removed:**
* <news item>
**Fixed:**
* Fixed exception "object has no attribute readlines" in case of redirect callable alias output.
**Security:**
* <news item>

View file

@ -16,7 +16,7 @@
**Fixed:**
* Fixed ``$AUTO_CD`` regress after previous refactoring.
* Fixed non-int sys.exit codes raising ValueError.
**Security:**

View file

@ -1,23 +0,0 @@
**Added:**
* executables: Added ``locate_relative_path`` functionality to ``locate_file``.
**Changed:**
* <news item>
**Deprecated:**
* <news item>
**Removed:**
* <news item>
**Fixed:**
* <news item>
**Security:**
* <news item>

View file

@ -1,24 +0,0 @@
**Added:**
* <news item>
**Changed:**
* ``$MULTILINE_PROMPT`` changed from ``'.'`` to ``' '`` (space)
to have an ability to copy the multiline functions from shell history without deleting the dot manually (#5624 #5634).
**Deprecated:**
* <news item>
**Removed:**
* <news item>
**Fixed:**
* <news item>
**Security:**
* <news item>

View file

@ -15,9 +15,7 @@ authors = [{ name = "Anthony Scopatz" }, { email = "scopatz@gmail.com" }]
maintainers = [{ name = "Xonsh Community" }, { email = "xonsh@gil.forsyth.dev" }]
license = { text = "BSD 2-Clause License" }
requires-python = ">=3.9"
dependencies = [
"case-insensitive-dictionary; platform_system=='Windows'",
]
dependencies = []
[tool.setuptools.dynamic]
version = {attr = "xonsh.__version__"}
@ -137,7 +135,6 @@ doc = [
"psutil",
"pyzmq",
"matplotlib",
"doctr",
"tornado",
"runthis-sphinxext",
"livereload",
@ -204,6 +201,7 @@ ignore = [
"E402", # Module level import not at top of file
"E501", # line length
"E731", # Do not assign a lambda expression, use a def
"UP031", # Use format specifiers instead of percent format
]
select = [
"B", # https://beta.ruff.rs/docs/rules/#flake8-bugbear-b

View file

@ -10,6 +10,7 @@ from xonsh.parser import Parser
from xonsh.parsers.ast import AST, Call, Pass, With, is_const_str
from xonsh.parsers.fstring_adaptor import FStringAdaptor
from xonsh.pytest.tools import (
ON_WINDOWS,
VER_MAJOR_MINOR,
nodes_equal,
skip_if_pre_3_8,
@ -2652,7 +2653,14 @@ def test_echo_slash_question(check_xonsh_ast):
@pytest.mark.parametrize(
"case",
[
"[]",
pytest.param(
"[]",
marks=pytest.mark.xfail(
ON_WINDOWS,
reason="non-zero exit code being raised by brackets",
strict=True,
), # TODO: fix this on a windows machine
),
"[[]]",
"[a]",
"[a][b]",

View file

@ -8,7 +8,19 @@ import pytest
from xonsh.platform import ON_WINDOWS
from xonsh.procs.pipelines import CommandPipeline
from xonsh.pytest.tools import skip_if_on_unix, skip_if_on_windows
from xonsh.pytest.tools import (
VER_MAJOR_MINOR,
skip_if_on_unix,
skip_if_on_windows,
)
# TODO: track down which pipeline + spec test is hanging CI
# Skip entire test file for Linux on Python 3.12
pytestmark = pytest.mark.skipif(
not ON_WINDOWS and VER_MAJOR_MINOR == (3, 12),
reason="Backgrounded test is hanging on CI on 3.12 only",
allow_module_level=True,
)
@pytest.fixture(autouse=True)
@ -122,6 +134,7 @@ def test_casting(cmdline, result, xonsh_execer):
@skip_if_on_windows
@skip_if_on_unix
def test_background_pgid(xonsh_session, monkeypatch):
monkeypatch.setitem(xonsh_session.env, "XONSH_INTERACTIVE", True)
pipeline = xonsh_session.execer.eval("![echo hi &]")

View file

@ -17,9 +17,17 @@ from xonsh.procs.specs import (
cmds_to_specs,
run_subproc,
)
from xonsh.pytest.tools import skip_if_on_windows
from xonsh.pytest.tools import ON_WINDOWS, VER_MAJOR_MINOR, skip_if_on_windows
from xonsh.tools import XonshError
# TODO: track down which pipeline + spec test is hanging CI
# Skip entire test file for Linux on Python 3.12
pytestmark = pytest.mark.skipif(
not ON_WINDOWS and VER_MAJOR_MINOR == (3, 12),
reason="Backgrounded test is hanging on CI on 3.12 only",
allow_module_level=True,
)
def cmd_sig(sig):
return [

View file

@ -46,16 +46,6 @@ def check_token(xsh):
_cases = {
"ls": {
"ls -al": [
(Name.Builtin, "ls"),
],
},
"ls-bin": {
"/bin/ls -al": [
(Name.Builtin, "/bin/ls"),
],
},
"print": {
'print("hello")': [
(Name.Builtin, "print"),
@ -94,6 +84,69 @@ _cases = {
(Error, "non-existance-cmd"),
],
},
"nested": {
"print($(cd))": [
(Name.Builtin, "print"),
(Punctuation, "("),
(Keyword, "$"),
(Punctuation, "("),
(Name.Builtin, "cd"),
(Punctuation, ")"),
(Punctuation, ")"),
(Text.Whitespace, "\n"),
],
},
"subproc-args": {
"cd 192.168.0.1": [
(Text, "192.168.0.1"),
],
},
"backtick": {
r"echo g`.*\w+`": [
(String.Affix, "g"),
(String.Backtick, "`"),
(String.Regex, "."),
(String.Regex, "*"),
(String.Escape, r"\w"),
],
},
"macro": {
r"g!(42, *, 65)": [
(Name, "g"),
(Keyword, "!"),
(Punctuation, "("),
(Number.Integer, "42"),
],
r"bash -c ! export var=42; echo $var": [
(Name.Builtin, "bash"),
(Text, "-c"),
(Keyword, "!"),
(String, "export var=42; echo $var"),
],
},
}
_cases_no_win = {
"ls": {
"ls -al": [
(Name.Builtin, "ls"),
],
},
"ls-bin": {
"/bin/ls -al": [
(Name.Builtin, "/bin/ls"),
],
},
"print": {
'print("hello")': [
(Name.Builtin, "print"),
(Punctuation, "("),
(Literal.String.Double, '"'),
(Literal.String.Double, "hello"),
(Literal.String.Double, '"'),
(Punctuation, ")"),
(Text.Whitespace, "\n"),
]
},
"nested": {
'echo @("hello")': [
(Name.Builtin, "echo"),
@ -125,20 +178,6 @@ _cases = {
(Text.Whitespace, "\n"),
],
},
"subproc-args": {
"cd 192.168.0.1": [
(Text, "192.168.0.1"),
],
},
"backtick": {
r"echo g`.*\w+`": [
(String.Affix, "g"),
(String.Backtick, "`"),
(String.Regex, "."),
(String.Regex, "*"),
(String.Escape, r"\w"),
],
},
"macro": {
r"g!(42, *, 65)": [
(Name, "g"),
@ -167,12 +206,23 @@ def _convert_cases():
yield pytest.param(*item, id=f"{title}-{idx}")
def _convert_cases_no_win():
for title, input_dict in _cases_no_win.items():
for idx, item in enumerate(input_dict.items()):
yield pytest.param(*item, id=f"{title}-{idx}")
@pytest.mark.parametrize("inp, expected", list(_convert_cases()))
@skip_if_on_windows
def test_xonsh_lexer(inp, expected, check_token):
check_token(inp, expected)
@pytest.mark.parametrize("inp, expected", list(_convert_cases_no_win()))
@skip_if_on_windows
def test_xonsh_lexer_no_win(inp, expected, check_token):
check_token(inp, expected)
# can't seem to get thie test to import pyghooks and define on_lscolors_change handler like live code does.
# so we declare the event handler directly here.
@pytest.fixture

View file

@ -8,6 +8,7 @@ import pytest
from xonsh.commands_cache import (
SHELL_PREDICTOR_PARSER,
CaseInsensitiveDict,
CommandsCache,
_Commands,
executables_in,
@ -306,3 +307,77 @@ def test_executables_in(xession):
else:
result = set(executables_in(test_path))
assert expected == result
def test_caseinsdict_constructor():
actual = CaseInsensitiveDict({"key1": "val1", "Key2": "Val2"})
assert isinstance(actual, CaseInsensitiveDict)
assert actual["key1"] == "val1"
assert actual["Key2"] == "Val2"
def test_caseinsdict_getitem():
actual = CaseInsensitiveDict({"Key1": "Val1"})
assert actual["Key1"] == "Val1"
assert actual["key1"] == "Val1"
def test_caseinsdict_setitem():
actual = CaseInsensitiveDict({"Key1": "Val1"})
actual["Key1"] = "Val2"
assert actual["Key1"] == "Val2"
assert actual["key1"] == "Val2"
actual["key1"] = "Val3"
assert actual["Key1"] == "Val3"
assert actual["key1"] == "Val3"
def test_caseinsdict_delitem():
actual = CaseInsensitiveDict({"Key1": "Val1", "Key2": "Val2"})
del actual["Key1"]
assert actual == CaseInsensitiveDict({"Key2": "Val2"})
del actual["key2"]
assert actual == CaseInsensitiveDict({})
def test_caseinsdict_contains():
actual = CaseInsensitiveDict({"Key1": "Val1"})
assert actual.__contains__("Key1")
assert actual.__contains__("key1")
assert not actual.__contains__("key2")
def test_caseinsdict_get():
actual = CaseInsensitiveDict({"Key1": "Val1"})
assert actual.get("Key1") == "Val1"
assert actual.get("key1") == "Val1"
assert actual.get("key2", "no val") == "no val"
assert actual.get("key1", "no val") == "Val1"
def test_caseinsdict_update():
actual = CaseInsensitiveDict({"Key1": "Val1"})
actual.update({"Key2": "Val2"})
assert actual["key2"] == "Val2"
def test_caseinsdict_keys():
actual = CaseInsensitiveDict({"Key1": "Val1"})
assert next(actual.keys()) == "Key1"
def test_caseinsdict_items():
actual = CaseInsensitiveDict({"Key1": "Val1"})
assert next(actual.items()) == ("Key1", "Val1")
def test_caseinsdict_repr():
actual = CaseInsensitiveDict({"Key1": "Val1"})
assert actual.__repr__() == "CaseInsensitiveDict({'Key1': 'Val1'})"
def test_caseinsdict_copy():
initial = CaseInsensitiveDict({"Key1": "Val1"})
actual = initial.copy()
assert actual == initial
assert id(actual) != id(initial)

View file

@ -17,6 +17,7 @@ from xonsh.pytest.tools import (
ON_DARWIN,
ON_TRAVIS,
ON_WINDOWS,
VER_FULL,
skip_if_on_darwin,
skip_if_on_msys,
skip_if_on_unix,
@ -329,6 +330,22 @@ f
"hello\n",
0,
),
# test system exit in unthreadable alias (see #5689)
(
"""
from xonsh.tools import unthreadable
@unthreadable
def _f():
import sys
sys.exit(42)
aliases['f'] = _f
print(![f].returncode)
""",
"42\n",
0,
),
# test ambiguous globs
(
"""
@ -594,8 +611,9 @@ first
),
# testing alias stack: parallel threaded callable aliases.
# This breaks if the __ALIAS_STACK variables leak between threads.
(
"""
pytest.param(
(
"""
from time import sleep
aliases['a'] = lambda: print(1, end="") or sleep(0.2) or print(1, end="")
aliases['b'] = 'a'
@ -604,8 +622,14 @@ a | a
a | b | a
a | a | b | b
""",
"1" * 2 * 4,
0,
"1" * 2 * 4,
0,
),
# TODO: investigate errors on Python 3.13
marks=pytest.mark.skipif(
VER_FULL > (3, 12) and not ON_WINDOWS,
reason="broken pipes on Python 3.13 likely due to changes in threading behavior",
),
),
# test $SHLVL
(
@ -723,7 +747,7 @@ if not ON_WINDOWS:
@skip_if_no_xonsh
@pytest.mark.parametrize("case", ALL_PLATFORMS)
@pytest.mark.flaky(reruns=3, reruns_delay=2)
@pytest.mark.flaky(reruns=4, reruns_delay=2)
def test_script(case):
script, exp_out, exp_rtn = case
if ON_DARWIN:

View file

@ -2,12 +2,15 @@ import sys
from pathlib import Path
from subprocess import check_output
import pytest
from xonsh.pytest.tools import ON_WINDOWS
def test_xonsh_activator(tmp_path):
@pytest.mark.parametrize("dir_name", ["venv", "venv with space"])
def test_xonsh_activator(tmp_path, dir_name):
# Create virtualenv
venv_dir = tmp_path / "venv"
venv_dir = tmp_path / dir_name
assert b"XonshActivator" in check_output(
[sys.executable, "-m", "virtualenv", str(venv_dir)]
)
@ -35,7 +38,13 @@ def test_xonsh_activator(tmp_path):
# Activate
venv_python = check_output(
[sys.executable, "-m", "xonsh", "-c", f"source {activate_path}; which python"]
[
sys.executable,
"-m",
"xonsh",
"-c",
f"source r'{activate_path}'; which python",
]
).decode()
assert Path(venv_python).parent == bin_path
@ -46,7 +55,7 @@ def test_xonsh_activator(tmp_path):
"-m",
"xonsh",
"-c",
f"source {activate_path}; deactivate; "
f"source r'{activate_path}'; deactivate; "
"import shutil; shutil.which('python') or shutil.which('python3')",
]
).decode()

View file

@ -1 +1 @@
__version__ = "0.18.2"
__version__ = "0.19.0"

2
xonsh/api/README.md Normal file
View file

@ -0,0 +1,2 @@
Xonsh API was introduced to reduce boilerplate code in a solutions that based on xonsh.
We're very welcome to extend Xonsh API with shortcuts, code snippets and helpful functions.

View file

@ -354,7 +354,9 @@ class ArgParser(ap.ArgumentParser):
add_args(parser, func, allowed_params=args, doc=doc)
return parser
def _parse_known_args(self, arg_strings: list[str], namespace: ap.Namespace):
def _parse_known_args(
self, arg_strings: list[str], namespace: ap.Namespace, *args, **kwargs
):
arg_set = set(arg_strings)
if (
self.commands
@ -363,7 +365,7 @@ class ArgParser(ap.ArgumentParser):
and (set(self.commands.choices).isdisjoint(arg_set))
):
arg_strings = [self.default_command] + arg_strings
return super()._parse_known_args(arg_strings, namespace)
return super()._parse_known_args(arg_strings, namespace, *args, **kwargs)
def run_with_partial_args(func: tp.Callable, ns: dict[str, tp.Any]):
@ -543,6 +545,9 @@ class ArgparseCompleter:
if not act_res:
# it is not a option string: pass
break
if isinstance(act_res, list):
assert len(act_res) == 1
act_res = act_res[0]
# it is a valid option and advance
self.remaining_args = self.remaining_args[1:]
act, *_, value = act_res

View file

@ -23,8 +23,52 @@ from xonsh.procs.executables import (
is_executable_in_windows,
)
class CaseInsensitiveDict(dict[tp.Any, tp.Any]):
def __init__(self, *args, **kwargs):
super().__init__()
self._store = {}
self.update(*args, **kwargs)
def __setitem__(self, key, value):
# Store the key in lowercase but preserve the original case for display
self._store[key.casefold()] = key
super().__setitem__(key.casefold(), value)
def __getitem__(self, key):
return super().__getitem__(key.casefold())
def __delitem__(self, key):
del self._store[key.casefold()]
super().__delitem__(key.casefold())
def __contains__(self, key):
return key.casefold() in self._store
def get(self, key, default=None):
return super().get(key.casefold(), default)
def update(self, *args, **kwargs):
for k, v in dict(*args, **kwargs).items():
self[k] = v
def keys(self):
# Return the original keys with their original casing
return (self._store[k] for k in self._store)
def items(self):
return ((self._store[k], self[k]) for k in self._store)
def __repr__(self):
return f"{self.__class__.__name__}({dict(self.items())})"
def copy(self):
return CaseInsensitiveDict(self.items())
CacheDict: tp.Union[type[CaseInsensitiveDict], type[dict]]
if ON_WINDOWS:
from case_insensitive_dict import CaseInsensitiveDict as CacheDict
CacheDict = CaseInsensitiveDict
else:
CacheDict = dict

View file

@ -33,7 +33,7 @@ def complete_command(command: CommandContext):
kwargs = {}
if show_desc:
kwargs["description"] = "Alias" if is_alias else path
yield RichCompletion(s, append_space=True, **kwargs)
yield RichCompletion(s, append_space=True, **kwargs) # type: ignore
if xp.ON_WINDOWS:
for i in executables_in("."):
if i.startswith(cmd):

View file

@ -1627,6 +1627,10 @@ class PromptSetting(Xettings):
"For example, to have stderr appear on a red background, the "
'prefix & postfix pair would be "{BACKGROUND_RED}" & "{RESET}".',
)
XONSH_SUPPRESS_WELCOME = Var.with_default(
False,
"Suppresses the welcome message.",
)
class PromptHistorySetting(Xettings):

1
xonsh/lib/README.md Normal file
View file

@ -0,0 +1 @@
Xonsh library contains the code that independent to xonsh core or a code that is fork from another projects.

View file

@ -548,6 +548,7 @@ def main_xonsh(args):
ignore_sigtstp()
if (
env["XONSH_INTERACTIVE"]
and not env["XONSH_SUPPRESS_WELCOME"]
and sys.stdin.isatty() # In case the interactive mode is forced but no tty (input from pipe).
and not any(os.path.isfile(i) for i in env["XONSHRC"])
and not any(os.path.isdir(i) for i in env["XONSHRC_DIR"])
@ -605,7 +606,14 @@ def main_xonsh(args):
err_type, err, _ = exc_info
if err_type is SystemExit:
code = getattr(exc_info[1], "code", 0)
exit_code = int(code) if code is not None else 0
if code is None:
exit_code = 0
else:
exit_code = code
try:
exit_code = int(code)
except ValueError:
pass
XSH.exit = exit_code
else:
exit_code = 1

View file

@ -6,7 +6,9 @@ from xonsh.platform import PYTHON_VERSION_INFO
@lazyobject
def Parser():
if PYTHON_VERSION_INFO > (3, 10):
if PYTHON_VERSION_INFO >= (3, 13):
from xonsh.parsers.v313 import Parser as p
elif PYTHON_VERSION_INFO > (3, 10):
from xonsh.parsers.v310 import Parser as p
elif PYTHON_VERSION_INFO > (3, 9):
from xonsh.parsers.v39 import Parser as p

View file

@ -109,8 +109,10 @@ from ast import ( # noqa # pylint: disable=unused-import
walk,
withitem,
)
from typing import Optional
from xonsh.built_ins import XSH
from xonsh.platform import PYTHON_VERSION_INFO
from xonsh.tools import find_next_break, get_logical_line, subproc_toks
STATEMENTS = (
@ -139,8 +141,25 @@ STATEMENTS = (
)
def const_str(s: str, **kwargs):
return Constant(value=s, kind="str", **kwargs)
def const_str(
s: str,
lineno: Optional[int] = None,
col_offset: Optional[int] = None,
is_raw: bool = True,
):
if PYTHON_VERSION_INFO >= (3, 13):
# looks like this attribute is no longer needed to be set explicitly
constant = Constant(value=s, kind="str")
else:
constant = Constant(value=s, kind="str")
if is_raw:
# this attribute is not documented within the ast object
constant.is_raw = is_raw # type: ignore
if lineno is not None:
constant.lineno = lineno
if col_offset is not None:
constant.col_offset = col_offset
return constant
def is_const_str(node):

View file

@ -738,7 +738,9 @@ class BaseParser:
def p_eval_input(self, p):
"""eval_input : testlist newlines_opt"""
p1 = p[1]
p[0] = ast.Expression(body=p1, lineno=p1.lineno, col_offset=p1.col_offset)
p[0] = ast.Expression(body=p1)
p[0].lineno = p1.lineno
p[0].col_offset = p1.col_offset
def p_func_call(self, p):
"""func_call : LPAREN arglist_opt RPAREN"""
@ -2155,7 +2157,8 @@ class BaseParser:
| minus_tok term
"""
p1 = p[1]
op = self._term_binops[p1.value](lineno=p1.lineno, col_offset=p1.lexpos)
op = self._term_binops[p1.value]()
op.lineno, op.col_offset = p1.lineno, p1.lexpos
p[0] = [op, p[2]]
def p_term(self, p):
@ -2194,7 +2197,9 @@ class BaseParser:
f"operation {p1!r} not supported",
self.currloc(lineno=p.lineno, column=p.lexpos),
)
p[0] = [op(lineno=p1.lineno, col_offset=p1.lexpos), p[2]]
op_node = op()
op_node.lineno, op_node.col_offset = p1.lineno, p1.lexpos
p[0] = [op_node, p[2]]
_factor_ops = {"+": ast.UAdd, "-": ast.USub, "~": ast.Invert}
@ -3047,7 +3052,7 @@ class BaseParser:
else:
targ = ensure_has_elts(targs)
store_ctx(targ)
comp = ast.comprehension(target=targ, iter=it, ifs=[])
comp = ast.comprehension(target=targ, iter=it, ifs=[], is_async=0)
comps = [comp]
p0 = {"comps": comps}
if p5 is not None:

264
xonsh/parsers/v313.py Normal file
View file

@ -0,0 +1,264 @@
# type: ignore
# TODO: remove line above once mypy understands the match statement
"""Handles changes since PY313
handle
- import-alias requiring lineno
- match statement
"""
from ast import match_case
from ast import parse as pyparse
from xonsh.parsers import ast
from xonsh.parsers.ast import xonsh_call
from xonsh.parsers.base import (
RE_STRINGPREFIX,
del_ctx,
ensure_has_elts,
lopen_loc,
store_ctx,
)
from xonsh.parsers.fstring_adaptor import FStringAdaptor
from xonsh.parsers.v310 import Parser as ThreeTenParser
class Parser(ThreeTenParser):
def p_eval_input(self, p):
"""eval_input : testlist newlines_opt"""
p1 = p[1]
expression = ast.Expression(body=p1)
expression.lineno = p1.lineno
expression.col_offset = p1.col_offset
p[0] = expression
def p_pm_term(self, p):
"""
pm_term : plus_tok term
| minus_tok term
"""
p1 = p[1]
op = self._term_binops[p1.value]()
op.lineno = p1.lineno
op.col_offset = p1.lexpos
p[0] = [op, p[2]]
def p_atom_lbrace(self, p):
"""atom : lbrace_tok dictorsetmaker_opt RBRACE"""
p1, p2 = p[1], p[2]
p1, p1_tok = p1.value, p1
if p2 is None:
p0 = ast.Dict(
keys=[],
values=[],
lineno=self.lineno,
col_offset=self.col,
)
p0.ctx = ast.Load()
else:
p0 = p2
p0.lineno, p0.col_offset = p1_tok.lineno, p1_tok.lexpos
p[0] = p0
# case blocks
def p_case_block(self, p):
"""
case_block : case_tok patterns COLON suite
| case_tok patterns IF test COLON suite
"""
loc = self.get_line_cols(p, 1)
match list(p):
case [_, _, pattern, _, suite]:
p[0] = match_case(pattern=pattern, body=suite)
p[0].lineno = loc["lineno"]
p[0].end_lineno = loc["end_lineno"]
p[0].col_offset = loc["col_offset"]
p[0].end_col_offset = loc["end_col_offset"]
case [_, _, pattern, _, guard, _, suite]:
p[0] = match_case(pattern=pattern, body=suite, guard=guard)
p[0].lineno = loc["lineno"]
p[0].end_lineno = loc["end_lineno"]
p[0].col_offset = loc["col_offset"]
p[0].end_col_offset = loc["end_col_offset"]
case _:
raise AssertionError()
def p_string_literal(self, p):
"""string_literal : string_tok"""
p1 = p[1]
prefix = RE_STRINGPREFIX.match(p1.value).group().lower()
if "p" in prefix and "f" in prefix:
new_pref = prefix.replace("p", "")
value_without_p = new_pref + p1.value[len(prefix) :]
try:
s = pyparse(value_without_p).body[0].value
except SyntaxError:
s = None
if s is None:
try:
s = FStringAdaptor(
value_without_p, new_pref, filename=self.lexer.fname
).run()
except SyntaxError as e:
self._set_error(
str(e), self.currloc(lineno=p1.lineno, column=p1.lexpos)
)
s = ast.increment_lineno(s, p1.lineno - 1)
p[0] = xonsh_call(
"__xonsh__.path_literal", [s], lineno=p1.lineno, col=p1.lexpos
)
elif "p" in prefix:
value_without_p = prefix.replace("p", "") + p1.value[len(prefix) :]
s = ast.const_str(
s=ast.literal_eval(value_without_p),
lineno=p1.lineno,
col_offset=p1.lexpos,
)
p[0] = xonsh_call(
"__xonsh__.path_literal", [s], lineno=p1.lineno, col=p1.lexpos
)
elif "f" in prefix:
try:
s = pyparse(p1.value).body[0].value
except SyntaxError:
s = None
if s is None:
try:
s = FStringAdaptor(
p1.value, prefix, filename=self.lexer.fname
).run()
except SyntaxError as e:
self._set_error(
str(e), self.currloc(lineno=p1.lineno, column=p1.lexpos)
)
s = ast.increment_lineno(s, p1.lineno - 1)
if "r" in prefix:
s.is_raw = True
p[0] = s
else:
s = ast.literal_eval(p1.value)
is_bytes = "b" in prefix
is_raw = "r" in prefix
cls = ast.const_bytes if is_bytes else ast.const_str
p[0] = cls(s=s, lineno=p1.lineno, col_offset=p1.lexpos)
p[0].is_raw = is_raw
def p_atom_expr_await(self, p):
"""atom_expr : await_tok atom trailer_list_opt"""
p0 = self.apply_trailers(p[2], p[3])
p1 = p[1]
p0 = ast.Await(value=p0, lineno=p1.lineno, col_offset=p1.lexpos)
p0.ctx = ast.Load()
p[0] = p0
#
# For normal assignments, additional restrictions enforced
# by the interpreter
#
def p_del_stmt(self, p):
"""del_stmt : del_tok exprlist"""
p1 = p[1]
p2 = p[2]
for targ in p2:
del_ctx(targ)
p0 = ast.Delete(targets=p2, lineno=p1.lineno, col_offset=p1.lexpos)
p[0] = p0
#
# Dict or set maker
#
def p_dictorsetmaker_t6(self, p):
"""dictorsetmaker : test COLON test comma_item_list comma_opt"""
p1, p4 = p[1], p[4]
keys = [p1]
vals = [p[3]]
for k, v in zip(p4[::2], p4[1::2]):
keys.append(k)
vals.append(v)
lineno, col = lopen_loc(p1)
p[0] = ast.Dict(keys=keys, values=vals, lineno=lineno, col_offset=col)
p[0].ctx = ast.Load()
def p_dictorsetmaker_i4(self, p):
"""dictorsetmaker : item comma_item_list comma_opt"""
p1, p2 = p[1], p[2]
keys = [p1[0]]
vals = [p1[1]]
for k, v in zip(p2[::2], p2[1::2]):
keys.append(k)
vals.append(v)
lineno, col = lopen_loc(p1[0] or p1[1])
p[0] = ast.Dict(keys=keys, values=vals, lineno=lineno, col_offset=col)
p[0].ctx = ast.Load()
def p_dictorsetmaker_t4_dict(self, p):
"""dictorsetmaker : test COLON testlist"""
keys = [p[1]]
vals = self._list_or_elts_if_not_real_tuple(p[3])
lineno, col = lopen_loc(p[1])
p[0] = ast.Dict(keys=keys, values=vals, lineno=lineno, col_offset=col)
p[0].ctx = ast.Load()
def p_dictorsetmaker_item_comma(self, p):
"""dictorsetmaker : item comma_opt"""
p1 = p[1]
keys = [p1[0]]
vals = [p1[1]]
lineno, col = lopen_loc(p1[0] or p1[1])
p[0] = ast.Dict(keys=keys, values=vals, lineno=lineno, col_offset=col)
p[0].ctx = ast.Load()
def p_dictorsetmaker_t4_set(self, p):
"""dictorsetmaker : test_or_star_expr comma_test_or_star_expr_list comma_opt"""
p[0] = ast.Set(elts=[p[1]] + p[2], lineno=self.lineno, col_offset=self.col)
p[0].ctx = ast.Load()
def p_dictorsetmaker_test_comma(self, p):
"""dictorsetmaker : test_or_star_expr comma_opt"""
elts = self._list_or_elts_if_not_real_tuple(p[1])
p[0] = ast.Set(elts=elts, lineno=self.lineno, col_offset=self.col)
p[0].ctx = ast.Load()
def p_dictorsetmaker_testlist(self, p):
"""dictorsetmaker : testlist"""
elts = self._list_or_elts_if_not_real_tuple(p[1])
p[0] = ast.Set(elts=elts, lineno=self.lineno, col_offset=self.col)
p[0].ctx = ast.Load()
def p_op_factor(self, p):
"""
op_factor : times_tok factor
| at_tok factor
| divide_tok factor
| mod_tok factor
| doublediv_tok factor
"""
p1 = p[1]
op = self._term_binops[p1.value]
if op is None:
self._set_error(
f"operation {p1!r} not supported",
self.currloc(lineno=p.lineno, column=p.lexpos),
)
op = op()
op.lineno = p1.lineno
op.col_offset = p1.lexpos
p[0] = [op, p[2]]
def p_comp_for(self, p):
"""comp_for : FOR exprlist IN or_test comp_iter_opt"""
targs, it, p5 = p[2], p[4], p[5]
if len(targs) == 1:
targ = targs[0]
else:
targ = ensure_has_elts(targs)
store_ctx(targ)
comp = ast.comprehension(target=targ, iter=it, ifs=[], is_async=0)
comps = [comp]
p0 = {"comps": comps}
if p5 is not None:
comps += p5.get("comps", [])
comp.ifs += p5.get("if", [])
p[0] = p0

View file

@ -816,6 +816,10 @@ class ProcProxy:
"stack": spec.stack,
},
)
except SystemExit as e:
# the alias function is running in the main thread, so we need to
# catch SystemExit to prevent the entire shell from exiting (see #5689)
r = e.code if isinstance(e.code, int) else int(bool(e.code))
except Exception:
xt.print_exception(source_msg="Exception in " + get_proc_proxy_name(self))
r = 1

View file

@ -18,6 +18,7 @@ VER_MAJOR_MINOR = sys.version_info[:2]
VER_FULL = sys.version_info[:3]
ON_DARWIN = platform.system() == "Darwin"
ON_WINDOWS = platform.system() == "Windows"
ON_LINUX = platform.system() == "Linux"
ON_MSYS = sys.platform == "msys"
ON_CONDA = True in [
conda in pytest.__file__.lower() for conda in ["conda", "anaconda", "miniconda"]

View file

@ -5,6 +5,11 @@ class XonshActivator(ViaTemplateActivator):
def templates(self):
yield "activate.xsh"
@staticmethod
def quote(string):
# leave string unchanged since we do quoting in activate.xsh (see #5699)
return string
@classmethod
def supports(cls, interpreter):
return interpreter.version_info >= (3, 5)

View file

@ -138,7 +138,7 @@ def bind_server_to(
httpd = cls(("", port), handler_cls)
url = f"http://localhost:{port}"
print(f"Web config started at '{url}'. Hit Crtl+C to stop.")
print(f"Web config started at '{url}'. Hit Ctrl+C to stop.")
if browser:
import webbrowser