Package: pjy
pjyis a command-line tool to process JSON data and execute queries on it.
It is a bit likejqbut with a Python syntax for queries.InstallFromPyPI:pip install pjyUsagepjy [EXPR] [FILES]pjywill read JSON data fromFILESand print the evaluation result of the Python expressionEXPR.IfFILESis missing or is “-”, pjy will use stdin.The simplest expression to use, which outputs the input unchanged is “d” (for data).It’s possible to use multiple input files.ExamplesInpjy, expressions are also called “filters”, as injq.Just pretty-printd(short for “data”) is the most basic filter, it represents the whole input:pjy 'd'
    {"foo":"bar","baz":[1,2,3]}Prints:{
  "foo": "bar",
  "baz": [
    1,
    2,
    3
  ]
}Select a dict keyThe filters are Python expressions, hence we can select a dict key:pjy 'd["baz"]'
    {"foo":"bar","baz":[1,2,3]}Alternatively, inpjy, dicts keys are also attributes:pjy 'd.baz'
    {"foo":"bar","baz":[1,2,3]}Both filters will print:[
  1,
  2,
  3
]In case a key has a reserved name, likeimport(keyword) orkeys(dict method), simply use the bracket form.Non-existent keysNon-existent keys:pjy 'd.baz'
    {"foo":"bar"}will returnNone:nullSame for out-of-bounds indices:pjy 'd[3]'
    [1, 2]Do a basic operationIt’s possible to use everything that a Python expression can contain:pjy '[i + 1 for i in d["baz"]]'
    {"foo":"bar","baz":[1,2,3]}Prints:[
  2,
  3,
  4
]Lambda-placeholderA special identifier,_can be used to create lambdas. This identifier will absorb most operations done to it and return a lambda applying them.
Then, the returned lambda can be applied:pjy 'map(_ + 1, d.baz)'
    {"foo":"bar","baz":[1,2,3]}Is equivalent to:pjy 'map((lambda x: x + 1), d.baz)'
    {"foo":"bar","baz":[1,2,3]}Which will print:[
  2,
  3,
  4
]The lambda-placeholder will absorb chained operations:pjy 'map((_ + 1) * 2, d.baz)'
    {"foo":"bar","baz":[1,2,3]}Will result in:[
  4,
  6,
  8
]And:pjy 'map(_[1:3] * 2, d)'
    {"foo":"bar","baz":[1,2,3]}Will return:{
  "foo": "arar",
  "baz": [
    2,
    3,
    2,
    3
  ]
}Pipe-like iterationThe pipe (|) can be used to iterate on a list, it accepts a function as right operand:pjy 'd.baz | _ + 1'
    {"foo":"bar","baz":[1,2,3]}Which prints:[
  2,
  3,
  4
]It also operates on a dict’s values, and returns a dict:pjy 'd | (lambda x: repr(x))'
    {"foo":"bar","baz":[1,2,3]}The values are replaced by the right operand value, the keys are unchanged:{
  "foo": "'bar'",
  "baz": "[1, 2, 3]"
}Ampersand for filteringSimilar to the pipe, the ampersand (&) is used on a list and a function, but its purpose is to filter:pjy 'd & (_ % 2 == 0)'
    [0, 1, 2, 3]outputs:[
  0,
  2
]Which is equivalent to running:pjy 'filter(_ % 2 == 0, d)'
    [0, 1, 2, 3]Like the pipe, it works on a dict, and the filter is applied on the dict values.Partial placeholderIt’s not possible to call a function on a placeholder, for example,len(_)will not work.
However, it’s possible to use thepartialhelper to prepare the function call:pjy 'd | partial(len, _)'
    {"foo":"bar","baz":[1,2,3]}Prints:{
  "foo": 3,
  "baz": 3
}partialressembles thefunctools.partialfunction: it returns a function wrapping the function passed as first argument.
The returned function will call the original function with the fixed arguments passed.
The difference is that lambda-placeholders can be passed, and they will be replaced by the wrapper’s argument.pis a short alias for thepartialfunction which can be used in pjy expressions.ImportsIt’s possible to import modules with theimpfunction:pjy 'filter(p(imp("fnmatch").fnmatch, _, "f*"), d.keys())'
     {"foo":"bar","baz":[1,2,3]}Will print:[
  "foo"
]Themathandremodules are already imported and available directly without having to callimp.Multiple inputsInpjy, aninputsvariable exists, which is a list containing the JSON data of each input file passed on the command line.
Thedvariable is simply an alias toinputs[0].For example:pjy 'filter(_[0] != _[1], zip(inputs[0], inputs[1]))' before.json after.jsonwill read 2 filesbefore.jsonandafter.json, which consist in a list of objects, andpjywill compare each zipped-pair of objects together.
Then it will print the list of differing pairs.OptionsInput options--null-inputDon’t read any input, act as if the input was onlynull.--argVAR VALUEInject a variable named VAR with a VALUE in the expression.Output options--monochrome-outputForce no colors even if output is a TTY. Can also setNO_COLORenvironment variable to do the same.--ascii-outputWhen outputting non-ASCII strings, use\uXXXXnotation instead of directly Unicode characters by default.--tabIndent output with tabs instead of 2 spaces.--indentNIndent output with N spaces instead of 2 spaces.--compact-outputDon’t indent output and don’t add extra whitespace between key/values and list elements.Environment variablesNO_COLOR: set it to disable colors even if output is a TTY.CLICOLOR_FORCE: set it to enable colors even if output is not a TTY.Securitypjyby itself does not write files (except stdout/stderr) or sockets, or run external commands.
However,pjyruns the given expressions passed as argument, in the Python interpreter, without a sandbox.
Hence, do NOT pass dangerous or untrusted Python expressions topjy.Dependenciespjyis written in Python 3. Itssetup.pyrequiressetuptools.Ifpygmentsis installed,pjy’s output will be colorized, but it’s entirely optional.Version and licensepjyis at version 0.13.0, it usessemantic versioning.
It is licensed under the WTFPLv2, see COPYING.WTFPL for license text.