I want to build an online Python shell like this. Currently I am trying to build a module
in Python which does the following things
Creates a new session.
Runs a code passed as string keeping and maintains the environment variables of the current session.
I am trying to achieve this using Pysandbox. Here is my effort till now
from sandbox import Sandbox, SandboxConfig
from optparse import OptionParser
import sys,traceback
class Runner:
def __init__(self):
self.options = self.parseOptions()
self.sandbox = Sandbox(self.createConfig())
self.localvars = dict()
def parseOptions(self):
parser = OptionParser(usage="%prog [options]")
SandboxConfig.createOptparseOptions(parser, default_timeout=None)
parser.add_option("--debug",
help="Debug mode",
action="store_true", default=False)
parser.add_option("--verbose", "-v",
help="Verbose mode",
action="store_true", default=False)
parser.add_option("--quiet", "-q",
help="Quiet mode",
action="store_true", default=False)
options, argv = parser.parse_args()
if argv:
parser.print_help()
exit(1)
if options.quiet:
options.verbose = False
return options
def createConfig(self):
config = SandboxConfig.fromOptparseOptions(self.options)
config.enable('traceback')
config.enable('stdin')
config.enable('stdout')
config.enable('stderr')
config.enable('exit')
config.enable('site')
config.enable('encodings')
config._builtins_whitelist.add('compile')
config.allowModuleSourceCode('code')
config.allowModule('sys',
'api_version', 'version', 'hexversion')
config.allowSafeModule('sys', 'version_info')
if self.options.debug:
config.allowModule('sys', '_getframe')
config.allowSafeModule('_sandbox', '_test_crash')
config.allowModuleSourceCode('sandbox')
if not config.cpython_restricted:
config.allowPath(__file__)
return config
def Run(self,code):
# log and compile the statement up front
try:
#logging.info('Compiling and evaluating:\n%s' % statement)
compiled = compile(code, '<string>', 'single')
except:
traceback.print_exc(file=sys.stdout)
return
try:
self.sandbox.execute(code)
except:
traceback.print_exc(file=sys.stdout)
def f():
f = open('test.py')
code = ''
for lines in f:
code = code+lines
runner = Runner()
runner.Run('a = 5')
runner.Run('b = 5')
runner.Run('print a+b')
f()
I am encountering 3 major problems.
How to nicely display error? For example, running the above code results in following output
File "execute.py", line 60, in Run
self.sandbox.execute(code)
File "/home/aaa/aaa/aaa/pysandbox-master/sandbox/sandbox_class.py", line 90, in execute
return self.execute_subprocess(self, code, globals, locals)
File "/home/aaa/aaa/aaa/pysandbox-master/sandbox/subprocess_parent.py", line 119, in execute_subprocess
raise output_data['error']
NameError: name 'a' is not defined
The undesirable thing here is the call traceback of "execute.py". I just want the function to return the following error.
NameError: name 'a' is not defined
How do I maintain the environment of the current session? For example, in the above code sequence
a = 5
b = 5
print a+b
should result in output 10.
Any ideas?
This should work, though you might want to play with the output of the exception:
from sandbox import Sandbox, SandboxConfig
from optparse import OptionParser
import sys,traceback
class Runner:
def __init__(self):
self.options = self.parseOptions()
self.sandbox = Sandbox(self.createConfig())
self.localvars = dict()
self.code = ''
def parseOptions(self):
parser = OptionParser(usage="%prog [options]")
SandboxConfig.createOptparseOptions(parser)#, default_timeout=None)
parser.add_option("--debug",
help="Debug mode",
action="store_true", default=False)
parser.add_option("--verbose", "-v",
help="Verbose mode",
action="store_true", default=False)
parser.add_option("--quiet", "-q",
help="Quiet mode",
action="store_true", default=False)
options, argv = parser.parse_args()
if argv:
parser.print_help()
exit(1)
if options.quiet:
options.verbose = False
return options
def createConfig(self):
config = SandboxConfig.fromOptparseOptions(self.options)
config.enable('traceback')
config.enable('stdin')
config.enable('stdout')
config.enable('stderr')
config.enable('exit')
config.enable('site')
config.enable('encodings')
config._builtins_whitelist.add('compile')
config.allowModuleSourceCode('code')
config.allowModule('sys',
'api_version', 'version', 'hexversion')
config.allowSafeModule('sys', 'version_info')
if self.options.debug:
config.allowModule('sys', '_getframe')
config.allowSafeModule('_sandbox', '_test_crash')
config.allowModuleSourceCode('sandbox')
if not config.cpython_restricted:
config.allowPath(__file__)
return config
def Run(self,code):
code = '\n'.join([self.code,code])
# log and compile the statement up front
try:
#logging.info('Compiling and evaluating:\n%s' % statement)
compiled = compile(code, '<string>', 'single')
except:
traceback.print_exc(file=sys.stdout)
return
try:
self.sandbox.execute(code)
except:
err = sys.exc_info()[1]
print type(err), err
else:
self.code = code
def f():
f = open('test.py')
code = ''
for lines in f:
code = code+lines
runner = Runner()
runner.Run('a = 5')
runner.Run('b = 5')
runner.Run('print a+b')
f()
Related
I am trying to run the below program,
#!/usr/bin/env python3
""" Compute GC content """
import argparse\
import sys\
from typing import NamedTuple, TextIO, List, Tuple\
from Bio import SeqIO
class Args(NamedTuple):\
""" Command-line arguments """\
file: TextIO
# --------------------------------------------------
def get_args() -> Args:\
""" Get command-line arguments """
parser = argparse.ArgumentParser(
description='Compute GC content',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('file',
metavar='FILE',
type=argparse.FileType('rt'),
nargs='?',
default=sys.stdin,
help='Input sequence file')
args = parser.parse_args()
return Args(args.file)
# --------------------------------------------------
def main() -> None:
""" Make a jazz noise here """
args = get_args()
seqs: List[Tuple[float, str]] = []
for rec in SeqIO.parse(args.file, 'fasta'):
# Iterate each base and compare to G or C, add 1 to counter
gc = 0
for base in rec.seq.upper():
if base in ('C', 'G'):
gc += 1
pct = (gc * 100) / len(rec.seq)
seqs.append((pct, rec.id))
high = max(seqs)
print(f'{high[1]} {high[0]:0.6f}')
# --------------------------------------------------
if __name__ == '__main__':
main()
When I try to run this program, its showing the error which is stated as below,
""ImportError: cannot import name '_aligners' from partially initialized module 'Bio.Align' (most likely due to a circular import)"
I am trying to write tests (using pytest) for a script, but I don't know how to create/pass arguments to main(), especially when it doesn't recieve arguments. and even if I change it to def main(args = None): then it'll initiate it on the first line.
tests.py
def test_main(capfd):
main()
out, err = capfd.readouterr()
assert out == "my expected output"
script.py
def init_parser():
parser = argparse.ArgumentParser(description="The script searches one or \
more named input files for lines \
containing a match to a regular \
expression pattern.")
parser.add_argument('regex', help='the regular expression.')
parser.add_argument('infile', nargs='*', type=argparse.FileType('r'), default=[sys.stdin],
help='the name of the file(s) to search.')
group = parser.add_mutually_exclusive_group()
group.add_argument('-u', '--underscore', action='store_true', help='prints \
"^" under the matching text.')
group.add_argument('-c', '--color', action='store_true', help='highlights \
matching text.')
group.add_argument('-m', '--machine', action='store_true', help='generates \
machine readable output.')
return parser
def main():
args = init_parser().parse_args()
for file in args.infile:
for i, line in enumerate(iter(file.readline, '')):
for substring in re.finditer(args.regex, line):
if args.underscore:
underscore_output(file.name, i + 1, line[:-1],
substring.start(), substring.end())
elif args.color:
color_output(file.name, i + 1, line[:-1],
substring.group())
elif args.machine:
machine_output(file.name, i + 1, substring.start(),
substring.group())
else:
print_line(file.name, i + 1, line[:-1])```
In the test code, you would patch out sys.argv before calling main:
def test_main(monkeypatch):
monkeypatch.setattr("sys.argv", ["script.py", "test_regex", "test_infile"])
main()
# put your assertions here
parse_args can take an explicit None argument to tell it to parse sys.argv[1:]. Write your code so that it can be easily tested:
def main(args=None):
args = init_parser().parse_args(args)
...
In production use, you'll call main() to let it parse sys.argv. For tests, you'll pass a specific set of arguments.
def test_main(capfd):
main(['[a-z]*', 'foo.txt', '-u']) # For example
out, err = capfd.readouterr()
assert out == "my expected output"
python call ansibleApi with celery return None,I have searched a few days.It works well with call deploy function without celery ,but with celery my code call ansibleApi return None.
reproduce steps.
1.tasks.py
from celery import shared_task
from .deploy_tomcat2 import django_process
#shared_task
def deploy(jira_num):
#return 'hello world {0}'.format(jira_num)
#rdb.set_trace()
return django_process(jira_num)
2.deploy_tomcat2.py
from .AnsibleApi import CallApi
def django_process(jira_num):
server = '10.10.10.30'
name = 'abc'
port = 11011
code = 'efs'
jdk = '1.12.13'
jvm = 'xxxx'
if str.isdigit(jira_num):
# import pdb
# pdb.set_trace()
call = CallApi(server,name,port,code,jdk,jvm)
return call.run_task()
3.AnsibleApi.py
#!/usr/bin/env python
import logging
from .Logger import Logger
from django.conf import settings
from collections import namedtuple
from ansible.parsing.dataloader import DataLoader
from ansible.vars import VariableManager
from ansible.inventory import Inventory
from ansible.playbook.play import Play
from ansible.executor.task_queue_manager import TaskQueueManager
from ansible.plugins.callback import CallbackBase
Log = Logger('/tmp/auto_deploy_tomcat.log',logging.INFO)
class ResultCallback(CallbackBase):
def __init__(self, *args, **kwargs):
super(ResultCallback ,self).__init__(*args, **kwargs)
self.host_ok = {}
self.host_unreachable = {}
self.host_failed = {}
def v2_runner_on_unreachable(self, result):
self.host_unreachable[result._host.get_name()] = result
def v2_runner_on_ok(self, result, *args, **kwargs):
self.host_ok[result._host.get_name()] = result
def v2_runner_on_failed(self, result, *args, **kwargs):
self.host_failed[result._host.get_name()] = result
class CallApi(object):
user = settings.SSH_USER
ssh_private_key_file = settings.SSH_PRIVATE_KEY_FILE
results_callback = ResultCallback()
Options = namedtuple('Options',
['connection', 'module_path', 'private_key_file', 'forks', 'become', 'become_method',
'become_user', 'check'])
def __init__(self,ip,name,port,code,jdk,jvm):
self.ip = ip
self.name = name
self.port = port
self.code = code
self.jdk = jdk
self.jvm = jvm
self.results_callback = ResultCallback()
self.results_raw = {}
def _gen_user_task(self):
tasks = []
deploy_script = 'autodeploy/tomcat_deploy.sh'
dst_script = '/tmp/tomcat_deploy.sh'
cargs = dict(src=deploy_script, dest=dst_script, owner=self.user, group=self.user, mode='0755')
args = "%s %s %d %s %s '%s'" % (dst_script, self.name, self.port, self.code, self.jdk, self.jvm)
tasks.append(dict(action=dict(module='copy', args=cargs),register='shell_out'))
tasks.append(dict(action=dict(module='debug', args=dict(msg='{{shell_out}}'))))
# tasks.append(dict(action=dict(module='command', args=args)))
# tasks.append(dict(action=dict(module='command', args=args), register='result'))
# tasks.append(dict(action=dict(module='debug', args=dict(msg='{{result.stdout}}'))))
self.tasks = tasks
def _set_option(self):
self._gen_user_task()
self.variable_manager = VariableManager()
self.loader = DataLoader()
self.options = self.Options(connection='smart', module_path=None, private_key_file=self.ssh_private_key_file, forks=None,
become=True, become_method='sudo', become_user='root', check=False)
self.inventory = Inventory(loader=self.loader, variable_manager=self.variable_manager, host_list=[self.ip])
self.variable_manager.set_inventory(self.inventory)
play_source = dict(
name = "auto deploy tomcat",
hosts = self.ip,
remote_user = self.user,
gather_facts='no',
tasks = self.tasks
)
self.play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)
def run_task(self):
self.results_raw = {'success':{}, 'failed':{}, 'unreachable':{}}
tqm = None
from celery.contrib import rdb;rdb.set_trace()
#import pdb;pdb.set_trace()
self._set_option()
try:
tqm = TaskQueueManager(
inventory=self.inventory,
variable_manager=self.variable_manager,
loader=self.loader,
options=self.options,
passwords=None,
stdout_callback=self.results_callback,
)
result = tqm.run(self.play)
finally:
if tqm is not None:
tqm.cleanup()
for host, result in self.results_callback.host_ok.items():
self.results_raw['success'][host] = result._result
for host, result in self.results_callback.host_failed.items():
self.results_raw['failed'][host] = result._result
for host, result in self.results_callback.host_unreachable.items():
self.results_raw['unreachable'][host]= result._result
Log.info("result is :%s" % self.results_raw)
return self.results_raw
4.celery worker
celery -A jira worker -Q queue.ops.deploy -n "deploy.%h" -l info
5.produce msg:
deploy.apply_async(args=['150'], queue='queue.ops.deploy', routing_key='ops.deploy')
It seems OK.
The only question is None is really the deploy task return?
It will be better that if you can post your celery worker log.
there are two method to solve this problem ,disable assert:
1.where celery starts set export PYTHONOPTIMIZE=1 OR start celery with this parameter -O OPTIMIZATION
2.disable python packet multiprocessing process.py line 102:
assert not _current_process._config.get('daemon'), \
'daemonic processes are not allowed to have children'
I know only the very basics of python. I have this project for my INFORMATION STORAGE AND MANAGEMENT subject. I have to give an explanation the following code.
I searched every command used in this script but could not find most of them. The code can be found here:
import glob
import json
import os
import re
import string
import sys
from oslo.config import cfg
from nova import context
from nova.db.sqlalchemy import api as db_api
from nova.db.sqlalchemy import models
from nova import utils
CONF = cfg.CONF
def usage():
print("""
Usage:
python %s --config-file /etc/nova/nova.conf
Note: This script intends to clean up the iSCSI multipath faulty devices
hosted by VNX Block Storage.""" % sys.argv[0])
class FaultyDevicesCleaner(object):
def __init__(self):
# Get host name of Nova computer node.
self.host_name = self._get_host_name()
def _get_host_name(self):
(out, err) = utils.execute('hostname')
return out
def _get_ncpu_emc_target_info_list(self):
target_info_list = []
# Find the targets used by VM on the compute node
bdms = db_api.model_query(context.get_admin_context(),
models.BlockDeviceMapping,
session = db_api.get_session())
bdms = bdms.filter(models.BlockDeviceMapping.connection_info != None)
bdms = bdms.join(models.BlockDeviceMapping.instance).filter_by(
host=string.strip(self.host_name))
for bdm in bdms:
conn_info = json.loads(bdm.connection_info)
if 'data' in conn_info:
if 'target_iqns' in conn_info['data']:
target_iqns = conn_info['data']['target_iqns']
target_luns = conn_info['data']['target_luns']
elif 'target_iqn' in conn_info['data']:
target_iqns = [conn_info['data']['target_iqn']]
target_luns = [conn_info['data']['target_lun']]
else:
target_iqns = []
target_luns = []
for target_iqn, target_lun in zip(target_iqns, target_luns):
if 'com.emc' in target_iqn:
target_info = {
'target_iqn': target_iqn,
'target_lun': target_lun,
}
target_info_list.append(target_info)
return target_info_list
def _get_ncpu_emc_target_info_set(self):
target_info_set = set()
for target_info in self._get_ncpu_emc_target_info_list():
target_iqn = target_info['target_iqn']
target_lun = target_info['target_lun']
target_info_key = "%s-%s" % (target_iqn.rsplit('.', 1)[0],
target_lun)
# target_iqn=iqn.1992-04.com.emc:cx.fnm00130200235.a7
# target_lun=203
# target_info_key=iqn.1992-04.com.emc:cx.fnm00130200235-203
target_info_set.add(target_info_key)
return target_info_set
def _get_target_info_key(self, path):
temp_tuple = path.split('-lun-', 1)
target_lun = temp_tuple[1]
target_iqn = temp_tuple[0].split('-iscsi-')[1]
target_info_key = "%s-%s" % (target_iqn.rsplit('.', 1)[0], target_lun)
# path=/dev/disk/by-path/ip-192.168.3.52:3260-iscsi-iqn.1992-
# 04.com.emc:cx.fnm00130200235.a7-lun-203
# target_info_key=iqn.1992-04.com.emc:cx.fnm00130200235-203
return target_info_key
def _get_non_ncpu_target_info_map(self):
# Group the paths by target_info_key
ncpu_target_info_set = self._get_ncpu_emc_target_info_set()
device_paths = self._get_emc_device_paths()
target_info_map = {}
for path in device_paths:
target_info_key = self._get_target_info_key(path)
if target_info_key in ncpu_target_info_set:
continue
if target_info_key not in target_info_map:
target_info_map[target_info_key] = []
target_info_map[target_info_key].append(path)
return target_info_map
def _all_related_paths_faulty(self, paths):
for path in paths:
real_path = os.path.realpath(path)
out, err = self._run_multipath(['-ll', real_path],
run_as_root=True,
check_exit_code=False)
if 'active ready' in out:
# At least one path is still working
return False
return True
def _delete_all_related_paths(self, paths):
for path in paths:
real_path = os.path.realpath(path)
device_name = os.path.basename(real_path)
device_delete = '/sys/block/%s/device/delete' % device_name
if os.path.exists(device_delete):
# Copy '1' from stdin to the device delete control file
utils.execute('cp', '/dev/stdin', device_delete,
process_input='1', run_as_root=True)
else:
print "Unable to delete %s" % real_path
def _cleanup_faulty_paths(self):
non_ncpu_target_info_map = self._get_non_ncpu_target_info_map()
for paths in non_ncpu_target_info_map.itervalues():
if self._all_related_paths_faulty(paths):
self._delete_all_related_paths(paths)
def _cleanup_faulty_dm_devices(self):
out_ll, err_ll = self._run_multipath(['-ll'],
run_as_root=True,
check_exit_code=False)
# Pattern to split the dm device contents as follows
# Each section starts with a WWN and ends with a line with
# " `-" as the prefix
#
# 3600601601bd032007c097518e96ae411 dm-2 ,
# size=1.0G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
# `-+- policy='round-robin 0' prio=0 status=active
# `- #:#:#:# - #:# active faulty running
# 36006016020d03200bb93e048f733e411 dm-0 DGC,VRAID
# size=1.0G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
# |-+- policy='round-robin 0' prio=130 status=active
# | |- 3:0:0:2 sdd 8:48 active ready running
# | `- 5:0:0:2 sdj 8:144 active ready running
# `-+- policy='round-robin 0' prio=10 status=enabled
# |- 4:0:0:2 sdg 8:96 active ready running
# `- 6:0:0:2 sdm 8:192 active ready running
dm_pat = r'([0-9a-fA-F]{30,})[^\n]+,[^\n]*\n[^,]* `-[^\n]*'
dm_m = re.compile(dm_pat)
path_pat = r'- \d+:\d+:\d+:\d+ '
path_m = re.compile(path_pat)
for m in dm_m.finditer(out_ll):
if not path_m.search(m.group(0)):
# Only #:#:#:# remain in the output, all the paths of the dm
# device should have been deleted. No need to keep the device
out_f, err_f = self._run_multipath(['-f', m.group(1)],
run_as_root=True,
check_exit_code=False)
def cleanup(self):
self._cleanup_faulty_paths()
# Make sure the following configuration is in /etc/multipath.conf
# Otherwise, there may be "map in use" failure when deleting
# dm device
#
# defaults {
# flush_on_last_del yes
# }
#
self._cleanup_faulty_dm_devices()
def _get_emc_device_paths(self):
# Find all the EMC iSCSI devices under /dev/disk/by-path
# except LUNZ and partition reference
pattern = '/dev/disk/by-path/ip-*-iscsi-iqn*com.emc*-lun-*'
device_paths = [path for path in glob.glob(pattern)
if ('lun-0' not in path and '-part' not in path)]
return device_paths
def _run_multipath(self, multipath_command, **kwargs):
check_exit_code = kwargs.pop('check_exit_code', 0)
(out, err) = utils.execute('multipath',
*multipath_command,
run_as_root=True,
check_exit_code=check_exit_code)
print ("multipath %(command)s: stdout=%(out)s stderr=%(err)s"
% {'command': multipath_command, 'out': out, 'err': err})
return out, err
if __name__ == "__main__":
if len(sys.argv) != 3 or sys.argv[1] != '--config-file':
usage()
exit(1)
out, err = utils.execute('which', 'multipath', check_exit_code=False)
if 'multipath' not in out:
print('Info: Multipath tools not installed. No cleanup need be done.')
exit(0)
multipath_flush_on_last_del = False
multipath_conf_path = "/etc/multipath.conf"
if os.path.exists(multipath_conf_path):
flush_on_last_del_yes = re.compile(r'\s*flush_on_last_del.*yes')
for line in open(multipath_conf_path, "r"):
if flush_on_last_del_yes.match(line):
multipath_flush_on_last_del = True
break
if not multipath_flush_on_last_del:
print("Warning: 'flush_on_last_del yes' is not seen in"
" /etc/multipath.conf."
" 'map in use' failure may show up during cleanup.")
CONF(sys.argv[1:])
# connect_volume and disconnect_volume in nova/virt/libvirt/volume.py
# need be adjusted to take the same 'external=True' lock for
# synchronization
#utils.synchronized('connect_volume', external=True)
def do_cleanup():
cleaner = FaultyDevicesCleaner()
cleaner.cleanup()
do_cleanup()
https://wiki.python.org/moin/BeginnersGuide/Programmers
http://www.astro.ufl.edu/~warner/prog/python.html
looks like this python version 3 so. go for the tutorials of version three.
try downloading any IDE. eric5 is good by the way.
try executing this file once.
learn indentations
and dynamic variable declaration
do not jump into the ocean first try swimming pool : )
Also Try to learn method declaration.
Python is a bit different than java.
I will give you a hint looks like system call are also made to execute os commands so try looking at subprocess and how its output is directed to an output stream and error stream.
I have a python version of grep, that I am building for an assignment. I want my python module to take multiple patterns from the command line, just like grep. However no matter what I do, I keep getting conflicts with my 'debug' argument.
This is what it currently looks like from command line (with -h):
pgreper.py [-h] [--debug] pattern
At the moment I can only search with one pattern:
cat input.txt | ./pgreper.py "were"
I would like to be able to search the input.txt file like so, with multiple patterns:
cat input.txt | ./pgreper.py "were" "you"
However when I try and do this, I get the following error:
pgreper.py: error: unrecognized argument: you
I know that it is related to the fact I generate a pattern to search by reading sys.argv[1]. How would I go about editing my script, to allow it to take multiple patterns from sys.argv, without affecting the optional arguments I have implemented?
Many thanks :)
ps Please ignore my comments, thanks.
#!/usr/bin/python3
import sys
import re
import time
import datetime
import inspect
import argparse
parser = argparse.ArgumentParser(description='Python Grep.')
parser.add_argument('--debug', default='debug', action='store_true', help='Print debug messages')
parser.add_argument('pattern', type=str, help='Pattern for pgrepping')
args = parser.parse_args()
class CodeTrace(object):
def __init__(self, line, pattern):
self.line = line
self.pattern = pattern
# #staticmethod
def trace(self, line, pattern):
# Creating Timestamp
ts = time.time()
# Formatting Timestamp
ts = datetime.datetime.fromtimestamp(ts).strftime('[%Y-%m-%d %H:%M:%S:%f]')
stack = inspect.stack()
# Retrieve calling class information
the_class = stack[1][0].f_locals["self"].__class__
# Retrieve calling method information
the_method = stack[1][0].f_code.co_name
the_variables = stack[1][0].f_code.co_varnames
# Formats the contents of the debug trace into a readable format,
# Any parameters passed to the method and the return value, are included in the debug trace
debug_trace = ("{} {}.{}.{} {} {} ".format(ts, str(the_class), the_method, the_variables, pattern, line))
# Send out the debug trace as a standard error output
sys.stderr.write(debug_trace + "\n")
class Grepper(object):
def __init__(self, pattern):
self.pattern = pattern
# #CodeTrace.trace()
def matchline(self, pattern):
regex = re.compile(self.pattern)
for line in sys.stdin:
if regex.search(line):
sys.stdout.write(line)
if args.debug != 'debug':
(CodeTrace(line, pattern).trace(line, pattern))
def main():
pattern = str(sys.argv[1])
print(sys.argv)
Grepper(pattern).matchline(pattern)
if __name__ == "__main__":
main()
You can tell argparse to expect 1 or more arguments, using the nargs keyword argument:
parser.add_argument('patterns', type=str, nargs='+', help='Pattern(s) for pgrepping')
Here + means 1 or more. You can then combine these patterns:
pattern = '|'.join(['(?:{})'.format(p) for p in args.patterns])
and pass that to your grepper. The patterns are combined with | after first being placed in a non-capturing group ((?:...)) to make sure each pattern is treated as distinct.
I'd place all argument parsing in the main() function here:
def main():
parser = argparse.ArgumentParser(description='Python Grep.')
parser.add_argument('--debug', action='store_true', help='Print debug messages')
parser.add_argument('pattern', type=str, nargs='+', help='Pattern(s) for pgrepping')
args = parser.parse_args()
pattern = '|'.join(['(?:{})'.format(p) for p in args.pattern])
Grepper(pattern, args.debug).matchline()
I also removed the default for the --debug option; using store_true means it'll default to False; you can then simply test for args.debug being true or not.
You don't need to pass in pattern twice to Grepper(); you can simply use self.pattern in the matchline method, throughout. Instead, I'd pass in args.debug to Grepper() as well (no need for it to be a global).
Quick demo of what the argument parsing look like, including the help message:
>>> import argparse
>>> parser = argparse.ArgumentParser(description='Python Grep.')
>>> parser.add_argument('--debug', action='store_true', help='Print debug messages')
_StoreTrueAction(option_strings=['--debug'], dest='debug', nargs=0, const=True, default=False, type=None, choices=None, help='Print debug messages', metavar=None)
>>> parser.add_argument('pattern', type=str, nargs='+', help='Pattern(s) for pgrepping')
_StoreAction(option_strings=[], dest='pattern', nargs='+', const=None, default=None, type=<type 'str'>, choices=None, help='Pattern(s) for pgrepping', metavar=None)
>>> parser.print_help()
usage: [-h] [--debug] pattern [pattern ...]
Python Grep.
positional arguments:
pattern Pattern(s) for pgrepping
optional arguments:
-h, --help show this help message and exit
--debug Print debug messages
>>> parser.parse_args(['where'])
Namespace(debug=False, pattern=['where'])
>>> parser.parse_args(['were'])
Namespace(debug=False, pattern=['were'])
>>> parser.parse_args(['were', 'you'])
Namespace(debug=False, pattern=['were', 'you'])
>>> parser.parse_args(['--debug', 'were', 'you'])
Namespace(debug=True, pattern=['were', 'you'])
The pattern then looks like this:
>>> args = parser.parse_args(['were', 'you'])
>>> args.pattern
['were', 'you']
>>> pattern = '|'.join(['(?:{})'.format(p) for p in args.pattern])
>>> pattern
'(?:were)|(?:you)'
If instead you wanted all patterns to match, you'll need to alter Grepper() to take multiple patterns and test all those patterns. Use the all() function to make that efficient (only test as many patterns as is required):
def main():
parser = argparse.ArgumentParser(description='Python Grep.')
parser.add_argument('--debug', action='store_true', help='Print debug messages')
parser.add_argument('pattern', type=str, nargs='+', help='Pattern(s) for pgrepping')
args = parser.parse_args()
Grepper(args.pattern, args.debug).matchline()
and the Grepper class becomes:
class Grepper(object):
def __init__(self, patterns, debug=False):
self.patterns = [re.compile(p) for p in patterns]
self.debug = debug
def matchline(self, debug):
for line in sys.stdin:
if all(p.search(line) for p in self.patterns):
sys.stdout.write(line)
if self.debug:
CodeTrace(line, self.patterns).trace(line)
with appropriate adjustments for the CodeTrace class.
Your argparse argument configuration were not correct. This is really now how you configure the argument. Check the Python documentation for argparse as there is a very good example in there.
the format should always be yourscript.py -aARGUMENTVAL -bARGUMENTVAL ...etc. the -a and -b styles are important.
Your code is edited to have a better application of argparse module below. See if this works better (without action argument for debug):
import sys
import re
import time
import datetime
import inspect
import argparse
parser = argparse.ArgumentParser(description='Python Grep.')
parser.add_argument('-p', '--pattern', type=str, help='Pattern for pgrepping')
parser.add_argument('-d','--debug', type=str, default="false", help='Print debug messages')
args = vars(parser.parse_args());
class CodeTrace(object):
def __init__(self, line, pattern):
self.line = line
self.pattern = pattern
# #staticmethod
def trace(self, line, pattern):
# Creating Timestamp
ts = time.time()
# Formatting Timestamp
ts = datetime.datetime.fromtimestamp(ts).strftime('[%Y-%m-%d %H:%M:%S:%f]')
stack = inspect.stack()
# Retrieve calling class information
the_class = stack[1][0].f_locals["self"].__class__
# Retrieve calling method information
the_method = stack[1][0].f_code.co_name
the_variables = stack[1][0].f_code.co_varnames
# Formats the contents of the debug trace into a readable format,
# Any parameters passed to the method and the return value, are included in the debug trace
debug_trace = ("{} {}.{}.{} {} {} ".format(ts, str(the_class), the_method, the_variables, pattern, line))
# Send out the debug trace as a standard error output
sys.stderr.write(debug_trace + "\n")
class Grepper(object):
def __init__(self, pattern):
self.pattern = pattern
# #CodeTrace.trace()
def matchline(self, pattern):
regex = re.compile(self.pattern)
for line in sys.stdin:
if regex.search(line):
sys.stdout.write(line)
if args.debug != 'debug':
(CodeTrace(line, pattern).trace(line, pattern))
def main():
pattern = str(args['pattern'])
print(sys.argv)
Grepper(pattern).matchline(pattern)
if __name__ == "__main__":
main()
You can supply comma delimited string to separate patters `-p"were,you". Use python's powerful string functions for that
pattern = ((args['pattern']).replace(" ", "")).split(",");
the above will give you a list of patterns to look for?