Hello community,

here is the log from the commit of package xonsh for openSUSE:Factory checked 
in at 2020-04-07 10:28:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/xonsh (Old)
 and      /work/SRC/openSUSE:Factory/.xonsh.new.3248 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "xonsh"

Tue Apr  7 10:28:37 2020 rev:21 rq:791562 version:0.9.15

Changes:
--------
--- /work/SRC/openSUSE:Factory/xonsh/xonsh.changes      2020-03-07 
21:41:24.984400893 +0100
+++ /work/SRC/openSUSE:Factory/.xonsh.new.3248/xonsh.changes    2020-04-07 
10:28:48.334328429 +0200
@@ -1,0 +2,26 @@
+Sun Mar 29 19:01:45 UTC 2020 - Sebastian Wagner <sebix+novell....@sebix.at>
+
+- update to version 0.9.15:
+ - Added:
+  - Adds documentation for how to setup an emacs editing mode for xonsh.
+  - New ``$XONSH_TRACE_SUBPROC`` environment variable.
+  - Added ``-l``, ``-c`` and ``-a`` options to ``xexec``, works now like 
``exec``
+    in bash/zsh
+  - **$HISTCONTROL** - *errordups* support for history-sqlite backend
+ - Changed:
+  - ``-l`` switch works like bash, loads environment in non-interactive shell
+  - The xonsh pytest plugin no longer messes up the test order for pytest. Xsh 
test
+    are still executed first to avoid a bug were other tests would prevent 
``test_*.xsh`` 
+    files to run correctly.
+  - New repo name for xxh
+ - Fixed:
+  - Correctly follow symlinks when using dot-dot paths with cd -P.
+  - ``execx`` does not require the input string to be newline-terminated.
+  - ``evalx`` accepts newline-terminated input string.
+  - Fixed issue where negative exit codes (such as those produced
+    by core dumps) where treated as logical successes when chaining
+    processes with other boolean expressions.
+  - Fixed XONSH_TRACE_SUBPROC for pipeline command.
+  - updated CONTRIBUTING.rst about running pylint for changed files
+
+-------------------------------------------------------------------

Old:
----
  xonsh-0.9.14.tar.gz

New:
----
  xonsh-0.9.15.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ xonsh.spec ++++++
--- /var/tmp/diff_new_pack.nfE4xF/_old  2020-04-07 10:28:48.854329007 +0200
+++ /var/tmp/diff_new_pack.nfE4xF/_new  2020-04-07 10:28:48.858329012 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           xonsh
-Version:        0.9.14
+Version:        0.9.15
 Release:        0
 Summary:        A general purpose, Python-ish shell
 License:        BSD-3-Clause AND BSD-2-Clause

++++++ xonsh-0.9.14.tar.gz -> xonsh-0.9.15.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/.appveyor.yml 
new/xonsh-0.9.15/.appveyor.yml
--- old/xonsh-0.9.14/.appveyor.yml      2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/.appveyor.yml      2020-03-19 21:38:46.000000000 +0100
@@ -1,4 +1,4 @@
-version: 0.9.14.{build}
+version: 0.9.15.{build}
 os: Windows Server 2012 R2
 environment:
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/.authors.yml 
new/xonsh-0.9.15/.authors.yml
--- old/xonsh-0.9.14/.authors.yml       2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/.authors.yml       2020-03-19 21:38:46.000000000 +0100
@@ -68,7 +68,7 @@
   github: gforsyth
 - name: Morten Enemark Lund
   email: mel...@gmail.com
-  num_commits: 486
+  num_commits: 490
   first_commit: 2015-07-10 07:54:10
   github: melund
 - name: Ned Letcher
@@ -384,7 +384,7 @@
   email: laloc...@gmail.com
   aliases:
   - laloch
-  num_commits: 43
+  num_commits: 47
   first_commit: 2018-07-26 13:51:50
   github: laloch
 - name: Nico Lehmann
@@ -434,7 +434,7 @@
   github: funkyfuture
 - name: Anthony Scopatz
   email: scop...@gmail.com
-  num_commits: 2587
+  num_commits: 2593
   first_commit: 2015-01-21 17:04:13
   github: scopatz
 - name: anatoly techtonik
@@ -1016,7 +1016,7 @@
   first_commit: 2018-09-16 22:50:24
 - name: Gyuri Horak
   email: dy...@horak.hu
-  num_commits: 1
+  num_commits: 2
   first_commit: 2019-06-18 12:00:16
   github: dyuri
 - name: Ke Zhang
@@ -1092,12 +1092,14 @@
   email: drmikecr...@gmail.com
   aliases:
   - drmikecrowe
-  num_commits: 1
+  num_commits: 6
   first_commit: 2020-01-28 09:44:58
   github: drmikecrowe
 - name: anki-code
   email: anki-c...@users.noreply.github.com
-  num_commits: 14
+  alternate_emails:
+  - anki-code
+  num_commits: 21
   first_commit: 2019-10-15 18:20:58
 - name: Sylvain Corlay
   email: sylvain.cor...@gmail.com
@@ -1118,3 +1120,26 @@
   num_commits: 1
   first_commit: 2020-02-05 13:38:52
   github: marciomazza
