From 16f16b9c6a06a39af02d282d46e12edbcfac9cf9 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 00:41:27 -0700 Subject: [PATCH 001/173] Changed license to MIT. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 82f664a..5fbedfb 100644 --- a/setup.py +++ b/setup.py @@ -6,6 +6,6 @@ version='0.1.5', description='Command line utility for Python', scripts=[os.path.join('bin', 'pythonpy')], - license='Creative Commons Attribution-Noncommercial-Share Alike license', + license='MIT', long_description=open('README.rst').read(), ) From 7ee3e62bd6d82476e3f76f596694d2a7059c3c97 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 11:30:24 -0700 Subject: [PATCH 002/173] 0.1.6 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5fbedfb..2bd295f 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.1.5', + version='0.1.6', description='Command line utility for Python', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From 148b562b9107bd4a4ab801405dab62794e0c6033 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 11:37:39 -0700 Subject: [PATCH 003/173] Fixed readme issue for 0.1.7 --- MANIFEST | 2 +- setup.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MANIFEST b/MANIFEST index 69e500c..c217127 100644 --- a/MANIFEST +++ b/MANIFEST @@ -2,4 +2,4 @@ README.txt setup.py bin/pythonpy -pythonpy/__init__.py +test/test_pythonpy.py diff --git a/setup.py b/setup.py index 2bd295f..2ecc3c4 100644 --- a/setup.py +++ b/setup.py @@ -3,9 +3,9 @@ setup( name='pythonpy', - version='0.1.6', + version='0.1.7', description='Command line utility for Python', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', - long_description=open('README.rst').read(), + #long_description=open('README.rst').read(), ) From 8c0f6d95a1cd20600f96bd05e3ba6787f1d05538 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 11:42:03 -0700 Subject: [PATCH 004/173] Added readme back to setup.py --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 2ecc3c4..0be56af 100644 --- a/setup.py +++ b/setup.py @@ -3,9 +3,9 @@ setup( name='pythonpy', - version='0.1.7', + version='0.1.8dev', description='Command line utility for Python', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', - #long_description=open('README.rst').read(), + long_description=open('README.txt').read(), ) From 031dc71ea697d3b10c666e1920ba324158e891d7 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 11:50:56 -0700 Subject: [PATCH 005/173] Added README.txt back to setup.py for 0.1.8 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0be56af..182634a 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.1.8dev', + version='0.1.8', description='Command line utility for Python', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From eda9fc713b8a29d0e3d754a7885273be30907428 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 16:22:48 -0700 Subject: [PATCH 006/173] Changed initial example in README to be more interesting. --- README.txt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/README.txt b/README.txt index 27aef0c..80d6a2f 100644 --- a/README.txt +++ b/README.txt @@ -1,13 +1,9 @@ # install sudo pip install pythonpy; alias py='pythonpy' -# float arithmetic -$ py '3 * 1.5' -4.5 - -# exponentiation -$ py '7**3' -343 +# arithmetic +$ py '24 * 60 ** 2' +86400 # number sequence $ py 'range(3)' From f94a5e33cfaf73934819704cd5833af1d8666982 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 16:25:02 -0700 Subject: [PATCH 007/173] Added floating point example back to readme. --- README.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.txt b/README.txt index 80d6a2f..0e22ea5 100644 --- a/README.txt +++ b/README.txt @@ -5,6 +5,10 @@ sudo pip install pythonpy; alias py='pythonpy' $ py '24 * 60 ** 2' 86400 +# floating point numbers +$ py '1.0/98' +0.010204081632 + # number sequence $ py 'range(3)' 0 From 2012ebdfb2c3ced75c09d528e2f50b97f36a3832 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 16:29:33 -0700 Subject: [PATCH 008/173] Updated README.rst to match README.txt --- README.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index ceab535..07e4751 100644 --- a/README.rst +++ b/README.rst @@ -15,23 +15,23 @@ For a permanent alias (For Bash users): :: -Float arithmetic +Arithmetic ---------------- :: - $ py '3 * 1.5' - 4.5 + $ py '24 * 60 ** 2' + 86400 :: -Exponentiation +Floating point -------------- :: - $ py '7**3' - 343 + $ py '1.0/98' + 0.010204081632 :: From 9307b2f80b9c7383f65b5912904227a6f7f42e33 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 19:27:00 -0700 Subject: [PATCH 009/173] Changed -sv system to --si and --so system This will make it easier to understand --so and --si as they behave analogously to --jo and --ji --- bin/pythonpy | 57 ++++++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index 4f03da5..896572a 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -13,34 +13,34 @@ import sys parser = argparse.ArgumentParser() parser.add_argument('evaluation', nargs='?', default='None') parser.add_argument('-c', '--cmd') -parser.add_argument('--ji' '--json_in', - dest='json_input', action='store_const', - const=True, default=False) -parser.add_argument('--jo' '--json_out', - dest='json_output', action='store_const', - const=True, default=False) parser.add_argument('-x' '--line_by_line', dest='line_by_line', action='store_const', const=True, default=False, help='sum the integers (default: find the max)') -parser.add_argument('-sv' '--split_values', - dest='split_values', - default=False, - help='sum the integers (default: find the max)') -parser.add_argument('-l', '--list_of_stdin', - dest='list_of_stdin', action='store_const', - const=True, default=False) parser.add_argument('-fx', '--filter', dest='filter_result', action='store_const', const=True, default=False) +parser.add_argument('-l', '--list_of_stdin', + dest='list_of_stdin', action='store_const', + const=True, default=False) parser.add_argument('--i', '--ignore_exceptions', dest='ignore_exceptions', action='store_const', const=True, default=False) +parser.add_argument('--si', '--split_input', dest='split_input') +parser.add_argument('--so', '--split_output', dest='split_output') +parser.add_argument('--ji' '--json_input', + dest='json_input', action='store_const', + const=True, default=False) +parser.add_argument('--jo' '--json_output', + dest='json_output', action='store_const', + const=True, default=False) args = parser.parse_args() if args.json_input: stdin = (json.loads(x.rstrip()) for x in sys.stdin) +elif args.split_input: + stdin = (re.split(args.split_input, x.rstrip()) for x in sys.stdin) else: stdin = (x.rstrip() for x in sys.stdin) @@ -67,21 +67,26 @@ elif args.list_of_stdin: result = eval(args.evaluation) elif args.filter_result: result = (x for x in stdin if eval(args.evaluation)) -elif args.split_values: - result = (eval(args.evaluation) for sv in - (re.split(args.split_values, x) for x in stdin)) else: result = eval(args.evaluation) +def format(output): + if output == None: + return None + elif args.json_output: + return json.dumps(output) + elif args.split_output: + return args.split_output.join(output) + else: + return output + + if hasattr(result, '__iter__'): for x in result: - if x is not None: - if args.json_output: - print json.dumps(x) - else: - print x -elif result is not None: - if args.json_output: - print json.dumps(result) - else: - print result + formatted = format(x) + if formatted: + print formatted +else: + formatted = format(result) + if formatted: + print formatted From 185c0a2c6264e449086f0bc649c6ef941cbf213a Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 19:45:54 -0700 Subject: [PATCH 010/173] Improved the help descriptions --- bin/pythonpy | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index 896572a..5739a03 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -12,28 +12,32 @@ import sys parser = argparse.ArgumentParser() parser.add_argument('evaluation', nargs='?', default='None') -parser.add_argument('-c', '--cmd') -parser.add_argument('-x' '--line_by_line', - dest='line_by_line', action='store_const', +parser.add_argument('-x', dest='lines_of_stdin', action='store_const', const=True, default=False, - help='sum the integers (default: find the max)') -parser.add_argument('-fx', '--filter', - dest='filter_result', action='store_const', - const=True, default=False) -parser.add_argument('-l', '--list_of_stdin', - dest='list_of_stdin', action='store_const', - const=True, default=False) + help='treat each row as x') +parser.add_argument('-fx', dest='filter_result', action='store_const', + const=True, default=False, + help='keep rows satisfying condition(x)') +parser.add_argument('-l', dest='list_of_stdin', action='store_const', + const=True, default=False, + help='treat list of stdin as l') +parser.add_argument('-c', dest='cmd', help='run code before expression') parser.add_argument('--i', '--ignore_exceptions', dest='ignore_exceptions', action='store_const', - const=True, default=False) -parser.add_argument('--si', '--split_input', dest='split_input') -parser.add_argument('--so', '--split_output', dest='split_output') + const=True, default=False, + help='') +parser.add_argument('--si', '--split_input', dest='split_input', + help='pre-process each row with re.split(delimiter)') +parser.add_argument('--so', '--split_output', dest='split_output', + help='post-process each row with delimiter.join(row)') parser.add_argument('--ji' '--json_input', dest='json_input', action='store_const', - const=True, default=False) + const=True, default=False, + help='pre-process each row with json.loads(row)') parser.add_argument('--jo' '--json_output', dest='json_output', action='store_const', - const=True, default=False) + const=True, default=False, + help='post-process each row with json.dumps(row)') args = parser.parse_args() @@ -52,7 +56,7 @@ if args.cmd: if args.cmd: exec(args.cmd) -if args.line_by_line: +if args.lines_of_stdin: if args.ignore_exceptions: def safe_eval(text, x): try: From b072a33b22de4c0b348c5550288de005c796cacb Mon Sep 17 00:00:00 2001 From: Low Kian Seong Date: Thu, 12 Jun 2014 15:48:27 +0800 Subject: [PATCH 011/173] Update setup.py I forgot to add this the other day for you, the url that links from pypi to github. --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 182634a..9aea9f0 100644 --- a/setup.py +++ b/setup.py @@ -8,4 +8,5 @@ scripts=[os.path.join('bin', 'pythonpy')], license='MIT', long_description=open('README.txt').read(), + url='https://github.com/Russell91/pythonpy', ) From 3c4a5f155ad5ad18a25aafee38dc8125e919477f Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 19:39:06 -0700 Subject: [PATCH 012/173] Changed back first to readme examples and changed rst formatting. --- README.rst | 33 +++++++++++++++++---------------- README.txt | 12 ++++++------ 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/README.rst b/README.rst index 07e4751..9805214 100644 --- a/README.rst +++ b/README.rst @@ -15,28 +15,29 @@ For a permanent alias (For Bash users): :: -Arithmetic ----------------- +Float Arithmetic +~~~~~~~~~~~~~~~~ :: - $ py '24 * 60 ** 2' - 86400 + $ py '3 * 1.5' + 4.5 + :: -Floating point --------------- +Exponentiation +~~~~~~~~~~~~~~ :: - $ py '1.0/98' - 0.010204081632 + $ py '7**3' + 343 :: Number sequence ---------------- +~~~~~~~~~~~~~~~ :: @@ -48,7 +49,7 @@ Number sequence :: List comprehensions -------------------- +~~~~~~~~~~~~~~~~~~~ :: @@ -61,7 +62,7 @@ List comprehensions :: Math library usage ------------------- +~~~~~~~~~~~~~~~~~~ :: @@ -71,7 +72,7 @@ Math library usage :: Random library usage --------------------- +~~~~~~~~~~~~~~~~~~~~ :: @@ -81,7 +82,7 @@ Random library usage :: Multiply each line of input by 7. ---------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: @@ -93,7 +94,7 @@ Multiply each line of input by 7. :: Append ".txt" to each line of input ------------------------------------ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: @@ -121,7 +122,7 @@ Reverse a list :: Sum a list of numbers ---------------------- +~~~~~~~~~~~~~~~~~~~~~ :: @@ -131,7 +132,7 @@ Sum a list of numbers :: Count the lines of input ------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~ :: diff --git a/README.txt b/README.txt index 0e22ea5..27aef0c 100644 --- a/README.txt +++ b/README.txt @@ -1,13 +1,13 @@ # install sudo pip install pythonpy; alias py='pythonpy' -# arithmetic -$ py '24 * 60 ** 2' -86400 +# float arithmetic +$ py '3 * 1.5' +4.5 -# floating point numbers -$ py '1.0/98' -0.010204081632 +# exponentiation +$ py '7**3' +343 # number sequence $ py 'range(3)' From e5f67714946c01b6afc3d1fd80bfe097ba08b639 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 20:49:09 -0700 Subject: [PATCH 013/173] Changed AttributeError to Error in README. --- README.rst | 2 +- README.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 9805214..a6b01bb 100644 --- a/README.rst +++ b/README.rst @@ -215,7 +215,7 @@ Get long palindromes :: -Ignore AttributeErrors if they pop up with (--i) +Ignore Errors if they pop up with (--i) ------------------------------------------------ Get the local network ip diff --git a/README.txt b/README.txt index 27aef0c..e98b613 100644 --- a/README.txt +++ b/README.txt @@ -98,7 +98,7 @@ kayak level ma'am -# ignore AttributeErrors if they pop up with (--i). +# ignore Errors if they pop up with (--i). # get the local network ip $ ifconfig | py -x --i 're.search(r"192\.168[\d\.]+", x).group()' 192.168.1.41 From 352785d7540ea8ddaf9f537341c59ce6bae08a54 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 20:51:24 -0700 Subject: [PATCH 014/173] Changed reverse a list example in readme. --- README.rst | 2 +- README.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index a6b01bb..b29d258 100644 --- a/README.rst +++ b/README.rst @@ -113,7 +113,7 @@ Reverse a list :: - $ py 'range(4)' | py -l 'sorted(l, reverse=True)' + $ py 'range(4)' | py -l 'l[::-1]' 3 2 1 diff --git a/README.txt b/README.txt index e98b613..7a4a606 100644 --- a/README.txt +++ b/README.txt @@ -44,7 +44,7 @@ $ py 'range(3)' | py -x 'x + ".txt"' # Sometimes you want to treat the input as a python list. # reverse a list -$ py 'range(4)' | py -l 'sorted(l, reverse=True)' +$ py 'range(4)' | py -l 'l[::-1]' 3 2 1 From 95dbdb1dd0034f6957c04484834eeebd60aa0d18 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 23:30:18 -0700 Subject: [PATCH 015/173] 0.1.9dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9aea9f0..42650a0 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.1.8', + version='0.1.9dev', description='Command line utility for Python', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From 4dcc2e26394c13ce6efc8099e264a4d28e15fda6 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 23:41:57 -0700 Subject: [PATCH 016/173] Relasing 0.2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 42650a0..5294fa6 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.1.9dev', + version='0.2.0', description='Command line utility for Python', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From 68a350bc348e57e6d65fab0a7daa4d1be86ef778 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 10 Jun 2014 23:45:34 -0700 Subject: [PATCH 017/173] Bugfix for not displaying values evaluating to False --- bin/pythonpy | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index 5739a03..357a95d 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -88,9 +88,9 @@ def format(output): if hasattr(result, '__iter__'): for x in result: formatted = format(x) - if formatted: + if formatted is not None: print formatted else: formatted = format(result) - if formatted: + if formatted is not None: print formatted diff --git a/setup.py b/setup.py index 5294fa6..28be197 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.0', + version='0.2.1', description='Command line utility for Python', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From 8832b72673add3d855006c37a2256169f5e25a30 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 22:44:13 -0700 Subject: [PATCH 018/173] Changed Error message in tutorial again. --- README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.txt b/README.txt index 7a4a606..e7e09f3 100644 --- a/README.txt +++ b/README.txt @@ -98,7 +98,7 @@ kayak level ma'am -# ignore Errors if they pop up with (--i). +# keep going if row raises Error with (--i). # get the local network ip $ ifconfig | py -x --i 're.search(r"192\.168[\d\.]+", x).group()' 192.168.1.41 From 339a9d156927449983fd43f7eab88825ed00198c Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 22:48:57 -0700 Subject: [PATCH 019/173] 0.2.2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 28be197..46ef54c 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.1', + version='0.2.2dev', description='Command line utility for Python', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From 360a0b655729d8e3a34cbf00c7b0afe5306d0e84 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 22:52:52 -0700 Subject: [PATCH 020/173] 0.2.2dev2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 46ef54c..0f4acbd 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.2dev', + version='0.2.2dev2', description='Command line utility for Python', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From 8fff08222fe275c725c7841feba5e73e4927ae34 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 22:57:01 -0700 Subject: [PATCH 021/173] Removed long_description from pip in favor of url only. --- setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 0f4acbd..d621fa2 100644 --- a/setup.py +++ b/setup.py @@ -4,9 +4,8 @@ setup( name='pythonpy', version='0.2.2dev2', - description='Command line utility for Python', + description='Take advantage of your python skills from the command line', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', - long_description=open('README.txt').read(), url='https://github.com/Russell91/pythonpy', ) From a01778e8cc00f0b79c4ac2d001cdb1fbd2252e3b Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 22:57:20 -0700 Subject: [PATCH 022/173] 0.2.2dev3 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d621fa2..b072c9d 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.2dev2', + version='0.2.2dev3', description='Take advantage of your python skills from the command line', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From 1c9e18af75aa090716afb17bc75601e21e8aad0f Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 22:59:03 -0700 Subject: [PATCH 023/173] Added blank long desciption to force pypi. --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index b072c9d..6539fe9 100644 --- a/setup.py +++ b/setup.py @@ -8,4 +8,5 @@ scripts=[os.path.join('bin', 'pythonpy')], license='MIT', url='https://github.com/Russell91/pythonpy', + long_description='', ) From 7c5f6ce0f627bad8f88c251c563012193f40a246 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 22:59:21 -0700 Subject: [PATCH 024/173] 0.2.2dev4 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6539fe9..e7c4a88 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.2dev3', + version='0.2.2dev4', description='Take advantage of your python skills from the command line', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From 0c6d2dc402978549beec9bc130bd2e66589f04ba Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 23:10:57 -0700 Subject: [PATCH 025/173] Brought rst and txt readmes into equivalence. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index b29d258..1402504 100644 --- a/README.rst +++ b/README.rst @@ -215,7 +215,7 @@ Get long palindromes :: -Ignore Errors if they pop up with (--i) +Keep going if some rows raise Errors with (--i). ------------------------------------------------ Get the local network ip From c24982983d4ef088b52fa07e59b8ff6fa2934ab9 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 23:33:49 -0700 Subject: [PATCH 026/173] Added safe_eval --i option to work for -fx in addition to -x mode. --- bin/pythonpy | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index 357a95d..bfc7671 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -56,21 +56,25 @@ if args.cmd: if args.cmd: exec(args.cmd) +def safe_eval(text, x): + try: + return eval(text) + except: + return None + if args.lines_of_stdin: if args.ignore_exceptions: - def safe_eval(text, x): - try: - return eval(text) - except: - return None result = (safe_eval(args.evaluation, x) for x in stdin) else: result = (eval(args.evaluation) for x in stdin) +elif args.filter_result: + if args.ignore_exceptions: + result = (x for x in stdin if safe_eval(args.evaluation, x)) + else: + result = (x for x in stdin if eval(args.evaluation)) elif args.list_of_stdin: l = list(stdin) result = eval(args.evaluation) -elif args.filter_result: - result = (x for x in stdin if eval(args.evaluation)) else: result = eval(args.evaluation) From 02b2c22a132c3d86756e22494e7ed53b4922b88b Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 23:34:25 -0700 Subject: [PATCH 027/173] Updated .gitignore to ignore .swp files. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5c1d549..1bcc247 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ dist *.pyc +*swp From 6b7c9312f3e07d05b7a64c07ad417de5b24b7972 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 12 Jun 2014 23:47:00 -0700 Subject: [PATCH 028/173] Added some good __future__ statements to pythonpy. --- bin/pythonpy | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index bfc7671..aab0141 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -1,4 +1,6 @@ #!/usr/bin/env python +from __future__ import (unicode_literals, absolute_import, + print_function, division) import argparse import glob import itertools @@ -93,8 +95,8 @@ if hasattr(result, '__iter__'): for x in result: formatted = format(x) if formatted is not None: - print formatted + print(formatted) else: formatted = format(result) if formatted is not None: - print formatted + print(formatted) From fef752e0825f1587eb707548a95f506b62b5307b Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 00:28:40 -0700 Subject: [PATCH 029/173] Added a bunch more imports and a lazy import strategy for 25% perf boost. --- bin/pythonpy | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index aab0141..b468ce4 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -2,15 +2,30 @@ from __future__ import (unicode_literals, absolute_import, print_function, division) import argparse -import glob -import itertools +import sys import json -import math -import os -import random import re -import shutil -import sys + +def lazy_imports(evaluation, cmd): + query = (evaluation if evaluation else '' + + cmd if cmd else '') + if 'glob' in query: global glob; import glob + if 'itertools' in query: global itertools; import itertools + if 'json' in query: global json; import json + if 'math' in query: global math; import math + if 'os' in query: global os; import os + if 'random' in query: global random; import random + if 're' in query: global re; import re + if 'shutil' in query: global shutil; import shutil + if 'tempfile' in query: global tempfile; import tempfile + if 'datetime' in query: global datetime; import datetime + if 'hashlib' in query: global hashlib; import hashlib + if 'csv' in query: global csv; import csv + if 'base64' in query: global base64; import base64 + if 'calendar' in query: global calendar; import calendar + if 'Counter' in query: global Counter; from collections import Counter + if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict + if 'uuid4' in query: global uuid4; from uuid import uuid4 parser = argparse.ArgumentParser() parser.add_argument('evaluation', nargs='?', default='None') @@ -55,6 +70,8 @@ if args.evaluation: if args.cmd: args.cmd = args.cmd.replace("`", "'") +lazy_imports(args.evaluation, args.cmd) + if args.cmd: exec(args.cmd) From 7fcd56664d721c32fd6a1efedaea14200e596be6 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 00:29:02 -0700 Subject: [PATCH 030/173] Added a few more unit tests. --- test/test_pythonpy.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test_pythonpy.py b/test/test_pythonpy.py index a9aa9d1..ad7043d 100644 --- a/test/test_pythonpy.py +++ b/test/test_pythonpy.py @@ -8,6 +8,17 @@ def test_empty(self): def test_numbers(self): self.assertEqual(check_output(['pythonpy', '3 * 4.5']),'13.5\n') + def test_range(self): + self.assertEqual(check_output(['pythonpy', 'range(3)']), '\n'.join(map(str, range(3))) + '\n') + + def test_range(self): + self.assertEqual(check_output(["""echo a,b | pythonpy -x 'x[1]' --si ,"""], shell=True), 'b\n') + + def test_ignore_errors(self): + self.assertEqual(check_output("""echo a | pythonpy -x --i 'None.None'""", shell=True), '') + self.assertEqual(check_output("""echo a | pythonpy -fx --i 'None.None'""", shell=True), '') + + if __name__ == '__main__': unittest.main() From 220e5ef05dbc703f02e94534119e161890368a2f Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 00:54:58 -0700 Subject: [PATCH 031/173] Changed implementation to use OOP :(. --- bin/pythonpy | 223 ++++++++++++++++++++++++++++----------------------- 1 file changed, 122 insertions(+), 101 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index b468ce4..b2595e5 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -6,114 +6,135 @@ import sys import json import re -def lazy_imports(evaluation, cmd): - query = (evaluation if evaluation else '' + - cmd if cmd else '') - if 'glob' in query: global glob; import glob - if 'itertools' in query: global itertools; import itertools - if 'json' in query: global json; import json - if 'math' in query: global math; import math - if 'os' in query: global os; import os - if 'random' in query: global random; import random - if 're' in query: global re; import re - if 'shutil' in query: global shutil; import shutil - if 'tempfile' in query: global tempfile; import tempfile - if 'datetime' in query: global datetime; import datetime - if 'hashlib' in query: global hashlib; import hashlib - if 'csv' in query: global csv; import csv - if 'base64' in query: global base64; import base64 - if 'calendar' in query: global calendar; import calendar - if 'Counter' in query: global Counter; from collections import Counter - if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict - if 'uuid4' in query: global uuid4; from uuid import uuid4 +class PythonPy(object): + def __init__(self): + self.parser = self.get_parser() -parser = argparse.ArgumentParser() -parser.add_argument('evaluation', nargs='?', default='None') -parser.add_argument('-x', dest='lines_of_stdin', action='store_const', - const=True, default=False, - help='treat each row as x') -parser.add_argument('-fx', dest='filter_result', action='store_const', - const=True, default=False, - help='keep rows satisfying condition(x)') -parser.add_argument('-l', dest='list_of_stdin', action='store_const', - const=True, default=False, - help='treat list of stdin as l') -parser.add_argument('-c', dest='cmd', help='run code before expression') -parser.add_argument('--i', '--ignore_exceptions', - dest='ignore_exceptions', action='store_const', - const=True, default=False, - help='') -parser.add_argument('--si', '--split_input', dest='split_input', - help='pre-process each row with re.split(delimiter)') -parser.add_argument('--so', '--split_output', dest='split_output', - help='post-process each row with delimiter.join(row)') -parser.add_argument('--ji' '--json_input', - dest='json_input', action='store_const', - const=True, default=False, - help='pre-process each row with json.loads(row)') -parser.add_argument('--jo' '--json_output', - dest='json_output', action='store_const', - const=True, default=False, - help='post-process each row with json.dumps(row)') + def run(self): + self.args = self.parser.parse_args() + stdin = self.preprocess() + self.lazy_imports() + if self.args.cmd: + exec(self.args.cmd) + results = self.process(stdin) + self.post_process(results) -args = parser.parse_args() + def get_parser(self): + parser = argparse.ArgumentParser() + parser.add_argument('evaluation', nargs='?', default='None') + parser.add_argument('-x', dest='lines_of_stdin', action='store_const', + const=True, default=False, + help='treat each row as x') + parser.add_argument('-fx', dest='filter_result', action='store_const', + const=True, default=False, + help='keep rows satisfying condition(x)') + parser.add_argument('-l', dest='list_of_stdin', action='store_const', + const=True, default=False, + help='treat list of stdin as l') + parser.add_argument('-c', dest='cmd', help='run code before expression') + parser.add_argument('--i', '--ignore_exceptions', + dest='ignore_exceptions', action='store_const', + const=True, default=False, + help='') + parser.add_argument('--si', '--split_input', dest='split_input', + help='pre-process each row with re.split(delimiter)') + parser.add_argument('--so', '--split_output', dest='split_output', + help='post-process each row with delimiter.join(row)') + parser.add_argument('--ji' '--json_input', + dest='json_input', action='store_const', + const=True, default=False, + help='pre-process each row with json.loads(row)') + parser.add_argument('--jo' '--json_output', + dest='json_output', action='store_const', + const=True, default=False, + help='post-process each row with json.dumps(row)') + return parser -if args.json_input: - stdin = (json.loads(x.rstrip()) for x in sys.stdin) -elif args.split_input: - stdin = (re.split(args.split_input, x.rstrip()) for x in sys.stdin) -else: - stdin = (x.rstrip() for x in sys.stdin) + def lazy_imports(self): + query = (self.args.evaluation if self.args.evaluation else '' + + self.args.cmd if self.args.cmd else '') + if 'glob' in query: global glob; import glob + if 'itertools' in query: global itertools; import itertools + if 'json' in query: global json; import json + if 'math' in query: global math; import math + if 'os' in query: global os; import os + if 'random' in query: global random; import random + if 're' in query: global re; import re + if 'shutil' in query: global shutil; import shutil + if 'tempfile' in query: global tempfile; import tempfile + if 'datetime' in query: global datetime; import datetime + if 'hashlib' in query: global hashlib; import hashlib + if 'csv' in query: global csv; import csv + if 'base64' in query: global base64; import base64 + if 'calendar' in query: global calendar; import calendar + if 'Counter' in query: global Counter; from collections import Counter + if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict + if 'uuid4' in query: global uuid4; from uuid import uuid4 -if args.evaluation: - args.evaluation = args.evaluation.replace("`", "'") -if args.cmd: - args.cmd = args.cmd.replace("`", "'") + def preprocess(self): + if self.args.json_input: + stdin = (json.loads(x.rstrip()) for x in sys.stdin) + elif self.args.split_input: + stdin = (re.split(self.args.split_input, x.rstrip()) for x in sys.stdin) + else: + stdin = (x.rstrip() for x in sys.stdin) -lazy_imports(args.evaluation, args.cmd) + if self.args.evaluation: + self.args.evaluation = self.args.evaluation.replace("`", "'") + if self.args.cmd: + self.args.cmd = self.args.cmd.replace("`", "'") + return stdin -if args.cmd: - exec(args.cmd) + def process(self, stdin): + def safe_eval(text, x): + try: + return eval(text) + except: + return None -def safe_eval(text, x): - try: - return eval(text) - except: - return None + if self.args.lines_of_stdin: + if self.args.ignore_exceptions: + result = (safe_eval(self.args.evaluation, x) for x in stdin) + else: + result = (eval(self.args.evaluation) for x in stdin) + elif self.args.filter_result: + if self.args.ignore_exceptions: + result = (x for x in stdin if safe_eval(self.args.evaluation, x)) + else: + result = (x for x in stdin if eval(self.args.evaluation)) + elif self.args.list_of_stdin: + l = list(stdin) + result = eval(self.args.evaluation) + else: + result = eval(self.args.evaluation) + return result -if args.lines_of_stdin: - if args.ignore_exceptions: - result = (safe_eval(args.evaluation, x) for x in stdin) - else: - result = (eval(args.evaluation) for x in stdin) -elif args.filter_result: - if args.ignore_exceptions: - result = (x for x in stdin if safe_eval(args.evaluation, x)) - else: - result = (x for x in stdin if eval(args.evaluation)) -elif args.list_of_stdin: - l = list(stdin) - result = eval(args.evaluation) -else: - result = eval(args.evaluation) + def post_process(self, results): + def format(output): + if output == None: + return None + elif self.args.json_output: + return json.dumps(output) + elif self.args.split_output: + return self.args.split_output.join(output) + else: + return output -def format(output): - if output == None: - return None - elif args.json_output: - return json.dumps(output) - elif args.split_output: - return args.split_output.join(output) - else: - return output - + if hasattr(results, '__iter__'): + for x in results: + formatted = format(x) + if formatted is not None: + print(formatted) + else: + formatted = format(results) + if formatted is not None: + print(formatted) -if hasattr(result, '__iter__'): - for x in result: - formatted = format(x) - if formatted is not None: - print(formatted) -else: - formatted = format(result) - if formatted is not None: - print(formatted) + +def main(): + pythonpy = PythonPy() + pythonpy.run() + + +if __name__ == '__main__': + main() From f0786f825b1ac144ddf7dd67fb7fcadc17c25679 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 00:56:43 -0700 Subject: [PATCH 032/173] Simplified main() function. --- bin/pythonpy | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index b2595e5..502f0ba 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -132,8 +132,7 @@ class PythonPy(object): def main(): - pythonpy = PythonPy() - pythonpy.run() + PythonPy().run() if __name__ == '__main__': From e4e16b17ba9098c2455ab0b20b12a03e4fdbe22e Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 01:01:51 -0700 Subject: [PATCH 033/173] 0.2.2dev5 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e7c4a88..7f73e93 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.2dev4', + version='0.2.2dev5', description='Take advantage of your python skills from the command line', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From fa9733726d65fdfdf40119b156c83aac55e0bff0 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 01:07:09 -0700 Subject: [PATCH 034/173] 0.2.2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7f73e93..0adc04b 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.2dev5', + version='0.2.2', description='Take advantage of your python skills from the command line', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From f68e6949c2fcb12571c8e90d72b540cbc912278b Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 01:51:54 -0700 Subject: [PATCH 035/173] Rearranged imports in alphabetical order --- bin/pythonpy | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index 502f0ba..5adf9a7 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -53,7 +53,12 @@ class PythonPy(object): def lazy_imports(self): query = (self.args.evaluation if self.args.evaluation else '' + self.args.cmd if self.args.cmd else '') + if 'base64' in query: global base64; import base64 + if 'calendar' in query: global calendar; import calendar + if 'csv' in query: global csv; import csv + if 'datetime' in query: global datetime; import datetime if 'glob' in query: global glob; import glob + if 'hashlib' in query: global hashlib; import hashlib if 'itertools' in query: global itertools; import itertools if 'json' in query: global json; import json if 'math' in query: global math; import math @@ -62,11 +67,6 @@ class PythonPy(object): if 're' in query: global re; import re if 'shutil' in query: global shutil; import shutil if 'tempfile' in query: global tempfile; import tempfile - if 'datetime' in query: global datetime; import datetime - if 'hashlib' in query: global hashlib; import hashlib - if 'csv' in query: global csv; import csv - if 'base64' in query: global base64; import base64 - if 'calendar' in query: global calendar; import calendar if 'Counter' in query: global Counter; from collections import Counter if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict if 'uuid4' in query: global uuid4; from uuid import uuid4 From 22bd488995026e4c79290f815bcb9f1afa579c86 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 01:52:06 -0700 Subject: [PATCH 036/173] Rearranged imports in alphabetical order --- bin/pythonpy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pythonpy b/bin/pythonpy index 5adf9a7..abcbdf0 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -2,9 +2,9 @@ from __future__ import (unicode_literals, absolute_import, print_function, division) import argparse -import sys import json import re +import sys class PythonPy(object): def __init__(self): From a605a600c515466aa3e37b732486a531967cf7d4 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 01:54:13 -0700 Subject: [PATCH 037/173] Removed redundant re and json lazy import. --- bin/pythonpy | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index abcbdf0..0fd2364 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -60,11 +60,9 @@ class PythonPy(object): if 'glob' in query: global glob; import glob if 'hashlib' in query: global hashlib; import hashlib if 'itertools' in query: global itertools; import itertools - if 'json' in query: global json; import json if 'math' in query: global math; import math if 'os' in query: global os; import os if 'random' in query: global random; import random - if 're' in query: global re; import re if 'shutil' in query: global shutil; import shutil if 'tempfile' in query: global tempfile; import tempfile if 'Counter' in query: global Counter; from collections import Counter From ea1adfa8423d019db7b69ea96145eb7ceab9da1a Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 02:01:47 -0700 Subject: [PATCH 038/173] Mentioned the wiki at the end of the README. --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 1402504..a8ed179 100644 --- a/README.rst +++ b/README.rst @@ -227,3 +227,7 @@ Get the local network ip 192.168.1.41 :: + + +Check out the wiki at github.com/Russell91/pythonpy/wiki for more advanced features +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From f41ef15851f6a768aa0db12edbd4a83d4aa6b30d Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 02:02:42 -0700 Subject: [PATCH 039/173] Made wiki mention more optional. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index a8ed179..a077e1c 100644 --- a/README.rst +++ b/README.rst @@ -229,5 +229,5 @@ Get the local network ip :: -Check out the wiki at github.com/Russell91/pythonpy/wiki for more advanced features +If you haven't had enough yet, check out the wiki at github.com/Russell91/pythonpy/wiki for more advanced features ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From e7a554233b6f5d5fb8fdf3a389c7d7467d93fe86 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 02:42:03 -0700 Subject: [PATCH 040/173] Fixed bug neutralizing -c argument. --- bin/pythonpy | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index 0fd2364..de468f8 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -12,11 +12,9 @@ class PythonPy(object): def run(self): self.args = self.parser.parse_args() - stdin = self.preprocess() + self.stdin = self.preprocess() self.lazy_imports() - if self.args.cmd: - exec(self.args.cmd) - results = self.process(stdin) + results = self.process() self.post_process(results) def get_parser(self): @@ -70,6 +68,7 @@ class PythonPy(object): if 'uuid4' in query: global uuid4; from uuid import uuid4 def preprocess(self): + if self.args.json_input: stdin = (json.loads(x.rstrip()) for x in sys.stdin) elif self.args.split_input: @@ -83,25 +82,28 @@ class PythonPy(object): self.args.cmd = self.args.cmd.replace("`", "'") return stdin - def process(self, stdin): - def safe_eval(text, x): - try: - return eval(text) - except: - return None + def safe_eval(self, text, x): + try: + return eval(text) + except: + return None + + def process(self): + if self.args.cmd: + exec self.args.cmd in globals(), locals() if self.args.lines_of_stdin: if self.args.ignore_exceptions: - result = (safe_eval(self.args.evaluation, x) for x in stdin) + result = (self.safe_eval(self.args.evaluation, x) for x in self.stdin) else: - result = (eval(self.args.evaluation) for x in stdin) + result = (eval(self.args.evaluation) for x in self.stdin) elif self.args.filter_result: if self.args.ignore_exceptions: - result = (x for x in stdin if safe_eval(self.args.evaluation, x)) + result = (x for x in self.stdin if self.safe_eval(self.args.evaluation, x)) else: - result = (x for x in stdin if eval(self.args.evaluation)) + result = (x for x in self.stdin if eval(self.args.evaluation)) elif self.args.list_of_stdin: - l = list(stdin) + l = list(self.stdin) result = eval(self.args.evaluation) else: result = eval(self.args.evaluation) From 945e7d3c04e35da2febf627349d63bc685a72b99 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 02:42:23 -0700 Subject: [PATCH 041/173] 0.2.3dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0adc04b..3f6475b 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.2', + version='0.2.3dev', description='Take advantage of your python skills from the command line', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From 4628b8878e669076d9e2d127c0eb151c34e60f40 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 11:42:35 -0700 Subject: [PATCH 042/173] Changed help description for --si. --- bin/pythonpy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pythonpy b/bin/pythonpy index de468f8..42b07f6 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -35,7 +35,7 @@ class PythonPy(object): const=True, default=False, help='') parser.add_argument('--si', '--split_input', dest='split_input', - help='pre-process each row with re.split(delimiter)') + help='pre-process each row with re.split(delimiter, row)') parser.add_argument('--so', '--split_output', dest='split_output', help='post-process each row with delimiter.join(row)') parser.add_argument('--ji' '--json_input', From fc6f6f276d968c55899e651e96ab36bdf30dda5d Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 15:53:15 -0700 Subject: [PATCH 043/173] Got rid of OOP as it was messing up exec function. --- bin/pythonpy | 246 +++++++++++++++++++++++---------------------------- setup.py | 2 +- 2 files changed, 114 insertions(+), 134 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index 42b07f6..a1826b1 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -1,139 +1,119 @@ -#!/usr/bin/env python +#!/usr/bin/python from __future__ import (unicode_literals, absolute_import, print_function, division) import argparse +import sys import json import re -import sys - -class PythonPy(object): - def __init__(self): - self.parser = self.get_parser() - - def run(self): - self.args = self.parser.parse_args() - self.stdin = self.preprocess() - self.lazy_imports() - results = self.process() - self.post_process(results) - - def get_parser(self): - parser = argparse.ArgumentParser() - parser.add_argument('evaluation', nargs='?', default='None') - parser.add_argument('-x', dest='lines_of_stdin', action='store_const', - const=True, default=False, - help='treat each row as x') - parser.add_argument('-fx', dest='filter_result', action='store_const', - const=True, default=False, - help='keep rows satisfying condition(x)') - parser.add_argument('-l', dest='list_of_stdin', action='store_const', - const=True, default=False, - help='treat list of stdin as l') - parser.add_argument('-c', dest='cmd', help='run code before expression') - parser.add_argument('--i', '--ignore_exceptions', - dest='ignore_exceptions', action='store_const', - const=True, default=False, - help='') - parser.add_argument('--si', '--split_input', dest='split_input', - help='pre-process each row with re.split(delimiter, row)') - parser.add_argument('--so', '--split_output', dest='split_output', - help='post-process each row with delimiter.join(row)') - parser.add_argument('--ji' '--json_input', - dest='json_input', action='store_const', - const=True, default=False, - help='pre-process each row with json.loads(row)') - parser.add_argument('--jo' '--json_output', - dest='json_output', action='store_const', - const=True, default=False, - help='post-process each row with json.dumps(row)') - return parser - - def lazy_imports(self): - query = (self.args.evaluation if self.args.evaluation else '' + - self.args.cmd if self.args.cmd else '') - if 'base64' in query: global base64; import base64 - if 'calendar' in query: global calendar; import calendar - if 'csv' in query: global csv; import csv - if 'datetime' in query: global datetime; import datetime - if 'glob' in query: global glob; import glob - if 'hashlib' in query: global hashlib; import hashlib - if 'itertools' in query: global itertools; import itertools - if 'math' in query: global math; import math - if 'os' in query: global os; import os - if 'random' in query: global random; import random - if 'shutil' in query: global shutil; import shutil - if 'tempfile' in query: global tempfile; import tempfile - if 'Counter' in query: global Counter; from collections import Counter - if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict - if 'uuid4' in query: global uuid4; from uuid import uuid4 - - def preprocess(self): - - if self.args.json_input: - stdin = (json.loads(x.rstrip()) for x in sys.stdin) - elif self.args.split_input: - stdin = (re.split(self.args.split_input, x.rstrip()) for x in sys.stdin) - else: - stdin = (x.rstrip() for x in sys.stdin) - - if self.args.evaluation: - self.args.evaluation = self.args.evaluation.replace("`", "'") - if self.args.cmd: - self.args.cmd = self.args.cmd.replace("`", "'") - return stdin - - def safe_eval(self, text, x): - try: - return eval(text) - except: - return None - - def process(self): - if self.args.cmd: - exec self.args.cmd in globals(), locals() - - if self.args.lines_of_stdin: - if self.args.ignore_exceptions: - result = (self.safe_eval(self.args.evaluation, x) for x in self.stdin) - else: - result = (eval(self.args.evaluation) for x in self.stdin) - elif self.args.filter_result: - if self.args.ignore_exceptions: - result = (x for x in self.stdin if self.safe_eval(self.args.evaluation, x)) - else: - result = (x for x in self.stdin if eval(self.args.evaluation)) - elif self.args.list_of_stdin: - l = list(self.stdin) - result = eval(self.args.evaluation) - else: - result = eval(self.args.evaluation) - return result - - def post_process(self, results): - def format(output): - if output == None: - return None - elif self.args.json_output: - return json.dumps(output) - elif self.args.split_output: - return self.args.split_output.join(output) - else: - return output - - if hasattr(results, '__iter__'): - for x in results: - formatted = format(x) - if formatted is not None: - print(formatted) - else: - formatted = format(results) - if formatted is not None: - print(formatted) - - -def main(): - PythonPy().run() - -if __name__ == '__main__': - main() +def lazy_imports(evaluation, cmd): + query = (evaluation if evaluation else '' + + cmd if cmd else '') + if 'glob' in query: global glob; import glob + if 'itertools' in query: global itertools; import itertools + if 'json' in query: global json; import json + if 'math' in query: global math; import math + if 'os' in query: global os; import os + if 'random' in query: global random; import random + if 're' in query: global re; import re + if 'shutil' in query: global shutil; import shutil + if 'tempfile' in query: global tempfile; import tempfile + if 'datetime' in query: global datetime; import datetime + if 'hashlib' in query: global hashlib; import hashlib + if 'csv' in query: global csv; import csv + if 'base64' in query: global base64; import base64 + if 'calendar' in query: global calendar; import calendar + if 'Counter' in query: global Counter; from collections import Counter + if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict + if 'uuid4' in query: global uuid4; from uuid import uuid4 + +parser = argparse.ArgumentParser() +parser.add_argument('evaluation', nargs='?', default='None') +parser.add_argument('-x', dest='lines_of_stdin', action='store_const', + const=True, default=False, + help='treat each row as x') +parser.add_argument('-fx', dest='filter_result', action='store_const', + const=True, default=False, + help='keep rows satisfying condition(x)') +parser.add_argument('-l', dest='list_of_stdin', action='store_const', + const=True, default=False, + help='treat list of stdin as l') +parser.add_argument('-c', dest='cmd', help='run code before expression') +parser.add_argument('--i', '--ignore_exceptions', + dest='ignore_exceptions', action='store_const', + const=True, default=False, + help='') +parser.add_argument('--si', '--split_input', dest='split_input', + help='pre-process each row with re.split(delimiter)') +parser.add_argument('--so', '--split_output', dest='split_output', + help='post-process each row with delimiter.join(row)') +parser.add_argument('--ji' '--json_input', + dest='json_input', action='store_const', + const=True, default=False, + help='pre-process each row with json.loads(row)') +parser.add_argument('--jo' '--json_output', + dest='json_output', action='store_const', + const=True, default=False, + help='post-process each row with json.dumps(row)') + +args = parser.parse_args() + +if args.json_input: + stdin = (json.loads(x.rstrip()) for x in sys.stdin) +elif args.split_input: + stdin = (re.split(args.split_input, x.rstrip()) for x in sys.stdin) +else: + stdin = (x.rstrip() for x in sys.stdin) + +if args.evaluation: + args.evaluation = args.evaluation.replace("`", "'") +if args.cmd: + args.cmd = args.cmd.replace("`", "'") + +lazy_imports(args.evaluation, args.cmd) + +if args.cmd: + exec(args.cmd) + +def safe_eval(text, x): + try: + return eval(text) + except: + return None + +if args.lines_of_stdin: + if args.ignore_exceptions: + result = (safe_eval(args.evaluation, x) for x in stdin) + else: + result = (eval(args.evaluation) for x in stdin) +elif args.filter_result: + if args.ignore_exceptions: + result = (x for x in stdin if safe_eval(args.evaluation, x)) + else: + result = (x for x in stdin if eval(args.evaluation)) +elif args.list_of_stdin: + l = list(stdin) + result = eval(args.evaluation) +else: + result = eval(args.evaluation) + +def format(output): + if output == None: + return None + elif args.json_output: + return json.dumps(output) + elif args.split_output: + return args.split_output.join(output) + else: + return output + + +if hasattr(result, '__iter__'): + for x in result: + formatted = format(x) + if formatted is not None: + print(formatted) +else: + formatted = format(result) + if formatted is not None: + print(formatted) diff --git a/setup.py b/setup.py index 3f6475b..408921d 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.3dev', + version='0.2.4dev', description='Take advantage of your python skills from the command line', scripts=[os.path.join('bin', 'pythonpy')], license='MIT', From e74a2fc728f9379ef3ba7fadf9e5e4356470ae5d Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 15:58:00 -0700 Subject: [PATCH 044/173] Rearranged imports and added from itertools import groupby. --- bin/pythonpy | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index a1826b1..c23f9f4 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -9,6 +9,11 @@ import re def lazy_imports(evaluation, cmd): query = (evaluation if evaluation else '' + cmd if cmd else '') + if 'base64' in query: global base64; import base64 + if 'calendar' in query: global calendar; import calendar + if 'csv' in query: global csv; import csv + if 'datetime' in query: global datetime; import datetime + if 'hashlib' in query: global hashlib; import hashlib if 'glob' in query: global glob; import glob if 'itertools' in query: global itertools; import itertools if 'json' in query: global json; import json @@ -18,13 +23,9 @@ def lazy_imports(evaluation, cmd): if 're' in query: global re; import re if 'shutil' in query: global shutil; import shutil if 'tempfile' in query: global tempfile; import tempfile - if 'datetime' in query: global datetime; import datetime - if 'hashlib' in query: global hashlib; import hashlib - if 'csv' in query: global csv; import csv - if 'base64' in query: global base64; import base64 - if 'calendar' in query: global calendar; import calendar if 'Counter' in query: global Counter; from collections import Counter if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict + if 'groupby' in query: global OrderedDict; from collections import OrderedDict if 'uuid4' in query: global uuid4; from uuid import uuid4 parser = argparse.ArgumentParser() From 7bd2f6403ff55832cf9fb85494f2b2d7bca1634c Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 16:01:28 -0700 Subject: [PATCH 045/173] Added -C option to run statement after expression. --- bin/pythonpy | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index c23f9f4..7cb3000 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -6,9 +6,10 @@ import sys import json import re -def lazy_imports(evaluation, cmd): +def lazy_imports(evaluation, pre_cmd, post_cmd): query = (evaluation if evaluation else '' + - cmd if cmd else '') + pre_cmd if pre_cmd else '' + + post_cmd if post_cmd else '') if 'base64' in query: global base64; import base64 if 'calendar' in query: global calendar; import calendar if 'csv' in query: global csv; import csv @@ -39,7 +40,8 @@ parser.add_argument('-fx', dest='filter_result', action='store_const', parser.add_argument('-l', dest='list_of_stdin', action='store_const', const=True, default=False, help='treat list of stdin as l') -parser.add_argument('-c', dest='cmd', help='run code before expression') +parser.add_argument('-c', dest='pre_cmd', help='run code before expression') +parser.add_argument('-C', dest='post_cmd', help='run code after expression') parser.add_argument('--i', '--ignore_exceptions', dest='ignore_exceptions', action='store_const', const=True, default=False, @@ -68,13 +70,13 @@ else: if args.evaluation: args.evaluation = args.evaluation.replace("`", "'") -if args.cmd: - args.cmd = args.cmd.replace("`", "'") +if args.pre_cmd: + args.pre_cmd = args.pre_cmd.replace("`", "'") -lazy_imports(args.evaluation, args.cmd) +lazy_imports(args.evaluation, args.pre_cmd, args.post_cmd) -if args.cmd: - exec(args.cmd) +if args.pre_cmd: + exec(args.pre_cmd) def safe_eval(text, x): try: @@ -118,3 +120,6 @@ else: formatted = format(result) if formatted is not None: print(formatted) + +if args.post_cmd: + exec(args.post_cmd) From e9d683f4136f46950da939e467cc65f9ece84969 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 16:02:47 -0700 Subject: [PATCH 046/173] Removed README.txt, as it has been superceded by README.rst. --- README.txt | 104 ----------------------------------------------------- 1 file changed, 104 deletions(-) delete mode 100644 README.txt diff --git a/README.txt b/README.txt deleted file mode 100644 index e7e09f3..0000000 --- a/README.txt +++ /dev/null @@ -1,104 +0,0 @@ -# install -sudo pip install pythonpy; alias py='pythonpy' - -# float arithmetic -$ py '3 * 1.5' -4.5 - -# exponentiation -$ py '7**3' -343 - -# number sequence -$ py 'range(3)' -0 -1 -2 - -# list comprehensions -$ py '[x**2 for x in range(1,5)]' -1 -4 -9 -16 - -# math library usage -$ py 'math.exp(1)' -2.71828182846 - -# random library usage -$ py 'random.random()' -0.103173957713 - -# multiply each line of input by 7. -$ py 'range(3)' | py -x 'int(x)*7' -0 -7 -14 - -# append ".txt" to each line of input -$ py 'range(3)' | py -x 'x + ".txt"' -0.txt -1.txt -2.txt - -# Sometimes you want to treat the input as a python list. -# reverse a list -$ py 'range(4)' | py -l 'l[::-1]' -3 -2 -1 -0 - -# sum a list of numbers -$ py 'range(4)' | py -l 'sum(int(x) for x in l)' -6 - -# count the lines of input -$ py 'range(17)' | py -l 'len(l)' -17 - -# Other times you just want to filter out lines from the input. -# get only even numbers -$ py 'range(8)' | py -x 'x if int(x)%2 == 0 else None' -0 -2 -4 -6 - -# The shorthand -fx (filter on x) is also available. -# get only odd numbers -$ py 'range(8)' | py -fx 'int(x)%2 == 1' -1 -3 -5 -7 - -# get words starting with "and" -$ cat /usr/share/dict/words | py -fx 're.match(r"and", x)' | head -5 -and -andante -andante's -andantes -andiron - -#get verbs starting with ba -$ cat /usr/share/dict/words | py -fx 're.match(r"ba.*ing$", x)' | head -5 -baaing -babbling -babying -babysitting -backbiting - -# get long palindromes -$ cat /usr/share/dict/words | py -fx 'x==x[::-1] and len(x) >= 5' | head -5 -civic -deified -kayak -level -ma'am - -# keep going if row raises Error with (--i). -# get the local network ip -$ ifconfig | py -x --i 're.search(r"192\.168[\d\.]+", x).group()' -192.168.1.41 From fc6b53f17a0cb31017f1cfd603ada50034e79555 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 16:07:17 -0700 Subject: [PATCH 047/173] Fixed groupby import typo. --- bin/pythonpy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pythonpy b/bin/pythonpy index 7cb3000..67facf3 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -26,7 +26,7 @@ def lazy_imports(evaluation, pre_cmd, post_cmd): if 'tempfile' in query: global tempfile; import tempfile if 'Counter' in query: global Counter; from collections import Counter if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict - if 'groupby' in query: global OrderedDict; from collections import OrderedDict + if 'groupby' in query: global groupby; from itertools import groupby if 'uuid4' in query: global uuid4; from uuid import uuid4 parser = argparse.ArgumentParser() From 93e8911272d25af47c91b035d87af84d5e2a8e2b Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 16:21:00 -0700 Subject: [PATCH 048/173] Fixed bug failing to import for -c/-C statements. --- bin/pythonpy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/pythonpy b/bin/pythonpy index 67facf3..86430d3 100755 --- a/bin/pythonpy +++ b/bin/pythonpy @@ -7,9 +7,9 @@ import json import re def lazy_imports(evaluation, pre_cmd, post_cmd): - query = (evaluation if evaluation else '' + - pre_cmd if pre_cmd else '' + - post_cmd if post_cmd else '') + query = ((evaluation if evaluation else '') + + (pre_cmd if pre_cmd else '') + + (post_cmd if post_cmd else '')) if 'base64' in query: global base64; import base64 if 'calendar' in query: global calendar; import calendar if 'csv' in query: global csv; import csv From bfd99a2590e0f3676bb51d3f988d75d27a869a99 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 16:21:14 -0700 Subject: [PATCH 049/173] Added a few more unit tests!. --- test/test_pythonpy.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/test/test_pythonpy.py b/test/test_pythonpy.py index ad7043d..a1768e7 100644 --- a/test/test_pythonpy.py +++ b/test/test_pythonpy.py @@ -11,13 +11,40 @@ def test_numbers(self): def test_range(self): self.assertEqual(check_output(['pythonpy', 'range(3)']), '\n'.join(map(str, range(3))) + '\n') - def test_range(self): + def test_split_input(self): self.assertEqual(check_output(["""echo a,b | pythonpy -x 'x[1]' --si ,"""], shell=True), 'b\n') + def test_split_output(self): + self.assertEqual(check_output(["""echo abc | pythonpy -x x --si '' --so ','"""], shell=True), 'a,b,c\n') + def test_ignore_errors(self): self.assertEqual(check_output("""echo a | pythonpy -x --i 'None.None'""", shell=True), '') self.assertEqual(check_output("""echo a | pythonpy -fx --i 'None.None'""", shell=True), '') + def test_statements(self): + self.assertEqual(check_output("""pythonpy -c 'a=5' -C 'print(a)'""", shell=True), '5\n') + self.assertEqual(check_output("""echo 3 | pythonpy -c 'a=5' -x x -C 'print(a)'""", shell=True), '3\n5\n') + + def test_imports(self): + check_output("pythonpy 'math'", shell=True) + check_output("pythonpy 'base64'", shell=True) + check_output("pythonpy 'calendar'", shell=True) + check_output("pythonpy 'csv'", shell=True) + check_output("pythonpy 'datetime'", shell=True) + check_output("pythonpy 'hashlib'", shell=True) + check_output("pythonpy 'glob'", shell=True) + check_output("pythonpy 'itertools'", shell=True) + check_output("pythonpy 'json'", shell=True) + check_output("pythonpy 'math'", shell=True) + check_output("pythonpy 'os'", shell=True) + check_output("pythonpy 'random'", shell=True) + check_output("pythonpy 're'", shell=True) + check_output("pythonpy 'shutil'", shell=True) + check_output("pythonpy 'tempfile'", shell=True) + check_output("pythonpy -c 'Counter'", shell=True) + check_output("pythonpy -c 'OrderedDict'", shell=True) + check_output("pythonpy -c 'groupby'", shell=True) + check_output("pythonpy 'uuid4'", shell=True) if __name__ == '__main__': From 724a6a16e48d22dd7d50d337118ffbd6f6222eac Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 16:39:17 -0700 Subject: [PATCH 050/173] Moved pythonpy out of bin into primary directory. --- bin/pythonpy => pythonpy | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename bin/pythonpy => pythonpy (99%) diff --git a/bin/pythonpy b/pythonpy similarity index 99% rename from bin/pythonpy rename to pythonpy index 86430d3..55b801b 100755 --- a/bin/pythonpy +++ b/pythonpy @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from __future__ import (unicode_literals, absolute_import, print_function, division) import argparse diff --git a/setup.py b/setup.py index 408921d..3bc5b39 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ name='pythonpy', version='0.2.4dev', description='Take advantage of your python skills from the command line', - scripts=[os.path.join('bin', 'pythonpy')], + scripts=['pythonpy'], license='MIT', url='https://github.com/Russell91/pythonpy', long_description='', From 9cc9f85c1bf51f3016cd486afff9f8e3251bd68d Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 16:58:48 -0700 Subject: [PATCH 051/173] Changed "evaluation" to "expression" in source code. --- pythonpy | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/pythonpy b/pythonpy index 55b801b..0968d53 100755 --- a/pythonpy +++ b/pythonpy @@ -6,8 +6,8 @@ import sys import json import re -def lazy_imports(evaluation, pre_cmd, post_cmd): - query = ((evaluation if evaluation else '') + +def lazy_imports(expression, pre_cmd, post_cmd): + query = ((expression if expression else '') + (pre_cmd if pre_cmd else '') + (post_cmd if post_cmd else '')) if 'base64' in query: global base64; import base64 @@ -29,8 +29,10 @@ def lazy_imports(evaluation, pre_cmd, post_cmd): if 'groupby' in query: global groupby; from itertools import groupby if 'uuid4' in query: global uuid4; from uuid import uuid4 -parser = argparse.ArgumentParser() -parser.add_argument('evaluation', nargs='?', default='None') +parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter) + +parser.add_argument('expression', nargs='?', default='None') parser.add_argument('-x', dest='lines_of_stdin', action='store_const', const=True, default=False, help='treat each row as x') @@ -68,12 +70,12 @@ elif args.split_input: else: stdin = (x.rstrip() for x in sys.stdin) -if args.evaluation: - args.evaluation = args.evaluation.replace("`", "'") +if args.expression: + args.expression = args.expression.replace("`", "'") if args.pre_cmd: args.pre_cmd = args.pre_cmd.replace("`", "'") -lazy_imports(args.evaluation, args.pre_cmd, args.post_cmd) +lazy_imports(args.expression, args.pre_cmd, args.post_cmd) if args.pre_cmd: exec(args.pre_cmd) @@ -86,19 +88,19 @@ def safe_eval(text, x): if args.lines_of_stdin: if args.ignore_exceptions: - result = (safe_eval(args.evaluation, x) for x in stdin) + result = (safe_eval(args.expression, x) for x in stdin) else: - result = (eval(args.evaluation) for x in stdin) + result = (eval(args.expression) for x in stdin) elif args.filter_result: if args.ignore_exceptions: - result = (x for x in stdin if safe_eval(args.evaluation, x)) + result = (x for x in stdin if safe_eval(args.expression, x)) else: - result = (x for x in stdin if eval(args.evaluation)) + result = (x for x in stdin if eval(args.expression)) elif args.list_of_stdin: l = list(stdin) - result = eval(args.evaluation) + result = eval(args.expression) else: - result = eval(args.evaluation) + result = eval(args.expression) def format(output): if output == None: From e8e80e200ed6e3e6868aed7a9863f914ac26f6de Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 16:59:58 -0700 Subject: [PATCH 052/173] Changed help for --si. --- pythonpy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pythonpy b/pythonpy index 0968d53..bbd25c9 100755 --- a/pythonpy +++ b/pythonpy @@ -49,7 +49,7 @@ parser.add_argument('--i', '--ignore_exceptions', const=True, default=False, help='') parser.add_argument('--si', '--split_input', dest='split_input', - help='pre-process each row with re.split(delimiter)') + help='pre-process each row with re.split(delimiter, row)') parser.add_argument('--so', '--split_output', dest='split_output', help='post-process each row with delimiter.join(row)') parser.add_argument('--ji' '--json_input', From 5483b405524d7ad49508a87f1682e6ad6f9b3f86 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 17:01:52 -0700 Subject: [PATCH 053/173] 0.2.4dev2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3bc5b39..b36866f 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.4dev', + version='0.2.4dev2', description='Take advantage of your python skills from the command line', scripts=['pythonpy'], license='MIT', From 27d5adb13d374a072614abc230241006434495af Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 17:35:35 -0700 Subject: [PATCH 054/173] Updated README.rst. --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index a077e1c..b7d71e2 100644 --- a/README.rst +++ b/README.rst @@ -229,5 +229,5 @@ Get the local network ip :: -If you haven't had enough yet, check out the wiki at github.com/Russell91/pythonpy/wiki for more advanced features -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If you haven't had enough yet, check out the wiki at github.com/Russell91/pythonpy/wiki +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From b2089bcd759ca641cc109dca4b6afc0df863ab0f Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 18:37:09 -0700 Subject: [PATCH 055/173] 0.2.4 --- MANIFEST | 3 +-- setup.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/MANIFEST b/MANIFEST index c217127..acd664e 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,5 +1,4 @@ # file GENERATED by distutils, do NOT edit -README.txt +pythonpy setup.py -bin/pythonpy test/test_pythonpy.py diff --git a/setup.py b/setup.py index b36866f..3b1bd9e 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.4dev2', + version='0.2.4', description='Take advantage of your python skills from the command line', scripts=['pythonpy'], license='MIT', From 5315dbaee5b7df0ccc762309a8654393402745d7 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 20:20:40 -0700 Subject: [PATCH 056/173] Stopped tracking auto-generated MANIFEST with git. --- .gitignore | 1 + MANIFEST | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 MANIFEST diff --git a/.gitignore b/.gitignore index 1bcc247..35379c1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ dist *.pyc *swp +MANIFEST diff --git a/MANIFEST b/MANIFEST deleted file mode 100644 index acd664e..0000000 --- a/MANIFEST +++ /dev/null @@ -1,4 +0,0 @@ -# file GENERATED by distutils, do NOT edit -pythonpy -setup.py -test/test_pythonpy.py From f870ef1b89ee7ec4eb055fa94766535bf0ec7639 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 20:25:10 -0700 Subject: [PATCH 057/173] Changed wiki to link. --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index b7d71e2..024b11f 100644 --- a/README.rst +++ b/README.rst @@ -229,5 +229,6 @@ Get the local network ip :: -If you haven't had enough yet, check out the wiki at github.com/Russell91/pythonpy/wiki +If you haven't had enough yet, check out the `wiki `__ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + From d9e60f684a9607ccfcf422c01d23a540e0f9b563 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 20:26:52 -0700 Subject: [PATCH 058/173] Changed wiki link again --- README.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 024b11f..c2ec0ac 100644 --- a/README.rst +++ b/README.rst @@ -229,6 +229,5 @@ Get the local network ip :: -If you haven't had enough yet, check out the `wiki `__ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - +If you haven't had enough yet, check out the `wiki `__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 445b193fccbe99e23db1b81dbcbb5e1631f671b0 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 20:39:54 -0700 Subject: [PATCH 059/173] Added letter count example to README. --- README.rst | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.rst b/README.rst index c2ec0ac..06ad488 100644 --- a/README.rst +++ b/README.rst @@ -215,6 +215,42 @@ Get long palindromes :: +Count words beginning with each letter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + $ cat /usr/share/dict/words | py -x 'x[0].lower()' | py -l 'Counter(l).items()' + ('\xc3', 17) + ('a', 5895) + ('c', 9521) + ('b', 6068) + ('e', 3851) + ('d', 5823) + ('g', 3456) + ('f', 4127) + ('i', 3667) + ('h', 3804) + ('k', 1163) + ('j', 1262) + ('m', 5922) + ('l', 3400) + ('o', 2270) + ('n', 2018) + ('q', 467) + ('p', 7659) + ('s', 11327) + ('r', 5356) + ('u', 1943) + ('t', 5085) + ('w', 2739) + ('v', 1576) + ('y', 421) + ('x', 53) + ('z', 281) + +:: + Keep going if some rows raise Errors with (--i). ------------------------------------------------ From 60b084ccf4506e1a95afa975bf77a6cc9af512b8 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 20:41:32 -0700 Subject: [PATCH 060/173] Shortened letter count example in README. --- README.rst | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/README.rst b/README.rst index 06ad488..c662756 100644 --- a/README.rst +++ b/README.rst @@ -220,34 +220,12 @@ Count words beginning with each letter :: - $ cat /usr/share/dict/words | py -x 'x[0].lower()' | py -l 'Counter(l).items()' - ('\xc3', 17) - ('a', 5895) + $ cat /usr/share/dict/words | py -x 'x[0].lower()' | py -l 'Counter(l).most_common(5)' + ('s', 11327) ('c', 9521) + ('p', 7659) ('b', 6068) - ('e', 3851) - ('d', 5823) - ('g', 3456) - ('f', 4127) - ('i', 3667) - ('h', 3804) - ('k', 1163) - ('j', 1262) ('m', 5922) - ('l', 3400) - ('o', 2270) - ('n', 2018) - ('q', 467) - ('p', 7659) - ('s', 11327) - ('r', 5356) - ('u', 1943) - ('t', 5085) - ('w', 2739) - ('v', 1576) - ('y', 421) - ('x', 53) - ('z', 281) :: From 77f425371851afad731009fc50dae9b847d46899 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 13 Jun 2014 20:48:20 -0700 Subject: [PATCH 061/173] Fixed bug not replacing tics inside post_cmd. --- pythonpy | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pythonpy b/pythonpy index bbd25c9..6923642 100755 --- a/pythonpy +++ b/pythonpy @@ -74,6 +74,8 @@ if args.expression: args.expression = args.expression.replace("`", "'") if args.pre_cmd: args.pre_cmd = args.pre_cmd.replace("`", "'") +if args.post_cmd: + args.post_cmd = args.post_cmd.replace("`", "'") lazy_imports(args.expression, args.pre_cmd, args.post_cmd) From 7e263c6e5f43526d0ab44010ea0d4f217b7306c4 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 16 Jun 2014 19:23:52 -0700 Subject: [PATCH 062/173] Added ./py so alias is unnecessary. --- py | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 2 files changed, 130 insertions(+), 1 deletion(-) create mode 100755 py diff --git a/py b/py new file mode 100755 index 0000000..6923642 --- /dev/null +++ b/py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +from __future__ import (unicode_literals, absolute_import, + print_function, division) +import argparse +import sys +import json +import re + +def lazy_imports(expression, pre_cmd, post_cmd): + query = ((expression if expression else '') + + (pre_cmd if pre_cmd else '') + + (post_cmd if post_cmd else '')) + if 'base64' in query: global base64; import base64 + if 'calendar' in query: global calendar; import calendar + if 'csv' in query: global csv; import csv + if 'datetime' in query: global datetime; import datetime + if 'hashlib' in query: global hashlib; import hashlib + if 'glob' in query: global glob; import glob + if 'itertools' in query: global itertools; import itertools + if 'json' in query: global json; import json + if 'math' in query: global math; import math + if 'os' in query: global os; import os + if 'random' in query: global random; import random + if 're' in query: global re; import re + if 'shutil' in query: global shutil; import shutil + if 'tempfile' in query: global tempfile; import tempfile + if 'Counter' in query: global Counter; from collections import Counter + if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict + if 'groupby' in query: global groupby; from itertools import groupby + if 'uuid4' in query: global uuid4; from uuid import uuid4 + +parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter) + +parser.add_argument('expression', nargs='?', default='None') +parser.add_argument('-x', dest='lines_of_stdin', action='store_const', + const=True, default=False, + help='treat each row as x') +parser.add_argument('-fx', dest='filter_result', action='store_const', + const=True, default=False, + help='keep rows satisfying condition(x)') +parser.add_argument('-l', dest='list_of_stdin', action='store_const', + const=True, default=False, + help='treat list of stdin as l') +parser.add_argument('-c', dest='pre_cmd', help='run code before expression') +parser.add_argument('-C', dest='post_cmd', help='run code after expression') +parser.add_argument('--i', '--ignore_exceptions', + dest='ignore_exceptions', action='store_const', + const=True, default=False, + help='') +parser.add_argument('--si', '--split_input', dest='split_input', + help='pre-process each row with re.split(delimiter, row)') +parser.add_argument('--so', '--split_output', dest='split_output', + help='post-process each row with delimiter.join(row)') +parser.add_argument('--ji' '--json_input', + dest='json_input', action='store_const', + const=True, default=False, + help='pre-process each row with json.loads(row)') +parser.add_argument('--jo' '--json_output', + dest='json_output', action='store_const', + const=True, default=False, + help='post-process each row with json.dumps(row)') + +args = parser.parse_args() + +if args.json_input: + stdin = (json.loads(x.rstrip()) for x in sys.stdin) +elif args.split_input: + stdin = (re.split(args.split_input, x.rstrip()) for x in sys.stdin) +else: + stdin = (x.rstrip() for x in sys.stdin) + +if args.expression: + args.expression = args.expression.replace("`", "'") +if args.pre_cmd: + args.pre_cmd = args.pre_cmd.replace("`", "'") +if args.post_cmd: + args.post_cmd = args.post_cmd.replace("`", "'") + +lazy_imports(args.expression, args.pre_cmd, args.post_cmd) + +if args.pre_cmd: + exec(args.pre_cmd) + +def safe_eval(text, x): + try: + return eval(text) + except: + return None + +if args.lines_of_stdin: + if args.ignore_exceptions: + result = (safe_eval(args.expression, x) for x in stdin) + else: + result = (eval(args.expression) for x in stdin) +elif args.filter_result: + if args.ignore_exceptions: + result = (x for x in stdin if safe_eval(args.expression, x)) + else: + result = (x for x in stdin if eval(args.expression)) +elif args.list_of_stdin: + l = list(stdin) + result = eval(args.expression) +else: + result = eval(args.expression) + +def format(output): + if output == None: + return None + elif args.json_output: + return json.dumps(output) + elif args.split_output: + return args.split_output.join(output) + else: + return output + + +if hasattr(result, '__iter__'): + for x in result: + formatted = format(x) + if formatted is not None: + print(formatted) +else: + formatted = format(result) + if formatted is not None: + print(formatted) + +if args.post_cmd: + exec(args.post_cmd) diff --git a/setup.py b/setup.py index 3b1bd9e..199da5c 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ name='pythonpy', version='0.2.4', description='Take advantage of your python skills from the command line', - scripts=['pythonpy'], + scripts=['pythonpy', 'py'], license='MIT', url='https://github.com/Russell91/pythonpy', long_description='', From 3a681112b8ff3710ecdd7499782bfd764ba49f18 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 16 Jun 2014 19:24:09 -0700 Subject: [PATCH 063/173] 0.2.5dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 199da5c..8857a28 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.4', + version='0.2.5dev', description='Take advantage of your python skills from the command line', scripts=['pythonpy', 'py'], license='MIT', From aa8a9edea6c706027e379006154b2dda7e628f05 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 16 Jun 2014 19:31:40 -0700 Subject: [PATCH 064/173] Added wpy for windows --- wpy | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100755 wpy diff --git a/wpy b/wpy new file mode 100755 index 0000000..6923642 --- /dev/null +++ b/wpy @@ -0,0 +1,129 @@ +#!/usr/bin/env python +from __future__ import (unicode_literals, absolute_import, + print_function, division) +import argparse +import sys +import json +import re + +def lazy_imports(expression, pre_cmd, post_cmd): + query = ((expression if expression else '') + + (pre_cmd if pre_cmd else '') + + (post_cmd if post_cmd else '')) + if 'base64' in query: global base64; import base64 + if 'calendar' in query: global calendar; import calendar + if 'csv' in query: global csv; import csv + if 'datetime' in query: global datetime; import datetime + if 'hashlib' in query: global hashlib; import hashlib + if 'glob' in query: global glob; import glob + if 'itertools' in query: global itertools; import itertools + if 'json' in query: global json; import json + if 'math' in query: global math; import math + if 'os' in query: global os; import os + if 'random' in query: global random; import random + if 're' in query: global re; import re + if 'shutil' in query: global shutil; import shutil + if 'tempfile' in query: global tempfile; import tempfile + if 'Counter' in query: global Counter; from collections import Counter + if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict + if 'groupby' in query: global groupby; from itertools import groupby + if 'uuid4' in query: global uuid4; from uuid import uuid4 + +parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter) + +parser.add_argument('expression', nargs='?', default='None') +parser.add_argument('-x', dest='lines_of_stdin', action='store_const', + const=True, default=False, + help='treat each row as x') +parser.add_argument('-fx', dest='filter_result', action='store_const', + const=True, default=False, + help='keep rows satisfying condition(x)') +parser.add_argument('-l', dest='list_of_stdin', action='store_const', + const=True, default=False, + help='treat list of stdin as l') +parser.add_argument('-c', dest='pre_cmd', help='run code before expression') +parser.add_argument('-C', dest='post_cmd', help='run code after expression') +parser.add_argument('--i', '--ignore_exceptions', + dest='ignore_exceptions', action='store_const', + const=True, default=False, + help='') +parser.add_argument('--si', '--split_input', dest='split_input', + help='pre-process each row with re.split(delimiter, row)') +parser.add_argument('--so', '--split_output', dest='split_output', + help='post-process each row with delimiter.join(row)') +parser.add_argument('--ji' '--json_input', + dest='json_input', action='store_const', + const=True, default=False, + help='pre-process each row with json.loads(row)') +parser.add_argument('--jo' '--json_output', + dest='json_output', action='store_const', + const=True, default=False, + help='post-process each row with json.dumps(row)') + +args = parser.parse_args() + +if args.json_input: + stdin = (json.loads(x.rstrip()) for x in sys.stdin) +elif args.split_input: + stdin = (re.split(args.split_input, x.rstrip()) for x in sys.stdin) +else: + stdin = (x.rstrip() for x in sys.stdin) + +if args.expression: + args.expression = args.expression.replace("`", "'") +if args.pre_cmd: + args.pre_cmd = args.pre_cmd.replace("`", "'") +if args.post_cmd: + args.post_cmd = args.post_cmd.replace("`", "'") + +lazy_imports(args.expression, args.pre_cmd, args.post_cmd) + +if args.pre_cmd: + exec(args.pre_cmd) + +def safe_eval(text, x): + try: + return eval(text) + except: + return None + +if args.lines_of_stdin: + if args.ignore_exceptions: + result = (safe_eval(args.expression, x) for x in stdin) + else: + result = (eval(args.expression) for x in stdin) +elif args.filter_result: + if args.ignore_exceptions: + result = (x for x in stdin if safe_eval(args.expression, x)) + else: + result = (x for x in stdin if eval(args.expression)) +elif args.list_of_stdin: + l = list(stdin) + result = eval(args.expression) +else: + result = eval(args.expression) + +def format(output): + if output == None: + return None + elif args.json_output: + return json.dumps(output) + elif args.split_output: + return args.split_output.join(output) + else: + return output + + +if hasattr(result, '__iter__'): + for x in result: + formatted = format(x) + if formatted is not None: + print(formatted) +else: + formatted = format(result) + if formatted is not None: + print(formatted) + +if args.post_cmd: + exec(args.post_cmd) From ccf55930ad63e3df94bac9e7ea1d09a650a2688d Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 16 Jun 2014 19:33:14 -0700 Subject: [PATCH 065/173] Removed defunct alias info from readme. --- README.rst | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index c662756..70cf076 100644 --- a/README.rst +++ b/README.rst @@ -3,15 +3,7 @@ Installation :: - sudo pip install pythonpy && alias py='pythonpy' - -:: - -For a permanent alias (For Bash users): - -:: - - echo "alias py='pythonpy'" >> ~/.bashrc + sudo pip install pythonpy :: @@ -20,7 +12,7 @@ Float Arithmetic :: - $ py '3 * 1.5' + $ py '3 * 1.5' # use wpy on windows 4.5 From 878f87ad77c7cc76a265b1b333395efcc9bfbacc Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 16 Jun 2014 19:33:46 -0700 Subject: [PATCH 066/173] 0.2.5dev2. --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 8857a28..627bc77 100644 --- a/setup.py +++ b/setup.py @@ -3,9 +3,9 @@ setup( name='pythonpy', - version='0.2.5dev', + version='0.2.5dev2', description='Take advantage of your python skills from the command line', - scripts=['pythonpy', 'py'], + scripts=['pythonpy', 'py', 'wpy'], license='MIT', url='https://github.com/Russell91/pythonpy', long_description='', From aae781c4406465d66dc637bb84f257b3f8c40f24 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 16 Jun 2014 19:36:29 -0700 Subject: [PATCH 067/173] 0.2.5 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 627bc77..a18a994 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.5dev2', + version='0.2.5', description='Take advantage of your python skills from the command line', scripts=['pythonpy', 'py', 'wpy'], license='MIT', From 4df631752b12ecb2ba7c97f793b52355392e0090 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 16 Jun 2014 19:40:05 -0700 Subject: [PATCH 068/173] Updated README style. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 70cf076..ee19fc4 100644 --- a/README.rst +++ b/README.rst @@ -12,7 +12,7 @@ Float Arithmetic :: - $ py '3 * 1.5' # use wpy on windows + $ py '3 * 1.5' # For Windows use: wpy '3 * 1.5' 4.5 From 472569888b65335c45e6ea651257074be058f37b Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 16 Jun 2014 19:41:42 -0700 Subject: [PATCH 069/173] Moved alternat binary names to bin to keep home folder clean. --- pythonpy => bin/pythonpy | 0 wpy => bin/wpy | 0 setup.py | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename pythonpy => bin/pythonpy (100%) rename wpy => bin/wpy (100%) diff --git a/pythonpy b/bin/pythonpy similarity index 100% rename from pythonpy rename to bin/pythonpy diff --git a/wpy b/bin/wpy similarity index 100% rename from wpy rename to bin/wpy diff --git a/setup.py b/setup.py index a18a994..33475d1 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ name='pythonpy', version='0.2.5', description='Take advantage of your python skills from the command line', - scripts=['pythonpy', 'py', 'wpy'], + scripts=['bin/pythonpy', 'py', 'bin/wpy'], license='MIT', url='https://github.com/Russell91/pythonpy', long_description='', From 4faa4bfc514728282a7d00f79d826348d03f0777 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 16 Jun 2014 20:54:49 -0700 Subject: [PATCH 070/173] temp remove of py. --- py | 129 ------------------------------------------------------------- 1 file changed, 129 deletions(-) delete mode 100755 py diff --git a/py b/py deleted file mode 100755 index 6923642..0000000 --- a/py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env python -from __future__ import (unicode_literals, absolute_import, - print_function, division) -import argparse -import sys -import json -import re - -def lazy_imports(expression, pre_cmd, post_cmd): - query = ((expression if expression else '') + - (pre_cmd if pre_cmd else '') + - (post_cmd if post_cmd else '')) - if 'base64' in query: global base64; import base64 - if 'calendar' in query: global calendar; import calendar - if 'csv' in query: global csv; import csv - if 'datetime' in query: global datetime; import datetime - if 'hashlib' in query: global hashlib; import hashlib - if 'glob' in query: global glob; import glob - if 'itertools' in query: global itertools; import itertools - if 'json' in query: global json; import json - if 'math' in query: global math; import math - if 'os' in query: global os; import os - if 'random' in query: global random; import random - if 're' in query: global re; import re - if 'shutil' in query: global shutil; import shutil - if 'tempfile' in query: global tempfile; import tempfile - if 'Counter' in query: global Counter; from collections import Counter - if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict - if 'groupby' in query: global groupby; from itertools import groupby - if 'uuid4' in query: global uuid4; from uuid import uuid4 - -parser = argparse.ArgumentParser( - formatter_class=argparse.RawDescriptionHelpFormatter) - -parser.add_argument('expression', nargs='?', default='None') -parser.add_argument('-x', dest='lines_of_stdin', action='store_const', - const=True, default=False, - help='treat each row as x') -parser.add_argument('-fx', dest='filter_result', action='store_const', - const=True, default=False, - help='keep rows satisfying condition(x)') -parser.add_argument('-l', dest='list_of_stdin', action='store_const', - const=True, default=False, - help='treat list of stdin as l') -parser.add_argument('-c', dest='pre_cmd', help='run code before expression') -parser.add_argument('-C', dest='post_cmd', help='run code after expression') -parser.add_argument('--i', '--ignore_exceptions', - dest='ignore_exceptions', action='store_const', - const=True, default=False, - help='') -parser.add_argument('--si', '--split_input', dest='split_input', - help='pre-process each row with re.split(delimiter, row)') -parser.add_argument('--so', '--split_output', dest='split_output', - help='post-process each row with delimiter.join(row)') -parser.add_argument('--ji' '--json_input', - dest='json_input', action='store_const', - const=True, default=False, - help='pre-process each row with json.loads(row)') -parser.add_argument('--jo' '--json_output', - dest='json_output', action='store_const', - const=True, default=False, - help='post-process each row with json.dumps(row)') - -args = parser.parse_args() - -if args.json_input: - stdin = (json.loads(x.rstrip()) for x in sys.stdin) -elif args.split_input: - stdin = (re.split(args.split_input, x.rstrip()) for x in sys.stdin) -else: - stdin = (x.rstrip() for x in sys.stdin) - -if args.expression: - args.expression = args.expression.replace("`", "'") -if args.pre_cmd: - args.pre_cmd = args.pre_cmd.replace("`", "'") -if args.post_cmd: - args.post_cmd = args.post_cmd.replace("`", "'") - -lazy_imports(args.expression, args.pre_cmd, args.post_cmd) - -if args.pre_cmd: - exec(args.pre_cmd) - -def safe_eval(text, x): - try: - return eval(text) - except: - return None - -if args.lines_of_stdin: - if args.ignore_exceptions: - result = (safe_eval(args.expression, x) for x in stdin) - else: - result = (eval(args.expression) for x in stdin) -elif args.filter_result: - if args.ignore_exceptions: - result = (x for x in stdin if safe_eval(args.expression, x)) - else: - result = (x for x in stdin if eval(args.expression)) -elif args.list_of_stdin: - l = list(stdin) - result = eval(args.expression) -else: - result = eval(args.expression) - -def format(output): - if output == None: - return None - elif args.json_output: - return json.dumps(output) - elif args.split_output: - return args.split_output.join(output) - else: - return output - - -if hasattr(result, '__iter__'): - for x in result: - formatted = format(x) - if formatted is not None: - print(formatted) -else: - formatted = format(result) - if formatted is not None: - print(formatted) - -if args.post_cmd: - exec(args.post_cmd) From 43d748392751a2d561de36361bca1425c007510d Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 16 Jun 2014 20:55:09 -0700 Subject: [PATCH 071/173] Moved pythonpy to py. --- bin/pythonpy => py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename bin/pythonpy => py (100%) diff --git a/bin/pythonpy b/py similarity index 100% rename from bin/pythonpy rename to py From cc63cd7a8d20438530f5e7e7da1393073181c5ed Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 16 Jun 2014 20:57:49 -0700 Subject: [PATCH 072/173] Changed unittests to use "py". --- setup.py | 2 +- test/test_pythonpy.py | 56 +++++++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/setup.py b/setup.py index 33475d1..e502dbf 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ name='pythonpy', version='0.2.5', description='Take advantage of your python skills from the command line', - scripts=['bin/pythonpy', 'py', 'bin/wpy'], + scripts=['py', 'bin/wpy'], license='MIT', url='https://github.com/Russell91/pythonpy', long_description='', diff --git a/test/test_pythonpy.py b/test/test_pythonpy.py index a1768e7..ab4f349 100644 --- a/test/test_pythonpy.py +++ b/test/test_pythonpy.py @@ -3,48 +3,48 @@ class TestPythonPy(unittest.TestCase): def test_empty(self): - self.assertEqual(check_output(['pythonpy']),'') + self.assertEqual(check_output(['py']),'') def test_numbers(self): - self.assertEqual(check_output(['pythonpy', '3 * 4.5']),'13.5\n') + self.assertEqual(check_output(['py', '3 * 4.5']),'13.5\n') def test_range(self): - self.assertEqual(check_output(['pythonpy', 'range(3)']), '\n'.join(map(str, range(3))) + '\n') + self.assertEqual(check_output(['py', 'range(3)']), '\n'.join(map(str, range(3))) + '\n') def test_split_input(self): - self.assertEqual(check_output(["""echo a,b | pythonpy -x 'x[1]' --si ,"""], shell=True), 'b\n') + self.assertEqual(check_output(["""echo a,b | py -x 'x[1]' --si ,"""], shell=True), 'b\n') def test_split_output(self): - self.assertEqual(check_output(["""echo abc | pythonpy -x x --si '' --so ','"""], shell=True), 'a,b,c\n') + self.assertEqual(check_output(["""echo abc | py -x x --si '' --so ','"""], shell=True), 'a,b,c\n') def test_ignore_errors(self): - self.assertEqual(check_output("""echo a | pythonpy -x --i 'None.None'""", shell=True), '') - self.assertEqual(check_output("""echo a | pythonpy -fx --i 'None.None'""", shell=True), '') + self.assertEqual(check_output("""echo a | py -x --i 'None.None'""", shell=True), '') + self.assertEqual(check_output("""echo a | py -fx --i 'None.None'""", shell=True), '') def test_statements(self): - self.assertEqual(check_output("""pythonpy -c 'a=5' -C 'print(a)'""", shell=True), '5\n') - self.assertEqual(check_output("""echo 3 | pythonpy -c 'a=5' -x x -C 'print(a)'""", shell=True), '3\n5\n') + self.assertEqual(check_output("""py -c 'a=5' -C 'print(a)'""", shell=True), '5\n') + self.assertEqual(check_output("""echo 3 | py -c 'a=5' -x x -C 'print(a)'""", shell=True), '3\n5\n') def test_imports(self): - check_output("pythonpy 'math'", shell=True) - check_output("pythonpy 'base64'", shell=True) - check_output("pythonpy 'calendar'", shell=True) - check_output("pythonpy 'csv'", shell=True) - check_output("pythonpy 'datetime'", shell=True) - check_output("pythonpy 'hashlib'", shell=True) - check_output("pythonpy 'glob'", shell=True) - check_output("pythonpy 'itertools'", shell=True) - check_output("pythonpy 'json'", shell=True) - check_output("pythonpy 'math'", shell=True) - check_output("pythonpy 'os'", shell=True) - check_output("pythonpy 'random'", shell=True) - check_output("pythonpy 're'", shell=True) - check_output("pythonpy 'shutil'", shell=True) - check_output("pythonpy 'tempfile'", shell=True) - check_output("pythonpy -c 'Counter'", shell=True) - check_output("pythonpy -c 'OrderedDict'", shell=True) - check_output("pythonpy -c 'groupby'", shell=True) - check_output("pythonpy 'uuid4'", shell=True) + check_output("py 'math'", shell=True) + check_output("py 'base64'", shell=True) + check_output("py 'calendar'", shell=True) + check_output("py 'csv'", shell=True) + check_output("py 'datetime'", shell=True) + check_output("py 'hashlib'", shell=True) + check_output("py 'glob'", shell=True) + check_output("py 'itertools'", shell=True) + check_output("py 'json'", shell=True) + check_output("py 'math'", shell=True) + check_output("py 'os'", shell=True) + check_output("py 'random'", shell=True) + check_output("py 're'", shell=True) + check_output("py 'shutil'", shell=True) + check_output("py 'tempfile'", shell=True) + check_output("py -c 'Counter'", shell=True) + check_output("py -c 'OrderedDict'", shell=True) + check_output("py -c 'groupby'", shell=True) + check_output("py 'uuid4'", shell=True) if __name__ == '__main__': From 792c3b36faa631b236020e57f29a207e38446d80 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 17 Jun 2014 23:57:48 -0700 Subject: [PATCH 073/173] Fixed bug where piping to head caused IOError. --- py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/py b/py index 6923642..ee1ec45 100755 --- a/py +++ b/py @@ -1,6 +1,9 @@ #!/usr/bin/env python from __future__ import (unicode_literals, absolute_import, print_function, division) +from signal import signal, SIGPIPE, SIG_DFL +signal(SIGPIPE,SIG_DFL) + import argparse import sys import json From 5d8d3df1d91c101f391f1274f25e502eea9b2eb0 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 00:20:23 -0700 Subject: [PATCH 074/173] Added command line completion!. --- extras/pycompleter | 83 ++++++++++++++++++++++++++++++++++++++++++ extras/pycompletion.sh | 7 ++++ setup.py | 5 ++- 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100755 extras/pycompleter create mode 100644 extras/pycompletion.sh diff --git a/extras/pycompleter b/extras/pycompleter new file mode 100755 index 0000000..8b4ba66 --- /dev/null +++ b/extras/pycompleter @@ -0,0 +1,83 @@ +#!/usr/bin/env python +from __future__ import (unicode_literals, absolute_import, + print_function, division) +import argparse +import sys +import json +import re +import base64 +import calendar +import csv +import datetime +import hashlib +import glob +import itertools +import json +import math +import os +import random +import re +import shutil +import tempfile +from collections import Counter +from collections import OrderedDict +from itertools import groupby +from uuid import uuid4 + +#if args.pre_cmd: + #exec(args.pre_cmd) + +#if args.post_cmd: + #exec(args.post_cmd) + +import rlcompleter + + +def complete_all(c, s, idx): + global x + global l + x = str() + l = list() + if c.complete(s, idx): + return [c.complete(s, idx)] + complete_all(c, s, idx + 1) + return [] + + +def parse_string(prefix, raw_input): + if prefix == '': + return ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'glob', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil', 'tempfile'] + elif prefix.startswith('--') and not any(q in raw_input for q in ["'", '"']): + return ['--si', '--so', '--ji', '--jo', '--i'] + elif prefix.startswith('-') and not any(q in raw_input for q in ["'", '"']): + return ['-h', '-x', '-fx', '-l', '-c', '-C'] + c = rlcompleter.Completer() + options = list(set(complete_all(c, prefix, 0))) + if prefix.endswith('.'): + options = [x for x in options if '_' not in x] + return options + + + +def parse_input(raw_input): + input = raw_input.rstrip().split(' ')[-1] + if len(input) > 0 and input[0] in ['"', "'"]: + input = input[1:] + return input + + +def main(): + raw_input = next(sys.stdin) + prefix = parse_input(raw_input) + options = parse_string(prefix, raw_input) + + with open('/tmp/a.txt', 'w') as f: + f.write(raw_input + '\n') + f.write(prefix + '\n') + for x in options: + f.write(x + '\n') + if len(options) <= 1: + options = options + [x + "'" for x in options] + print(' '.join(options)) + +if __name__ == '__main__': + main() diff --git a/extras/pycompletion.sh b/extras/pycompletion.sh new file mode 100644 index 0000000..7692e60 --- /dev/null +++ b/extras/pycompletion.sh @@ -0,0 +1,7 @@ +_py() +{ + local cur=${COMP_WORDS[COMP_CWORD]} + COMPREPLY=($(echo ${COMP_WORDS[@]:1} | pycompleter)) +} + +complete -F _py -o nospace py diff --git a/setup.py b/setup.py index e502dbf..e2c4956 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,10 @@ name='pythonpy', version='0.2.5', description='Take advantage of your python skills from the command line', - scripts=['py', 'bin/wpy'], + scripts=['py', 'extras/pycompleter', 'bin/wpy'], + data_files=[ + ('/etc/bash_completion.d', ['extras/pycompletion.sh']), + ], license='MIT', url='https://github.com/Russell91/pythonpy', long_description='', From 099647bbd4e1bbacc53f489f0e4dd2c2bc02ff56 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 00:20:51 -0700 Subject: [PATCH 075/173] Moved wpy to new extras folder. --- {bin => extras}/wpy | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {bin => extras}/wpy (100%) diff --git a/bin/wpy b/extras/wpy similarity index 100% rename from bin/wpy rename to extras/wpy From 04070e6736af688b8a871edfbbef52099d734d4f Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 00:22:08 -0700 Subject: [PATCH 076/173] Moved wpy to new extras folder. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e2c4956..d4e07ee 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ name='pythonpy', version='0.2.5', description='Take advantage of your python skills from the command line', - scripts=['py', 'extras/pycompleter', 'bin/wpy'], + scripts=['py', 'extras/pycompleter', 'extras/wpy'], data_files=[ ('/etc/bash_completion.d', ['extras/pycompletion.sh']), ], From c4a39da92b1750ad6777a43c8af72fac52108c28 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 00:35:50 -0700 Subject: [PATCH 077/173] 0.2.6dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d4e07ee..0077b05 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='pythonpy', - version='0.2.5', + version='0.2.6dev', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/pycompleter', 'extras/wpy'], data_files=[ From 52076e92ad5fb76ca22732cde9a1947bb5adefd5 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 00:52:28 -0700 Subject: [PATCH 078/173] Removed some less common modules from completion list. --- extras/pycompleter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/pycompleter b/extras/pycompleter index 8b4ba66..4640b31 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -45,7 +45,7 @@ def complete_all(c, s, idx): def parse_string(prefix, raw_input): if prefix == '': - return ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'glob', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil', 'tempfile'] + return ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil'] elif prefix.startswith('--') and not any(q in raw_input for q in ["'", '"']): return ['--si', '--so', '--ji', '--jo', '--i'] elif prefix.startswith('-') and not any(q in raw_input for q in ["'", '"']): From 6a86f460aa57eed5c20b765ca14bbb88fa9826af Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 01:22:50 -0700 Subject: [PATCH 079/173] Ignoring tab completion if root is not used. --- setup.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 0077b05..abe3346 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,20 @@ from distutils.core import setup import os +try: + with open('/etc/bash_completion.d/pycompletion.sh', 'w') eo: + eo.write('test') + data_files = [('/etc/bash_completion.d', ['extras/pycompletion.sh']),] +except error: + print 'User does not have write access to /etc completion will not work' + data_files = [('bash_completion.d', ['extras/pycompletion.sh']),] + setup( name='pythonpy', version='0.2.6dev', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/pycompleter', 'extras/wpy'], - data_files=[ - ('/etc/bash_completion.d', ['extras/pycompletion.sh']), - ], + data_files=data_files, license='MIT', url='https://github.com/Russell91/pythonpy', long_description='', From 423d2354a8b4b84662593bfc6884bc4a6fb5bd51 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 01:25:10 -0700 Subject: [PATCH 080/173] 0.2.6dev2 --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index abe3346..612801f 100644 --- a/setup.py +++ b/setup.py @@ -2,16 +2,16 @@ import os try: - with open('/etc/bash_completion.d/pycompletion.sh', 'w') eo: + with open('/etc/bash_completion.d/pycompletion.sh', 'w') as eo: eo.write('test') data_files = [('/etc/bash_completion.d', ['extras/pycompletion.sh']),] -except error: +except: print 'User does not have write access to /etc completion will not work' data_files = [('bash_completion.d', ['extras/pycompletion.sh']),] setup( name='pythonpy', - version='0.2.6dev', + version='0.2.6dev2', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/pycompleter', 'extras/wpy'], data_files=data_files, From b275b09a62550e449f48161b9e180bf88cb14335 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 19:00:02 -0700 Subject: [PATCH 081/173] Removed dead $cur reference from pycompletion.sh. --- extras/pycompletion.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/extras/pycompletion.sh b/extras/pycompletion.sh index 7692e60..7a32916 100644 --- a/extras/pycompletion.sh +++ b/extras/pycompletion.sh @@ -1,6 +1,5 @@ _py() { - local cur=${COMP_WORDS[COMP_CWORD]} COMPREPLY=($(echo ${COMP_WORDS[@]:1} | pycompleter)) } From e489210312cb7e6ddd2dfd6e553440a2806ff0f5 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 19:03:33 -0700 Subject: [PATCH 082/173] 0.2.6dev3 --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 612801f..fdeb4a6 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ try: with open('/etc/bash_completion.d/pycompletion.sh', 'w') as eo: - eo.write('test') + eo.write('test2') data_files = [('/etc/bash_completion.d', ['extras/pycompletion.sh']),] except: print 'User does not have write access to /etc completion will not work' @@ -11,7 +11,7 @@ setup( name='pythonpy', - version='0.2.6dev2', + version='0.2.6dev3', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/pycompleter', 'extras/wpy'], data_files=data_files, From da47b0f1c71b564f22af7c467676ee26a2cbd4e4 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 19:07:39 -0700 Subject: [PATCH 083/173] 0.2.6dev4 --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index fdeb4a6..3515996 100644 --- a/setup.py +++ b/setup.py @@ -2,8 +2,8 @@ import os try: - with open('/etc/bash_completion.d/pycompletion.sh', 'w') as eo: - eo.write('test2') + with open('/etc/bash_completion.d/pycompletion_test.sh', 'w') as eo: + eo.write('test3') data_files = [('/etc/bash_completion.d', ['extras/pycompletion.sh']),] except: print 'User does not have write access to /etc completion will not work' @@ -11,7 +11,7 @@ setup( name='pythonpy', - version='0.2.6dev3', + version='0.2.6dev4', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/pycompleter', 'extras/wpy'], data_files=data_files, From 323974a08742c567feeae24cf47db5ea1de58a4e Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 19:11:50 -0700 Subject: [PATCH 084/173] 0.2.6dev5 --- setup.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 3515996..973fd48 100644 --- a/setup.py +++ b/setup.py @@ -1,17 +1,15 @@ from distutils.core import setup import os -try: - with open('/etc/bash_completion.d/pycompletion_test.sh', 'w') as eo: - eo.write('test3') +if os.geteuid() == 0: data_files = [('/etc/bash_completion.d', ['extras/pycompletion.sh']),] -except: +else: print 'User does not have write access to /etc completion will not work' data_files = [('bash_completion.d', ['extras/pycompletion.sh']),] setup( name='pythonpy', - version='0.2.6dev4', + version='0.2.6dev5', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/pycompleter', 'extras/wpy'], data_files=data_files, From dbf9b0fd2a1f4074c3abcc44106dc2136360da96 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 19:23:54 -0700 Subject: [PATCH 085/173] 0.3.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 973fd48..eddaf48 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name='pythonpy', - version='0.2.6dev5', + version='0.3.0', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/pycompleter', 'extras/wpy'], data_files=data_files, From 2821f897e6c255647f36d11c3d18317fbfa2fc07 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 18 Jun 2014 19:26:43 -0700 Subject: [PATCH 086/173] Added bash refresh to install command in README. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ee19fc4..cb42d99 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ Installation :: - sudo pip install pythonpy + sudo pip install pythonpy && bash :: From 1af9b33b578f554b1226fa5268f40de669d9b82f Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 19 Jun 2014 10:26:14 -0700 Subject: [PATCH 087/173] Added requirement isinstance(result, Iterable) for multi-line output. --- py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/py b/py index ee1ec45..294273e 100755 --- a/py +++ b/py @@ -8,6 +8,7 @@ import argparse import sys import json import re +from collections import Iterable def lazy_imports(expression, pre_cmd, post_cmd): query = ((expression if expression else '') + @@ -118,7 +119,7 @@ def format(output): return output -if hasattr(result, '__iter__'): +if isinstance(result, Iterable) and hasattr(result, '__iter__') and not isinstance(result, str): for x in result: formatted = format(x) if formatted is not None: From 939be417fdbe6992e3e003de362e6b5c10ff3b3e Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 19 Jun 2014 10:54:40 -0700 Subject: [PATCH 088/173] Added docstring to wpy. --- extras/wpy | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extras/wpy b/extras/wpy index 6923642..3548252 100755 --- a/extras/wpy +++ b/extras/wpy @@ -1,4 +1,8 @@ #!/usr/bin/env python +''' +Windows version of py. Still in development. +''' + from __future__ import (unicode_literals, absolute_import, print_function, division) import argparse From 56840815c8f9ba03ac9a8321be3791609f0b8f1e Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 19 Jun 2014 10:59:15 -0700 Subject: [PATCH 089/173] Added py3 executable for use with python3. --- extras/py3 | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 2 files changed, 134 insertions(+), 1 deletion(-) create mode 100755 extras/py3 diff --git a/extras/py3 b/extras/py3 new file mode 100755 index 0000000..eb512f9 --- /dev/null +++ b/extras/py3 @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 +from __future__ import (unicode_literals, absolute_import, + print_function, division) +from signal import signal, SIGPIPE, SIG_DFL +signal(SIGPIPE,SIG_DFL) + +import argparse +import sys +import json +import re +from collections import Iterable + +def lazy_imports(expression, pre_cmd, post_cmd): + query = ((expression if expression else '') + + (pre_cmd if pre_cmd else '') + + (post_cmd if post_cmd else '')) + if 'base64' in query: global base64; import base64 + if 'calendar' in query: global calendar; import calendar + if 'csv' in query: global csv; import csv + if 'datetime' in query: global datetime; import datetime + if 'hashlib' in query: global hashlib; import hashlib + if 'glob' in query: global glob; import glob + if 'itertools' in query: global itertools; import itertools + if 'json' in query: global json; import json + if 'math' in query: global math; import math + if 'os' in query: global os; import os + if 'random' in query: global random; import random + if 're' in query: global re; import re + if 'shutil' in query: global shutil; import shutil + if 'tempfile' in query: global tempfile; import tempfile + if 'Counter' in query: global Counter; from collections import Counter + if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict + if 'groupby' in query: global groupby; from itertools import groupby + if 'uuid4' in query: global uuid4; from uuid import uuid4 + +parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter) + +parser.add_argument('expression', nargs='?', default='None') +parser.add_argument('-x', dest='lines_of_stdin', action='store_const', + const=True, default=False, + help='treat each row as x') +parser.add_argument('-fx', dest='filter_result', action='store_const', + const=True, default=False, + help='keep rows satisfying condition(x)') +parser.add_argument('-l', dest='list_of_stdin', action='store_const', + const=True, default=False, + help='treat list of stdin as l') +parser.add_argument('-c', dest='pre_cmd', help='run code before expression') +parser.add_argument('-C', dest='post_cmd', help='run code after expression') +parser.add_argument('--i', '--ignore_exceptions', + dest='ignore_exceptions', action='store_const', + const=True, default=False, + help='') +parser.add_argument('--si', '--split_input', dest='split_input', + help='pre-process each row with re.split(delimiter, row)') +parser.add_argument('--so', '--split_output', dest='split_output', + help='post-process each row with delimiter.join(row)') +parser.add_argument('--ji' '--json_input', + dest='json_input', action='store_const', + const=True, default=False, + help='pre-process each row with json.loads(row)') +parser.add_argument('--jo' '--json_output', + dest='json_output', action='store_const', + const=True, default=False, + help='post-process each row with json.dumps(row)') + +args = parser.parse_args() + +if args.json_input: + stdin = (json.loads(x.rstrip()) for x in sys.stdin) +elif args.split_input: + stdin = (re.split(args.split_input, x.rstrip()) for x in sys.stdin) +else: + stdin = (x.rstrip() for x in sys.stdin) + +if args.expression: + args.expression = args.expression.replace("`", "'") +if args.pre_cmd: + args.pre_cmd = args.pre_cmd.replace("`", "'") +if args.post_cmd: + args.post_cmd = args.post_cmd.replace("`", "'") + +lazy_imports(args.expression, args.pre_cmd, args.post_cmd) + +if args.pre_cmd: + exec(args.pre_cmd) + +def safe_eval(text, x): + try: + return eval(text) + except: + return None + +if args.lines_of_stdin: + if args.ignore_exceptions: + result = (safe_eval(args.expression, x) for x in stdin) + else: + result = (eval(args.expression) for x in stdin) +elif args.filter_result: + if args.ignore_exceptions: + result = (x for x in stdin if safe_eval(args.expression, x)) + else: + result = (x for x in stdin if eval(args.expression)) +elif args.list_of_stdin: + l = list(stdin) + result = eval(args.expression) +else: + result = eval(args.expression) + +def format(output): + if output == None: + return None + elif args.json_output: + return json.dumps(output) + elif args.split_output: + return args.split_output.join(output) + else: + return output + + +if isinstance(result, Iterable) and hasattr(result, '__iter__') and not isinstance(result, str): + for x in result: + formatted = format(x) + if formatted is not None: + print(formatted) +else: + formatted = format(result) + if formatted is not None: + print(formatted) + +if args.post_cmd: + exec(args.post_cmd) diff --git a/setup.py b/setup.py index eddaf48..fbc6e44 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ name='pythonpy', version='0.3.0', description='Take advantage of your python skills from the command line', - scripts=['py', 'extras/pycompleter', 'extras/wpy'], + scripts=['py', 'extras/py3', 'extras/pycompleter', 'extras/wpy'], data_files=data_files, license='MIT', url='https://github.com/Russell91/pythonpy', From 377f04a5f2c8f35fb744d9065ba64fbdbe15042c Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 19 Jun 2014 11:01:05 -0700 Subject: [PATCH 090/173] Added docstring to py3. --- extras/py3 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extras/py3 b/extras/py3 index eb512f9..c73835f 100755 --- a/extras/py3 +++ b/extras/py3 @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +''' +Just like py but using python3! +Tab completion not yet supported :(. +''' from __future__ import (unicode_literals, absolute_import, print_function, division) from signal import signal, SIGPIPE, SIG_DFL From 3eecdbeec65ce1d5c702a03e3f5a189937aa3530 Mon Sep 17 00:00:00 2001 From: Bartosz Marcinkowski Date: Thu, 19 Jun 2014 19:52:11 +0200 Subject: [PATCH 091/173] py3k installation fix --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index eddaf48..37718de 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ if os.geteuid() == 0: data_files = [('/etc/bash_completion.d', ['extras/pycompletion.sh']),] else: - print 'User does not have write access to /etc completion will not work' + print('User does not have write access to /etc completion will not work') data_files = [('bash_completion.d', ['extras/pycompletion.sh']),] setup( From def6a8be95c70042d791c831639c84f84552cdb3 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 19 Jun 2014 15:33:44 -0700 Subject: [PATCH 092/173] Menitioned tab completion in README. --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index cb42d99..81df47d 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,8 @@ Installation :: - sudo pip install pythonpy && bash + sudo pip install pythonpy + bash # restart your shell for tab completion to take effect :: From 9938d29d9fb3c692afbfcb5874eaad5a22dcbb96 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 19 Jun 2014 15:35:18 -0700 Subject: [PATCH 093/173] Changed spacing on README. --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 81df47d..add2abb 100644 --- a/README.rst +++ b/README.rst @@ -4,7 +4,7 @@ Installation :: sudo pip install pythonpy - bash # restart your shell for tab completion to take effect + bash # restart your shell for tab completion to take effect :: @@ -13,7 +13,7 @@ Float Arithmetic :: - $ py '3 * 1.5' # For Windows use: wpy '3 * 1.5' + $ py '3 * 1.5' # For Windows use: wpy '3 * 1.5' 4.5 From 3406d5657d3ead8e0cd3dcbbfbb27ad6b29b6b21 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 20 Jun 2014 21:30:08 -0700 Subject: [PATCH 094/173] Changed the flow of the readme. --- README.rst | 154 ++++++++++++++++++++--------------------------------- 1 file changed, 59 insertions(+), 95 deletions(-) diff --git a/README.rst b/README.rst index add2abb..cd1053b 100644 --- a/README.rst +++ b/README.rst @@ -8,29 +8,38 @@ Installation :: +py 'expression' ≅ python -c 'print(expression)' +----------------------------------------------- + Float Arithmetic ~~~~~~~~~~~~~~~~ :: - $ py '3 * 1.5' # For Windows use: wpy '3 * 1.5' + $ py '3 * 1.5' 4.5 - :: -Exponentiation -~~~~~~~~~~~~~~ +Access common imports directly +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: - $ py '7**3' - 343 + $ py 'math.exp(1)' + 2.71828182846 + + $ py 'random.random()' + 0.103173957713 + + $ py 'datetime.datetime.now()' + 2014-06-20 20:22:03.699290 + :: -Number sequence -~~~~~~~~~~~~~~~ +Lists are printed row by row +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: @@ -39,40 +48,13 @@ Number sequence 1 2 -:: - -List comprehensions -~~~~~~~~~~~~~~~~~~~ - -:: - - $ py '[x**2 for x in range(1,5)]' - 1 - 4 - 9 - 16 - -:: - -Math library usage -~~~~~~~~~~~~~~~~~~ - -:: - - $ py 'math.exp(1)' - 2.71828182846 - -:: - -Random library usage -~~~~~~~~~~~~~~~~~~~~ + $ py '[range(3)]' + [0, 1, 2] :: - $ py 'random.random()' - 0.103173957713 - -:: +py -x 'foo(x)' will apply foo to each line of input +--------------------------------------------------- Multiply each line of input by 7. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -92,51 +74,12 @@ Append ".txt" to each line of input :: $ py 'range(3)' | py -x 'x + ".txt"' - 0.txt 1.txt 2.txt + 3.txt :: -Sometimes you want to treat the input as a python list ------------------------------------------------------- - -Reverse a list -~~~~~~~~~~~~~~ - -:: - - $ py 'range(4)' | py -l 'l[::-1]' - 3 - 2 - 1 - 0 - -:: - -Sum a list of numbers -~~~~~~~~~~~~~~~~~~~~~ - -:: - - $ py 'range(4)' | py -l 'sum(int(x) for x in l)' - 6 - -:: - -Count the lines of input -~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - $ py 'range(17)' | py -l 'len(l)' - 17 - -:: - -Other times you just want to filter out lines from the input ------------------------------------------------------------- - Get only even numbers ~~~~~~~~~~~~~~~~~~~~~ @@ -150,8 +93,8 @@ Get only even numbers :: -The shorthand -fx (filter on x) is also available -------------------------------------------------- +py -fx 'predicate(x)' filters rows satisfying a condition +--------------------------------------------------------- Get only odd numbers ~~~~~~~~~~~~~~~~~~~~ @@ -208,33 +151,54 @@ Get long palindromes :: -Count words beginning with each letter -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +py -l will set l = list(sys.stdin) +------------------------------------------- + +Reverse the input +~~~~~~~~~~~~~~~~~ :: - $ cat /usr/share/dict/words | py -x 'x[0].lower()' | py -l 'Counter(l).most_common(5)' - ('s', 11327) - ('c', 9521) - ('p', 7659) - ('b', 6068) - ('m', 5922) + $ py 'range(3)' | py -l 'l[::-1]' + 2 + 1 + 0 + +:: + +Sum the input +~~~~~~~~~~~~~ :: -Keep going if some rows raise Errors with (--i). ------------------------------------------------- + $ py 'range(3)' | py -l 'sum(int(x) for x in l)' + 3 + +:: -Get the local network ip +Count the lines of input ~~~~~~~~~~~~~~~~~~~~~~~~ :: - $ ifconfig | py -x --i 're.search(r"192\.168[\d\.]+", x).group()' - 192.168.1.41 + $ py 'range(17)' | py -l 'len(l)' + 17 + +:: + +Count words beginning with each letter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: + $ cat /usr/share/dict/words | py -x 'x[0].lower()' | py -l 'Counter(l).most_common(5)' + ('s', 11327) + ('c', 9521) + ('p', 7659) + ('b', 6068) + ('m', 5922) + +:: If you haven't had enough yet, check out the `wiki `__ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From caeacf122bffb95d8c7d0651072fcd2eb59d62a6 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 19 Jun 2014 23:46:30 -0700 Subject: [PATCH 095/173] Fixed some space bugs in tab completion. --- extras/pycompleter | 7 +------ extras/pycompletion.sh | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 4640b31..9097cf2 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -59,7 +59,7 @@ def parse_string(prefix, raw_input): def parse_input(raw_input): - input = raw_input.rstrip().split(' ')[-1] + input = raw_input.split(' ')[-1].rstrip() if len(input) > 0 and input[0] in ['"', "'"]: input = input[1:] return input @@ -70,11 +70,6 @@ def main(): prefix = parse_input(raw_input) options = parse_string(prefix, raw_input) - with open('/tmp/a.txt', 'w') as f: - f.write(raw_input + '\n') - f.write(prefix + '\n') - for x in options: - f.write(x + '\n') if len(options) <= 1: options = options + [x + "'" for x in options] print(' '.join(options)) diff --git a/extras/pycompletion.sh b/extras/pycompletion.sh index 7a32916..b1aff5b 100644 --- a/extras/pycompletion.sh +++ b/extras/pycompletion.sh @@ -1,6 +1,6 @@ _py() { - COMPREPLY=($(echo ${COMP_WORDS[@]:1} | pycompleter)) + COMPREPLY=($(echo "${COMP_WORDS[@]:1}" | pycompleter)) } complete -F _py -o nospace py From 515260fdc82bd8c0033e1a8727b02ddce947938b Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 20 Jun 2014 00:33:56 -0700 Subject: [PATCH 096/173] Moving towards import completion. --- extras/pycompleter | 75 +++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 9097cf2..323b94b 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -24,51 +24,58 @@ from collections import OrderedDict from itertools import groupby from uuid import uuid4 -#if args.pre_cmd: - #exec(args.pre_cmd) - -#if args.post_cmd: - #exec(args.post_cmd) - import rlcompleter -def complete_all(c, s, idx): - global x - global l - x = str() - l = list() - if c.complete(s, idx): - return [c.complete(s, idx)] + complete_all(c, s, idx + 1) - return [] +def complete_all(prefix, c_arg): + if c_arg: + exec(c_arg) + idx = 0 + options_set = set() + completer = rlcompleter.Completer() + while completer.complete(prefix, idx): + options_set.add(completer.complete(prefix, idx)) + idx += 1 + return list(options_set) -def parse_string(prefix, raw_input): - if prefix == '': - return ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil'] - elif prefix.startswith('--') and not any(q in raw_input for q in ["'", '"']): - return ['--si', '--so', '--ji', '--jo', '--i'] +def parse_string(input, raw_input): + options = [] + prefix = input[-1].lstrip('"\'') + prior = input[:-1] + if prefix.startswith('--') and not any(q in raw_input for q in ["'", '"']): + options = ['--si', '--so', '--ji', '--jo', '--i'] elif prefix.startswith('-') and not any(q in raw_input for q in ["'", '"']): - return ['-h', '-x', '-fx', '-l', '-c', '-C'] - c = rlcompleter.Completer() - options = list(set(complete_all(c, prefix, 0))) - if prefix.endswith('.'): - options = [x for x in options if '_' not in x] + options = ['-h', '-x', '-fx', '-l', '-c', '-C'] + elif prefix == '': + options = ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil'] # +x,l + if '-x' in input[:-1] or '-fx' in input[:-1]: + options += 'x' + if '-l' in input[:-1]: + options += 'l' + else: + c_arg = None + if '-x' in prior or '-fx' in prior: + global x + x = str() + if '-l' in prior: + global l + l = list() + if '-c' in prior: + c_index = prior.index('-c') + if (c_index + 1) < len(prior): + c_arg = prior[c_index + 1] + options = complete_all(prefix, c_arg) + if prefix.endswith('.'): + options = [x for x in options if '._' not in x] return options - -def parse_input(raw_input): - input = raw_input.split(' ')[-1].rstrip() - if len(input) > 0 and input[0] in ['"', "'"]: - input = input[1:] - return input - - def main(): raw_input = next(sys.stdin) - prefix = parse_input(raw_input) - options = parse_string(prefix, raw_input) + input = raw_input.split(' ') + input[-1] = input[-1].rstrip() + options = parse_string(input, raw_input) if len(options) <= 1: options = options + [x + "'" for x in options] From 01aa3e88933f03af78c450d8db51b1d0417b612a Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 00:22:45 -0700 Subject: [PATCH 097/173] import module, module.tab_complete works! --- extras/pycompleter | 17 ++++++++--------- extras/pycompletion.sh | 3 ++- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 323b94b..8047e27 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -29,23 +29,23 @@ import rlcompleter def complete_all(prefix, c_arg): if c_arg: - exec(c_arg) + exec(c_arg.strip('"\'')) idx = 0 options_set = set() - completer = rlcompleter.Completer() + completer = rlcompleter.Completer(locals()) while completer.complete(prefix, idx): options_set.add(completer.complete(prefix, idx)) idx += 1 return list(options_set) -def parse_string(input, raw_input): +def parse_string(input): options = [] prefix = input[-1].lstrip('"\'') prior = input[:-1] - if prefix.startswith('--') and not any(q in raw_input for q in ["'", '"']): + if prefix.startswith('--') and not any(q in ''.join(input) for q in ["'", '"']): options = ['--si', '--so', '--ji', '--jo', '--i'] - elif prefix.startswith('-') and not any(q in raw_input for q in ["'", '"']): + elif prefix.startswith('-') and not any(q in ''.join(input) for q in ["'", '"']): options = ['-h', '-x', '-fx', '-l', '-c', '-C'] elif prefix == '': options = ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil'] # +x,l @@ -65,6 +65,7 @@ def parse_string(input, raw_input): c_index = prior.index('-c') if (c_index + 1) < len(prior): c_arg = prior[c_index + 1] + #sys.stderr.write(c_arg) options = complete_all(prefix, c_arg) if prefix.endswith('.'): options = [x for x in options if '._' not in x] @@ -72,10 +73,8 @@ def parse_string(input, raw_input): def main(): - raw_input = next(sys.stdin) - input = raw_input.split(' ') - input[-1] = input[-1].rstrip() - options = parse_string(input, raw_input) + input = sys.argv[1:] + options = parse_string(input) if len(options) <= 1: options = options + [x + "'" for x in options] diff --git a/extras/pycompletion.sh b/extras/pycompletion.sh index b1aff5b..8d9f299 100644 --- a/extras/pycompletion.sh +++ b/extras/pycompletion.sh @@ -1,6 +1,7 @@ _py() { - COMPREPLY=($(echo "${COMP_WORDS[@]:1}" | pycompleter)) + #COMPREPLY=($(echo "${COMP_WORDS[@]:1}" | pycompleter)) + COMPREPLY=($(pycompleter "${COMP_WORDS[@]:1}" )) } complete -F _py -o nospace py From 49e8b8aa5d5659998587c917fcb70baf0c22c735 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 01:07:09 -0700 Subject: [PATCH 098/173] Starting to build import completion. --- extras/pycompleter | 56 +++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 8047e27..4eb422a 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -25,14 +25,17 @@ from itertools import groupby from uuid import uuid4 import rlcompleter +import IPython.core.completerlib as completerlib def complete_all(prefix, c_arg): if c_arg: exec(c_arg.strip('"\'')) + context = locals() + context.update(globals()) + completer = rlcompleter.Completer(context) idx = 0 options_set = set() - completer = rlcompleter.Completer(locals()) while completer.complete(prefix, idx): options_set.add(completer.complete(prefix, idx)) idx += 1 @@ -41,34 +44,37 @@ def complete_all(prefix, c_arg): def parse_string(input): options = [] - prefix = input[-1].lstrip('"\'') + current_full = input[-1].lstrip('"\'') + current_prefix = current_full.split(' ')[-1] prior = input[:-1] - if prefix.startswith('--') and not any(q in ''.join(input) for q in ["'", '"']): + if input[-1].startswith('--'): options = ['--si', '--so', '--ji', '--jo', '--i'] - elif prefix.startswith('-') and not any(q in ''.join(input) for q in ["'", '"']): + elif input[-1].startswith('-'): options = ['-h', '-x', '-fx', '-l', '-c', '-C'] - elif prefix == '': - options = ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil'] # +x,l - if '-x' in input[:-1] or '-fx' in input[:-1]: - options += 'x' - if '-l' in input[:-1]: - options += 'l' + elif len(prior) > 0 and prior[-1] == '-c': + options = completerlib.module_completion(current_full) or [] else: - c_arg = None - if '-x' in prior or '-fx' in prior: - global x - x = str() - if '-l' in prior: - global l - l = list() - if '-c' in prior: - c_index = prior.index('-c') - if (c_index + 1) < len(prior): - c_arg = prior[c_index + 1] - #sys.stderr.write(c_arg) - options = complete_all(prefix, c_arg) - if prefix.endswith('.'): - options = [x for x in options if '._' not in x] + if current_full == '': + options = ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil'] + if '-x' in input[:-1] or '-fx' in input[:-1]: + options += 'x' + if '-l' in input[:-1]: + options += 'l' + else: + c_arg = None + if '-x' in prior or '-fx' in prior: + global x + x = str() + if '-l' in prior: + global l + l = list() + if '-c' in prior: + c_index = prior.index('-c') + if (c_index + 1) < len(prior): + c_arg = prior[c_index + 1] + options = complete_all(current_prefix, c_arg) + if current_prefix.endswith('.'): + options = [x for x in options if '._' not in x] return options From 69799289403ce1b4a94b6d380282549a18b80ad9 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 01:16:45 -0700 Subject: [PATCH 099/173] 0.3.1dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3a2d14f..099a939 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name='pythonpy', - version='0.3.0', + version='0.3.1dev', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/py3', 'extras/pycompleter', 'extras/wpy'], data_files=data_files, From 2c8dde7f65314f0bb449eba88ffeac0a41b2db30 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 01:18:26 -0700 Subject: [PATCH 100/173] Removed wpy until it`s ready. --- extras/wpy | 133 ----------------------------------------------------- setup.py | 2 +- 2 files changed, 1 insertion(+), 134 deletions(-) delete mode 100755 extras/wpy diff --git a/extras/wpy b/extras/wpy deleted file mode 100755 index 3548252..0000000 --- a/extras/wpy +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python -''' -Windows version of py. Still in development. -''' - -from __future__ import (unicode_literals, absolute_import, - print_function, division) -import argparse -import sys -import json -import re - -def lazy_imports(expression, pre_cmd, post_cmd): - query = ((expression if expression else '') + - (pre_cmd if pre_cmd else '') + - (post_cmd if post_cmd else '')) - if 'base64' in query: global base64; import base64 - if 'calendar' in query: global calendar; import calendar - if 'csv' in query: global csv; import csv - if 'datetime' in query: global datetime; import datetime - if 'hashlib' in query: global hashlib; import hashlib - if 'glob' in query: global glob; import glob - if 'itertools' in query: global itertools; import itertools - if 'json' in query: global json; import json - if 'math' in query: global math; import math - if 'os' in query: global os; import os - if 'random' in query: global random; import random - if 're' in query: global re; import re - if 'shutil' in query: global shutil; import shutil - if 'tempfile' in query: global tempfile; import tempfile - if 'Counter' in query: global Counter; from collections import Counter - if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict - if 'groupby' in query: global groupby; from itertools import groupby - if 'uuid4' in query: global uuid4; from uuid import uuid4 - -parser = argparse.ArgumentParser( - formatter_class=argparse.RawDescriptionHelpFormatter) - -parser.add_argument('expression', nargs='?', default='None') -parser.add_argument('-x', dest='lines_of_stdin', action='store_const', - const=True, default=False, - help='treat each row as x') -parser.add_argument('-fx', dest='filter_result', action='store_const', - const=True, default=False, - help='keep rows satisfying condition(x)') -parser.add_argument('-l', dest='list_of_stdin', action='store_const', - const=True, default=False, - help='treat list of stdin as l') -parser.add_argument('-c', dest='pre_cmd', help='run code before expression') -parser.add_argument('-C', dest='post_cmd', help='run code after expression') -parser.add_argument('--i', '--ignore_exceptions', - dest='ignore_exceptions', action='store_const', - const=True, default=False, - help='') -parser.add_argument('--si', '--split_input', dest='split_input', - help='pre-process each row with re.split(delimiter, row)') -parser.add_argument('--so', '--split_output', dest='split_output', - help='post-process each row with delimiter.join(row)') -parser.add_argument('--ji' '--json_input', - dest='json_input', action='store_const', - const=True, default=False, - help='pre-process each row with json.loads(row)') -parser.add_argument('--jo' '--json_output', - dest='json_output', action='store_const', - const=True, default=False, - help='post-process each row with json.dumps(row)') - -args = parser.parse_args() - -if args.json_input: - stdin = (json.loads(x.rstrip()) for x in sys.stdin) -elif args.split_input: - stdin = (re.split(args.split_input, x.rstrip()) for x in sys.stdin) -else: - stdin = (x.rstrip() for x in sys.stdin) - -if args.expression: - args.expression = args.expression.replace("`", "'") -if args.pre_cmd: - args.pre_cmd = args.pre_cmd.replace("`", "'") -if args.post_cmd: - args.post_cmd = args.post_cmd.replace("`", "'") - -lazy_imports(args.expression, args.pre_cmd, args.post_cmd) - -if args.pre_cmd: - exec(args.pre_cmd) - -def safe_eval(text, x): - try: - return eval(text) - except: - return None - -if args.lines_of_stdin: - if args.ignore_exceptions: - result = (safe_eval(args.expression, x) for x in stdin) - else: - result = (eval(args.expression) for x in stdin) -elif args.filter_result: - if args.ignore_exceptions: - result = (x for x in stdin if safe_eval(args.expression, x)) - else: - result = (x for x in stdin if eval(args.expression)) -elif args.list_of_stdin: - l = list(stdin) - result = eval(args.expression) -else: - result = eval(args.expression) - -def format(output): - if output == None: - return None - elif args.json_output: - return json.dumps(output) - elif args.split_output: - return args.split_output.join(output) - else: - return output - - -if hasattr(result, '__iter__'): - for x in result: - formatted = format(x) - if formatted is not None: - print(formatted) -else: - formatted = format(result) - if formatted is not None: - print(formatted) - -if args.post_cmd: - exec(args.post_cmd) diff --git a/setup.py b/setup.py index 099a939..e446b8b 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ name='pythonpy', version='0.3.1dev', description='Take advantage of your python skills from the command line', - scripts=['py', 'extras/py3', 'extras/pycompleter', 'extras/wpy'], + scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, license='MIT', url='https://github.com/Russell91/pythonpy', From ab335f29bc1c9326a34ebad9d0b02754dccd1c05 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 01:24:18 -0700 Subject: [PATCH 101/173] Used lazy import of completer lib for. --- extras/pycompleter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/pycompleter b/extras/pycompleter index 4eb422a..b3d6e86 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -25,7 +25,6 @@ from itertools import groupby from uuid import uuid4 import rlcompleter -import IPython.core.completerlib as completerlib def complete_all(prefix, c_arg): @@ -52,6 +51,7 @@ def parse_string(input): elif input[-1].startswith('-'): options = ['-h', '-x', '-fx', '-l', '-c', '-C'] elif len(prior) > 0 and prior[-1] == '-c': + import IPython.core.completerlib as completerlib options = completerlib.module_completion(current_full) or [] else: if current_full == '': From 21d2af81e3af49f072a14fcdfa92e5a96b1171c4 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 01:31:56 -0700 Subject: [PATCH 102/173] Return from completion immediately if no input. --- extras/pycompleter | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extras/pycompleter b/extras/pycompleter index b3d6e86..9f91de7 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -80,6 +80,8 @@ def parse_string(input): def main(): input = sys.argv[1:] + if len(input) == 0: + return options = parse_string(input) if len(options) <= 1: From 6b71ef0874eb12c34b1a50123f2b59d08666c7c6 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 01:32:16 -0700 Subject: [PATCH 103/173] 0.3.1dev2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e446b8b..4de7c9c 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name='pythonpy', - version='0.3.1dev', + version='0.3.1dev2', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From ee5793d42e14bae3e5261f04b6cff8d7e970e126 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 11:03:48 -0700 Subject: [PATCH 104/173] Muted errors in pycompleter. --- extras/pycompletion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/pycompletion.sh b/extras/pycompletion.sh index 8d9f299..1902210 100644 --- a/extras/pycompletion.sh +++ b/extras/pycompletion.sh @@ -1,7 +1,7 @@ _py() { #COMPREPLY=($(echo "${COMP_WORDS[@]:1}" | pycompleter)) - COMPREPLY=($(pycompleter "${COMP_WORDS[@]:1}" )) + COMPREPLY=($(pycompleter "${COMP_WORDS[@]:1}" 2>/dev/null )) } complete -F _py -o nospace py From 6d8b989d41bb97d74d732c4d350b41256c5d4496 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 12:30:30 -0700 Subject: [PATCH 105/173] Added -c import completion. --- extras/completerlib.py | 189 +++++++++++++++++++++++++++++++++++++++++ extras/pycompleter | 35 +++++--- 2 files changed, 211 insertions(+), 13 deletions(-) create mode 100644 extras/completerlib.py diff --git a/extras/completerlib.py b/extras/completerlib.py new file mode 100644 index 0000000..b96fdc8 --- /dev/null +++ b/extras/completerlib.py @@ -0,0 +1,189 @@ +"""Implementations for various useful completers. + +These are all loaded by default by IPython. +""" +#----------------------------------------------------------------------------- +# Copyright (C) 2010-2011 The IPython Development Team. +# +# Distributed under the terms of the BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- +from __future__ import print_function + +import inspect +import os +import re +import sys + +try: + # Python >= 3.3 + from importlib.machinery import all_suffixes + _suffixes = all_suffixes() +except ImportError: + from imp import get_suffixes + _suffixes = [ s[0] for s in get_suffixes() ] + +# Third-party imports +from time import time +from zipimport import zipimporter + +TIMEOUT_STORAGE = 2 + +TIMEOUT_GIVEUP = 20 + +# Regular expression for the python import statement +import_re = re.compile(r'(?P[a-zA-Z_][a-zA-Z0-9_]*?)' + r'(?P[/\\]__init__)?' + r'(?P%s)$' % + r'|'.join(re.escape(s) for s in _suffixes)) + +# RE for the ipython %run command (python + ipython scripts) +magic_run_re = re.compile(r'.*(\.ipy|\.ipynb|\.py[w]?)$') + +def module_list(path): + """ + Return the list containing the names of the modules available in the given + folder. + """ + # sys.path has the cwd as an empty string, but isdir/listdir need it as '.' + if path == '': + path = '.' + + # A few local constants to be used in loops below + pjoin = os.path.join + + if os.path.isdir(path): + # Build a list of all files in the directory and all files + # in its subdirectories. For performance reasons, do not + # recurse more than one level into subdirectories. + files = [] + for root, dirs, nondirs in os.walk(path): + subdir = root[len(path)+1:] + if subdir: + files.extend(pjoin(subdir, f) for f in nondirs) + dirs[:] = [] # Do not recurse into additional subdirectories. + else: + files.extend(nondirs) + + else: + try: + files = list(zipimporter(path)._files.keys()) + except: + files = [] + + # Build a list of modules which match the import_re regex. + modules = [] + for f in files: + m = import_re.match(f) + if m: + modules.append(m.group('name')) + return list(set(modules)) + + +def get_root_modules(): + """ + Returns a list containing the names of all the modules available in the + folders of the pythonpath. + + ip.db['rootmodules_cache'] maps sys.path entries to list of modules. + """ + #ip = get_ipython() + #rootmodules_cache = ip.db.get('rootmodules_cache', {}) + rootmodules_cache = {} + rootmodules = list(sys.builtin_module_names) + start_time = time() + #store = False + for path in sys.path: + try: + modules = rootmodules_cache[path] + except KeyError: + modules = module_list(path) + try: + modules.remove('__init__') + except ValueError: + pass + if path not in ('', '.'): # cwd modules should not be cached + rootmodules_cache[path] = modules + if time() - start_time > TIMEOUT_STORAGE and not store: + #store = True + #print("\nCaching the list of root modules, please wait!") + #print("(This will only be done once - type '%rehashx' to " + #"reset cache!)\n") + sys.stdout.flush() + if time() - start_time > TIMEOUT_GIVEUP: + print("This is taking too long, we give up.\n") + return [] + rootmodules.extend(modules) + #if store: + #ip.db['rootmodules_cache'] = rootmodules_cache + rootmodules = list(set(rootmodules)) + return rootmodules + + +def is_importable(module, attr, only_modules): + if only_modules: + return inspect.ismodule(getattr(module, attr)) + else: + return not(attr[:2] == '__' and attr[-2:] == '__') + + +def try_import(mod, only_modules=False): + try: + m = __import__(mod) + except: + return [] + mods = mod.split('.') + for module in mods[1:]: + m = getattr(m, module) + + m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__ + + completions = [] + if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init: + completions.extend( [attr for attr in dir(m) if + is_importable(m, attr, only_modules)]) + + completions.extend(getattr(m, '__all__', [])) + if m_is_init: + completions.extend(module_list(os.path.dirname(m.__file__))) + completions = set(completions) + if '__init__' in completions: + completions.remove('__init__') + return list(completions) + + +def module_completion(line): + """ + Returns a list containing the completion possibilities for an import line. + + The line looks like this : + 'import xml.d' + 'from xml.dom import' + """ + + words = line.split(' ') + nwords = len(words) + + # from whatever -> 'import ' + if nwords == 3 and words[0] == 'from': + return ['import '] + + # 'from xy' or 'import xy' + if nwords < 3 and (words[0] in ['import','from']) : + if nwords == 1: + return get_root_modules() + mod = words[1].split('.') + if len(mod) < 2: + return get_root_modules() + completion_list = try_import('.'.join(mod[:-1]), True) + return ['.'.join(mod[:-1] + [el]) for el in completion_list] + + # 'from xyz import abc' + if nwords >= 3 and words[0] == 'from': + mod = words[1] + return try_import(mod) diff --git a/extras/pycompleter b/extras/pycompleter index 9f91de7..1c89966 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -26,10 +26,14 @@ from uuid import uuid4 import rlcompleter - -def complete_all(prefix, c_arg): - if c_arg: - exec(c_arg.strip('"\'')) +def complete_all(prefix, args): + if args: + if args['x_arg']: + x = str() + if args['l_arg']: + l = list() + if args['c_arg']: + exec(args['c_arg'].strip('"\'')) context = locals() context.update(globals()) completer = rlcompleter.Completer(context) @@ -51,8 +55,14 @@ def parse_string(input): elif input[-1].startswith('-'): options = ['-h', '-x', '-fx', '-l', '-c', '-C'] elif len(prior) > 0 and prior[-1] == '-c': - import IPython.core.completerlib as completerlib - options = completerlib.module_completion(current_full) or [] + if 'import'.startswith(current_full): + options = ["'import"] + else: + import completerlib + options = completerlib.module_completion(current_full) + options += completerlib.module_list('') + if options: + options = [x for x in options if x.startswith(current_prefix)] else: if current_full == '': options = ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil'] @@ -61,18 +71,17 @@ def parse_string(input): if '-l' in input[:-1]: options += 'l' else: - c_arg = None + from collections import defaultdict + args = defaultdict(lambda: None) if '-x' in prior or '-fx' in prior: - global x - x = str() + args['x_arg'] = True if '-l' in prior: - global l - l = list() + args['l_arg'] = True if '-c' in prior: c_index = prior.index('-c') if (c_index + 1) < len(prior): - c_arg = prior[c_index + 1] - options = complete_all(current_prefix, c_arg) + args['c_arg'] = prior[c_index + 1] + options = complete_all(current_prefix, args) if current_prefix.endswith('.'): options = [x for x in options if '._' not in x] return options From 8a2d15bf58e18647d770659c3d9d0a3f7d07afed Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 12:43:52 -0700 Subject: [PATCH 106/173] 0.3.1dev3 --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4de7c9c..539cf0c 100644 --- a/setup.py +++ b/setup.py @@ -9,8 +9,9 @@ setup( name='pythonpy', - version='0.3.1dev2', + version='0.3.1dev3', description='Take advantage of your python skills from the command line', + py_modules=['extras/completerlib.py'], scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, license='MIT', From ee76dfba7c7bb0f3864e708c18bc5df9714ab7e1 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 12:48:33 -0700 Subject: [PATCH 107/173] 0.3.1dev3 --- completion/__init__.py | 0 {extras => completion}/completerlib.py | 0 setup.py | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 completion/__init__.py rename {extras => completion}/completerlib.py (100%) diff --git a/completion/__init__.py b/completion/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extras/completerlib.py b/completion/completerlib.py similarity index 100% rename from extras/completerlib.py rename to completion/completerlib.py diff --git a/setup.py b/setup.py index 539cf0c..65e13af 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ name='pythonpy', version='0.3.1dev3', description='Take advantage of your python skills from the command line', - py_modules=['extras/completerlib.py'], + py_modules=['completion'], scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, license='MIT', From 0c2f6e47530ed2d3ffb9df03dd7606dd9eaac8cb Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:02:14 -0700 Subject: [PATCH 108/173] Moved competerlib into pycompleter to avoid using a source package. --- completion/__init__.py | 0 completion/completerlib.py | 189 ---------------------------------- extras/pycompleter | 204 ++++++++++++++++++++++++++++++++++++- setup.py | 1 - 4 files changed, 201 insertions(+), 193 deletions(-) delete mode 100644 completion/__init__.py delete mode 100644 completion/completerlib.py diff --git a/completion/__init__.py b/completion/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/completion/completerlib.py b/completion/completerlib.py deleted file mode 100644 index b96fdc8..0000000 --- a/completion/completerlib.py +++ /dev/null @@ -1,189 +0,0 @@ -"""Implementations for various useful completers. - -These are all loaded by default by IPython. -""" -#----------------------------------------------------------------------------- -# Copyright (C) 2010-2011 The IPython Development Team. -# -# Distributed under the terms of the BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- -from __future__ import print_function - -import inspect -import os -import re -import sys - -try: - # Python >= 3.3 - from importlib.machinery import all_suffixes - _suffixes = all_suffixes() -except ImportError: - from imp import get_suffixes - _suffixes = [ s[0] for s in get_suffixes() ] - -# Third-party imports -from time import time -from zipimport import zipimporter - -TIMEOUT_STORAGE = 2 - -TIMEOUT_GIVEUP = 20 - -# Regular expression for the python import statement -import_re = re.compile(r'(?P[a-zA-Z_][a-zA-Z0-9_]*?)' - r'(?P[/\\]__init__)?' - r'(?P%s)$' % - r'|'.join(re.escape(s) for s in _suffixes)) - -# RE for the ipython %run command (python + ipython scripts) -magic_run_re = re.compile(r'.*(\.ipy|\.ipynb|\.py[w]?)$') - -def module_list(path): - """ - Return the list containing the names of the modules available in the given - folder. - """ - # sys.path has the cwd as an empty string, but isdir/listdir need it as '.' - if path == '': - path = '.' - - # A few local constants to be used in loops below - pjoin = os.path.join - - if os.path.isdir(path): - # Build a list of all files in the directory and all files - # in its subdirectories. For performance reasons, do not - # recurse more than one level into subdirectories. - files = [] - for root, dirs, nondirs in os.walk(path): - subdir = root[len(path)+1:] - if subdir: - files.extend(pjoin(subdir, f) for f in nondirs) - dirs[:] = [] # Do not recurse into additional subdirectories. - else: - files.extend(nondirs) - - else: - try: - files = list(zipimporter(path)._files.keys()) - except: - files = [] - - # Build a list of modules which match the import_re regex. - modules = [] - for f in files: - m = import_re.match(f) - if m: - modules.append(m.group('name')) - return list(set(modules)) - - -def get_root_modules(): - """ - Returns a list containing the names of all the modules available in the - folders of the pythonpath. - - ip.db['rootmodules_cache'] maps sys.path entries to list of modules. - """ - #ip = get_ipython() - #rootmodules_cache = ip.db.get('rootmodules_cache', {}) - rootmodules_cache = {} - rootmodules = list(sys.builtin_module_names) - start_time = time() - #store = False - for path in sys.path: - try: - modules = rootmodules_cache[path] - except KeyError: - modules = module_list(path) - try: - modules.remove('__init__') - except ValueError: - pass - if path not in ('', '.'): # cwd modules should not be cached - rootmodules_cache[path] = modules - if time() - start_time > TIMEOUT_STORAGE and not store: - #store = True - #print("\nCaching the list of root modules, please wait!") - #print("(This will only be done once - type '%rehashx' to " - #"reset cache!)\n") - sys.stdout.flush() - if time() - start_time > TIMEOUT_GIVEUP: - print("This is taking too long, we give up.\n") - return [] - rootmodules.extend(modules) - #if store: - #ip.db['rootmodules_cache'] = rootmodules_cache - rootmodules = list(set(rootmodules)) - return rootmodules - - -def is_importable(module, attr, only_modules): - if only_modules: - return inspect.ismodule(getattr(module, attr)) - else: - return not(attr[:2] == '__' and attr[-2:] == '__') - - -def try_import(mod, only_modules=False): - try: - m = __import__(mod) - except: - return [] - mods = mod.split('.') - for module in mods[1:]: - m = getattr(m, module) - - m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__ - - completions = [] - if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init: - completions.extend( [attr for attr in dir(m) if - is_importable(m, attr, only_modules)]) - - completions.extend(getattr(m, '__all__', [])) - if m_is_init: - completions.extend(module_list(os.path.dirname(m.__file__))) - completions = set(completions) - if '__init__' in completions: - completions.remove('__init__') - return list(completions) - - -def module_completion(line): - """ - Returns a list containing the completion possibilities for an import line. - - The line looks like this : - 'import xml.d' - 'from xml.dom import' - """ - - words = line.split(' ') - nwords = len(words) - - # from whatever -> 'import ' - if nwords == 3 and words[0] == 'from': - return ['import '] - - # 'from xy' or 'import xy' - if nwords < 3 and (words[0] in ['import','from']) : - if nwords == 1: - return get_root_modules() - mod = words[1].split('.') - if len(mod) < 2: - return get_root_modules() - completion_list = try_import('.'.join(mod[:-1]), True) - return ['.'.join(mod[:-1] + [el]) for el in completion_list] - - # 'from xyz import abc' - if nwords >= 3 and words[0] == 'from': - mod = words[1] - return try_import(mod) diff --git a/extras/pycompleter b/extras/pycompleter index 1c89966..bd5c5b4 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -26,6 +26,7 @@ from uuid import uuid4 import rlcompleter + def complete_all(prefix, args): if args: if args['x_arg']: @@ -45,6 +46,7 @@ def complete_all(prefix, args): return list(options_set) + def parse_string(input): options = [] current_full = input[-1].lstrip('"\'') @@ -58,9 +60,9 @@ def parse_string(input): if 'import'.startswith(current_full): options = ["'import"] else: - import completerlib - options = completerlib.module_completion(current_full) - options += completerlib.module_list('') + module_completion, module_list = get_completerlib() + options = module_completion(current_full) + options += module_list('') if options: options = [x for x in options if x.startswith(current_prefix)] else: @@ -87,6 +89,200 @@ def parse_string(input): return options +def get_completerlib(): + """Implementations for various useful completers. + + These are all loaded by default by IPython. + """ + #----------------------------------------------------------------------------- + # Copyright (C) 2010-2011 The IPython Development Team. + # + # Distributed under the terms of the BSD License. + # + # The full license is in the file COPYING.txt, distributed with this software. + #----------------------------------------------------------------------------- + + #----------------------------------------------------------------------------- + # Imports + #----------------------------------------------------------------------------- + #from __future__ import print_function + + import inspect + #import os + #import re + #import sys + + try: + # Python >= 3.3 + from importlib.machinery import all_suffixes + _suffixes = all_suffixes() + except ImportError: + from imp import get_suffixes + _suffixes = [ s[0] for s in get_suffixes() ] + + # Third-party imports + from time import time + from zipimport import zipimporter + + TIMEOUT_STORAGE = 2 + + TIMEOUT_GIVEUP = 20 + + # Regular expression for the python import statement + import_re = re.compile(r'(?P[a-zA-Z_][a-zA-Z0-9_]*?)' + r'(?P[/\\]__init__)?' + r'(?P%s)$' % + r'|'.join(re.escape(s) for s in _suffixes)) + + # RE for the ipython %run command (python + ipython scripts) + magic_run_re = re.compile(r'.*(\.ipy|\.ipynb|\.py[w]?)$') + + def module_list(path): + """ + Return the list containing the names of the modules available in the given + folder. + """ + # sys.path has the cwd as an empty string, but isdir/listdir need it as '.' + if path == '': + path = '.' + + # A few local constants to be used in loops below + pjoin = os.path.join + + if os.path.isdir(path): + # Build a list of all files in the directory and all files + # in its subdirectories. For performance reasons, do not + # recurse more than one level into subdirectories. + files = [] + for root, dirs, nondirs in os.walk(path): + subdir = root[len(path)+1:] + if subdir: + files.extend(pjoin(subdir, f) for f in nondirs) + dirs[:] = [] # Do not recurse into additional subdirectories. + else: + files.extend(nondirs) + + else: + try: + files = list(zipimporter(path)._files.keys()) + except: + files = [] + + # Build a list of modules which match the import_re regex. + modules = [] + for f in files: + m = import_re.match(f) + if m: + modules.append(m.group('name')) + return list(set(modules)) + + + def get_root_modules(): + """ + Returns a list containing the names of all the modules available in the + folders of the pythonpath. + + ip.db['rootmodules_cache'] maps sys.path entries to list of modules. + """ + #ip = get_ipython() + #rootmodules_cache = ip.db.get('rootmodules_cache', {}) + rootmodules_cache = {} + rootmodules = list(sys.builtin_module_names) + start_time = time() + #store = False + for path in sys.path: + try: + modules = rootmodules_cache[path] + except KeyError: + modules = module_list(path) + try: + modules.remove('__init__') + except ValueError: + pass + if path not in ('', '.'): # cwd modules should not be cached + rootmodules_cache[path] = modules + if time() - start_time > TIMEOUT_STORAGE and not store: + #store = True + #print("\nCaching the list of root modules, please wait!") + #print("(This will only be done once - type '%rehashx' to " + #"reset cache!)\n") + sys.stdout.flush() + if time() - start_time > TIMEOUT_GIVEUP: + print("This is taking too long, we give up.\n") + return [] + rootmodules.extend(modules) + #if store: + #ip.db['rootmodules_cache'] = rootmodules_cache + rootmodules = list(set(rootmodules)) + return rootmodules + + + def is_importable(module, attr, only_modules): + if only_modules: + return inspect.ismodule(getattr(module, attr)) + else: + return not(attr[:2] == '__' and attr[-2:] == '__') + + + def try_import(mod, only_modules=False): + try: + m = __import__(mod) + except: + return [] + mods = mod.split('.') + for module in mods[1:]: + m = getattr(m, module) + + m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__ + + completions = [] + if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init: + completions.extend( [attr for attr in dir(m) if + is_importable(m, attr, only_modules)]) + + completions.extend(getattr(m, '__all__', [])) + if m_is_init: + completions.extend(module_list(os.path.dirname(m.__file__))) + completions = set(completions) + if '__init__' in completions: + completions.remove('__init__') + return list(completions) + + + def module_completion(line): + """ + Returns a list containing the completion possibilities for an import line. + + The line looks like this : + 'import xml.d' + 'from xml.dom import' + """ + + words = line.split(' ') + nwords = len(words) + + # from whatever -> 'import ' + if nwords == 3 and words[0] == 'from': + return ['import '] + + # 'from xy' or 'import xy' + if nwords < 3 and (words[0] in ['import','from']) : + if nwords == 1: + return get_root_modules() + mod = words[1].split('.') + if len(mod) < 2: + return get_root_modules() + completion_list = try_import('.'.join(mod[:-1]), True) + return ['.'.join(mod[:-1] + [el]) for el in completion_list] + + # 'from xyz import abc' + if nwords >= 3 and words[0] == 'from': + mod = words[1] + return try_import(mod) + + return module_completion, module_list + + def main(): input = sys.argv[1:] if len(input) == 0: @@ -97,5 +293,7 @@ def main(): options = options + [x + "'" for x in options] print(' '.join(options)) + + if __name__ == '__main__': main() diff --git a/setup.py b/setup.py index 65e13af..2d758ea 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,6 @@ name='pythonpy', version='0.3.1dev3', description='Take advantage of your python skills from the command line', - py_modules=['completion'], scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, license='MIT', From c59c40939d125c58fe49682768297c2cc5fe51ce Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:03:21 -0700 Subject: [PATCH 109/173] 0.3.1dev4 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2d758ea..9309960 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name='pythonpy', - version='0.3.1dev3', + version='0.3.1dev4', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 90c6cd96cbb56189c0eccef133bef839267ee0f1 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:09:22 -0700 Subject: [PATCH 110/173] Updated sudo failure message. --- extras/pycompletion.sh | 1 - setup.py | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/extras/pycompletion.sh b/extras/pycompletion.sh index 1902210..85b4ce9 100644 --- a/extras/pycompletion.sh +++ b/extras/pycompletion.sh @@ -1,6 +1,5 @@ _py() { - #COMPREPLY=($(echo "${COMP_WORDS[@]:1}" | pycompleter)) COMPREPLY=($(pycompleter "${COMP_WORDS[@]:1}" 2>/dev/null )) } diff --git a/setup.py b/setup.py index 9309960..03f8f53 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,11 @@ if os.geteuid() == 0: data_files = [('/etc/bash_completion.d', ['extras/pycompletion.sh']),] else: - print('User does not have write access to /etc completion will not work') + print( +'''PERMISSION DENIED: User does not have write access to /etc. +To add completion manually, run + source bash_completion.d/pycompletion.sh +from the install directory.''') data_files = [('bash_completion.d', ['extras/pycompletion.sh']),] setup( From 3eaf43ce99b63b976b2333ac93d76e189c4f052d Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:09:44 -0700 Subject: [PATCH 111/173] Added debug_completion which prints to stderr. --- extras/debug_pycompletion.sh | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 extras/debug_pycompletion.sh diff --git a/extras/debug_pycompletion.sh b/extras/debug_pycompletion.sh new file mode 100644 index 0000000..2c41c15 --- /dev/null +++ b/extras/debug_pycompletion.sh @@ -0,0 +1,6 @@ +_py() +{ + COMPREPLY=($(pycompleter "${COMP_WORDS[@]:1}" )) +} + +complete -F _py -o nospace py From b190f2df87cd86cec6c742b375141a808de9cda0 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:10:10 -0700 Subject: [PATCH 112/173] 0.3.1dev5 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 03f8f53..584c681 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name='pythonpy', - version='0.3.1dev4', + version='0.3.1dev5', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 51a3b209b48126cb577043108e9dcd18b4fd72ac Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:13:22 -0700 Subject: [PATCH 113/173] Fixed None+= Error in pycompletion. --- extras/pycompleter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/pycompleter b/extras/pycompleter index bd5c5b4..cc1a8df 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -61,7 +61,7 @@ def parse_string(input): options = ["'import"] else: module_completion, module_list = get_completerlib() - options = module_completion(current_full) + options = module_completion(current_full) or [] options += module_list('') if options: options = [x for x in options if x.startswith(current_prefix)] From 7dfe7500a36be57048bf31e1d9e463145f0fc08c Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:14:36 -0700 Subject: [PATCH 114/173] 0.3.1dev6 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 584c681..6826a8d 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name='pythonpy', - version='0.3.1dev5', + version='0.3.1dev6', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 6ffa9a07d8d41f04d751cc7ce4711660f97f6cde Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:20:50 -0700 Subject: [PATCH 115/173] Added defaultdict to py. --- py | 1 + 1 file changed, 1 insertion(+) diff --git a/py b/py index 294273e..2a6fd03 100755 --- a/py +++ b/py @@ -30,6 +30,7 @@ def lazy_imports(expression, pre_cmd, post_cmd): if 'tempfile' in query: global tempfile; import tempfile if 'Counter' in query: global Counter; from collections import Counter if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict + if 'defaultdict' in query: global defaultdict; from collections import defaultdict if 'groupby' in query: global groupby; from itertools import groupby if 'uuid4' in query: global uuid4; from uuid import uuid4 From dce0515e92193c9cd84a280f0965359f9fb600a6 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:22:57 -0700 Subject: [PATCH 116/173] Updated -c completion to fall back to expression completion without imports. --- extras/pycompleter | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index cc1a8df..6498a83 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -21,20 +21,21 @@ import shutil import tempfile from collections import Counter from collections import OrderedDict +from collections import defaultdict from itertools import groupby from uuid import uuid4 import rlcompleter -def complete_all(prefix, args): - if args: - if args['x_arg']: +def complete_all(prefix, completion_args): + if completion_args: + if completion_args['x_arg']: x = str() - if args['l_arg']: + if completion_args['l_arg']: l = list() - if args['c_arg']: - exec(args['c_arg'].strip('"\'')) + if completion_args['c_arg']: + exec(completion_args['c_arg'].strip('"\'')) context = locals() context.update(globals()) completer = rlcompleter.Completer(context) @@ -52,6 +53,7 @@ def parse_string(input): current_full = input[-1].lstrip('"\'') current_prefix = current_full.split(' ')[-1] prior = input[:-1] + completion_args = defaultdict(lambda: None) if input[-1].startswith('--'): options = ['--si', '--so', '--ji', '--jo', '--i'] elif input[-1].startswith('-'): @@ -59,12 +61,16 @@ def parse_string(input): elif len(prior) > 0 and prior[-1] == '-c': if 'import'.startswith(current_full): options = ["'import"] - else: + elif current_full.startswith('import '): module_completion, module_list = get_completerlib() options = module_completion(current_full) or [] options += module_list('') if options: options = [x for x in options if x.startswith(current_prefix)] + else: + options = complete_all(current_prefix, completion_args) + if current_prefix.endswith('.'): + options = [x for x in options if '._' not in x] else: if current_full == '': options = ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil'] @@ -73,17 +79,15 @@ def parse_string(input): if '-l' in input[:-1]: options += 'l' else: - from collections import defaultdict - args = defaultdict(lambda: None) if '-x' in prior or '-fx' in prior: - args['x_arg'] = True + completion_args['x_arg'] = True if '-l' in prior: - args['l_arg'] = True + completion_args['l_arg'] = True if '-c' in prior: c_index = prior.index('-c') if (c_index + 1) < len(prior): - args['c_arg'] = prior[c_index + 1] - options = complete_all(current_prefix, args) + completion_args['c_arg'] = prior[c_index + 1] + options = complete_all(current_prefix, completion_args) if current_prefix.endswith('.'): options = [x for x in options if '._' not in x] return options From 8072a8b42a075c773a39cd790b0400764d884755 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:23:14 -0700 Subject: [PATCH 117/173] 0.3.1dev7 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6826a8d..3627cdc 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name='pythonpy', - version='0.3.1dev6', + version='0.3.1dev7', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 715dda6c7ac0e6571103f3587f88c6e648b78b9d Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:32:28 -0700 Subject: [PATCH 118/173] Added support for importing local modules. --- py | 1 + 1 file changed, 1 insertion(+) diff --git a/py b/py index 2a6fd03..4ca8789 100755 --- a/py +++ b/py @@ -10,6 +10,7 @@ import json import re from collections import Iterable +sys.path.append('.') def lazy_imports(expression, pre_cmd, post_cmd): query = ((expression if expression else '') + (pre_cmd if pre_cmd else '') + From 4a7cffb3c1ba395fb55a553e450bfa3c6be8c53f Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:33:19 -0700 Subject: [PATCH 119/173] 0.3.1dev8 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3627cdc..9d187bc 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name='pythonpy', - version='0.3.1dev7', + version='0.3.1dev8', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 076c479f4c0d9dd94b80889258c4aea93cdff8fd Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:40:25 -0700 Subject: [PATCH 120/173] Supported tab completion of local modules and from A import B. --- extras/pycompleter | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 6498a83..467dd87 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -26,6 +26,7 @@ from itertools import groupby from uuid import uuid4 import rlcompleter +sys.path.append('.') def complete_all(prefix, completion_args): @@ -61,10 +62,9 @@ def parse_string(input): elif len(prior) > 0 and prior[-1] == '-c': if 'import'.startswith(current_full): options = ["'import"] - elif current_full.startswith('import '): + elif current_full.startswith('import ') or current_full.startswith('from '): module_completion, module_list = get_completerlib() options = module_completion(current_full) or [] - options += module_list('') if options: options = [x for x in options if x.startswith(current_prefix)] else: From 9c79eeafe131a15efe0ad1c7a0a0f4ceb9b1f70b Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:45:15 -0700 Subject: [PATCH 121/173] Fixed print behavior with complete(from * imp...). --- extras/pycompleter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/pycompleter b/extras/pycompleter index 467dd87..27cc5fe 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -66,7 +66,7 @@ def parse_string(input): module_completion, module_list = get_completerlib() options = module_completion(current_full) or [] if options: - options = [x for x in options if x.startswith(current_prefix)] + options = [x.rstrip(' ') for x in options if x.startswith(current_prefix)] else: options = complete_all(current_prefix, completion_args) if current_prefix.endswith('.'): From 4e32161beac5729a033196cf8ace7d87533afa95 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:51:16 -0700 Subject: [PATCH 122/173] 0.3.1dev9 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9d187bc..9eae362 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name='pythonpy', - version='0.3.1dev8', + version='0.3.1dev9', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 6ebe2d72327b2be867b585354494b84848d07333 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 13:54:08 -0700 Subject: [PATCH 123/173] 0.3.1 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9eae362..ff7abb2 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name='pythonpy', - version='0.3.1dev9', + version='0.3.1', description='Take advantage of your python skills from the command line', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 1b30b300aaaa4334036747395a8afa2c70c4a776 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 14:20:12 -0700 Subject: [PATCH 124/173] Changed the pypi description. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ff7abb2..56b361b 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( name='pythonpy', version='0.3.1', - description='Take advantage of your python skills from the command line', + description='python -c, with tab completion and shorthand', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, license='MIT', From 56e232932f7eb5decd133ada519a42f2b8d3ce06 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sat, 21 Jun 2014 14:21:59 -0700 Subject: [PATCH 125/173] Changed warning message for installation without sudo. --- setup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 56b361b..6295465 100644 --- a/setup.py +++ b/setup.py @@ -5,10 +5,12 @@ data_files = [('/etc/bash_completion.d', ['extras/pycompletion.sh']),] else: print( -'''PERMISSION DENIED: User does not have write access to /etc. +'''****************************************************************************** +PERMISSION DENIED: User does not have write access to /etc. To add completion manually, run source bash_completion.d/pycompletion.sh -from the install directory.''') +from the install directory. +*****************************************************************************''') data_files = [('bash_completion.d', ['extras/pycompletion.sh']),] setup( From 4398b6bee3e3a4e8955099e9ee6498ae756dde58 Mon Sep 17 00:00:00 2001 From: Finn Grimwood Date: Wed, 25 Jun 2014 19:16:09 +0100 Subject: [PATCH 126/173] Added ability to import any python module --- extras/py3 | 25 ++++++++++--------------- py | 25 ++++++++++--------------- test/test_pythonpy.py | 37 +++++++++++++++++-------------------- 3 files changed, 37 insertions(+), 50 deletions(-) diff --git a/extras/py3 b/extras/py3 index c73835f..3c81c45 100755 --- a/extras/py3 +++ b/extras/py3 @@ -18,24 +18,19 @@ def lazy_imports(expression, pre_cmd, post_cmd): query = ((expression if expression else '') + (pre_cmd if pre_cmd else '') + (post_cmd if post_cmd else '')) - if 'base64' in query: global base64; import base64 - if 'calendar' in query: global calendar; import calendar - if 'csv' in query: global csv; import csv - if 'datetime' in query: global datetime; import datetime - if 'hashlib' in query: global hashlib; import hashlib - if 'glob' in query: global glob; import glob - if 'itertools' in query: global itertools; import itertools - if 'json' in query: global json; import json - if 'math' in query: global math; import math - if 'os' in query: global os; import os - if 'random' in query: global random; import random - if 're' in query: global re; import re - if 'shutil' in query: global shutil; import shutil - if 'tempfile' in query: global tempfile; import tempfile + + regex = re.compile("([a-zA-z0-9]+)\.") + matches = regex.findall(query) + for module_name in matches: + try: + module = __import__(module_name) + globals()[module_name] = module + except ImportError as e: + pass + if 'Counter' in query: global Counter; from collections import Counter if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict if 'groupby' in query: global groupby; from itertools import groupby - if 'uuid4' in query: global uuid4; from uuid import uuid4 parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter) diff --git a/py b/py index 4ca8789..685d123 100755 --- a/py +++ b/py @@ -15,25 +15,20 @@ def lazy_imports(expression, pre_cmd, post_cmd): query = ((expression if expression else '') + (pre_cmd if pre_cmd else '') + (post_cmd if post_cmd else '')) - if 'base64' in query: global base64; import base64 - if 'calendar' in query: global calendar; import calendar - if 'csv' in query: global csv; import csv - if 'datetime' in query: global datetime; import datetime - if 'hashlib' in query: global hashlib; import hashlib - if 'glob' in query: global glob; import glob - if 'itertools' in query: global itertools; import itertools - if 'json' in query: global json; import json - if 'math' in query: global math; import math - if 'os' in query: global os; import os - if 'random' in query: global random; import random - if 're' in query: global re; import re - if 'shutil' in query: global shutil; import shutil - if 'tempfile' in query: global tempfile; import tempfile + + regex = re.compile("([a-zA-z0-9]+)\.") + matches = regex.findall(query) + for module_name in matches: + try: + module = __import__(module_name) + globals()[module_name] = module + except ImportError as e: + pass + if 'Counter' in query: global Counter; from collections import Counter if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict if 'defaultdict' in query: global defaultdict; from collections import defaultdict if 'groupby' in query: global groupby; from itertools import groupby - if 'uuid4' in query: global uuid4; from uuid import uuid4 parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter) diff --git a/test/test_pythonpy.py b/test/test_pythonpy.py index ab4f349..b0b0304 100644 --- a/test/test_pythonpy.py +++ b/test/test_pythonpy.py @@ -26,26 +26,23 @@ def test_statements(self): self.assertEqual(check_output("""echo 3 | py -c 'a=5' -x x -C 'print(a)'""", shell=True), '3\n5\n') def test_imports(self): - check_output("py 'math'", shell=True) - check_output("py 'base64'", shell=True) - check_output("py 'calendar'", shell=True) - check_output("py 'csv'", shell=True) - check_output("py 'datetime'", shell=True) - check_output("py 'hashlib'", shell=True) - check_output("py 'glob'", shell=True) - check_output("py 'itertools'", shell=True) - check_output("py 'json'", shell=True) - check_output("py 'math'", shell=True) - check_output("py 'os'", shell=True) - check_output("py 'random'", shell=True) - check_output("py 're'", shell=True) - check_output("py 'shutil'", shell=True) - check_output("py 'tempfile'", shell=True) - check_output("py -c 'Counter'", shell=True) - check_output("py -c 'OrderedDict'", shell=True) - check_output("py -c 'groupby'", shell=True) - check_output("py 'uuid4'", shell=True) - + module_commands = ["math.ceil(2.5)", + "base64.b64encode('data to be encoded')", + "calendar.weekday(1955, 11, 5)", + "csv.list_dialects()", + "datetime.timedelta(hours=-5)", + "hashlib.sha224(\"Nobody inspects the spammish repetition\").hexdigest()", + "glob.glob('*')", + "itertools.product(['a','b'], [1,2])", + "json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':'))", + "os.name", + "random.randint(0, 1000)", + "re.compile('[a-z]').findall('abcd')", + "shutil.get_archive_formats()", + "tempfile.gettempdir()", + "uuid.uuid1()"] + for command in module_commands: + check_output("py %r" % command, shell=True) if __name__ == '__main__': unittest.main() From 374b6cb533977fb7ec77b9367868fe001e1116e2 Mon Sep 17 00:00:00 2001 From: Finn Grimwood Date: Wed, 25 Jun 2014 19:35:50 +0100 Subject: [PATCH 127/173] Allow underscores in dynamically imported module names --- extras/py3 | 2 +- py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extras/py3 b/extras/py3 index 3c81c45..beb00b5 100755 --- a/extras/py3 +++ b/extras/py3 @@ -19,7 +19,7 @@ def lazy_imports(expression, pre_cmd, post_cmd): (pre_cmd if pre_cmd else '') + (post_cmd if post_cmd else '')) - regex = re.compile("([a-zA-z0-9]+)\.") + regex = re.compile("([a-zA-z0-9_]+)\.") matches = regex.findall(query) for module_name in matches: try: diff --git a/py b/py index 685d123..3862391 100755 --- a/py +++ b/py @@ -16,7 +16,7 @@ def lazy_imports(expression, pre_cmd, post_cmd): (pre_cmd if pre_cmd else '') + (post_cmd if post_cmd else '')) - regex = re.compile("([a-zA-z0-9]+)\.") + regex = re.compile("([a-zA-z0-9_]+)\.") matches = regex.findall(query) for module_name in matches: try: From 935d07d2604ec569b1bfa8d47c143f687c7a59df Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 26 Jun 2014 14:19:26 -0700 Subject: [PATCH 128/173] Removed clause disregarding "py" element of sys.argv --- extras/pycompletion.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/pycompletion.sh b/extras/pycompletion.sh index 85b4ce9..1486919 100644 --- a/extras/pycompletion.sh +++ b/extras/pycompletion.sh @@ -1,6 +1,6 @@ _py() { - COMPREPLY=($(pycompleter "${COMP_WORDS[@]:1}" 2>/dev/null )) + COMPREPLY=($(pycompleter "${COMP_WORDS[@]}" 2>/dev/null )) } complete -F _py -o nospace py From d5b712738c30b3a335d237e4faa1c2bebce4db73 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 26 Jun 2014 14:23:57 -0700 Subject: [PATCH 129/173] Added ' to default completion. --- extras/pycompleter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/pycompleter b/extras/pycompleter index 27cc5fe..229000e 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -73,7 +73,7 @@ def parse_string(input): options = [x for x in options if '._' not in x] else: if current_full == '': - options = ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil'] + options = ["'sys", "'json", "'re", "'base64", "'calendar", "'csv", "'datetime", "'hashlib", "'itertools", "'json", "'math", "'os", "'random", "'re", "'shutil"] if '-x' in input[:-1] or '-fx' in input[:-1]: options += 'x' if '-l' in input[:-1]: From 398fc6bfa52148c87f6a4ff029a005c5db4e33cf Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 26 Jun 2014 16:17:48 -0700 Subject: [PATCH 130/173] Added support for < filename_competion.txt. --- extras/pycompleter | 3 +++ extras/pycompletion.sh | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/extras/pycompleter b/extras/pycompleter index 229000e..951e675 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -291,6 +291,9 @@ def main(): input = sys.argv[1:] if len(input) == 0: return + elif '<' in input or '>' in input: + print('_pycd') + return options = parse_string(input) if len(options) <= 1: diff --git a/extras/pycompletion.sh b/extras/pycompletion.sh index 1486919..e37de22 100644 --- a/extras/pycompletion.sh +++ b/extras/pycompletion.sh @@ -1,6 +1,44 @@ +_pycd () +{ + local cur prev words cword; + _init_completion || return; + local IFS=' +' i j k; + compopt -o filenames; + if [[ -z "${CDPATH:-}" || "$cur" == ?(.)?(.)/* ]]; then + _filedir -d; + return 0; + fi; + local -r mark_dirs=$(_rl_enabled mark-directories && echo y); + local -r mark_symdirs=$(_rl_enabled mark-symlinked-directories && echo y); + for i in ${CDPATH//:/' +'}; + do + k="${#COMPREPLY[@]}"; + for j in $( compgen -d $i/$cur ); + do + if [[ ( -n $mark_symdirs && -h $j || -n $mark_dirs && ! -h $j ) && ! -d ${j#$i/} ]]; then + j+="/"; + fi; + COMPREPLY[k++]=${j#$i/}; + done; + done; + _filedir -d; + if [[ ${#COMPREPLY[@]} -eq 1 ]]; then + i=${COMPREPLY[0]}; + if [[ "$i" == "$cur" && $i != "*/" ]]; then + COMPREPLY[0]="${i}/"; + fi; + fi; + return 0 +} + _py() { COMPREPLY=($(pycompleter "${COMP_WORDS[@]}" 2>/dev/null )) + if [[ ${COMPREPLY[0]} == '_pycd' ]]; then + _pycd + fi } complete -F _py -o nospace py From 1aff746144cfc56083032f7f6dcf460a25485aaa Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 26 Jun 2014 16:18:29 -0700 Subject: [PATCH 131/173] 0.3.2dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6295465..bb41705 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name='pythonpy', - version='0.3.1', + version='0.3.2dev', description='python -c, with tab completion and shorthand', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 475eb00601bd1f54334213a30627f5cb2b25a629 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 26 Jun 2014 16:21:04 -0700 Subject: [PATCH 132/173] Removed ' from 'stdlibmodule completion because it felt weird. --- extras/pycompleter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/pycompleter b/extras/pycompleter index 951e675..650af35 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -73,7 +73,7 @@ def parse_string(input): options = [x for x in options if '._' not in x] else: if current_full == '': - options = ["'sys", "'json", "'re", "'base64", "'calendar", "'csv", "'datetime", "'hashlib", "'itertools", "'json", "'math", "'os", "'random", "'re", "'shutil"] + options = ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil'] if '-x' in input[:-1] or '-fx' in input[:-1]: options += 'x' if '-l' in input[:-1]: From 122dd4947b3e71a59c40c7fd7429ba7ee79d4851 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 26 Jun 2014 16:31:51 -0700 Subject: [PATCH 133/173] Changed bash completion to rely on ubiquitous _cd. --- extras/pycompletion.sh | 38 ++------------------------------------ 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/extras/pycompletion.sh b/extras/pycompletion.sh index e37de22..8c2fe1d 100644 --- a/extras/pycompletion.sh +++ b/extras/pycompletion.sh @@ -1,43 +1,9 @@ -_pycd () -{ - local cur prev words cword; - _init_completion || return; - local IFS=' -' i j k; - compopt -o filenames; - if [[ -z "${CDPATH:-}" || "$cur" == ?(.)?(.)/* ]]; then - _filedir -d; - return 0; - fi; - local -r mark_dirs=$(_rl_enabled mark-directories && echo y); - local -r mark_symdirs=$(_rl_enabled mark-symlinked-directories && echo y); - for i in ${CDPATH//:/' -'}; - do - k="${#COMPREPLY[@]}"; - for j in $( compgen -d $i/$cur ); - do - if [[ ( -n $mark_symdirs && -h $j || -n $mark_dirs && ! -h $j ) && ! -d ${j#$i/} ]]; then - j+="/"; - fi; - COMPREPLY[k++]=${j#$i/}; - done; - done; - _filedir -d; - if [[ ${#COMPREPLY[@]} -eq 1 ]]; then - i=${COMPREPLY[0]}; - if [[ "$i" == "$cur" && $i != "*/" ]]; then - COMPREPLY[0]="${i}/"; - fi; - fi; - return 0 -} - _py() { COMPREPLY=($(pycompleter "${COMP_WORDS[@]}" 2>/dev/null )) if [[ ${COMPREPLY[0]} == '_pycd' ]]; then - _pycd + COMPREPLY=() + _cd 2>/dev/null fi } From 648fa28f7b11c775e43a3e1b76e644bd23b058c7 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 26 Jun 2014 16:32:44 -0700 Subject: [PATCH 134/173] 0.3.2dev2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index bb41705..2585cd1 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name='pythonpy', - version='0.3.2dev', + version='0.3.2dev2', description='python -c, with tab completion and shorthand', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 249e5c1bfec22210600ab9a7dc9f97deb88d727a Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 26 Jun 2014 16:39:19 -0700 Subject: [PATCH 135/173] Changed _cd to _longopt. --- extras/pycompleter | 2 +- extras/pycompletion.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 650af35..5e1faa1 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -292,7 +292,7 @@ def main(): if len(input) == 0: return elif '<' in input or '>' in input: - print('_pycd') + print('_longopt') return options = parse_string(input) diff --git a/extras/pycompletion.sh b/extras/pycompletion.sh index 8c2fe1d..c37e48b 100644 --- a/extras/pycompletion.sh +++ b/extras/pycompletion.sh @@ -1,9 +1,9 @@ _py() { COMPREPLY=($(pycompleter "${COMP_WORDS[@]}" 2>/dev/null )) - if [[ ${COMPREPLY[0]} == '_pycd' ]]; then + if [[ ${COMPREPLY[0]} == '_longopt' ]]; then COMPREPLY=() - _cd 2>/dev/null + _longopt 2>/dev/null fi } From ec100b2d72516046fdeaaa969770e49c849bc092 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 26 Jun 2014 16:39:36 -0700 Subject: [PATCH 136/173] 0.3.2dev3 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2585cd1..48f35ef 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name='pythonpy', - version='0.3.2dev2', + version='0.3.2dev3', description='python -c, with tab completion and shorthand', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From bc7802ea3883cbaecc2b7280b2552a3f578988d6 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 26 Jun 2014 19:10:50 -0700 Subject: [PATCH 137/173] Show help() when expression ends with "?" --- py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/py b/py index 4ca8789..8bbcf34 100755 --- a/py +++ b/py @@ -78,6 +78,8 @@ else: if args.expression: args.expression = args.expression.replace("`", "'") + if args.expression.endswith('?') or args.expression.startswith('?'): + args.expression = 'help(%s)' % args.expression.strip('?') if args.pre_cmd: args.pre_cmd = args.pre_cmd.replace("`", "'") if args.post_cmd: From 3d547f99ca557b54250ae53a63e1d412bd4a4312 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sun, 29 Jun 2014 13:18:00 -0700 Subject: [PATCH 138/173] Added help? support. --- py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/py b/py index 8bbcf34..c8d0629 100755 --- a/py +++ b/py @@ -78,8 +78,11 @@ else: if args.expression: args.expression = args.expression.replace("`", "'") - if args.expression.endswith('?') or args.expression.startswith('?'): + if args.expression.startswith('?') or args.expression.endswith('?'): args.expression = 'help(%s)' % args.expression.strip('?') + if args.lines_of_stdin: + from itertools import islice + stdin = islice(stdin,1) if args.pre_cmd: args.pre_cmd = args.pre_cmd.replace("`", "'") if args.post_cmd: From f5c8b61a0e6f211ddf3c175fdac8b1f8d79a2d61 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 4 Jul 2014 18:20:17 -0700 Subject: [PATCH 139/173] Added support for automatic imports to tab completion. --- extras/pycompleter | 22 ++++++++++++++++++++++ py | 9 +++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 5e1faa1..2dbc166 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -29,6 +29,27 @@ import rlcompleter sys.path.append('.') +def lazy_imports(*args): + old_path = sys.path + sys.path = [x for x in sys.path if x != '.'] + + query = ' '.join([x for x in args if x]) + regex = re.compile("([a-zA-z0-9_]+)\.") + matches = regex.findall(query) + for module_name in matches: + try: + module = __import__(module_name) + globals()[module_name] = module + except ImportError as e: + pass + + if 'Counter' in query: global Counter; from collections import Counter + if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict + if 'defaultdict' in query: global defaultdict; from collections import defaultdict + if 'groupby' in query: global groupby; from itertools import groupby + sys.path = old_path + + def complete_all(prefix, completion_args): if completion_args: if completion_args['x_arg']: @@ -37,6 +58,7 @@ def complete_all(prefix, completion_args): l = list() if completion_args['c_arg']: exec(completion_args['c_arg'].strip('"\'')) + lazy_imports(prefix, completion_args['c_arg']) context = locals() context.update(globals()) completer = rlcompleter.Completer(context) diff --git a/py b/py index 514720d..a0990e8 100755 --- a/py +++ b/py @@ -10,12 +10,8 @@ import json import re from collections import Iterable -sys.path.append('.') -def lazy_imports(expression, pre_cmd, post_cmd): - query = ((expression if expression else '') + - (pre_cmd if pre_cmd else '') + - (post_cmd if post_cmd else '')) - +def lazy_imports(*args): + query = ' '.join([x for x in args if x]) regex = re.compile("([a-zA-z0-9_]+)\.") matches = regex.findall(query) for module_name in matches: @@ -84,6 +80,7 @@ if args.post_cmd: args.post_cmd = args.post_cmd.replace("`", "'") lazy_imports(args.expression, args.pre_cmd, args.post_cmd) +sys.path.append('.') if args.pre_cmd: exec(args.pre_cmd) From ff334c51e1aa046624eee1ac0111ec14df6b8155 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 4 Jul 2014 18:49:56 -0700 Subject: [PATCH 140/173] Added support for automatic imports to tab completion without -c. --- extras/pycompleter | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 2dbc166..547f36f 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -30,9 +30,6 @@ sys.path.append('.') def lazy_imports(*args): - old_path = sys.path - sys.path = [x for x in sys.path if x != '.'] - query = ' '.join([x for x in args if x]) regex = re.compile("([a-zA-z0-9_]+)\.") matches = regex.findall(query) @@ -47,7 +44,6 @@ def lazy_imports(*args): if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict if 'defaultdict' in query: global defaultdict; from collections import defaultdict if 'groupby' in query: global groupby; from itertools import groupby - sys.path = old_path def complete_all(prefix, completion_args): @@ -68,7 +64,12 @@ def complete_all(prefix, completion_args): options_set.add(completer.complete(prefix, idx)) idx += 1 - return list(options_set) + module_completion, module_list = get_completerlib() + options = module_completion("import " + prefix) or [] + if options: + options = [x.rstrip(' ') for x in options if x.startswith(prefix)] + + return options + list(options_set) def parse_string(input): From 7883630f707adac16b50ebc81e5b6265e81f9386 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 4 Jul 2014 18:59:21 -0700 Subject: [PATCH 141/173] Fixed bug with duplicate completion options. --- extras/pycompleter | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 547f36f..f548c75 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -317,13 +317,12 @@ def main(): elif '<' in input or '>' in input: print('_longopt') return - options = parse_string(input) + options = list(set(parse_string(input))) if len(options) <= 1: options = options + [x + "'" for x in options] print(' '.join(options)) - if __name__ == '__main__': main() From fa980f32b8d1208d446f9ab7644efaeb28190af6 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 4 Jul 2014 19:14:40 -0700 Subject: [PATCH 142/173] Fixed bug with tab completion when quoted input contained space. --- extras/pycompleter | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extras/pycompleter b/extras/pycompleter index f548c75..7d13c12 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -319,6 +319,9 @@ def main(): return options = list(set(parse_string(input))) + if ' ' in input[-1] and max(map(len, options)) + 1 >= len(input[-1]): + options.append(input[-1].split(' ')[-1]) + if len(options) <= 1: options = options + [x + "'" for x in options] print(' '.join(options)) From 224ab244f976e5fa63450303f12de02342c39a5f Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 4 Jul 2014 19:31:40 -0700 Subject: [PATCH 143/173] Removed support for sys.path = "." The system failed in lots of places and was more likely to cause problems for tab completion. --- extras/pycompleter | 1 - py | 1 - 2 files changed, 2 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 7d13c12..40d9b9c 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -26,7 +26,6 @@ from itertools import groupby from uuid import uuid4 import rlcompleter -sys.path.append('.') def lazy_imports(*args): diff --git a/py b/py index a0990e8..73f4826 100755 --- a/py +++ b/py @@ -80,7 +80,6 @@ if args.post_cmd: args.post_cmd = args.post_cmd.replace("`", "'") lazy_imports(args.expression, args.pre_cmd, args.post_cmd) -sys.path.append('.') if args.pre_cmd: exec(args.pre_cmd) From 8bbe6f2120f3b294390c2bf37fd85662a3ed06cb Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 4 Jul 2014 19:52:32 -0700 Subject: [PATCH 144/173] 0.3.2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 48f35ef..0c2082c 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name='pythonpy', - version='0.3.2dev3', + version='0.3.2', description='python -c, with tab completion and shorthand', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From f0e28a2c477a79762e6f1717a2b2f766ac417d4f Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 4 Jul 2014 19:57:58 -0700 Subject: [PATCH 145/173] Updated README. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index cd1053b..8f0e456 100644 --- a/README.rst +++ b/README.rst @@ -21,7 +21,7 @@ Float Arithmetic :: -Access common imports directly +Access imports directly ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: From 05193f8ac7258351b74ac062210982f0d046f3ca Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Sun, 6 Jul 2014 00:07:07 -0700 Subject: [PATCH 146/173] Fixed bug not replacing ` in -c tab completion. --- extras/pycompleter | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 40d9b9c..3f866df 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -46,14 +46,14 @@ def lazy_imports(*args): def complete_all(prefix, completion_args): + lazy_imports(prefix, completion_args['c_arg']) if completion_args: if completion_args['x_arg']: x = str() if completion_args['l_arg']: l = list() if completion_args['c_arg']: - exec(completion_args['c_arg'].strip('"\'')) - lazy_imports(prefix, completion_args['c_arg']) + exec(completion_args['c_arg'].strip('"\'').replace("`", "'")) context = locals() context.update(globals()) completer = rlcompleter.Completer(context) From a04cdf73d17759ba0723b7596e891891c3b79e1b Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 9 Jul 2014 15:05:54 -0700 Subject: [PATCH 147/173] Prevent error on py 'module' --- extras/pycompleter | 2 +- py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 3f866df..adf084b 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -30,7 +30,7 @@ import rlcompleter def lazy_imports(*args): query = ' '.join([x for x in args if x]) - regex = re.compile("([a-zA-z0-9_]+)\.") + regex = re.compile("([a-zA-z_][a-zA-Z0-9_]*)\.") matches = regex.findall(query) for module_name in matches: try: diff --git a/py b/py index 73f4826..26dc093 100755 --- a/py +++ b/py @@ -12,8 +12,10 @@ from collections import Iterable def lazy_imports(*args): query = ' '.join([x for x in args if x]) - regex = re.compile("([a-zA-z0-9_]+)\.") + regex = re.compile("([a-zA-Z_][a-zA-Z0-9_]*)\.") matches = regex.findall(query) + if not any(x in ['.', ' '] for x in args[0]): + matches.append(args[0]) for module_name in matches: try: module = __import__(module_name) From 506fd66cd82408c212ce4f67a3965c414e24ba1d Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 9 Jul 2014 15:27:33 -0700 Subject: [PATCH 148/173] Added -V, --version command. --- py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/py b/py index 26dc093..0876752 100755 --- a/py +++ b/py @@ -10,6 +10,7 @@ import json import re from collections import Iterable + def lazy_imports(*args): query = ' '.join([x for x in args if x]) regex = re.compile("([a-zA-Z_][a-zA-Z0-9_]*)\.") @@ -43,6 +44,10 @@ parser.add_argument('-l', dest='list_of_stdin', action='store_const', help='treat list of stdin as l') parser.add_argument('-c', dest='pre_cmd', help='run code before expression') parser.add_argument('-C', dest='post_cmd', help='run code after expression') +__version__ = '0.3.2' +import pkg_resources +__version__ = pkg_resources.require("Pythonpy")[0].version +parser.add_argument('-V', '--version', action='version', version='py version %s' % __version__, help='version info') parser.add_argument('--i', '--ignore_exceptions', dest='ignore_exceptions', action='store_const', const=True, default=False, From 5910ed066a79dc097999de2c4bf4c26c2736a42e Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 9 Jul 2014 15:37:52 -0700 Subject: [PATCH 149/173] Fixed -V, --version command. --- VERSION | 1 + py | 11 +++++++---- setup.py | 5 ++++- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 VERSION diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..d15723f --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.3.2 diff --git a/py b/py index 0876752..3be8923 100755 --- a/py +++ b/py @@ -29,6 +29,12 @@ def lazy_imports(*args): if 'defaultdict' in query: global defaultdict; from collections import defaultdict if 'groupby' in query: global groupby; from itertools import groupby + +def get_version(): + with open('VERSION', 'r') as f: + __version__ = f.read() + return __version__ + parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter) @@ -44,10 +50,7 @@ parser.add_argument('-l', dest='list_of_stdin', action='store_const', help='treat list of stdin as l') parser.add_argument('-c', dest='pre_cmd', help='run code before expression') parser.add_argument('-C', dest='post_cmd', help='run code after expression') -__version__ = '0.3.2' -import pkg_resources -__version__ = pkg_resources.require("Pythonpy")[0].version -parser.add_argument('-V', '--version', action='version', version='py version %s' % __version__, help='version info') +parser.add_argument('-V', '--version', action='version', version='py version %s' % get_version(), help='version info') parser.add_argument('--i', '--ignore_exceptions', dest='ignore_exceptions', action='store_const', const=True, default=False, diff --git a/setup.py b/setup.py index 0c2082c..d62f558 100644 --- a/setup.py +++ b/setup.py @@ -13,9 +13,12 @@ *****************************************************************************''') data_files = [('bash_completion.d', ['extras/pycompletion.sh']),] +with open('VERSION', 'r') as f: + __version__ = f.read() + setup( name='pythonpy', - version='0.3.2', + version=__version__, description='python -c, with tab completion and shorthand', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 74677be00cbd54d1126df8eff9478f67547755ba Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 9 Jul 2014 15:50:33 -0700 Subject: [PATCH 150/173] Just hard coded version in 2 places. --- VERSION | 1 - py | 2 +- setup.py | 5 +---- 3 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 VERSION diff --git a/VERSION b/VERSION deleted file mode 100644 index d15723f..0000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.3.2 diff --git a/py b/py index 3be8923..fea1fb2 100755 --- a/py +++ b/py @@ -50,7 +50,7 @@ parser.add_argument('-l', dest='list_of_stdin', action='store_const', help='treat list of stdin as l') parser.add_argument('-c', dest='pre_cmd', help='run code before expression') parser.add_argument('-C', dest='post_cmd', help='run code after expression') -parser.add_argument('-V', '--version', action='version', version='py version %s' % get_version(), help='version info') +parser.add_argument('-V', '--version', action='version', version='py version 0.3.2', help='version info') parser.add_argument('--i', '--ignore_exceptions', dest='ignore_exceptions', action='store_const', const=True, default=False, diff --git a/setup.py b/setup.py index d62f558..b8d0cf3 100644 --- a/setup.py +++ b/setup.py @@ -13,12 +13,9 @@ *****************************************************************************''') data_files = [('bash_completion.d', ['extras/pycompletion.sh']),] -with open('VERSION', 'r') as f: - __version__ = f.read() - setup( name='pythonpy', - version=__version__, + version='0.3.2, description='python -c, with tab completion and shorthand', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 5ceb17cd3d829c782b6734d537a8e06b367bbb4e Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 9 Jul 2014 15:51:28 -0700 Subject: [PATCH 151/173] Fixed typo in setup.py. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b8d0cf3..0c2082c 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name='pythonpy', - version='0.3.2, + version='0.3.2', description='python -c, with tab completion and shorthand', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 7f08754daf660224b3a3951f4921ec1a2e8f23d3 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 9 Jul 2014 16:09:30 -0700 Subject: [PATCH 152/173] Reduced number of default module recommendations. --- extras/pycompleter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/pycompleter b/extras/pycompleter index adf084b..c6bd1e1 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -95,7 +95,7 @@ def parse_string(input): options = [x for x in options if '._' not in x] else: if current_full == '': - options = ['sys', 'json', 're', 'base64', 'calendar', 'csv', 'datetime', 'hashlib', 'itertools', 'json', 'math', 'os', 'random', 're', 'shutil'] + options = ['sys', 'json', 're', 'csv', 'datetime', 'hashlib', 'itertools', 'math', 'os', 'random', 'shutil'] if '-x' in input[:-1] or '-fx' in input[:-1]: options += 'x' if '-l' in input[:-1]: From 60f580768c54f303ef2abccaecf5f0f8f9239dbf Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 9 Jul 2014 16:22:18 -0700 Subject: [PATCH 153/173] Changed print to output utf-8 by default. --- py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py b/py index fea1fb2..5bd4d01 100755 --- a/py +++ b/py @@ -131,11 +131,11 @@ if isinstance(result, Iterable) and hasattr(result, '__iter__') and not isinstan for x in result: formatted = format(x) if formatted is not None: - print(formatted) + print(formatted.encode('utf-8')) else: formatted = format(result) if formatted is not None: - print(formatted) + print(formatted.encode('utf-8')) if args.post_cmd: exec(args.post_cmd) From ba069b206626dd2a86da870c997d11653675f3f0 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 9 Jul 2014 16:25:05 -0700 Subject: [PATCH 154/173] Changed print to output utf-8 only when default fails. --- py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/py b/py index 5bd4d01..198168e 100755 --- a/py +++ b/py @@ -131,11 +131,17 @@ if isinstance(result, Iterable) and hasattr(result, '__iter__') and not isinstan for x in result: formatted = format(x) if formatted is not None: - print(formatted.encode('utf-8')) + try: + print(formatted) + except: + print(formatted.encode('utf-8')) else: formatted = format(result) if formatted is not None: - print(formatted.encode('utf-8')) + try: + print(formatted) + except: + print(formatted.encode('utf-8')) if args.post_cmd: exec(args.post_cmd) From b104350637c806298a10d7f37f0b3944ff1f1690 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 9 Jul 2014 16:28:28 -0700 Subject: [PATCH 155/173] Changed print to output utf-8 only when default fails with UnicodeEncodeError. --- py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py b/py index 198168e..999ea78 100755 --- a/py +++ b/py @@ -133,14 +133,14 @@ if isinstance(result, Iterable) and hasattr(result, '__iter__') and not isinstan if formatted is not None: try: print(formatted) - except: + except UnicodeEncodeError: print(formatted.encode('utf-8')) else: formatted = format(result) if formatted is not None: try: - print(formatted) - except: + print(formatted) + except UnicodeEncodeError: print(formatted.encode('utf-8')) if args.post_cmd: From b3c4f3fc9093d45bda3b9d92377172e7ad7fe396 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 24 Jul 2014 12:16:26 -0700 Subject: [PATCH 156/173] Fixed A-z typo in pycompleter. --- extras/pycompleter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/pycompleter b/extras/pycompleter index c6bd1e1..0ccb22e 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -30,7 +30,7 @@ import rlcompleter def lazy_imports(*args): query = ' '.join([x for x in args if x]) - regex = re.compile("([a-zA-z_][a-zA-Z0-9_]*)\.") + regex = re.compile("([a-zA-Z_][a-zA-Z0-9_]*)\.") matches = regex.findall(query) for module_name in matches: try: From e6c067700b0438f7012fba9f9c2cbcf52e36709a Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 24 Jul 2014 12:22:09 -0700 Subject: [PATCH 157/173] Removed dead get_version function. --- py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/py b/py index 999ea78..7be4511 100755 --- a/py +++ b/py @@ -29,12 +29,6 @@ def lazy_imports(*args): if 'defaultdict' in query: global defaultdict; from collections import defaultdict if 'groupby' in query: global groupby; from itertools import groupby - -def get_version(): - with open('VERSION', 'r') as f: - __version__ = f.read() - return __version__ - parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter) From 8dc340ce035c8cfc81daf01d54388c0c04b4304b Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 24 Jul 2014 12:24:35 -0700 Subject: [PATCH 158/173] 0.3.3 --- py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py b/py index 7be4511..975be09 100755 --- a/py +++ b/py @@ -44,7 +44,7 @@ parser.add_argument('-l', dest='list_of_stdin', action='store_const', help='treat list of stdin as l') parser.add_argument('-c', dest='pre_cmd', help='run code before expression') parser.add_argument('-C', dest='post_cmd', help='run code after expression') -parser.add_argument('-V', '--version', action='version', version='py version 0.3.2', help='version info') +parser.add_argument('-V', '--version', action='version', version='py version 0.3.3', help='version info') parser.add_argument('--i', '--ignore_exceptions', dest='ignore_exceptions', action='store_const', const=True, default=False, diff --git a/setup.py b/setup.py index 0c2082c..5c9eaf2 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name='pythonpy', - version='0.3.2', + version='0.3.3', description='python -c, with tab completion and shorthand', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From a4cffdf8d7341e650570c70a9c725a184c184fa5 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 24 Jul 2014 12:43:08 -0700 Subject: [PATCH 159/173] Changed method of supporting statements containing only module names. --- extras/pycompleter | 2 +- py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index 0ccb22e..e56c60a 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -30,7 +30,7 @@ import rlcompleter def lazy_imports(*args): query = ' '.join([x for x in args if x]) - regex = re.compile("([a-zA-Z_][a-zA-Z0-9_]*)\.") + regex = re.compile("([a-zA-Z_][a-zA-Z0-9_]*)\.?") matches = regex.findall(query) for module_name in matches: try: diff --git a/py b/py index 975be09..261577c 100755 --- a/py +++ b/py @@ -13,10 +13,8 @@ from collections import Iterable def lazy_imports(*args): query = ' '.join([x for x in args if x]) - regex = re.compile("([a-zA-Z_][a-zA-Z0-9_]*)\.") + regex = re.compile("([a-zA-Z_][a-zA-Z0-9_]*)\.?") matches = regex.findall(query) - if not any(x in ['.', ' '] for x in args[0]): - matches.append(args[0]) for module_name in matches: try: module = __import__(module_name) From bf2b6a40630fd9449ac0e88642298272ff03e175 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 24 Jul 2014 12:47:07 -0700 Subject: [PATCH 160/173] Added "math" and "[math]" to nosetests. --- test/test_pythonpy.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test_pythonpy.py b/test/test_pythonpy.py index b0b0304..bf03c8e 100644 --- a/test/test_pythonpy.py +++ b/test/test_pythonpy.py @@ -40,7 +40,10 @@ def test_imports(self): "re.compile('[a-z]').findall('abcd')", "shutil.get_archive_formats()", "tempfile.gettempdir()", - "uuid.uuid1()"] + "uuid.uuid1()", + "math", + "[math]", + ] for command in module_commands: check_output("py %r" % command, shell=True) From 2384fc5c420bac15e0222b39ac8300f4b111df23 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Mon, 28 Jul 2014 14:51:31 -0700 Subject: [PATCH 161/173] Fixed bug not importing submodules. --- py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/py b/py index 261577c..8d820bb 100755 --- a/py +++ b/py @@ -11,17 +11,20 @@ import re from collections import Iterable -def lazy_imports(*args): - query = ' '.join([x for x in args if x]) - regex = re.compile("([a-zA-Z_][a-zA-Z0-9_]*)\.?") - matches = regex.findall(query) +def import_matches(query, prefix=''): + matches = set(re.findall(r"(%s[a-zA-Z_][a-zA-Z0-9_]*)\.?" % prefix, query)) for module_name in matches: try: module = __import__(module_name) globals()[module_name] = module + import_matches(query, prefix='%s.' % module_name) except ImportError as e: pass +def lazy_imports(*args): + query = ' '.join([x for x in args if x]) + import_matches(query) + if 'Counter' in query: global Counter; from collections import Counter if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict if 'defaultdict' in query: global defaultdict; from collections import defaultdict From 335f8039f636eaed0f6d7c9e7c25c2e39e0b6ca5 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 29 Jul 2014 19:40:03 -0700 Subject: [PATCH 162/173] Refactored pycompleter --- extras/pycompleter | 123 ++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 62 deletions(-) diff --git a/extras/pycompleter b/extras/pycompleter index e56c60a..e393e6f 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -1,33 +1,31 @@ #!/usr/bin/env python from __future__ import (unicode_literals, absolute_import, print_function, division) -import argparse import sys -import json import re -import base64 -import calendar -import csv -import datetime -import hashlib -import glob -import itertools -import json -import math -import os -import random -import re -import shutil -import tempfile -from collections import Counter -from collections import OrderedDict from collections import defaultdict -from itertools import groupby -from uuid import uuid4 import rlcompleter +def current_raw(input): + if len(input[-1]) > 0 and input[-1][0] in '"\'': + return input[-1][1:] + return input[-1] + + +def current_list(input): + return re.split(r'[^a-zA-Z0-9\.]', current_raw(input)) + + +def current_prefix(input): + return current_list(input)[-1] + + +def prior(input): + return input[:-1] + + def lazy_imports(*args): query = ' '.join([x for x in args if x]) regex = re.compile("([a-zA-Z_][a-zA-Z0-9_]*)\.?") @@ -72,47 +70,44 @@ def complete_all(prefix, completion_args): def parse_string(input): - options = [] - current_full = input[-1].lstrip('"\'') - current_prefix = current_full.split(' ')[-1] - prior = input[:-1] - completion_args = defaultdict(lambda: None) - if input[-1].startswith('--'): - options = ['--si', '--so', '--ji', '--jo', '--i'] - elif input[-1].startswith('-'): - options = ['-h', '-x', '-fx', '-l', '-c', '-C'] - elif len(prior) > 0 and prior[-1] == '-c': - if 'import'.startswith(current_full): + if current_raw(input).startswith('--'): + return ['--si', '--so', '--ji', '--jo', '--i'] + elif current_raw(input).startswith('-'): + return ['-h', '-x', '-fx', '-l', '-c', '-C'] + elif len(prior(input)) > 0 and prior(input)[-1] == '-c': + if 'import'.startswith(current_raw(input)): options = ["'import"] - elif current_full.startswith('import ') or current_full.startswith('from '): + elif current_raw(input).startswith('import ') or current_raw(input).startswith('from '): module_completion, module_list = get_completerlib() - options = module_completion(current_full) or [] + options = module_completion(current_raw(input)) or [] if options: - options = [x.rstrip(' ') for x in options if x.startswith(current_prefix)] + options = [x.rstrip(' ') for x in options if x.startswith(current_prefix(input))] else: - options = complete_all(current_prefix, completion_args) - if current_prefix.endswith('.'): + options = complete_all(current_prefix(input), defaultdict(lambda: None)) + if current_prefix(input).endswith('.'): options = [x for x in options if '._' not in x] + return options + elif current_raw(input) == '': + options = ['sys', 'json', 're', 'csv', 'datetime', 'hashlib', 'itertools', 'math', 'os', 'random', 'shutil'] + if '-x' in input[:-1] or '-fx' in input[:-1]: + options += 'x' + if '-l' in input[:-1]: + options += 'l' + return options else: - if current_full == '': - options = ['sys', 'json', 're', 'csv', 'datetime', 'hashlib', 'itertools', 'math', 'os', 'random', 'shutil'] - if '-x' in input[:-1] or '-fx' in input[:-1]: - options += 'x' - if '-l' in input[:-1]: - options += 'l' - else: - if '-x' in prior or '-fx' in prior: - completion_args['x_arg'] = True - if '-l' in prior: - completion_args['l_arg'] = True - if '-c' in prior: - c_index = prior.index('-c') - if (c_index + 1) < len(prior): - completion_args['c_arg'] = prior[c_index + 1] - options = complete_all(current_prefix, completion_args) - if current_prefix.endswith('.'): - options = [x for x in options if '._' not in x] - return options + completion_args = defaultdict(lambda: None) + if '-x' in prior(input) or '-fx' in prior(input): + completion_args['x_arg'] = True + if '-l' in prior(input): + completion_args['l_arg'] = True + if '-c' in prior(input): + c_index = prior(input).index('-c') + if (c_index + 1) < len(prior(input)): + completion_args['c_arg'] = prior(input)[c_index + 1] + options = complete_all(current_prefix(input), completion_args) + if current_prefix(input).endswith('.'): + options = [x for x in options if '._' not in x] + return options def get_completerlib(): @@ -134,7 +129,7 @@ def get_completerlib(): #from __future__ import print_function import inspect - #import os + import os #import re #import sys @@ -316,14 +311,18 @@ def main(): elif '<' in input or '>' in input: print('_longopt') return - options = list(set(parse_string(input))) + else: + options = list(set(parse_string(input))) + + if len(options) == 0: + return - if ' ' in input[-1] and max(map(len, options)) + 1 >= len(input[-1]): - options.append(input[-1].split(' ')[-1]) + if len(current_list(input)) > 1 and max(map(len, options)) + 1 >= len(current_raw(input)): + options.append(current_prefix(input)) - if len(options) <= 1: - options = options + [x + "'" for x in options] - print(' '.join(options)) + if len(options) <= 1: + options = options + [x + "'" for x in options] + print(' '.join(options)) if __name__ == '__main__': From e1b390118afe466f100b454ea2cb93cc53cb0a7f Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 30 Jul 2014 16:29:16 -0700 Subject: [PATCH 163/173] Removed trailing parenthesis from tab completion options. --- extras/pycompleter | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extras/pycompleter b/extras/pycompleter index e393e6f..46db439 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -304,6 +304,12 @@ def get_completerlib(): return module_completion, module_list +def remove_trailing_paren(str_): + if str_.endswith('('): + return str_[:-1] + return str_ + + def main(): input = sys.argv[1:] if len(input) == 0: @@ -312,7 +318,7 @@ def main(): print('_longopt') return else: - options = list(set(parse_string(input))) + options = list(set(map(remove_trailing_paren, parse_string(input)))) if len(options) == 0: return From 3741965cd34156cea5b552c8ed5d54669d3294d3 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 30 Jul 2014 16:33:44 -0700 Subject: [PATCH 164/173] Added underscore to variable parsing for tab completion. --- extras/pycompleter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/pycompleter b/extras/pycompleter index 46db439..bd19e7e 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -15,7 +15,7 @@ def current_raw(input): def current_list(input): - return re.split(r'[^a-zA-Z0-9\.]', current_raw(input)) + return re.split(r'[^a-zA-Z0-9_\.]', current_raw(input)) def current_prefix(input): From 2eecb482df6340c88056ffb15680d8bf1fa80bfd Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 30 Jul 2014 16:47:09 -0700 Subject: [PATCH 165/173] Added ascii art to permission denied message. --- setup.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 5c9eaf2..d4cf54d 100644 --- a/setup.py +++ b/setup.py @@ -5,12 +5,14 @@ data_files = [('/etc/bash_completion.d', ['extras/pycompletion.sh']),] else: print( -'''****************************************************************************** -PERMISSION DENIED: User does not have write access to /etc. -To add completion manually, run - source bash_completion.d/pycompletion.sh -from the install directory. -*****************************************************************************''') +'''************************************************************************** +___ ____ ____ _ _ _ ____ ____ _ ____ _ _ ___ ____ _ _ _ ____ ___ +|__] |___ |__/ |\/| | [__ [__ | | | |\ | | \ |___ |\ | | |___ | \ +| |___ | \ | | | ___] ___] | |__| | \| |__/ |___ | \| | |___ |__/ +PERMISSION DENIED: Cannot copy pycompletion.sh to /etc/bash_completion.d +To configure tab completion without root, run + source /path/to/install_directory/bash_completion.d/pycompletion.sh +**************************************************************************''') data_files = [('bash_completion.d', ['extras/pycompletion.sh']),] setup( From 26d9bf1bf942b82e2ca89b6df28b8cc4853289a5 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 5 Aug 2014 15:10:48 -0700 Subject: [PATCH 166/173] Added source lookup to py. --- py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/py b/py index 8d820bb..e537ac7 100755 --- a/py +++ b/py @@ -21,6 +21,7 @@ def import_matches(query, prefix=''): except ImportError as e: pass + def lazy_imports(*args): query = ' '.join([x for x in args if x]) import_matches(query) @@ -30,6 +31,14 @@ def lazy_imports(*args): if 'defaultdict' in query: global defaultdict; from collections import defaultdict if 'groupby' in query: global groupby; from itertools import groupby + +def inspect_source(obj): + import inspect + try: + return ''.join(inspect.getsourcelines(obj)[0]) + except: + return help(obj) + parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter) @@ -75,7 +84,12 @@ else: if args.expression: args.expression = args.expression.replace("`", "'") if args.expression.startswith('?') or args.expression.endswith('?'): - args.expression = 'help(%s)' % args.expression.strip('?') + if args.expression.startswith('??') or args.expression.endswith('??'): + import inspect + #args.expression = "''.join(inspect.getsourcelines(%s)[0])" % args.expression.strip('?') + args.expression = "inspect_source(%s)" % args.expression.strip('?') + else: + args.expression = 'help(%s)' % args.expression.strip('?') if args.lines_of_stdin: from itertools import islice stdin = islice(stdin,1) From 9a48ba38aba15da8e382a7d9616fd5e9562ed40d Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 5 Aug 2014 15:22:39 -0700 Subject: [PATCH 167/173] Added support for help on multi-variable expressions. --- py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/py b/py index e537ac7..c05ee6e 100755 --- a/py +++ b/py @@ -32,6 +32,10 @@ def lazy_imports(*args): if 'groupby' in query: global groupby; from itertools import groupby +def current_list(input): + return re.split(r'[^a-zA-Z0-9_\.]', input) + + def inspect_source(obj): import inspect try: @@ -84,12 +88,18 @@ else: if args.expression: args.expression = args.expression.replace("`", "'") if args.expression.startswith('?') or args.expression.endswith('?'): - if args.expression.startswith('??') or args.expression.endswith('??'): + final_atom = current_list(args.expression.rstrip('?'))[-1] + first_atom = current_list(args.expression.lstrip('?'))[0] + if args.expression.startswith('??'): + import inspect + args.expression = "inspect_source(%s)" % first_atom + elif args.expression.endswith('??'): import inspect - #args.expression = "''.join(inspect.getsourcelines(%s)[0])" % args.expression.strip('?') - args.expression = "inspect_source(%s)" % args.expression.strip('?') + args.expression = "inspect_source(%s)" % final_atom + elif args.expression.startswith('?'): + args.expression = 'help(%s)' % first_atom else: - args.expression = 'help(%s)' % args.expression.strip('?') + args.expression = 'help(%s)' % final_atom if args.lines_of_stdin: from itertools import islice stdin = islice(stdin,1) From 051da19c3aa5b8513d952b5e03e71bf7bbd65139 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Tue, 5 Aug 2014 15:30:59 -0700 Subject: [PATCH 168/173] Made output of ?? use pydoc.pager instead of print. --- py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/py b/py index c05ee6e..2a73343 100755 --- a/py +++ b/py @@ -38,8 +38,10 @@ def current_list(input): def inspect_source(obj): import inspect + import pydoc try: - return ''.join(inspect.getsourcelines(obj)[0]) + pydoc.pager(''.join(inspect.getsourcelines(obj)[0])) + return None except: return help(obj) From af75159083e9210d1c276215a9c306adc81a47ab Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Wed, 6 Aug 2014 15:36:47 -0700 Subject: [PATCH 169/173] Added ? to README. --- README.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 8f0e456..dc20081 100644 --- a/README.rst +++ b/README.rst @@ -32,8 +32,11 @@ Access imports directly $ py 'random.random()' 0.103173957713 - $ py 'datetime.datetime.now()' - 2014-06-20 20:22:03.699290 + $ py 'datetime.datetime.now?' + Help on built-in function now: + + now(...) + [tz] -> new datetime with tz's local day and time. :: From 3cc2957a62ff195853383c329f565cb064bcca38 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Thu, 7 Aug 2014 13:11:04 -0700 Subject: [PATCH 170/173] Changed bash restart recommendation in installation section. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index dc20081..4846888 100644 --- a/README.rst +++ b/README.rst @@ -4,7 +4,7 @@ Installation :: sudo pip install pythonpy - bash # restart your shell for tab completion to take effect + # restart your shell for tab completion to take effect :: From 55710a6323bda36285eee40099baa2ac9daa8ef7 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 8 Aug 2014 12:43:40 -0700 Subject: [PATCH 171/173] 0.3.4 --- py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py b/py index 2a73343..a834014 100755 --- a/py +++ b/py @@ -60,7 +60,7 @@ parser.add_argument('-l', dest='list_of_stdin', action='store_const', help='treat list of stdin as l') parser.add_argument('-c', dest='pre_cmd', help='run code before expression') parser.add_argument('-C', dest='post_cmd', help='run code after expression') -parser.add_argument('-V', '--version', action='version', version='py version 0.3.3', help='version info') +parser.add_argument('-V', '--version', action='version', version='py version 0.3.4', help='version info') parser.add_argument('--i', '--ignore_exceptions', dest='ignore_exceptions', action='store_const', const=True, default=False, diff --git a/setup.py b/setup.py index d4cf54d..b9ed0eb 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( name='pythonpy', - version='0.3.3', + version='0.3.4', description='python -c, with tab completion and shorthand', scripts=['py', 'extras/py3', 'extras/pycompleter'], data_files=data_files, From 1db9705cce16269e686120d20b338266b03ab599 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 8 Aug 2014 13:05:44 -0700 Subject: [PATCH 172/173] Fixed bug from exception thrown in ipython code. --- extras/pycompleter | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extras/pycompleter b/extras/pycompleter index bd19e7e..436842b 100755 --- a/extras/pycompleter +++ b/extras/pycompleter @@ -62,7 +62,10 @@ def complete_all(prefix, completion_args): idx += 1 module_completion, module_list = get_completerlib() - options = module_completion("import " + prefix) or [] + try: + options = module_completion("import " + prefix) or [] + except: #module_completion may throw exception (e.g. on 'import sqlalchemy_utils.') + options = [] if options: options = [x.rstrip(' ') for x in options if x.startswith(prefix)] From 89f41d7ff1ce32b9e41d51a857e43ed52e131710 Mon Sep 17 00:00:00 2001 From: Russell Stewart Date: Fri, 8 Aug 2014 16:47:12 -0700 Subject: [PATCH 173/173] Added ... | sh example to readme. --- README.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.rst b/README.rst index 4846888..3a75324 100644 --- a/README.rst +++ b/README.rst @@ -83,6 +83,15 @@ Append ".txt" to each line of input :: +Append ".txt" to every file in the directory +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + $ ls | py -x '"mv %s %s.txt" % (x,x)' | sh + +:: + Get only even numbers ~~~~~~~~~~~~~~~~~~~~~