All Projects → hauntsaninja → Pyp

hauntsaninja / Pyp

Licence: mit
Easily run Python at the shell! Magical, but never mysterious.

Programming Languages

python
139335 projects - #7 most used programming language
shell
77523 projects
awk
318 projects

Projects that are alternatives of or similar to Pyp

Inquirer Checkbox Plus Prompt
Checkbox with autocomplete and other additions for Inquirer
Stars: ✭ 25 (-97.55%)
Mutual labels:  cli, command-line
Executor
Watch for file changes and then execute command. Very nice for test driven development.
Stars: ✭ 14 (-98.63%)
Mutual labels:  cli, command-line
Elodie
An EXIF-based photo assistant, organizer, manager and workflow automation tool.
Stars: ✭ 840 (-17.65%)
Mutual labels:  cli, command-line
Clifx
Declarative framework for building command line interfaces
Stars: ✭ 900 (-11.76%)
Mutual labels:  cli, command-line
Wonders
🌈 Declarative JavaScript framework to build command-line applications.
Stars: ✭ 34 (-96.67%)
Mutual labels:  cli, command-line
Mprislyrics
Small command-line utility that displays lyrics in sync with the currently playing song in a MPRIS2 capable player.
Stars: ✭ 24 (-97.65%)
Mutual labels:  cli, command-line
Xsv
A fast CSV command line toolkit written in Rust.
Stars: ✭ 7,831 (+667.75%)
Mutual labels:  cli, command-line
Ipt
Interactive Pipe To: The Node.js cli interactive workflow
Stars: ✭ 783 (-23.24%)
Mutual labels:  cli, command-line
Todo r
Find all your TODO notes with one command!
Stars: ✭ 28 (-97.25%)
Mutual labels:  cli, command-line
Cht.exe
cht.sh libcurl client for windows XP+ with changed colorization
Stars: ✭ 15 (-98.53%)
Mutual labels:  cli, command-line
Aruba
Test command-line applications with Cucumber-Ruby, RSpec or Minitest. The most up to date documentation can be found on Cucumber.Pro (https://app.cucumber.pro/projects/aruba)
Stars: ✭ 900 (-11.76%)
Mutual labels:  cli, command-line
Snoo
A Reddit command line client written in Node.js, using modern ES-features
Stars: ✭ 39 (-96.18%)
Mutual labels:  cli, command-line
Ntl
Node Task List: Interactive cli to list and run package.json scripts
Stars: ✭ 800 (-21.57%)
Mutual labels:  cli, command-line
Laminas Cli
Console command runner, exposing commands written in Laminas MVC and Mezzio components and applications
Stars: ✭ 25 (-97.55%)
Mutual labels:  cli, command-line
Prompts
❯ Lightweight, beautiful and user-friendly interactive prompts
Stars: ✭ 6,970 (+583.33%)
Mutual labels:  cli, command-line
Sit Up
🙇 Reminder to sit up straight.
Stars: ✭ 9 (-99.12%)
Mutual labels:  cli, command-line
Argh
Argh! A minimalist argument handler.
Stars: ✭ 752 (-26.27%)
Mutual labels:  cli, command-line
Js Liftoff
Launch your command line tool with ease.
Stars: ✭ 761 (-25.39%)
Mutual labels:  cli, command-line
Ecsctl
Command-line tool for managing AWS Elastic Container Service and Projects to run on it.
Stars: ✭ 15 (-98.53%)
Mutual labels:  cli, command-line
Make Me Lol
😄 A command-line tool to make you laugh
Stars: ✭ 38 (-96.27%)
Mutual labels:  cli, command-line

pyp

Build Status Coverage Status Checked with mypy

Easily run Python at the shell! Magical, but never mysterious.

Installation

Run pip install pypyp (note the extra "yp"!)

pyp requires Python 3.6 or above.

How it works

pyp will statically analyse the input code to detect undefined variables. Based on what it finds, it will proceed to transform the AST of the input code as needed. We then compile and execute the result, or if using --explain, unparse the AST back to source code.

Examples

This section will walk you through the details of using pyp, and hopefully replace your needs for many common shell utilities. For a cheatsheet / tldr, run pyp --help.

pyp can easily be used to apply Python code to each line in the input.

Just use one of the magic variables x, l, s or line to refer to the current line.

# pyp like cut
ls | pyp 'x[:3]'
ps x | pyp 'line.split()[4]'

pyp can be used to easily apply Python code to the entire input as well.

Use the magic variable lines for a list of rstripped lines or stdin for sys.stdin.

# pyp like wc -c
cat /usr/share/dict/words | pyp 'len(stdin.read())'

# pyp like awk
seq 1 5 | pyp 'sum(map(int, lines))'

pyp will automatically import modules you use.

# pyp like sh
echo echo echo | pyp 'subprocess.run(lines[0], shell=True); pass'

# pyp like jq
curl -s 'https://api.github.com/repos/hauntsaninja/pyp/commits?per_page=1' | pyp 'json.load(stdin)[0]["commit"]["author"]'

# pyp like egrep
cat /usr/share/dict/words | pyp 'x if re.search("(p|m)yth", x) else None'

For collections, math, itertools, pathlib.Path, pprint.pp, pyp will figure it out even if you don't use the qualified name.

# pyp like bc
pyp 'sqrt(5)'

# pyp like ${x##*.}
ls | pyp 'Path(x).suffix'

pyp can give you access to loop indices using the magic variables i, idx or index.

# pyp like line numbers
cat setup.py | pyp 'f"{idx+1: >3} {x}"'

Note so far you haven't had to call print!

By default, pyp will print the last expression in your code — except if it evaluates to None (or the last statement is pass). And you can always explicitly call print yourself, in which case pyp will stay out of your way.

# pyp like grep
cat /usr/share/dict/words | pyp 'x if "python" in x else None'
cat /usr/share/dict/words | pyp 'if "python" in x: print(x); "this will not be printed"'

pyp will attempt to intelligently print dicts and iterables.

This makes the output of pyp easier to compose with shell tools. Again, explicit printing will stop this magic, but pyp makes the function pypprint available if you do want to explicitly opt back in.

# pyp like tail
ls | pyp 'lines[-10:]'

# pyp like sort
ls | pyp 'sorted(lines)'
ls | pyp 'print(f"Sorting {len(lines)} lines"); pypprint(sorted(lines))'

# pyp like sort | uniq
ls | pyp 'sorted(set(lines))'

pyp lets you run snippets of Python before and after processing input.

Note if you run into trouble with semicolons and want a new line (without using a multiline string in your shell), you can just pass another string to pyp. You can also always pipe pyp to pyp!

# pyp like anything!
ps aux | pyp -b 'd = defaultdict(list)' 'user, pid, *_ = x.split()' 'd[user].append(pid)' -a 'del d["root"]' -a 'd'

pyp can be magical, but it doesn't have to be mysterious!

Use --explain or --script and pyp will output a script equivalent to what it would run. This can also serve as a useful starting point for more complex scripts.

pyp --explain -b 'd = defaultdict(list)' 'user, pid, *_ = x.split()' 'd[user].append(pid)' -a 'del d["root"]' -a 'd'
#!/usr/bin/env python3
from collections import defaultdict
from pyp import pypprint
import sys
d = defaultdict(list)
for x in sys.stdin:
    x = x.rstrip('\n')
    (user, pid, *_) = x.split()
    d[user].append(pid)
del d['root']
if d is not None:
    pypprint(d)

And if your command hits an exception, pyp will reconstruct a traceback into the generated code.

pyp is configurable.

Point the environment variable PYP_CONFIG_PATH to a file containing, for example:

import numpy as np
import tensorflow as tf
from pipetools import *

def p95(data):
    return np.percentile(data, 95)

class PotentiallyUsefulClass: ...

When attempting to define undefined names, pyp will statically* analyse this file as a source of possible definitions. This means that if you don't use tf, we won't import tensorflow! And of course, --explain will show you exactly what gets run (and hence what doesn't!):

pyp --explain 'print(p95(list(map(float, stdin))))'
#!/usr/bin/env python3
import sys
import numpy as np

def p95(data):
    return np.percentile(data, 95)
stdin = sys.stdin
print(p95(list(map(float, stdin))))

Note, importing things from libraries like pipetools in your configuration can allow you to achieve high levels of syntax sugar:

seq 1 110 | pyp 'lines > foreach(int) | where(X > 100) | group_by(X % 3) | sort_by(X[0])'

*If you use wildcard imports, we will need to import those modules if there remain undefined names, though we skip this in the happy path. If this matters to you, definitely don't from tensorflow import * in your config!

I have questions!

There's additional documentation and examples at FAQ. If that doesn't answer your question, please open an issue!

Related projects

Pyed Piper aka Python Power at the Prompt

pyp takes inspiration (and the command name!) from here. However, Pyed Piper appears to be unmaintained, Python 2 only, and further away from Python syntax than pyp aims to be. Github mirror here.

Pyped

I discovered Pyped while making this project! It's actually very similar, probably similar enough that I wouldn't have written this had I known. However, Pyped doesn't do the AST introspection and manipulation that we do. This means:

  • It's less magical! It relies on you to pass in flags to tell it what to do, when intention can be inferred from the input.
  • It doesn't provide easy automatic printing, or smart printing of iterables and dicts.
  • It hardcodes a list of imports and installs some libraries on your system. This project's automatic import will work for any library you use.
  • It doesn't have anything like --explain/--script.

However,

  • It has some conveniences, like regex splitting of input, that you'd have to do for yourself here.
  • It supports Python 2 and early versions of Python 3.
  • It's been around for much longer.

piep / spy / pyfil / pythonpy / oneliner

Since writing pyp, it turns out there are more alternatives out there than I thought :-) Some quick notes:

  • Most of them rely on the user passing in flags, like Pyped.
  • Most of them have limitations around automatic printing, like only being able to automatically print single expressions or not handling iterables and dicts well.
  • Some of them have custom syntax for in-process command chaining, which can be convenient.
  • Some of them have specialised support for things like JSON input or running shell commands.
  • Some of them expose the input in interesting ways with custom line / file / stream objects.
  • Some of them have more advanced options for error handling.
  • None of them have anything like --explain.

For whatever it's worth, I've listed these projects in approximate order of my personal preference.

mario

mario is a featureful take on shell processing with Python. It doesn't use undefined name detection, instead relying on a pluggable subcommand system. While the subcommands can be more verbose than pyp, mario makes up some ground by automatic application of functions and a custom command chaining syntax. The result can feel a little DSL-like, while pyp tries to feel very close to writing Python.

Consider using mario if:

  • You find yourself stringing together long sequences of pyp commands and want to be able to command chain within a single process out of the box.
  • You find yourself often needing to reuse complex pyp commands or doing a lot of domain specific shell processing that you wish you could reuse with a single command.
  • You want more builtin support for things like processing CSV or TOML.
  • You want to easily be able to use async functions to process your input concurrently.

Consider pyp if:

  • You want to minimise keystrokes for things that should be quick and easy.
  • You want something minimal and lightweight that feels very close to Python. You don't want to have to remember commands.
  • You're happy using Python libraries to do domain specific heavy lifting, for easy command chaining or syntax sugar. You don't mind (or want to be able to) fall back to a script via --script to deal with complexity.

xonsh

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.

awk

If awk works for you, how did you end up here?

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].