Giter VIP home page Giter VIP logo

mario's Introduction

Mario: Shell pipes in Python

GitHub

Documentation Status

Build status

PyPI package

Coverage

Have you ever wanted to use Python functions directly in your Unix shell? Mario can read and write csv, json, and yaml; traverse trees, and even do xpath queries. Plus, it supports async commands right out of the box. Build your own commands with a simple configuration file, and install plugins for even more!

Mario is the plumbing snake ๐Ÿ๐Ÿ”ง helping you build data pipelines in your shell ๐Ÿข.

What time is it in Sydney?

Features

  • Execute Python code in your shell.
  • Pass Python objects through multi-stage pipelines.
  • Read and write csv, json, yaml, toml, xml.
  • Run async functions natively.
  • Define your own commands in a simple configuration file or by writing Python code.
  • Install plugins to get more commands.
  • Enjoy high test coverage, continuous integration, and nightly releases.

Installation

Mario

Windows support is hopefully coming soon. Linux and MacOS are supported now.

Get Mario with pip:

python3.7 -m pip install mario

If you're not inside a virtualenv, you might get a PermissionsError. In that case, try using:

python3.7 -m pip install --user mario

or for more isolation, use pipx:

pipx install --python python3.7 mario

Mario addons

The mario-addons package provides a number of useful commands not found in the base collection.

Get Mario addons with pip:

python3.7 -m pip install mario-addons

If you're not inside a virtualenv, you might get a PermissionsError. In that case, try using:

python3.7 -m pip install --user mario-addons

or for more isolation, use pipx:

pipx install --python python3.7 mario
pipx inject mario mario-addons

Quickstart

Basics

Invoke with mario at the command line.

$ mario eval 1+1
2

Given a csv like this:

$ cat <<EOF > hackers.csv
name,age
Alice,21
Bob,22
Carol,23
EOF

Use read-csv-dicts to read each row into a dict:

$ mario read-csv-dicts < hackers.csv
{'name': 'Alice', 'age': '21'}
{'name': 'Bob', 'age': '22'}
{'name': 'Carol', 'age': '23'}

Use map to act on each input item x :

$ mario read-csv-dicts map 'x["name"]' < hackers.csv
Alice
Bob
Carol

Chain Python functions together with !:

$ mario read-csv-dicts map 'x["name"] ! len' < hackers.csv
5
3
5

or by adding another command

$ mario read-csv-dicts map 'x["name"]' map len < hackers.csv
5
3
5

Use x as a placeholder for the input at each stage:

$ mario read-csv-dicts map 'x["age"] ! int ! x*2'  < hackers.csv
42
44
46

Automatically import modules you need:

$ mario map 'collections.Counter ! dict' <<<mississippi
{'m': 1, 'i': 4, 's': 4, 'p': 2}

You don't need to explicitly call the function with some_function(x); just use the function's name, some_function. For example, instead of

$ mario map 'len(x)' <<EOF
a
bb
EOF
1
2

try

$ mario map len <<EOF
a
bb
EOF
1
2

More commands

Here are a few commands. See Command reference for the complete set, and get even more from mario-addons.

eval

Use eval to evaluate a Python expression.

% mario eval 'datetime.datetime.utcnow()'

2019-01-01 01:23:45.562736

map

Use map to act on each input item.

$ mario map 'x * 2' <<EOF
a
bb
EOF
aa
bbbb

filter

Use filter to evaluate a condition on each line of input and exclude false values.

$ mario filter 'len(x) > 1' <<EOF
a
bb
ccc
EOF
bb
ccc

apply

Use apply to act on the sequence of items.

$ mario apply 'len(x)' <<EOF
a
bb
EOF
2

chain

Use chain to flatten a list of lists into a single list, like itertools.chain.from_iterable.

For example, after generating a several rows of items,

$ mario read-csv-tuples <<EOF
a,b,c
d,e,f
g,h,i
EOF
('a', 'b', 'c')
('d', 'e', 'f')
('g', 'h', 'i')

use chain to put each item on its own row:

$ mario read-csv-tuples chain <<EOF
a,b,c
d,e,f
g,h,i
EOF
a
b
c
d
e
f
g
h
i

