Mario is a very featureful application of similar ideas, and includes multiple built-in transformations, concurrency support, user-defined commands, and extensive documentation.
Thanks for sharing! I hadn't seen Mario before. The async support is super nifty!
From a quick look, it looks like pyp might be a little quicker for some use cases since it doesn't need subcommands, but I'll definitely be updating https://github.com/hauntsaninja/pyp#related-projects
"xonsh is a shell whose language is a superset of Python; this is more ambitious and pretty different from pyp. pyp is easier to use for the one-liner piping use case, but if you need more Python in your shell, check out xonsh."
It's very useful to be able to automate with a language you already know. I use it quite a bit now, for instance to figure out which of my git repos need a push or a pull.
I'm sure I wasn't the first to scratch that particular itch. It always seemed odd, back then, that Python didn't have better support for the Perl one-liner style of programming.
It still seems odd to me. While these projects are nice, if the functionality is not supported in the core system, it is rarely worth the additional trouble (imho). Situation is similar to gitless - git's cli interface sucks, but it is available on every dev machine.
This is fantastic -- I will certainly turn to this instead of awk/sed in many instances. I expect I'll use this in place of particularly tricky greps too. Really nice that you can seamless interleave standard bash commands with pyp commands, if e.g. an existing bash tool can get a piece of the job done more simply.
I already turn to Python in place of Bash whenever any nontrivial amount of complexity is needed or if any reuse is expected in the script I'm writing (I do this with Python Fire). Now I think I'll be making that Bash->Python switch at even lower levels of complexity, and even when no reuse is expected at all.
Was hoping to find a comment just like yours! Thanks!
I use Ruby from the cli frequently for stuff that exceeds an easy jq expression or if jq is not availabel but Ruby is (which happens a lot on RHEL systems when EPEL is not enabled, which is the case in a lot of banks) Ruby's awk -> perl -> ruby heritage endows it with a pretty good cli mode, but sometimes it's verbose. For example parsing json:
But obviously that's wordier than it needs. (To pre-empt the "just use jq!" people, I agree. For simple examples I would just use jq. This example here is just an example).
Yup, that was the inspiration for this project and its name. See https://github.com/hauntsaninja/pyp#related-projects for more discussion.
By no means is this a new idea, but I think this iteration has some convenient twists :-)
Given that the original project has been unmaintained for several years and is Python 2 only, I think it's not unreasonable. There's very little reason to have both installed, so I don't think it's a problem for users either.
It's also just the perfect name! It's punny, it's short and it acknowledges prior art. And of course, if the original author took issue with it, I would change the name.
Brilliant, just the right amount of magic. The explain feature is what really sold me that you thought about users! I wonder if I can put a bit of humanfriendly support in there with a pr.
Very cool! I'm the author of sh.py, and seeing projects that use just the right amount of magic to accomplish something unique and powerful is inspiring. Great work and good luck with pyp!
This is very cool. This is faster than postman for me if I was to use something like you showed in the jq example for quickly playing around with a public api’s json response.
Something like this should be baked straight into CPython itself. There are so many similar projects, there clearly is some demand for this. This could boost pythons usage for shell-jobs significantly if people have a reliable installation of this behaviour.
Startup time hasn't been particularly perceptible in my use of it. Just ran a quick benchmark on my (old, not powerful) laptop:
~ λ hyperfine 'pyp x'
Benchmark #1: pyp x
Time (mean ± σ): 75.9 ms ± 1.2 ms [User: 55.9 ms, System: 15.1 ms]
Range (min … max): 74.5 ms … 79.0 ms 36 runs
Since there isn't any input, this should just measure startup and AST transformation time.
Not sure if this comment will ever get seen, but I just added the ability to configure pyp with statically analysed Python, so it's easy to define your own functions, import aliases, or use libraries like pipetools to make your life easier! More details at https://github.com/hauntsaninja/pyp#pyp-is-configurable
* Wait until one sees a line with a start marker (say 'start:')
* Perform on an operation on the lines until an end marker ('end:') is reached.
Would you do a whole-input operation on stdin to extract the relevant lines first and then operate on the individual lines? Or would you maintain boolean conditionals within the loop?
There are a number of possible options! And remember you can always pipe pyp to pyp. Here are some ideas, in order of what came to mind, where the operation is incrementing.
With the -n option, perl runs your code for every line in the input (stdin, or filenames). $_ holds the content of the line. And the .. operator is a stateful (!) operator that becomes true when its left part becomes true, until the right part becomes true.
So I write 95% of my code in Python, but for command line magic, it's hard to beat Perl.
I was going to ask "isn't this basically just awk" but the README quickly cleared that up! Excellent documentation.
One thing I'm wondering is how's the startup time/performance in general? awk is kinda slow overall, but Python starts a little too slow to be used in shell scripting.
Looks like there are no dependencies, so it should start pretty fast.
And sure enough, it's both easy and reasonably fast to run:
$ time seq 1 10000 | awk '{a+=$0}END{print a}'
50005000
seq 1 10000 0.00s user 0.00s system 91% cpu 0.002 total
awk '{a+=$0}END{print a}' 0.01s user 0.00s system 95% cpu 0.008 total
$ time seq 1 10000 | python3 pyp.py 'sum(map(int, lines))'
50005000
seq 1 10000 0.00s user 0.00s system 80% cpu 0.002 total
python3 pyp.py 'sum(map(int, lines))' 0.06s user 0.01s system 99% cpu 0.070 total
I wouldn't run it in a loop, but it's definitely a contender even in high-ish performance situations.
I remember using this waay back in the day when this was still hosted on google code, and having a really good experience with it, despite some performance issues. I thought the project was dead, but I'm glad it's still going on.
https://github.com/python-mario/mario