PK!w&&pyfil.py#!/usr/bin/env python3 ''' Use python as a filter on stdin. If the expression iterator, print each item on its own line. If the value is a builtin container type, attempt to serialize it as json before printing. pyfil automatically imports any modules used in expressions. If you'd like to create any other objects to use in the execution environment ~/.config/pyfil-env.py and put things in it. default objects: l = [] d = {} These are empty containers you might wish to add items to during iteration, for example. x is always the return value of the previous expression unless --exec. The execution environment also has a special object for stdin, creatively named "stdin". This differs from sys.stdin in that it removes trailing newlines when you iterate over it, and it has a property, stdin.l, which returns a list of the lines, rather than an iterator. Certain other flags; --loop (or anything that implies --loop), --json, --split or --field_sep; may create additional objects. Check the flag descriptions for further details. Home: https://github.com/ninjaaron/pyfil ''' import collections import sys import json import os import re import ast import argparse from functools import update_wrapper class LazyDict(dict): __getattr__ = dict.__getitem__ __setattr__ = dict.__setattr__ __delattr__ = dict.__delitem__ class reify(object): '"stolen" from Pylons' def __init__(self, wrapped): self.wrapped = wrapped update_wrapper(self, wrapped) def __get__(self, inst, objtype=None): if inst is None: return self val = self.wrapped(inst) setattr(inst, self.wrapped.__name__, val) return val class NameSpace(dict): 'namespace that imports modules lazily.' def __missing__(self, name): try: return __import__(name) except ImportError: raise NameError("name '{}' is not defined".format(name)) class StdIn: 'class for wrapping sys.stdin' def __init__(self): self.lines = (line.rstrip('\n') for line in sys.stdin) def __iter__(self): return self.lines @reify def l(self): return sys.stdin.read().splitlines() def __next__(self): return next(self.lines) def __getattr__(self, name): return getattr(sys.stdin, name) class SafeList(collections.UserList): 'class for getting fields from stdin without raising errors' def __getitem__(self, index): try: return self.data[index] except IndexError: return '' def __iter__(self): return iter(self.data) def handle_errors(exception, args): 'stupid simple error handling' if args.raise_errors: raise exception elif args.silence_errors: pass else: print( '\x1b[31m{}\x1b[0m:'.format(exception.__class__.__name__), exception, file=sys.stderr ) class SafeListEncode(json.JSONEncoder): def default(self, obj): if isinstance(obj, SafeList): return obj.data return json.JSONEncoder.default(self, obj) def print_obj(obj, indent=None): "print strings, serialize other stuff to json, or don't" if isinstance(obj, str): print(obj) else: try: print(json.dumps(obj, ensure_ascii=False, indent=indent, cls=SafeListEncode)) except TypeError: print(obj) def run(expressions, args, namespace={}): func = exec if args.exec else eval for expr in expressions: if args.exception_handler: exception, handler = tuple( i.strip() for i in args.exception_handler.split(':', maxsplit=1)) try: value = func(expr, namespace) except __builtins__[exception]: try: value = func(handler, namespace) except Exception as e: value = handle_errors(e, args) continue except Exception as e: value = handle_errors(e, args) continue else: try: value = func(expr, namespace) except Exception as e: value = handle_errors(e, args) continue if not args.exec: namespace.update(x=value) if not (args.quiet or args.exec): if args.join is not None and isinstance(value, collections.Iterable): print(ast.literal_eval("'''" + args.join.replace("'", r"\'") + "'''").join(map(str, value))) elif value is None: pass elif isinstance(value, collections.Iterator): for i in value: print_obj(i) else: indent = None if (args.loop or args.force_oneline_json) else 2 print_obj(value, indent) def main(): ap = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) ap.add_argument('expression', nargs='+', help='expression(s) to be ' 'executed. If multiple expression arguments are given, ' 'and --exec is not used, the value of the previous ' "expression is available as 'x' in the following " 'expression. if --exec is used, all assignment must be ' 'explicit.') ap.add_argument('-l', '--loop', action='store_true', help='for n, i in enumerate(stdin): expressions') ap.add_argument('-x', '--exec', action='store_true', help='use exec instead of eval. statements are allowed, ' 'but automatic printing is lost. ' "doesn't affect --post") ap.add_argument('-q', '--quiet', action='store_true', help="suppress automatic printing. doesn't affect --post") ap.add_argument('-j', '--json', action='store_true', help="load stdin as json into object 'j'; If used with " '--loop, treat each line of stdin as a new object') ap.add_argument('-J', '--real-dict-json', action='store_true', help='like -j, but creates real dictionaries instead of ' 'the wrapper that allows dot syntax.') ap.add_argument('-o', '--force-oneline-json', action='store_true', help='outside of loops and iterators, objects serialzed ' 'to json print with two-space indent. this forces ' 'this forces all json objects to print on a single ' 'line.') ap.add_argument('-b', '--pre', help='statement to evaluate before expression args. ' "multiple statements may be combined with ';'. " 'no automatic printing') ap.add_argument('-e', '--post', help='expression to evaluate after the loop. always ' 'handeled by eval, even if --exec, and always prints ' 'return value, even if --quiet. implies --loop') ap.add_argument('-s', '--split', action='store_true', help="split lines from stdin on whitespace into list 'f'. " 'implies --loop') ap.add_argument('-F', '--field-sep', metavar='PATTERN', help="regex used to split lines from stdin into list 'f'. " "implies --loop") ap.add_argument('-n', '--join', metavar='STRING', help='join items in iterables with STRING') ap.add_argument('-R', '--raise-errors', action='store_true', help='raise errors in evaluation and stop execution ' '(default: print message to stderr and continue)') ap.add_argument('-S', '--silence-errors', action='store_true', help='suppress error messages') ap.add_argument('-H', '--exception-handler', help='specify exception handler with the format ' "'Exception: alternative expression to eval'") a = ap.parse_args() func = 'exec' if a.exec else 'eval' expressions = [compile( e if a.exec else "(%s)" % e, '', func) for e in a.expression] user_env = os.environ['HOME'] + '/.config/pyfil-env.py' namespace = NameSpace(__builtins__) namespace.update(stdin=StdIn(), l=[], d={}) if os.path.exists(user_env): exec(open(user_env).read(), namespace) if a.json: jdecode = json.JSONDecoder(object_hook=LazyDict).decode elif a.real_dict_json: jdecode = json.loads a.json = True if a.post or a.split or a.field_sep: a.loop = True if a.loop: if a.pre: exec(a.pre, namespace) for n, i in enumerate(map(str.rstrip, sys.stdin)): namespace.update(i=i, n=n) if a.json: namespace.update(j=jdecode(i)) if a.field_sep: if len(a.field_sep) == 1: f = SafeList(i.split(a.field_sep)) else: f = SafeList(re.split(a.field_sep, i)) namespace.update(f=f) elif a.split: namespace.update(f=SafeList(i.split())) run(expressions, a, namespace) if a.post: if a.quiet or a.exec: a.loop, a.quiet, a.exec = None, None, None run(('(%s)' % a.post,), a, namespace) else: if a.pre: exec(a.pre, namespace) if a.json: namespace.update(j=jdecode(sys.stdin.read())) run(expressions, a, namespace) if __name__ == '__main__': main() PK!HH'3&pyfil-1.9.2.dist-info/entry_points.txtN+I/N.,()*ḺVy\E\.PK!rW|pyfil-1.9.2.dist-info/LICENSECopyright (c) 2016, Aaron Christianson All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PK!H STTpyfil-1.9.2.dist-info/WHEEL 1 0 нR. \I$ơ7.ZON `h6oi14m,b4>4ɛpK>X;baP>PK!HSpyfil-1.9.2.dist-info/METADATA\mƑlUtv|yYRIr+IAbHbh,v~=\YN%t{[[I\_mYE>1xm'f[Y޸} ^6u\&^)rfiA&MZ,kl2M0m8O|SmXeUכjr|LU38O8.XAxm^aW/GYT6xrbry*ӪN*rw+8&OK^ c ';毪tZL6y&KaPjY!6kLJGO̢,ֲ.Zkh&Ob,:nǘh+%ZKٸ*(5-0/i@IIL( t.j!Q[ᢙ&V+a&'yT Q>1YZϞ[L:}LߠUa!ƞ4=N_'h |)J`N31s0&`@`q0"E9e8 ZpRYN$I-[eUU(Fxl@bg)Uf$ΞB!U:ޅ9HDϨ*nXyf-1&hؒJ(,`4[Ge ;MF1d% Pl٥̋h8 'L9X7Y~0!XD" Rn&΍ ~Vtٰ{ƅ BivNpt1QjOze\pve-6>HDbtpDyPѫwΫͣmzfJ8*1}x,bst$tuJ h·,R8E~lU(e ӂMŖnl=/EE $5 %ťz ePZ͎+<.(KX%}"_@=~ e"tTE.AFe{= \lnQGK&żsL cyOΡ"2n0ƍ'qv˙>s V*nh^l/uo>}EL8}-C|/Ty_( 1UF斿v=ezis0TmPO^E:3XVck6(Jjf[YVl)U<gv +=TRK(bs!<0Tj!@ PH-{|.sYQ=Gu DXXT&=*p5+9MB:S^"60&HxSu w/HI(|VM j0o f?.,Z"F?0{:;ߠTV-urWs9bJbc8ӟ&ۯS?"$61LќY"הx햼e`H !$KEA(,sm@r5u$N P\H*J8H_<̟$u2YpEXm9<EF[$uVvSojCM^/)Ge0|'w܏ %n'-wn"軎oɳ9!W1v._twx-@-Y8r ryzx9ǘS.NIE)$ ?u1MxUD=4\~6+g `1n播QVv/:QiJu A^Vǀk D g bgtⴲ-KH`}PQ2ԍ3.b 7U$N֧ycGl6|w;uQ5%KgnNF 09r4S?drcN".aA8_?l*A $s~ܲΠ8Po8pD%pɽoHq/4H/am~ 2G->$/AJBj:H캴E%1:]hdq6sl ұx:.q+?!%a\m(P>9 Cd~س<^cS3jzIŮPK ULXuP݂;)NҺM f _~(c\s%UG(KF>+ĽI!b\-IZthdtƋ:N_) Tz0dNEIBAcΒ[GFL!⥚c/I!/^&ZeHJ.sZiVA7oOiN )AO{y鹿S;{h1BVv~ 0DZY4X Q-hi_8YCɾ2!4SI. }/5M] ӧIA6ɝ3$T2yqC\Qz.OL7@W͐*O6s7G}Gz8ה.2%Dnb֌cW'UViO P-rbk/+b-7ewi B9Ϣ .UDG5 %piy2 Qq޸MnQJCQ"0Jj@PZ*q#q 4kmj`_ΐeE+*:熵 |FspT{P/n&ļ݆M+'w|v'>ZS_vxN,1koWQV9Fr4v#<ҙ*<~J7݌~{[rF0?WcB#38 {ۣtb*x_xAsbNKʼn{;!'އib(?Oԉy5sc~q|/4P>^3+ޒ xs|1kҬL&OzfPځj ˷.l|~x}ǃ3vA$ӧ*H]cLqIR8>4G^q=& og>9i$pp<;y+$´GG\hl5mWL\da y 蝞gw_ۗ߆E&ԷA-FR>}eH\\SoikGY./90Wd?%$[-il/*{OZGhTKS7g/ m ,%ǦL s6XpBb26HSC U)kBE{2dzBF|2ݒzf1Wtq)}4hB$; hPX< rm6s_IGB.jykPg5յYBgLE%aэ葇\xFƇ(0ձ%3+2"7PT+(j*p*O5\nW)Wީ.p[Y2Z5T$ ` 2.U% X8b|+·EHr T `@ߓdFÊnn.׫^e>v>CA 4g>ms6*7ͽ셽nZN0ḽ˲'J8@V8`AUMw&iWBg߁2kWEUd~JHS[ۓXJ Q%i%-6ʗDn򂾓(NJ0+@e4H1ZmsM} @Z:YLiNvbUyv~4@ z2WіDpRcܱ3Qt-.)кE%`@4I i띩a8SbGn= F:Xxٿ侜Ӗj5nY#೭eޚnvװWJjeuYݯ!4}i1+g pZ]+xmEZ \X]Elf%D6.sirua;ZYݭ~y6"~'& VN.$$ږT)2ҳp U檄ԳҰo~lPZ`ujsI\ӂ9@dfYԼ2U'.%U\9"Ն /Wa$A$k. *AYv1#pqKmHEI|׭\<\צ"0f-P{Wj/մWļ?*kM},'>ichz2+Z6᩸%[W-#+:TضM'U~hA7u^x|2LED@aHLXŢۓ!PfM' A2V^8$ tU,rZ]𧺳:^SmJ(A@]繡4 aL1Zl{Uu8%Rm>,;;ǗO9r ?^Hn録yJ1hRRKB8UVnGeQiV.ᥐUCm=?tYkYpnO5N+{vص(Gi Ժ jý4U6s|nA1!(Z{]; ٜ5+49"KS2H\LͰ(/`3uk-Fε.ڰU/6w!;zp`ݏ7_=G'vMS߲Li7{RBbJXSu, Ԉ4{d뢎>7,WJz{=r:u*_`"Օcn}2+;_Ռ?akcG"^^ZFg7,is?&OiiCx1ljz]d9l_ms6݂PWeNZhcrdê-~ACqCSAz;+}nM׿<3){j#QމI(hz\;͏/app(t&Lgnb~lh=5i8uRdד̓ F[?ݚO‘ɧoG2:\bl zޣSߞFp& PpDX}ߎѯܫ[=T9",a_7^—VjA7}*~q- v>xM?كgu_D< <٣ӧ/O <1wO&'n䎣&`s4:c4ӞUA}MEe(&m(]1}Q ^]򒯈d7D< T5U~0j=[dEhr)2lJ3WMVaIp/pz̗zG1MoCs,2x~E;{n֟w1K;C4 Yέ20 [)| ЅPrCbMr9~1D<-Kŭ<tg2)fR&o=-C6҂s_Lk`}+JW9ѹ^@<#x컿>]NDZ)w6-@vCww=/p^#iHHݿ'ucqܗ将[Mpm[\V*';=>⿊νkh*B/4:G|Py6;g\\u(OA$p( ]yG\ȏxJ`$0#02y*iviMftWXcq,NFcWՆ :{]!9d}Lr$kNY\gP櫢y'kS{DWҴlΦH_߈Uh`Egimk_/.'ށb,~ M:.V%ԟm \ /%C8]>7+1]c ?7HUJyY _ (Hԉ:wZwcWdQ2v88cUMnOjn,^APK!HyK'pyfil-1.9.2.dist-info/RECORDuIv0нgA`Xt! Ȱ)<}_,퐗-. ~&ziS94H'GI撨 1-)$o>2žC6%aTd=Kp qkAVژq*e+Sا-4[