+- name: Noortheen Raja
+  email: jnoorth...@gmail.com
+  num_commits: 2
+  first_commit: 2020-03-15 10:13:56
+  github: jnoortheen
+- name: Samuel Lotz
+  email: samuel.l...@salotz.info
+  num_commits: 3
+  first_commit: 2020-03-03 11:30:33
+  github: salotz
+- name: Jerzy Drozdz
+  email: jerzy.dro...@gmail.com
+  num_commits: 1
+  first_commit: 2020-03-01 11:56:23
+- name: Gabriel Vogel
+  email: gabriel.vo...@online.de
+  num_commits: 2
+  first_commit: 2020-03-10 19:06:59
+  github: Gobbel2000
+- name: anki
+  email: anki@code.email
+  num_commits: 2
+  first_commit: 2020-03-02 04:59:17
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/.gitignore new/xonsh-0.9.15/.gitignore
--- old/xonsh-0.9.14/.gitignore 2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/.gitignore 2020-03-19 21:38:46.000000000 +0100
@@ -36,6 +36,7 @@
 bin/
 /lib/
 include/
+venv/
 
 # Mac
 .DS_Store
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/.mailmap new/xonsh-0.9.15/.mailmap
--- old/xonsh-0.9.14/.mailmap   2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/.mailmap   2020-03-19 21:38:46.000000000 +0100
@@ -27,8 +27,8 @@
 Jean-Benoist Leger <j...@leger.tf> Jean-Benoist Leger <jble...@hds.utc.fr>
 christopher <cjwright4...@gmail.com>
 Klaus Alexander Seistrup <kl...@seistrup.dk> Klaus Alexander Seistrup 
<kseist...@users.noreply.github.com>
-Leonardo Santagada <santag...@gmail.com>
 David Strobach <laloc...@gmail.com> laloch <laloc...@gmail.com>
+Leonardo Santagada <santag...@gmail.com>
 Burak Yiğit Kaya <b...@byk.im> Burak Yigit Kaya <b...@byk.im>
 Aaron Griffin <aig...@gmail.com>
 Rob Brewer <rwb...@gmail.com> Robert W. Brewer <rwb...@gmail.com>
@@ -40,6 +40,7 @@
 Gordon Ball <gor...@chronitis.net>
 Travis Shirk <tra...@pobox.com>
 Joel Gerber <j...@grrbrr.ca>
+anki-code <anki-c...@users.noreply.github.com> anki-code <anki-code>
 vaaaaanquish <6sy...@gmail.com> @vaaaaanquish <6sy...@gmail.com>
 vaaaaanquish <6sy...@gmail.com> vaaaaanquish <6sy...@gmail.com>
 vaaaaanquish <6sy...@gmail.com> 6syun9 <6sy...@gmail.com>
@@ -53,7 +54,6 @@
 Frank Sachsenheim <funkyfut...@riseup.net> Frank Sachsenheim 
<funkyfut...@users.noreply.github.com>
 Kurtis Rader <kra...@skepticism.us>
 cryzed <cry...@googlemail.com>
-anki-code <anki-c...@users.noreply.github.com>
 Brian Visel <e...@eptitude.net>
 Andrew Hundt <athu...@gmail.com>
 Jonathan Slenders <jonat...@slenders.be>
@@ -82,6 +82,7 @@
 Nathan Goldbaum <ngold...@illinois.edu> Nathan Goldbaum <goldb...@ucolick.org>
 mel <m...@anybodytech.com>
 Jared Crawford <jmcrawfor...@gmail.com>
+Mike Crowe <drmikecr...@gmail.com> drmikecrowe <drmikecr...@gmail.com>
 JuanPablo <jpabl...@gmail.com>
 Ollie Terrance <ollie.terra...@live.co.uk>
 Marcel Bollmann <bollm...@linguistics.rub.de>
@@ -139,6 +140,7 @@
 Sébastien Pierre <sebastien.pie...@gmail.com>
 shadow-light <42055707+shadow-li...@users.noreply.github.com>
 Jan Chren <dev.rind...@gmail.com>
+Samuel Lotz <samuel.l...@salotz.info>
 Mark Wiebe <mwwi...@gmail.com>
 Nathan Hoad <nat...@getoffmalawn.com>
 Eric Dill <ed...@bnl.gov>
@@ -161,11 +163,15 @@
 Steven Kryskalla <skryska...@gmail.com>
 cclauss <ccla...@me.com>
 Eddie Peters <edward.paul.pet...@gmail.com>
+Gyuri Horak <dy...@horak.hu>
 Ke Zhang <kezh...@bnl.gov> ke-zhang-rd <kezh...@bnl.gov>
 László Vaskó <vl...@balabit.hu>
 Allan Crooks <allan.cro...@sixtyten.org>
 micimize <rosenthal...@gmail.com>
 Edmund Miller <edmund.a.mil...@protonmail.com>
+Noortheen Raja <jnoorth...@gmail.com>
+Gabriel Vogel <gabriel.vo...@online.de>
+anki <anki@code.email>
 Dan Allan <dal...@bnl.gov>
 Ned Letcher <nletc...@gmail.com>
 Zach Crownover <zachary.crowno...@gmail.com>
@@ -222,16 +228,15 @@
 Ronny Pfannschmidt <opensou...@ronnypfannschmidt.de>
 Troy de Freitas <9503857+nt...@users.noreply.github.com>
 Rodrigo Oliveira <rodrigo.olive...@byne.com.br>
-Gyuri Horak <dy...@horak.hu>
 Daniel Smith <malor...@me.com>
 Nils ANDRÉ-CHANG <n...@nilsand.re>
 chengxuncc <chengxu...@gmail.com>
 nedsociety <nedsoci...@gmail.com>
 fanosta <git...@nageler.org>
 David Kalliecharan <david@david.science>
