mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 00:14:41 +01:00
Merge branch 'main' into fix_callias_double_open
This commit is contained in:
commit
1850e14061
43 changed files with 774 additions and 212 deletions
42
.authors.yml
42
.authors.yml
|
@ -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
|
||||
|
|
1
.github/workflows/publish.yml
vendored
1
.github/workflows/publish.yml
vendored
|
@ -22,6 +22,7 @@ jobs:
|
|||
- "3.10"
|
||||
- "3.11"
|
||||
- "3.12"
|
||||
- "3.13"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: setup-python
|
||||
|
|
11
.github/workflows/test.yml
vendored
11
.github/workflows/test.yml
vendored
|
@ -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 }}
|
||||
|
||||
|
|
15
.mailmap
15
.mailmap
|
@ -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>
|
||||
|
|
|
@ -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: |
|
||||
|
|
15
AUTHORS.rst
15
AUTHORS.rst
|
@ -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
|
||||
|
|
|
@ -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``
|
||||
|
|
|
@ -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.
|
||||
|
|
4
docs/_templates/index.html
vendored
4
docs/_templates/index.html
vendored
|
@ -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">
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
**Fixed:**
|
||||
|
||||
* Fixed ``$AUTO_CD`` regress after previous refactoring.
|
||||
* Fixed non-int sys.exit codes raising ValueError.
|
||||
|
||||
**Security:**
|
||||
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
||||
|
|
|
@ -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]",
|
||||
|
|
|
@ -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 &]")
|
||||
|
|
|
@ -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 [
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = "0.18.2"
|
||||
__version__ = "0.19.0"
|
||||
|
|
2
xonsh/api/README.md
Normal file
2
xonsh/api/README.md
Normal 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.
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
1
xonsh/lib/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
Xonsh library contains the code that independent to xonsh core or a code that is fork from another projects.
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
264
xonsh/parsers/v313.py
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue