py-singleline


Namepy-singleline JSON
Version 1.0.0a2 PyPI version JSON
download
home_pagehttp://github.com/whisperity/py-singleline
SummaryArbitrarily complex single-line Python scripts
upload_time2023-09-21 07:43:08
maintainer
docs_urlNone
authorWhisperity
requires_python>=3.6
licenseGPLv3+
keywords python shell pipeline script scripting
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            Arbitrarily complex single-line Python scripts
==============================================

**`pysln`** allows executing "Python"-ish scripts in the command line as parts of a pipeline.

_Why?_ Normally, the Python binary allows executing Python script specified in the command-line, but you have to write a proper Python script:

~~~~
python3 -c 'import json
print(json.dumps({0: 1}))
'
~~~~

This may make shell history unreadable, hard to edit, etc.

In addition, accessing information in a pipe, common with most command-line tools, is convoluted.
While you can easily say `some-command-generating-data | grep Foo | awk '{ print $2; }'`, doing a similar thing for data processing in Python is really hard, requiring you to open an editor, save a script file.

**`pysln`** takes this need off for **quick and dirty** command-line data processing.

Installation
------------

Install from [PyPI](http://pypi.org/project/pysln/).
The `pysln` entry point will be made available.

~~~
$ pip3 install pysln
$ pysln -h
usage: pysln [-h] [...]
~~~

Overview
--------

Use `pysln` just like you would use `sed` or `awk` in a pipe.
After the optional flags, specify the code to execute:

~~~~
$ seq 1 5 | pysln 'print(int(LINE) * 2);'
2
4
6
8
10
~~~~

_Py-SingleLine_ works by first *transcoding* the input code to real Python syntax, then *injecting* this input into a context, forming a full source code, and then running this code.

### Optional arguments

Help about individual modes is printed if no code is specified:

~~~~
$ pysln -t lines
Help for the 'lines' mode ...
~~~~

 * **`-n`**: Show the result of the transformed code, but do not execute.
 * **`-b`**: Show the result of the transformed and injected code, but do not execute.
 * **`-t XXX`**: use _`XXX`_ mode.

### Passing command-line arguments

Command-line arguments to `pysln` can be passed to the running script with the **`-X`** optional argument.
The argument vector (list) of the invocation is available inside the script as `ARGS`.

~~~~
$ pysln -X "username" -X "$(date)" 'print(ARGS[1], ARGS[2])'
username "Sun 14 Feb 2021 14:02:33"
~~~~


Usage modes
-----------

### `bare` mode

The bare mode does not perform any pre-parsing or business logic.
This is the default mode when the standard input is a terminal, and not a pipe.
The variables `STDIN`, `STDOUT`, and `STDERR` alias `sys.stdin`, `sys.stdout`, and `sys.stderr`, respectively.

### `lines` mode

Lines mode allows handling each line of the standard input.
This is the default mode if the standard input comes from a pipe.
The values are available through the `LINE` variable.

The functions `OUT` and `ERR` print the arguments verbatim to the standard output and error respectively, without adding an additional trailing newline.

#### FizzBuzz

~~~~
$ seq 1 15 | pysln 'if int(LINE) % 15 == 0: print("Fizzbuzz"); ' \
    'elif int(LINE) % 3 == 0: print("Fizz");' \
    'elif int(LINE) % 5 == 0: print("Buzz");' \
    'else: print(LINE); endif'
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
Fizzbuzz
~~~~

### `csv` mode

The input stream is loaded and parsed as a [CSV](http://docs.python.org/3.6/library/csv.html) file, with each row made available as `ROW`.
The `HEADER()` function returns `True` if the first row is in `ROW`.
After the user's code is executed and the rows are transformed one by one, the resulting CSV is printed to the standard output.

~~~~
$ echo -e "Foo,Bar,Baz\n1,2,3\n4,5,6" | \
    pysln -t csv 'for idx, elem in enumerate(ROW): ' \
        'if not HEADER(): ROW[idx] = int(elem) * 10; endif; endfor;'
Foo,Bar,Baz
10,20,30
40,50,60
~~~~

### `json` mode

The input stream is loaded and parsed as a [JSON](http://json.org), and made available as `DATA`.
This mode is aimed at implementing JSON filters and transformers.
After the user's code executed, the JSON is formatted and printed to the standard output.

#### JSON filter

~~~~
$ echo '[{"Timezone": "Europe/London"}, {"Timezone": "America/New York"}]' | \
    pysln -t json 'for rec in DATA: for k, v in dict(rec).items(): ' \
        'if k == "Timezone": split = v.split("/"); ' \
        'rec["Country"] = split[0]; rec["City"] = split[1]; del rec["Timezone"]; ' \
        'endif; endfor; endfor;'
[{"Country": "Europe", "City": "London"}, {"Country": "America", "City": "New York"}]
~~~~

The JSON mode also offers the `PRETTY()` function, which turns out formatted JSON output:

~~~~
$ echo '[{"Timezone": "Europe/London"}, {"Timezone": "America/New York"}]' | \
    pysln -t json 'for rec in DATA: for k, v in dict(rec).items(): ' \
        'if k == "Timezone": split = v.split("/"); ' \
        'rec["Country"] = split[0]; rec["City"] = split[1]; del rec["Timezone"]; ' \
        'endif; endfor; endfor; ' \
        'PRETTY();'
[
    {
        "City": "London",
        "Country": "Europe"
    },
    {
        "City": "New York",
        "Country": "America"
    }
]
~~~~


Syntax
------

The code given to `pysln` is generally the same as normal Python code, except for a few key differences:

 * **Lines are terminated by `;` (semicolon)**, instead of a newline. Newlines still work, but the entire idea is to not deal with newlines.
 * Due to not dealing with newlines and whitespace, the indentation-based "scoping" is also side-stepped:
    * Everything that would begin a scope and require indented code is instead closed with an `end___` keyword.
    * For example: `if X: print(X); endif;`, `while True: pass; endwhile;`, `def identity(a): return a; enddef`.

Everything else in-between is expected to behave as it would in Python.

            

Raw data

            {
    "_id": null,
    "home_page": "http://github.com/whisperity/py-singleline",
    "name": "py-singleline",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": "",
    "keywords": "python shell pipeline script scripting",
    "author": "Whisperity",
    "author_email": "whisperity-packages@protonmail.com",
    "download_url": "https://files.pythonhosted.org/packages/99/21/3c3fd9b0be797d145b7e1f39dfac57814234045ea166235983586d6d48f0/py-singleline-1.0.0a2.tar.gz",
    "platform": null,
    "description": "Arbitrarily complex single-line Python scripts\n==============================================\n\n**`pysln`** allows executing \"Python\"-ish scripts in the command line as parts of a pipeline.\n\n_Why?_ Normally, the Python binary allows executing Python script specified in the command-line, but you have to write a proper Python script:\n\n~~~~\npython3 -c 'import json\nprint(json.dumps({0: 1}))\n'\n~~~~\n\nThis may make shell history unreadable, hard to edit, etc.\n\nIn addition, accessing information in a pipe, common with most command-line tools, is convoluted.\nWhile you can easily say `some-command-generating-data | grep Foo | awk '{ print $2; }'`, doing a similar thing for data processing in Python is really hard, requiring you to open an editor, save a script file.\n\n**`pysln`** takes this need off for **quick and dirty** command-line data processing.\n\nInstallation\n------------\n\nInstall from [PyPI](http://pypi.org/project/pysln/).\nThe `pysln` entry point will be made available.\n\n~~~\n$ pip3 install pysln\n$ pysln -h\nusage: pysln [-h] [...]\n~~~\n\nOverview\n--------\n\nUse `pysln` just like you would use `sed` or `awk` in a pipe.\nAfter the optional flags, specify the code to execute:\n\n~~~~\n$ seq 1 5 | pysln 'print(int(LINE) * 2);'\n2\n4\n6\n8\n10\n~~~~\n\n_Py-SingleLine_ works by first *transcoding* the input code to real Python syntax, then *injecting* this input into a context, forming a full source code, and then running this code.\n\n### Optional arguments\n\nHelp about individual modes is printed if no code is specified:\n\n~~~~\n$ pysln -t lines\nHelp for the 'lines' mode ...\n~~~~\n\n * **`-n`**: Show the result of the transformed code, but do not execute.\n * **`-b`**: Show the result of the transformed and injected code, but do not execute.\n * **`-t XXX`**: use _`XXX`_ mode.\n\n### Passing command-line arguments\n\nCommand-line arguments to `pysln` can be passed to the running script with the **`-X`** optional argument.\nThe argument vector (list) of the invocation is available inside the script as `ARGS`.\n\n~~~~\n$ pysln -X \"username\" -X \"$(date)\" 'print(ARGS[1], ARGS[2])'\nusername \"Sun 14 Feb 2021 14:02:33\"\n~~~~\n\n\nUsage modes\n-----------\n\n### `bare` mode\n\nThe bare mode does not perform any pre-parsing or business logic.\nThis is the default mode when the standard input is a terminal, and not a pipe.\nThe variables `STDIN`, `STDOUT`, and `STDERR` alias `sys.stdin`, `sys.stdout`, and `sys.stderr`, respectively.\n\n### `lines` mode\n\nLines mode allows handling each line of the standard input.\nThis is the default mode if the standard input comes from a pipe.\nThe values are available through the `LINE` variable.\n\nThe functions `OUT` and `ERR` print the arguments verbatim to the standard output and error respectively, without adding an additional trailing newline.\n\n#### FizzBuzz\n\n~~~~\n$ seq 1 15 | pysln 'if int(LINE) % 15 == 0: print(\"Fizzbuzz\"); ' \\\n    'elif int(LINE) % 3 == 0: print(\"Fizz\");' \\\n    'elif int(LINE) % 5 == 0: print(\"Buzz\");' \\\n    'else: print(LINE); endif'\n1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzbuzz\n~~~~\n\n### `csv` mode\n\nThe input stream is loaded and parsed as a [CSV](http://docs.python.org/3.6/library/csv.html) file, with each row made available as `ROW`.\nThe `HEADER()` function returns `True` if the first row is in `ROW`.\nAfter the user's code is executed and the rows are transformed one by one, the resulting CSV is printed to the standard output.\n\n~~~~\n$ echo -e \"Foo,Bar,Baz\\n1,2,3\\n4,5,6\" | \\\n    pysln -t csv 'for idx, elem in enumerate(ROW): ' \\\n        'if not HEADER(): ROW[idx] = int(elem) * 10; endif; endfor;'\nFoo,Bar,Baz\n10,20,30\n40,50,60\n~~~~\n\n### `json` mode\n\nThe input stream is loaded and parsed as a [JSON](http://json.org), and made available as `DATA`.\nThis mode is aimed at implementing JSON filters and transformers.\nAfter the user's code executed, the JSON is formatted and printed to the standard output.\n\n#### JSON filter\n\n~~~~\n$ echo '[{\"Timezone\": \"Europe/London\"}, {\"Timezone\": \"America/New York\"}]' | \\\n    pysln -t json 'for rec in DATA: for k, v in dict(rec).items(): ' \\\n        'if k == \"Timezone\": split = v.split(\"/\"); ' \\\n        'rec[\"Country\"] = split[0]; rec[\"City\"] = split[1]; del rec[\"Timezone\"]; ' \\\n        'endif; endfor; endfor;'\n[{\"Country\": \"Europe\", \"City\": \"London\"}, {\"Country\": \"America\", \"City\": \"New York\"}]\n~~~~\n\nThe JSON mode also offers the `PRETTY()` function, which turns out formatted JSON output:\n\n~~~~\n$ echo '[{\"Timezone\": \"Europe/London\"}, {\"Timezone\": \"America/New York\"}]' | \\\n    pysln -t json 'for rec in DATA: for k, v in dict(rec).items(): ' \\\n        'if k == \"Timezone\": split = v.split(\"/\"); ' \\\n        'rec[\"Country\"] = split[0]; rec[\"City\"] = split[1]; del rec[\"Timezone\"]; ' \\\n        'endif; endfor; endfor; ' \\\n        'PRETTY();'\n[\n    {\n        \"City\": \"London\",\n        \"Country\": \"Europe\"\n    },\n    {\n        \"City\": \"New York\",\n        \"Country\": \"America\"\n    }\n]\n~~~~\n\n\nSyntax\n------\n\nThe code given to `pysln` is generally the same as normal Python code, except for a few key differences:\n\n * **Lines are terminated by `;` (semicolon)**, instead of a newline. Newlines still work, but the entire idea is to not deal with newlines.\n * Due to not dealing with newlines and whitespace, the indentation-based \"scoping\" is also side-stepped:\n    * Everything that would begin a scope and require indented code is instead closed with an `end___` keyword.\n    * For example: `if X: print(X); endif;`, `while True: pass; endwhile;`, `def identity(a): return a; enddef`.\n\nEverything else in-between is expected to behave as it would in Python.\n",
    "bugtrack_url": null,
    "license": "GPLv3+",
    "summary": "Arbitrarily complex single-line Python scripts",
    "version": "1.0.0a2",
    "project_urls": {
        "Homepage": "http://github.com/whisperity/py-singleline"
    },
    "split_keywords": [
        "python",
        "shell",
        "pipeline",
        "script",
        "scripting"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1a5fead373ff97cadd1ea11e8aef92ccadca33be68993e2abbb2fc9ec4394ec3",
                "md5": "39d5c381800aa225b3db381f11042b90",
                "sha256": "025403648edaf2df94b9a20dcb9736d38c514ef1c6b50c705a03f9c129824dff"
            },
            "downloads": -1,
            "filename": "py_singleline-1.0.0a2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "39d5c381800aa225b3db381f11042b90",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6",
            "size": 35351,
            "upload_time": "2023-09-21T07:43:06",
            "upload_time_iso_8601": "2023-09-21T07:43:06.704000Z",
            "url": "https://files.pythonhosted.org/packages/1a/5f/ead373ff97cadd1ea11e8aef92ccadca33be68993e2abbb2fc9ec4394ec3/py_singleline-1.0.0a2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "99213c3fd9b0be797d145b7e1f39dfac57814234045ea166235983586d6d48f0",
                "md5": "f804e5cadb723f96096fd2f4c12d2945",
                "sha256": "c9cd3dc906dbb2ad6c0abdb5df8b6ef135dc92419cc52ca3a0ffde131da502d9"
            },
            "downloads": -1,
            "filename": "py-singleline-1.0.0a2.tar.gz",
            "has_sig": false,
            "md5_digest": "f804e5cadb723f96096fd2f4c12d2945",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 27143,
            "upload_time": "2023-09-21T07:43:08",
            "upload_time_iso_8601": "2023-09-21T07:43:08.644508Z",
            "url": "https://files.pythonhosted.org/packages/99/21/3c3fd9b0be797d145b7e1f39dfac57814234045ea166235983586d6d48f0/py-singleline-1.0.0a2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-09-21 07:43:08",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "whisperity",
    "github_project": "py-singleline",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "py-singleline"
}
        
Elapsed time: 0.11907s