-Mike Crowe <drmikecr...@gmail.com> drmikecrowe <drmikecr...@gmail.com>
 Sylvain Corlay <sylvain.cor...@gmail.com>
 Chris Lasher <chris.las...@gmail.com>
 Marcio Mazza <marcioma...@gmail.com>
+Jerzy Drozdz <jerzy.dro...@gmail.com>
 goodboy <tgood...@users.noreply.github.com>
 Atsushi Morimoto <atsushi.morim...@dena.com>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/AUTHORS.rst new/xonsh-0.9.15/AUTHORS.rst
--- old/xonsh-0.9.14/AUTHORS.rst        2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/AUTHORS.rst        2020-03-19 21:38:46.000000000 +0100
@@ -13,8 +13,8 @@
 * Jean-Benoist Leger
 * christopher
 * Klaus Alexander Seistrup
-* Leonardo Santagada
 * David Strobach
+* Leonardo Santagada
 * Burak Yiğit Kaya
 * Aaron Griffin
 * Rob Brewer
@@ -26,6 +26,7 @@
 * Gordon Ball
 * Travis Shirk
 * Joel Gerber
+* anki-code
 * vaaaaanquish
 * Bernardas Ališauskas
 * Derek Thomas
@@ -37,7 +38,6 @@
 * Frank Sachsenheim
 * Kurtis Rader
 * cryzed
-* anki-code
 * Brian Visel
 * Andrew Hundt
 * Jonathan Slenders
@@ -66,6 +66,7 @@
 * Nathan Goldbaum
 * mel
 * Jared Crawford
+* Mike Crowe
 * JuanPablo
 * Ollie Terrance
 * Marcel Bollmann
@@ -123,6 +124,7 @@
 * Sébastien Pierre
 * shadow-light
 * Jan Chren
+* Samuel Lotz
 * Mark Wiebe
 * Nathan Hoad
 * Eric Dill
@@ -145,11 +147,15 @@
 * Steven Kryskalla
 * cclauss
 * Eddie Peters
+* Gyuri Horak
 * Ke Zhang
 * László Vaskó
 * Allan Crooks
 * micimize
 * Edmund Miller
+* Noortheen Raja
+* Gabriel Vogel
+* anki
 * Dan Allan
 * Ned Letcher
 * Zach Crownover
@@ -206,16 +212,15 @@
 * Ronny Pfannschmidt
 * Troy de Freitas
 * Rodrigo Oliveira
-* Gyuri Horak
 * Daniel Smith
 * Nils ANDRÉ-CHANG
 * chengxuncc
 * nedsociety
 * fanosta
 * David Kalliecharan
-* Mike Crowe
 * Sylvain Corlay
 * Chris Lasher
 * Marcio Mazza
+* Jerzy Drozdz
 * goodboy
 * Atsushi Morimoto
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/CHANGELOG.rst 
new/xonsh-0.9.15/CHANGELOG.rst
--- old/xonsh-0.9.14/CHANGELOG.rst      2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/CHANGELOG.rst      2020-03-19 21:38:46.000000000 +0100
@@ -4,6 +4,51 @@
 
 .. current developments
 
+v0.9.15
+====================
+
+**Added:**
+
+* Adds documentation for how to setup an emacs editing mode for xonsh.
+* New ``$XONSH_TRACE_SUBPROC`` environment variable.
+* Added ``-l``, ``-c`` and ``-a`` options to ``xexec``, works now like ``exec``
+  in bash/zsh
+* **$HISTCONTROL** - *errordups* support for history-sqlite backend
+
+**Changed:**
+
+* ``-l`` switch works like bash, loads environment in non-interactive shell
+* The xonsh pytest plugin no longer messes up the test order for pytest. Xsh 
test
+  are still executed first to avoid a bug were other tests would prevent 
``test_*.xsh`` 
+  files to run correctly.
+* New repo name for xxh
+
+**Fixed:**
+
+* Correctly follow symlinks when using dot-dot paths with cd -P.
+* ``execx`` does not require the input string to be newline-terminated.
+* ``evalx`` accepts newline-terminated input string.
+* Fixed issue where negative exit codes (such as those produced
+  by core dumps) where treated as logical successes when chaining
+  processes with other boolean expressions.
+* Fixed XONSH_TRACE_SUBPROC for pipeline command.
+* updated CONTRIBUTING.rst about running pylint for changed files
+
+**Authors:**
+
+* Anthony Scopatz
+* Morten Enemark Lund
+* David Strobach
+* anki-code
+* Samuel Lotz
+* Gyuri Horak
+* Noortheen Raja
+* Gabriel Vogel
+* anki
+* Jerzy Drozdz
+
+
+
 v0.9.14
 ====================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/CONTRIBUTING.rst 
new/xonsh-0.9.15/CONTRIBUTING.rst
--- old/xonsh-0.9.14/CONTRIBUTING.rst   2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/CONTRIBUTING.rst   2020-03-19 21:38:46.000000000 +0100
@@ -119,7 +119,7 @@
 need to run "conda install pylint" once. You can easily run pylint on
 the edited files in your uncommited git change::
 
-    $ pylint $(git status -s | awk '/\.py$$/ { print $$2 }' | sort)
+    $ git status -s | awk '/\.py$$/ { print $2 }' | xargs pylint
 
 If you want to lint the entire code base run::
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/README.rst new/xonsh-0.9.15/README.rst
--- old/xonsh-0.9.14/README.rst 2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/README.rst 2020-03-19 21:38:46.000000000 +0100
@@ -29,4 +29,4 @@
 - `gitsome <https://github.com/donnemartin/gitsome>`_: A supercharged 