async-map

Making sequential requests is slow. These requests take 16 seconds to complete.

% time mario map 'await asks.get ! x.json()["url"]'  <<EOF
http://httpbin.org/delay/5
http://httpbin.org/delay/1
http://httpbin.org/delay/2
http://httpbin.org/delay/3
http://httpbin.org/delay/4
EOF
https://httpbin.org/delay/5
https://httpbin.org/delay/1
https://httpbin.org/delay/2
https://httpbin.org/delay/3
https://httpbin.org/delay/4
0.51s user
0.02s system
16.460 total

Concurrent requests can go much faster. The same requests now take only 6 seconds. Use async-map, or async-filter, or reduce with await some_async_function to get concurrency out of the box.

% time mario async-map 'await asks.get ! x.json()["url"]'  <<EOF
http://httpbin.org/delay/5
http://httpbin.org/delay/1
http://httpbin.org/delay/2
http://httpbin.org/delay/3
http://httpbin.org/delay/4
EOF
https://httpbin.org/delay/5
https://httpbin.org/delay/1
https://httpbin.org/delay/2
https://httpbin.org/delay/3
https://httpbin.org/delay/4
0.49s user
0.03s system
5.720 total

Configuration

Define new commands and set default options. See Configuration reference for details.

Plugins

Add new commands like map and reduce by installing Mario plugins. You can try them out without installing by adding them to any .py file in your ~/.config/mario/modules/.

Share popular commands by installing the mario-addons package.

Q & A

What's the status of this package?

  • This package is experimental and is subject to change without notice.
  • Check the issues page for open tickets.

Why another package?

A number of cool projects have pioneered in the Python-in-shell space. I wrote Mario because I didn't know these existed at the time, but now Mario has a bunch of features the others don't (user configuration, multi-stage pipelines, async, plugins, etc).

mario's People

Contributors

dependabot-preview[bot] avatar jakdar avatar kbd avatar probot-auto-merge[bot] avatar python-mario-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

mario's Issues

Getting a ValueError("incomplete frame") with the read-json operation

Given a JSON file addrx.json I get when calling mario like this

cat addrx.json  | mario read-json 

the following traceback

Traceback (most recent call last):
  File "/home/me/opt/pipx/bin/mario", line 8, in <module>
    sys.exit(cli())
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/click/core.py", line 1164, in invoke
    return _process_result(rv)
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/click/core.py", line 1102, in _process_result
    **ctx.params)
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/mario/cli.py", line 161, in cli_main
    app.main(pairs, **kwargs)
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/mario/app.py", line 113, in main
    trio.run(functools.partial(async_main, pairs, **kwargs))
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/trio/_core/_run.py", line 1444, in run
    raise runner.main_task_outcome.error
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/mario/app.py", line 105, in async_main
    stack, items = await program_runner(traversals, items, global_context)
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/mario/app.py", line 54, in program_runner
    items = await call_traversal(context, traversal, items, stack)
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/mario/app.py", line 44, in call_traversal
    return await traversal.plugin_object.traversal_function(**args)
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/mario/plugins/basic.py", line 239, in apply
    return traversals.AsyncIterableWrapper([await function([x async for x in items])])
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/mario/plugins/basic.py", line 239, in <listcomp>
    return traversals.AsyncIterableWrapper([await function([x async for x in items])])
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/mario/app.py", line 103, in <genexpr>
    items = (item.decode() async for item in receiver)
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/mario/asynch.py", line 82, in __anext__
    return await self.receive()
  File "/home/me/opt/pipx/venvs/mario/lib/python3.7/site-packages/mario/asynch.py", line 64, in receive
    raise ValueError("incomplete frame")

Happy to upload the (smallish) file addrx.json to somewhere to make this issue reproducible.

Side note

When I feed the input file first through jq for pretty-printing like this

cat addrx.json | jq . | mario read-json 

mario returns the expected result.

Dependabot can't resolve your Python dependency files

Dependabot can't resolve your Python dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

