Repository: xonsh/xonsh

Issue:
Why does a normal alias to 'history show all' fails in a pipe and how can I create a pipe-able alias?
Why does a normal alias to 'history show all' fails in a pipe and how can I create a pipe-able alias?

## Expected Behavior

With the alias

    aliases['hsa'] = ['history','show', 'all']

I expect that 

    hsa | head 

gives me the first 10 history entries as

    history show all | head

does. (`head` is here only an example. The problem occurs with all sorts of pipe filters like `grep`, `sed`, etc)

## Current Behavior

Instead when issuing

    hsa | head 

I get many lines of history output (but not all) followed by the error text:

    Unhandled exception in thread started by 

Note that after the `by` comes nothing...

## My Questions

1. **Why does this happen?** Ok, `history` is a function, not a subproces command, but why does this affect the piping *only* in an alias not when using the function directly?

2. **How can I create an alias for 'history show all' which does work with a pipe?** (I tried a callable with `return $('history show all')`, but this fails of course because history is not a subproces command.)

## xonfig

```
+------------------+---------------------------------+
| xonsh            | 0.8.3                           |
| Git SHA          | 07eb341c                        |
| Commit Date      | Nov 6 07:39:16 2018             |
| Python           | 3.6.4                           |
| PLY              | 3.11                            |
| have readline    | True                            |
| prompt toolkit   | 2.0.7                           |
| shell type       | readline                        |
| pygments         | None                            |
| on posix         | True                            |
| on linux         | True                            |
| distro           | Red Hat Enterprise Linux Server |
| on darwin        | False                           |
| on windows       | False                           |
| on cygwin        | False                           |
| on msys2         | False                           |
| is superuser     | False                           |
| default encoding | utf-8                           |
| xonsh encoding   | utf-8                           |
| encoding errors  | surrogateescape                 |
+------------------+---------------------------------+
```


Discussion:
Retested this with 0.8.8. Still happens. :-(

Does this ave anything to do with the magic `threadable_predictors` variable? Can a `predict_false` help like in other cases where pipes are involved?
Thanks for reporting @halloleo. It looks like there is some kind of unhandled exception in the code here.

Resolving patch:
diff --git a/xonsh/aliases.py b/xonsh/aliases.py
--- a/xonsh/aliases.py
+++ b/xonsh/aliases.py
@@ -84,9 +84,18 @@ def eval_alias(self, value, seen_tokens=frozenset(), acc_args=()):
         if callable(value):
             if acc_args:  # Partial application
 
-                def _alias(args, stdin=None):
+                def _alias(
+                    args, stdin=None, stdout=None, stderr=None, spec=None, stack=None
+                ):
                     args = list(acc_args) + args
-                    return value(args, stdin=stdin)
+                    return value(
+                        args,
+                        stdin=stdin,
+                        stdout=stdout,
+                        stderr=stderr,
+                        spec=spec,
+                        stack=stack,
+                    )
 
                 return _alias
             else:
diff --git a/xonsh/history/main.py b/xonsh/history/main.py
--- a/xonsh/history/main.py
+++ b/xonsh/history/main.py
@@ -184,37 +184,32 @@ def _xh_show_history(hist, ns, stdout=None, stderr=None):
             end_time=ns.end_time,
             datetime_format=ns.datetime_format,
         )
-    except ValueError as err:
+    except Exception as err:
         print("history: error: {}".format(err), file=stderr)
         return
     if ns.reverse:
         commands = reversed(list(commands))
+    end = "\0" if ns.null_byte else "\n"
     if ns.numerate and ns.timestamp:
         for c in commands:
             dt = datetime.datetime.fromtimestamp(c["ts"])
             print(
                 "{}:({}) {}".format(c["ind"], xt.format_datetime(dt), c["inp"]),
                 file=stdout,
-                end="\n" if not ns.null_byte else "\0",
+                end=end,
             )
     elif ns.numerate:
         for c in commands:
-            print(
-                "{}: {}".format(c["ind"], c["inp"]),
-                file=stdout,
-                end="\n" if not ns.null_byte else "\0",
-            )
+            print("{}: {}".format(c["ind"], c["inp"]), file=stdout, end=end)
     elif ns.timestamp:
         for c in commands:
             dt = datetime.datetime.fromtimestamp(c["ts"])
             print(
-                "({}) {}".format(xt.format_datetime(dt), c["inp"]),
-                file=stdout,
-                end="\n" if not ns.null_byte else "\0",
+                "({}) {}".format(xt.format_datetime(dt), c["inp"]), file=stdout, end=end
             )
     else:
         for c in commands:
-            print(c["inp"], file=stdout, end="\n" if not ns.null_byte else "\0")
+            print(c["inp"], file=stdout, end=end)
 
 
 @xla.lazyobject
@@ -382,7 +377,9 @@ def _xh_parse_args(args):
     return ns
 
 
-def history_main(args=None, stdin=None, stdout=None, stderr=None):
+def history_main(
+    args=None, stdin=None, stdout=None, stderr=None, spec=None, stack=None
+):
     """This is the history command entry point."""
     hist = builtins.__xonsh__.history
     ns = _xh_parse_args(args)


Test patch:
diff --git a/tests/test_aliases.py b/tests/test_aliases.py
--- a/tests/test_aliases.py
+++ b/tests/test_aliases.py
@@ -13,7 +13,7 @@
 from tools import skip_if_on_windows
 
 
-def cd(args, stdin=None):
+def cd(args, stdin=None, **kwargs):
     return args
 
 
@@ -61,3 +61,18 @@ def test_eval_recursive_callable_partial(xonsh_execer, xonsh_builtins):
     ales = make_aliases()
     xonsh_builtins.__xonsh__.env = Env(HOME=os.path.expanduser("~"))
     assert ales.get("indirect_cd")(["arg2", "arg3"]) == ["..", "arg2", "arg3"]
+
+
+def _return_to_sender(args, **kwargs):
+    return args, kwargs
+
+
+def test_recursive_callable_partial_(xonsh_execer, xonsh_builtins):
+    ales = Aliases({"rtn": _return_to_sender, "rtn-recurse": ["rtn", "arg1"]})
+    alias = ales.get("rtn-recurse")
+    assert callable(alias)
+    args, obs = alias(["arg2"], stdin="a", stdout="b", stderr="c", spec="d", stack="e")
+    assert args == ["arg1", "arg2"]
+    assert len(obs) == 5
+    exp = {"stdin": "a", "stdout": "b", "stderr": "c", "spec": "d", "stack": "e"}
+    assert obs == exp