Git/shell autocompleter with GitHub integration.
 - `rever <https://regro.github.io/rever-docs/>`_: Cross-platform software 
release tool.
 - `Regro autotick bot <https://github.com/regro/cf-scripts>`_: Regro 
Conda-Forge autoticker.
-- `xxh <https://github.com/xonssh/xxh>`_: Using xonsh wherever you go through 
the ssh.
+- `xxh <https://github.com/xxh/xxh>`_: Using xonsh wherever you go through the 
ssh.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/docs/editors.rst 
new/xonsh-0.9.15/docs/editors.rst
--- old/xonsh-0.9.14/docs/editors.rst   1970-01-01 01:00:00.000000000 +0100
+++ new/xonsh-0.9.15/docs/editors.rst   2020-03-19 21:38:46.000000000 +0100
@@ -0,0 +1,23 @@
+
+==============================
+Editor Support
+==============================
+
+.. contents::
+   :local:
+
+Emacs
+=====
+
+There is an emacs mode for editing xonsh scripts available from the
+`MELPA repository`_. If you are not familiar see the installation
+instructions there.
+
+Then just add this line to your emacs configuration file:
+
+.. code-block:: emacs-lisp
+
+    (require 'xonsh-mode)
+
+
+.. _MELPA repository: https://melpa.org/#/xonsh-mode
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/docs/installation.rst 
new/xonsh-0.9.15/docs/installation.rst
--- old/xonsh-0.9.14/docs/installation.rst      2020-02-28 22:07:39.000000000 
+0100
+++ new/xonsh-0.9.15/docs/installation.rst      2020-03-19 21:38:46.000000000 
+0100
@@ -17,3 +17,4 @@
     appimage
     containers
     customization
+    editors
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/aliases/test_xexec.py 
new/xonsh-0.9.15/tests/aliases/test_xexec.py
--- old/xonsh-0.9.14/tests/aliases/test_xexec.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/xonsh-0.9.15/tests/aliases/test_xexec.py        2020-03-19 
21:38:46.000000000 +0100
@@ -0,0 +1,84 @@
+import os
+import inspect
+import pytest
+import sys
+
+from xonsh.aliases import xexec
+
+
+@pytest.fixture
+def mockexecvpe(monkeypatch):
+    def mocked_execvpe(_command, _args, _env):
+        pass
+
+    monkeypatch.setattr(os, "execvpe", mocked_execvpe)
+
+
+def test_noargs(mockexecvpe):
+    assert xexec([]) == (None, "xonsh: exec: no args specified\n", 1)
+
+
+def test_missing_command(mockexecvpe):
+    assert xexec(["-a", "foo"]) == (None, "xonsh: exec: no command 
specified\n", 1)
+    assert xexec(["-c"]) == (None, "xonsh: exec: no command specified\n", 1)
+    assert xexec(["-l"]) == (None, "xonsh: exec: no command specified\n", 1)
+
+
+def test_command_not_found(monkeypatch):
+
+    dummy_error_msg = "This is dummy error message, file not found or 
something like that"
+    command = "non_existing_command"
+
+    def mocked_execvpe(_command, _args, _env):
+        raise FileNotFoundError(2, dummy_error_msg)
+    monkeypatch.setattr(os, "execvpe", mocked_execvpe)
+
+    assert xexec([command]) == (None,
+                                "xonsh: exec: file not found: {}: {}" 
"\n".format(dummy_error_msg, command),
+                                1)
+
+
+def test_help(mockexecvpe):
+    assert xexec(["-h"]) == inspect.getdoc(xexec)
+    assert xexec(["--help"]) == inspect.getdoc(xexec)
+
+
+def test_a_switch(monkeypatch):
+    called = {}
+
+    def mocked_execvpe(command, args, env):
+        called.update({"command": command, "args": args, "env": env})
+
+    monkeypatch.setattr(os, "execvpe", mocked_execvpe)
+    proc_name = "foo"
+    command = "bar"
+    command_args = ["1"]
+    xexec(["-a", proc_name, command] + command_args)
+    assert called["command"] == command
+    assert called["args"][0] == proc_name
+    assert len(called["args"]) == len([command] + command_args)
+
+
+def test_l_switch(monkeypatch):
+    called = {}
+
+    def mocked_execvpe(command, args, env):
+        called.update({"command": command, "args": args, "env": env})
+
+    monkeypatch.setattr(os, "execvpe", mocked_execvpe)
+    command = "bar"
+    xexec(["-l", command, "1"])
+
+    assert called["args"][0].startswith("-")
+
+
+def test_c_switch(monkeypatch):
+    called = {}
+
+    def mocked_execvpe(command, args, env):
+        called.update({"command": command, "args": args, "env": env})
+
+    monkeypatch.setattr(os, "execvpe", mocked_execvpe)
+    command = "sleep"
+    xexec(["-c", command, "1"])
+    assert called["env"] == {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/test_environ.py 
new/xonsh-0.9.15/tests/test_environ.py
--- old/xonsh-0.9.14/tests/test_environ.py      2020-02-28 22:07:39.000000000 
+0100
+++ new/xonsh-0.9.15/tests/test_environ.py      2020-03-19 21:38:46.000000000 
+0100
@@ -101,6 +101,14 @@
     assert "ignoredups" in env["HISTCONTROL"]
 
 
+def test_histcontrol_ignoreerr_ignoredups_erase_dups():
+    env = Env(HISTCONTROL="ignoreerr,ignoredups,ignoreerr,erasedups")
+    assert len(env["HISTCONTROL"]) == 3
+    assert "ignoreerr" in env["HISTCONTROL"]
+    assert "ignoredups" in env["HISTCONTROL"]
+    assert "erasedups" in env["HISTCONTROL"]
+
+
 def test_swap():
     env = Env(VAR="wakka")
     assert env["VAR"] == "wakka"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/test_execer.py 
new/xonsh-0.9.15/tests/test_execer.py
--- old/xonsh-0.9.14/tests/test_execer.py       2020-02-28 22:07:39.000000000 
+0100
+++ new/xonsh-0.9.15/tests/test_execer.py       2020-03-19 21:38:46.000000000 
+0100
@@ -2,7 +2,13 @@
 """Tests the xonsh lexer."""
 import os
 
-from tools import check_eval, check_parse, skip_if_on_unix, skip_if_on_windows
+from tools import (
+    check_eval,
+    check_exec,
+    check_parse,
+    skip_if_on_unix,
+    skip_if_on_windows,
+)
 
 import pytest
 
@@ -138,3 +144,12 @@
 )
 def test_two_echo_line_cont(code):
     assert check_parse(code)
+
+
+def test_eval_eol():
+    assert check_eval("0") and check_eval("0\n")
+
+
+def test_exec_eol():
+    locs = dict()
+    assert check_exec("a=0", locs=locs) and check_exec("a=0\n", locs=locs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/test_history_sqlite.py 
new/xonsh-0.9.15/tests/test_history_sqlite.py
--- old/xonsh-0.9.14/tests/test_history_sqlite.py       2020-02-28 
22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/tests/test_history_sqlite.py       2020-03-19 
21:38:46.000000000 +0100
@@ -169,6 +169,27 @@
     assert -1 == hist.rtns[-1]
 
 
+def test_histcontrol_erase_dup(hist, xonsh_builtins):
+    """Test HISTCONTROL=erasedups"""
+
+    xonsh_builtins.__xonsh__.env["HISTCONTROL"] = "erasedups"
+    assert len(hist) == 0
+
+    hist.append({"inp": "ls foo", "rtn": 2})
+    hist.append({"inp": "ls foobazz", "rtn": 0})
+    hist.append({"inp": "ls foo", "rtn": 0})
+    hist.append({"inp": "ls foobazz", "rtn": 0})
+    hist.append({"inp": "ls foo", "rtn": 0})
+    assert len(hist) == 2
+    assert len(hist.inps) == 5
+
+    items = list(hist.items())
+    assert "ls foo" == items[-1]["inp"]
+    assert "ls foobazz" == items[-2]["inp"]
+    assert items[-2]["frequency"] == 2
+    assert items[-1]["frequency"] == 3
+
+
 @pytest.mark.parametrize(
     "index, exp",
     [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/test_integrations.py 
new/xonsh-0.9.15/tests/test_integrations.py
--- old/xonsh-0.9.14/tests/test_integrations.py 2020-02-28 22:07:39.000000000 
+0100
+++ new/xonsh-0.9.15/tests/test_integrations.py 2020-03-19 21:38:46.000000000 
+0100
@@ -559,3 +559,11 @@
     "verify pipe between subprocesses doesn't throw an exception"
     check_run_xonsh(cmd, fmt, exp)
 
+
+@skip_if_on_windows
+def test_negative_exit_codes_fail():
+    # see issue 3309
+    script = 'python -c "import os; os.abort()" && echo OK\n'
+    out, err, rtn = run_xonsh(script)
+    assert "OK" is not out
+    assert "OK" is not err
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/tests/tools.py 
new/xonsh-0.9.15/tests/tools.py
--- old/xonsh-0.9.14/tests/tools.py     2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/tests/tools.py     2020-03-19 21:38:46.000000000 +0100
@@ -174,8 +174,6 @@
 
 
 def check_exec(input, **kwargs):
-    if not input.endswith("\n"):
-        input += "\n"
     builtins.__xonsh__.execer.exec(input, **kwargs)
     return True
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/__init__.py 
new/xonsh-0.9.15/xonsh/__init__.py
--- old/xonsh-0.9.14/xonsh/__init__.py  2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/__init__.py  2020-03-19 21:38:46.000000000 +0100
@@ -1,4 +1,4 @@
-__version__ = "0.9.14"
+__version__ = "0.9.15"
 
 
 # amalgamate exclude jupyter_kernel parser_table parser_test_table pyghooks
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/aliases.py 
new/xonsh-0.9.15/xonsh/aliases.py
--- old/xonsh-0.9.14/xonsh/aliases.py   2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/aliases.py   2020-03-19 21:38:46.000000000 +0100
@@ -610,7 +610,7 @@
 
 
 def xexec(args, stdin=None):
-    """exec [-h|--help] command [args...]
+    """exec [-h|--help] [-cl] [-a name] command [args...]
 
     exec (also aliased as xexec) uses the os.execvpe() function to
     replace the xonsh process with the specified program. This provides
@@ -620,6 +620,13 @@
         bash $
 
     The '-h' and '--help' options print this message and exit.
+    If the '-l' option is supplied, the shell places a dash at the
+    beginning of the zeroth argument passed to command to simulate login
+    shell.
+    The '-c' option causes command to be executed with an empty environment.
+    If '-a' is supplied, the shell passes name as the zeroth argument
+    to the executed command.
+
 
     Notes
     -----
@@ -633,18 +640,40 @@
     """
     if len(args) == 0:
         return (None, "xonsh: exec: no args specified\n", 1)
-    elif args[0] == "-h" or args[0] == "--help":
+
+    parser = argparse.ArgumentParser(add_help=False)
+    parser.add_argument("-h", "--help", action="store_true")
+    parser.add_argument("-l", dest="login", action="store_true")
+    parser.add_argument("-c", dest="clean", action="store_true")
+    parser.add_argument("-a", dest="name", nargs="?")
+    parser.add_argument("command", nargs=argparse.REMAINDER)
+    args = parser.parse_args(args)
+
+    if args.help:
         return inspect.getdoc(xexec)
-    else:
+
+    if len(args.command) == 0:
+        return (None, "xonsh: exec: no command specified\n", 1)
+
+    command = args.command[0]
+    if args.name is not None:
+        args.command[0] = args.name
+    if args.login:
+        args.command[0] = "-{}".format(args.command[0])
+
+    denv = {}
+    if not args.clean:
         denv = builtins.__xonsh__.env.detype()
-        try:
-            os.execvpe(args[0], args, denv)
-        except FileNotFoundError as e:
-            return (
-                None,
-                "xonsh: exec: file not found: {}: {}" "\n".format(e.args[1], 
args[0]),
-                1,
-            )
+
+    try:
+        os.execvpe(command, args.command, denv)
+    except FileNotFoundError as e:
+        return (
+            None,
+            "xonsh: exec: file not found: {}: {}"
+            "\n".format(e.args[1], args.command[0]),
+            1,
+        )
 
 
 class AWitchAWitch(argparse.Action):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/built_ins.py 
new/xonsh-0.9.15/xonsh/built_ins.py
--- old/xonsh-0.9.14/xonsh/built_ins.py 2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/built_ins.py 2020-03-19 21:38:46.000000000 +0100
@@ -934,6 +934,9 @@
 
     Lastly, the captured argument affects only the last real command.
     """
+    if builtins.__xonsh__.env.get("XONSH_TRACE_SUBPROC"):
+        print("TRACE SUBPROC: %s" % str(cmds), file=sys.stderr)
+
     specs = cmds_to_specs(cmds, captured=captured)
     captured = specs[-1].captured
     if captured == "hiddenobject":
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/dirstack.py 
new/xonsh-0.9.15/xonsh/dirstack.py
--- old/xonsh-0.9.14/xonsh/dirstack.py  2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/dirstack.py  2020-03-19 21:38:46.000000000 +0100
@@ -147,10 +147,10 @@
     env = builtins.__xonsh__.env
     old = env["PWD"]
     new = os.path.join(old, newdir)
-    absnew = os.path.abspath(new)
 
     if follow_symlinks:
-        absnew = os.path.realpath(absnew)
+        new = os.path.realpath(new)
+    absnew = os.path.abspath(new)
 
     try:
         os.chdir(absnew)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/environ.py 
new/xonsh-0.9.15/xonsh/environ.py
--- old/xonsh-0.9.14/xonsh/environ.py   2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/environ.py   2020-03-19 21:38:46.000000000 +0100
@@ -403,8 +403,8 @@
     @property
     def style_name(self):
         """Current XONSH_COLOR_STYLE value"""
-        env = builtins.__xonsh__.env
-        env_style_name = env.get("XONSH_COLOR_STYLE")
+        env = getattr(builtins.__xonsh__, "env", {})
+        env_style_name = env.get("XONSH_COLOR_STYLE", "default")
         if self._style_name is None or self._style_name != env_style_name:
             self._style_name = env_style_name
             self._style = self._dtyped = None
@@ -626,6 +626,7 @@
         "XONSH_STDERR_POSTFIX": (is_string, ensure_string, ensure_string),
         "XONSH_STORE_STDOUT": (is_bool, to_bool, bool_to_str),
         "XONSH_STORE_STDIN": (is_bool, to_bool, bool_to_str),
+        "XONSH_TRACE_SUBPROC": (is_bool, to_bool, bool_to_str),
         "XONSH_TRACEBACK_LOGFILE": (is_logfile_opt, to_logfile_opt, 
logfile_opt_to_str),
         "XONSH_DATETIME_FORMAT": (is_string, ensure_string, ensure_string),
     }
@@ -805,6 +806,7 @@
         "XONSH_HISTORY_SIZE": (8128, "commands"),
         "XONSH_LOGIN": False,
         "XONSH_PROC_FREQUENCY": 1e-4,
+        "XONSH_TRACE_SUBPROC": False,
         "XONSH_SHOW_TRACEBACK": False,
         "XONSH_STDERR_PREFIX": "",
         "XONSH_STDERR_POSTFIX": "",
@@ -1002,8 +1004,10 @@
             "that determine what commands are saved to the history list. By "
             "default all commands are saved. The option ``ignoredups`` will 
not "
             "save the command if it matches the previous command. The option "
-            "'ignoreerr' will cause any commands that fail (i.e. return 
non-zero "
-            "exit status) to not be added to the history list.",
+            "``ignoreerr`` will cause any commands that fail (i.e. return 
non-zero "
+            "exit status) to not be added to the history list. The option "
+            "``erasedups`` will remove all previous commands that matches and 
updates the frequency. "
+            "Note: ``erasedups`` is supported only in sqlite backend).",
             store_as_str=True,
         ),
         "IGNOREEOF": VarDocs("Prevents Ctrl-D from exiting the shell."),
@@ -1363,6 +1367,9 @@
             "xonsh process threads sleep for while running command pipelines. "
             "The value has units of seconds [s]."
         ),
+        "XONSH_TRACE_SUBPROC": VarDocs(
+            "Set to ``True`` to show arguments list of every executed 
subprocess command."
+        ),
         "XONSH_SHOW_TRACEBACK": VarDocs(
             "Controls if a traceback is shown if exceptions occur in the 
shell. "
             "Set to ``True`` to always show traceback or ``False`` to always 
hide. "
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/execer.py 
new/xonsh-0.9.15/xonsh/execer.py
--- old/xonsh-0.9.14/xonsh/execer.py    2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/execer.py    2020-03-19 21:38:46.000000000 +0100
@@ -145,6 +145,7 @@
         if isinstance(input, types.CodeType):
             code = input
         else:
+            input = input.rstrip("\n")
             if filename is None:
                 filename = self.filename
             code = self.compile(
@@ -174,6 +175,8 @@
         if isinstance(input, types.CodeType):
             code = input
         else:
+            if not input.endswith("\n"):
+                input += "\n"
             if filename is None:
                 filename = self.filename
             code = self.compile(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/history/sqlite.py 
new/xonsh-0.9.15/xonsh/history/sqlite.py
--- old/xonsh-0.9.14/xonsh/history/sqlite.py    2020-02-28 22:07:39.000000000 
+0100
+++ new/xonsh-0.9.15/xonsh/history/sqlite.py    2020-03-19 21:38:46.000000000 
+0100
@@ -12,6 +12,10 @@
 from xonsh.history.base import History
 import xonsh.tools as xt
 
+XH_SQLITE_CACHE = threading.local()
+XH_SQLITE_TABLE_NAME = "xonsh_history"
+XH_SQLITE_CREATED_SQL_TBL = "CREATED_SQL_TABLE"
+
 
 def _xh_sqlite_get_file_name():
     envs = builtins.__xonsh__.env
@@ -33,35 +37,84 @@
 
     Columns:
         info - JSON formatted, reserved for future extension.
+        frequency - in case of HISTCONTROL=erasedups,
+        it tracks the frequency of the inputs. helps in sorting autocompletion
     """
+    if not getattr(XH_SQLITE_CACHE, XH_SQLITE_CREATED_SQL_TBL, False):
+        cursor.execute(
+            """
+            CREATE TABLE IF NOT EXISTS {}
+                 (inp TEXT,
+                  rtn INTEGER,
+                  tsb REAL,
+                  tse REAL,
+                  sessionid TEXT,
+                  out TEXT,
+                  info TEXT,
+                  frequency INTEGER default 1
+                 )
+        """.format(
+                XH_SQLITE_TABLE_NAME
+            )
+        )
+        # add frequency column if not exists for backward compatibility
+        try:
+            cursor.execute(
+                "ALTER TABLE "
+                + XH_SQLITE_TABLE_NAME
+                + " ADD COLUMN frequency INTEGER default 1"
+            )
+        except sqlite3.OperationalError:
+            pass
+
+        # mark that this function ran for this session
+        setattr(XH_SQLITE_CACHE, XH_SQLITE_CREATED_SQL_TBL, True)
+
+
+def _xh_sqlite_get_frequency(cursor, input):
+    # type: (sqlite3.Cursor, str) -> int
+    sql = "SELECT sum(frequency) FROM {} WHERE 
inp=?".format(XH_SQLITE_TABLE_NAME)
+    cursor.execute(sql, (input,))
+    return cursor.fetchone()[0] or 0
+
+
+def _xh_sqlite_erase_dups(cursor, input):
+    freq = _xh_sqlite_get_frequency(cursor, input)
+    sql = "DELETE FROM {} WHERE inp=?".format(XH_SQLITE_TABLE_NAME)
+    cursor.execute(sql, (input,))
+    return freq
+
+
+def _sql_insert(cursor, values):
+    # type: (sqlite3.Cursor, dict) -> None
+    """handy function to run insert query"""
+    sql = "INSERT INTO {} ({}) VALUES ({});"
+    fields = ", ".join(values)
+    marks = ", ".join(["?"] * len(values))
     cursor.execute(
-        """
-        CREATE TABLE IF NOT EXISTS xonsh_history
-             (inp TEXT,
-              rtn INTEGER,
-              tsb REAL,
-              tse REAL,
-              sessionid TEXT,
-              out TEXT,
-              info TEXT
-             )
-    """
+        sql.format(XH_SQLITE_TABLE_NAME, fields, marks), tuple(values.values())
     )
 
 
-def _xh_sqlite_insert_command(cursor, cmd, sessionid, store_stdout):
-    sql = "INSERT INTO xonsh_history (inp, rtn, tsb, tse, sessionid"
+def _xh_sqlite_insert_command(cursor, cmd, sessionid, store_stdout, 
remove_duplicates):
     tss = cmd.get("ts", [None, None])
-    params = [cmd["inp"].rstrip(), cmd["rtn"], tss[0], tss[1], sessionid]
+    values = collections.OrderedDict(
+        [
+            ("inp", cmd["inp"].rstrip()),
+            ("rtn", cmd["rtn"]),
+            ("tsb", tss[0]),
+            ("tse", tss[1]),
+            ("sessionid", sessionid),
+        ]
+    )
     if store_stdout and "out" in cmd:
-        sql += ", out"
-        params.append(cmd["out"])
+        values["out"] = cmd["out"]
     if "info" in cmd:
-        sql += ", info"
         info = json.dumps(cmd["info"])
-        params.append(info)
-    sql += ") VALUES (" + ("?, " * len(params)).rstrip(", ") + ")"
-    cursor.execute(sql, tuple(params))
+        values["info"] = info
+    if remove_duplicates:
+        values["frequency"] = _xh_sqlite_erase_dups(cursor, values["inp"]) + 1
+    _sql_insert(cursor, values)
 
 
 def _xh_sqlite_get_count(cursor, sessionid=None):
@@ -75,7 +128,7 @@
 
 
 def _xh_sqlite_get_records(cursor, sessionid=None, limit=None, 
newest_first=False):
-    sql = "SELECT inp, tsb, rtn FROM xonsh_history "
+    sql = "SELECT inp, tsb, rtn, frequency FROM xonsh_history "
     params = []
     if sessionid is not None:
         sql += "WHERE sessionid = ? "
@@ -103,11 +156,13 @@
     return result.rowcount
 
 
-def xh_sqlite_append_history(cmd, sessionid, store_stdout, filename=None):
+def xh_sqlite_append_history(
+    cmd, sessionid, store_stdout, filename=None, remove_duplicates=False
+):
     with _xh_sqlite_get_conn(filename=filename) as conn:
         c = conn.cursor()
         _xh_sqlite_create_history_table(c)
-        _xh_sqlite_insert_command(c, cmd, sessionid, store_stdout)
+        _xh_sqlite_insert_command(c, cmd, sessionid, store_stdout, 
remove_duplicates)
         conn.commit()
 
 
@@ -181,9 +236,11 @@
         self.outs = []
         self.tss = []
 
+        # during init rerun create command
+        setattr(XH_SQLITE_CACHE, XH_SQLITE_CREATED_SQL_TBL, False)
+
     def append(self, cmd):
         envs = builtins.__xonsh__.env
-        opts = envs.get("HISTCONTROL")
         inp = cmd["inp"].rstrip()
         self.inps.append(inp)
         store_stdout = envs.get("XONSH_STORE_STDOUT", False)
@@ -203,22 +260,23 @@
             return
         self._last_hist_inp = inp
         xh_sqlite_append_history(
-            cmd, str(self.sessionid), store_stdout, filename=self.filename
+            cmd,
+            str(self.sessionid),
+            store_stdout,
+            filename=self.filename,
+            remove_duplicates=("erasedups" in opts),
         )
 
-    def all_items(self, newest_first=False):
+    def all_items(self, newest_first=False, session_id=None):
         """Display all history items."""
-        for item in xh_sqlite_items(filename=self.filename, 
newest_first=newest_first):
-            yield {"inp": item[0], "ts": item[1], "rtn": item[2]}
+        for inp, ts, rtn, freq in xh_sqlite_items(
+            filename=self.filename, newest_first=newest_first, 
sessionid=session_id
+        ):
+            yield {"inp": inp, "ts": ts, "rtn": rtn, "frequency": freq}
 
     def items(self, newest_first=False):
         """Display history items of current session."""
-        for item in xh_sqlite_items(
-            sessionid=str(self.sessionid),
-            filename=self.filename,
-            newest_first=newest_first,
-        ):
-            yield {"inp": item[0], "ts": item[1], "rtn": item[2]}
+        yield from self.all_items(newest_first, session_id=str(self.sessionid))
 
     def info(self):
         data = collections.OrderedDict()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/main.py 
new/xonsh-0.9.15/xonsh/main.py
--- old/xonsh-0.9.14/xonsh/main.py      2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/main.py      2020-03-19 21:38:46.000000000 +0100
@@ -292,7 +292,11 @@
     env = builtins.__xonsh__.env
     rc = shell_kwargs.get("rc", None)
     rc = env.get("XONSHRC") if rc is None else rc
-    if args.mode != XonshMode.interactive and not args.force_interactive:
+    if (
+        args.mode != XonshMode.interactive
+        and not args.force_interactive
+        and not args.login
+    ):
         #  Don't load xonshrc if not interactive shell
         rc = None
     events.on_pre_rc.fire()
@@ -329,7 +333,8 @@
         "cacheall": args.cacheall,
         "ctx": builtins.__xonsh__.ctx,
     }
-    if args.login:
+    if args.login or sys.argv[0].startswith("-"):
+        args.login = True
         shell_kwargs["login"] = True
     if args.norc:
         shell_kwargs["rc"] = ()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/proc.py 
new/xonsh-0.9.15/xonsh/proc.py
--- old/xonsh-0.9.14/xonsh/proc.py      2020-02-28 22:07:39.000000000 +0100
+++ new/xonsh-0.9.15/xonsh/proc.py      2020-03-19 21:38:46.000000000 +0100
@@ -2288,7 +2288,7 @@
         rtn = self.returncode
         if (
             rtn is not None
-            and rtn > 0
+            and rtn != 0
             and builtins.__xonsh__.env.get("RAISE_SUBPROC_ERROR")
         ):
             try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xonsh-0.9.14/xonsh/pytest_plugin.py 
new/xonsh-0.9.15/xonsh/pytest_plugin.py
--- old/xonsh-0.9.14/xonsh/pytest_plugin.py     2020-02-28 22:07:39.000000000 
+0100
+++ new/xonsh-0.9.15/xonsh/pytest_plugin.py     2020-03-19 21:38:46.000000000 
+0100
@@ -14,7 +14,17 @@
 
 
 def pytest_collection_modifyitems(items):
-    items.sort(key=lambda x: 0 if isinstance(x, XshFunction) else 1)
+    """ Move xsh test first to work around a bug in normal
+        pytest cleanup. The order of tests are otherwise preserved.
+    """
+    xsh_items = []
+    other_items = []
+    for item in items:
+        if isinstance(item, XshFunction):
+            xsh_items.append(item)
+        else:
+            other_items.append(item)
+    items[:] = xsh_items + other_items
 
 
 def _limited_traceback(excinfo):


Reply via email to