Creating virtualenv mario-tAGE4S8x-py3.9 in /home/dependabot/.cache/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies...

  PackageNotFound

  Package regex (2019.12.19) not found.

  at /usr/local/.pyenv/versions/3.9.0/lib/python3.9/site-packages/poetry/repositories/pool.py:144 in package
      140โ”‚                     self._packages.append(package)
      141โ”‚ 
      142โ”‚                     return package
      143โ”‚ 
    โ†’ 144โ”‚         raise PackageNotFound("Package {} ({}) not found.".format(name, version))
      145โ”‚ 
      146โ”‚     def find_packages(
      147โ”‚         self, dependency,
      148โ”‚     ):

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

View the update logs.

Error when trying to eval

I am facing this error when trying out the example in the docs.

user@path : mario eval 1+1
Traceback (most recent call last):
  File "/Users/user/.pyenv/versions/3.7.3/bin/mario", line 10, in <module>
    sys.exit(cli())
  File "/Users/user/.pyenv/versions/3.7.3/lib/python3.7/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/Users/user/.pyenv/versions/3.7.3/lib/python3.7/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/Users/user/.pyenv/versions/3.7.3/lib/python3.7/site-packages/click/core.py", line 1164, in invoke
    return _process_result(rv)
  File "/Users/user/.pyenv/versions/3.7.3/lib/python3.7/site-packages/click/core.py", line 1102, in _process_result
    **ctx.params)
  File "/Users/user/.pyenv/versions/3.7.3/lib/python3.7/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/Users/user/.pyenv/versions/3.7.3/lib/python3.7/site-packages/mario/cli.py", line 174, in cli_main
    app.main(pairs, **kwargs)
  File "/Users/user/.pyenv/versions/3.7.3/lib/python3.7/site-packages/mario/app.py", line 112, in main
    trio.run(functools.partial(async_main, pairs, **kwargs))
  File "/Users/user/.pyenv/versions/3.7.3/lib/python3.7/site-packages/trio/_core/_run.py", line 1783, in run
    raise runner.main_task_outcome.error
  File "/Users/user/.pyenv/versions/3.7.3/lib/python3.7/site-packages/mario/app.py", line 61, in async_main
    stream = trio._unix_pipes.PipeReceiveStream(os.dup(0))
AttributeError: module 'trio._unix_pipes' has no attribute 'PipeReceiveStream'

Threaded apply

Currently, apply builds a list of all the inputs instead of incrementally applying the function. This can result in large memory usage. Threading can be used to treat the AsyncIterable[T] stream as a sync Iterable[T] and apply the function without materializing a whole list. This would require users who want to build a list to explicitly create the list from the iterable.

traceback out of the box

  1. pipx install mario
  2. mario eval '"hello"'
Error in sys.excepthook:
Traceback (most recent call last):
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/trio/_core/_multierror.py", line 413, in trio_excepthook
    for chunk in traceback.format_exception(etype, value, tb):
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/traceback.py", line 139, in format_exception
    te = TracebackException(type(value), value, tb, limit=limit, compact=True)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: traceback_exception_init() got an unexpected keyword argument 'compact'

Original exception was:
Traceback (most recent call last):
  File "/Users/glyph/.local/bin/mario", line 8, in <module>
    sys.exit(cli())
             ^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/click/core.py", line 1164, in invoke
    return _process_result(rv)
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/click/core.py", line 1101, in _process_result
    value = ctx.invoke(self.result_callback, value,
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/mario/cli.py", line 161, in cli_main
    app.main(pairs, **kwargs)
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/mario/app.py", line 113, in main
    trio.run(functools.partial(async_main, pairs, **kwargs))
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/trio/_core/_run.py", line 1444, in run
    raise runner.main_task_outcome.error
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/mario/app.py", line 105, in async_main
    stack, items = await program_runner(traversals, items, global_context)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/mario/app.py", line 54, in program_runner
    items = await call_traversal(context, traversal, items, stack)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/mario/app.py", line 31, in call_traversal
    calculated_params = traversal.plugin_object.calculate_more_params(traversal)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/mario/plugins/basic.py", line 245, in <lambda>
    calculate_more_params=lambda x: calculate_function(
                                    ^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/mario/plugins/basic.py", line 38, in calculate_function
    "function": interpret.build_function(
                ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/mario/interpret.py", line 143, in build_function
    name_to_module = build_name_to_module(code)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/mario/interpret.py", line 134, in build_name_to_module
    components = split_pipestring(code)
                 ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/mario/interpret.py", line 88, in split_pipestring
    tree = parso.parse(s)
           ^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/parso/__init__.py", line 57, in parse
    grammar = load_grammar(version=version)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/parso/grammar.py", line 256, in load_grammar
    return load_grammar(**kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/parso/grammar.py", line 232, in load_grammar
    version_info = parse_version_string(version)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/parso/utils.py", line 175, in parse_version_string
    return _parse_version(version)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/glyph/.local/pipx/venvs/mario/lib/python3.11/site-packages/parso/utils.py", line 124, in _parse_version
    raise ValueError('The given version is not in the right format. '
ValueError: The given version is not in the right format. Use something like "3.2" or "3".

Dependabot can't resolve your Python dependency files

Dependabot can't resolve your Python dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

Creating virtualenv mario-BwuGrTQu-py3.9 in /home/dependabot/.cache/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies...

  PackageNotFound

  Package sphinx-jsonschema (1.16.6) not found.

  at /usr/local/.pyenv/versions/3.9.0/lib/python3.9/site-packages/poetry/repositories/pool.py:144 in package
      140โ”‚                     self._packages.append(package)
      141โ”‚ 
      142โ”‚                     return package
      143โ”‚ 
    โ†’ 144โ”‚         raise PackageNotFound("Package {} ({}) not found.".format(name, version))
      145โ”‚ 
      146โ”‚     def find_packages(
      147โ”‚         self, dependency,
      148โ”‚     ):

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

View the update logs.

Changing the signature of the write- commands

ls -l | mario map 're.split("\s+", x)' write-json

This gives a list of arrays (an array of arrays would seem nicer, but ok)

...
]
[
    "drwxr-xr-x",
    "6",
    "username",
    "group",
    "4096",
    "Jan",
    "18",
    "2019",
    "filename"
]
[
    "drwxr-xr-x",
...

ls -l | mario map 're.split("\s+", x)' write-csv-tuples

This splits each item with commas and groups the items in a line with double newlines... Huh?

...

d,r,w,x,r,-,x,r,-,x
6
u,s,e,r,n,a,m,e
g,r,o,u,p
4,0,9,6
J,a,n
1,8
2,0,1,9
f,i,l,e,n,a,m,e

d,r,w,x,r,-,x,r,-,x
...

Ubuntu 18.04 / Python 3.8.0 in a virtualenv without system site packages.

Could not find a version that satisfies the requirement mario (from versions: none)

I'm getting this error trying to install mario.

$ pip install --user mario
Collecting mario
  ERROR: Could not find a version that satisfies the requirement mario (from versions: none)
ERROR: No matching distribution found for mario

Tried several ways.

$ pip3 install --user mario
Collecting mario
  ERROR: Could not find a version that satisfies the requirement mario (from versions: none)
ERROR: No matching distribution found for mario
$ python3 -m pip install --user mario
Collecting mario
  ERROR: Could not find a version that satisfies the requirement mario (from versions: none)
ERROR: No matching distribution found for mario
$ sudo -H python3 -m pip install mario
Collecting mario
  ERROR: Could not find a version that satisfies the requirement mario (from versions: none)
ERROR: No matching distribution found for mario

Any ideas what could be wrong here?

Dependabot can't resolve your Python dependency files

Dependabot can't resolve your Python dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

Creating virtualenv mario-5rNCN-36-py3.9 in /home/dependabot/.cache/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies...

  PackageNotFound

  Package importlib-metadata (1.6.1) not found.

  at /usr/local/.pyenv/versions/3.9.0/lib/python3.9/site-packages/poetry/repositories/pool.py:144 in package
      140โ”‚                     self._packages.append(package)
      141โ”‚ 
      142โ”‚                     return package
      143โ”‚ 
    โ†’ 144โ”‚         raise PackageNotFound("Package {} ({}) not found.".format(name, version))
      145โ”‚ 
      146โ”‚     def find_packages(
      147โ”‚         self, dependency,
      148โ”‚     ):

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

View the update logs.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.