Getopt multiple argument syntaxes - python

So I'm working on an assignment in a python class that I'm taking, but have gotten stuck with something I can't really find any further information about (neither on SO, Google or in the courseware).
I need help with how to handle arguments with multiple types of syntaxes - like [arg] and < arg >, which is something I've been unable to find any further information about.
Here is an example use-case that SHOULD work.
>>> ./marvin-cli.py --output=<filename.txt> ping <http://google.com>
>>> Syntax error near unexpected token 'newline'
The below code works fine for any use-case where I haven't defined any further output than writing to the console:
# Switch through all options
try:
opts, args = getopt.getopt(sys.argv[1:], "hsv", ["help","version","silent", "get=", "ping=", "verbose", "input=", "json"])
for opt, arg in opts:
if opt in ("-h", "--help"):
printUsage(EXIT_SUCCESS)
elif opt in ("-s", "--silent"):
VERBOSE = False
elif opt in ("--verbose"):
VERBOSE = True
elif opt in ("--ping"):
ping(arg)
elif opt in ("--input"):
print("Printing to: ", arg)
else:
assert False, "Unhandled option"
except Exception as err:
print("Error " ,err)
print(MSG_USAGE)
# Prints the callstack, good for debugging, comment out for production
#traceback.print_exception(Exception, err, None)
sys.exit(EXIT_USAGE)
#print(sys.argv[1])
Example usage:
>>> ./marvin-cli.py ping http://google.com
>>> Latency 100ms
And this is a snippet showing how the ping works:
def ping(URL):
#Getting necessary imports
import requests
import time
#Setting up variables
start = time.time()
req = requests.head(URL)
end = time.time()
#printing result
if VERBOSE == False:
print("I'm pinging: ", URL)
print("Received HTTP response (status code): ", req.status_code)
print("Latency: {}ms".format(round((end - start) * 1000, 2)))

[] and <> are commonly used to visually indicate option requirement. Typically [xxxx] means the option or argument is optional and <xxxx> required.
The sample code you provide handles option flags, but not the required arguments. Code below should get you started in the right direction.
try:
opts, args = getopt.getopt(sys.argv[1:], "hsv", ["help", "version", "silent", "verbose", "output=", "json"])
for opt, arg in opts:
if opt in ("-h", "--help"):
printUsage(EXIT_SUCCESS)
elif opt in ("-s", "--silent"):
VERBOSE = False
elif opt in ("--verbose"):
VERBOSE = True
elif opt in ("--output"):
OUTPUTTO = arg
print("Printing to: ", arg)
else:
assert False, "Unhandled option"
assert len(args) > 0, "Invalid command usage"
# is there a "<command>" function defined?
assert args[0] in globals(), "Invalid command {}".format(args[0])
# pop first argument as the function to call
command = args.pop(0)
# pass args list to function
globals()[command](args)
def ping(args):
#Getting necessary imports
import requests
import time
# validate arguments
assert len(args) != 1, "Invalid argument to ping"
URL = args[0]
#Setting up variables
start = time.time()
req = requests.head(URL)
end = time.time()
#printing result
if VERBOSE == False:
print("I'm pinging: ", URL)
print("Received HTTP response (status code): ", req.status_code)
print("Latency: {}ms".format(round((end - start) * 1000, 2)))

Related

Rerun python script after 10 seconds

I am trying to rerun my python script every 10 seconds. I have tried various things with the time.sleep function but nothing seems to be working. I have tried different variants of time.sleep:
def job()
# script
if __name__ == '__main__':
while True:
job()
time.sleep(10)
but not finding the correct place/way to implement it. I don't want to rerun a function, but the full code.
This is the script I am trying to rerun:
import...
def main():
# parse the command line arguments
args = ConfigArgumentParser(description=__doc__).parse_args()
if _debug: _log.debug("initialization")
if _debug: _log.debug(" - args: %r", args)
# make a device object
this_device = LocalDeviceObject(
objectName=args.ini.objectname,
objectIdentifier=('device', int(args.ini.objectidentifier)),
maxApduLengthAccepted=int(args.ini.maxapdulengthaccepted),
segmentationSupported=args.ini.segmentationsupported,
vendorIdentifier=int(args.ini.vendoridentifier),
)
# make a sample application
this_application = BIPSimpleApplication(this_device, args.ini.address)
# make some random input objects
for i in range(1, RANDOM_OBJECT_COUNT + 1):
ravo = RandomAnalogValueObject(
objectIdentifier=('analogValue', i),
objectName='Temp%d' % (i,),
)
this_application.add_object(ravo)
# make sure they are all there
_log.debug(" - object list: %r", this_device.objectList)
_log.debug("running")
run()
_log.debug("fini")
if __name__ == "__main__":
main()
If you need the whole thing to run (even bootstrap code), you can use a shell script to do it.
This won't refresh environment variables though.
#!/usr/bin/env bash
while true; do
sleep 10
python script.py
done
If you need to refresh environment variables (you seem to need it because of RANDOM_OBJECTS), add eval "$(exec /usr/bin/env -i "${SHELL}" -l -c "export")" to the mix. Source: https://unix.stackexchange.com/a/581684
Try this:
if __name__ == "__main__":
time.sleep(10)
main()
What you can do is just restart your whole script after 10s.
Applied to your code it would look like this:
import os
import time
import json
import sys
from bacpypes.debugging import bacpypes_debugging, ModuleLogger
from bacpypes.consolelogging import ConfigArgumentParser
from bacpypes.core import run
from bacpypes.primitivedata import Real
from bacpypes.object import AnalogValueObject, Property, register_object_type
from bacpypes.errors import ExecutionError
from bacpypes.app import BIPSimpleApplication
from bacpypes.local.device import LocalDeviceObject
# Read Json
with open('ObjectList.json') as json_file:
data = json.load(json_file)
def get_present_value(no):
for a in data['AnalogValues']:
if a['ObjectIdentifier'] == int(no):
return a['PresentValue']
return None
ai_1 = (get_present_value(1))
print(ai_1)
# some debugging
_debug = 0
_log = ModuleLogger(globals())
# settings
RANDOM_OBJECT_COUNT = int(os.getenv('RANDOM_OBJECT_COUNT', 1))
#
# RandomValueProperty
#
class RandomValueProperty(Property):
def __init__(self, identifier):
if _debug: RandomValueProperty._debug("__init__ %r", identifier)
Property.__init__(self, identifier, Real, default=0.0, optional=True, mutable=False)
def ReadProperty(self, obj, arrayIndex=None):
if _debug: RandomValueProperty._debug("ReadProperty %r arrayIndex=%r", obj, arrayIndex)
# access an array
if arrayIndex is not None:
raise ExecutionError(errorClass='property', errorCode='propertyIsNotAnArray')
# return a random value
value = ai_1
if _debug: RandomValueProperty._debug(" - value: %r", value)
return value
def WriteProperty(self, obj, value, arrayIndex=None, priority=None, direct=False):
if _debug: RandomValueProperty._debug("WriteProperty %r %r arrayIndex=%r priority=%r direct=%r", obj, value,
arrayIndex, priority, direct)
raise ExecutionError(errorClass='property', errorCode='writeAccessDenied')
bacpypes_debugging(RandomValueProperty)
#
# Random Value Object Type
#
class RandomAnalogValueObject(AnalogValueObject):
properties = [
RandomValueProperty('presentValue'),
]
def __init__(self, **kwargs):
if _debug: RandomAnalogValueObject._debug("__init__ %r", kwargs)
AnalogValueObject.__init__(self, **kwargs)
bacpypes_debugging(RandomAnalogValueObject)
register_object_type(RandomAnalogValueObject)
#
# __main__
#
def main():
# parse the command line arguments
args = ConfigArgumentParser(description=__doc__).parse_args()
if _debug: _log.debug("initialization")
if _debug: _log.debug(" - args: %r", args)
# make a device object
this_device = LocalDeviceObject(
objectName=args.ini.objectname,
objectIdentifier=('device', int(args.ini.objectidentifier)),
maxApduLengthAccepted=int(args.ini.maxapdulengthaccepted),
segmentationSupported=args.ini.segmentationsupported,
vendorIdentifier=int(args.ini.vendoridentifier),
)
# make a sample application
this_application = BIPSimpleApplication(this_device, args.ini.address)
# make some random input objects
for i in range(1, RANDOM_OBJECT_COUNT + 1):
ravo = RandomAnalogValueObject(
objectIdentifier=('analogValue', i),
objectName='Temp%d' % (i,),
)
this_application.add_object(ravo)
# make sure they are all there
_log.debug(" - object list: %r", this_device.objectList)
_log.debug("running")
run()
_log.debug("fini")
if __name__ == "__main__":
main()
time.sleep(10)
os.execl(sys.executable, sys.executable, * sys.argv) # Your script restarts after 10s with this

Attempting to Understand Functional Arguments

I recognize this may be a very 101 type question, but I'm still having trouble understanding functional programming in general, and have a particular code snippet that I can't make sense of:
Full code, but leaving out most of the function definitions:
import blpapi
import sys
SESSION_STARTED = blpapi.Name("SessionStarted")
SESSION_STARTUP_FAILURE = blpapi.Name("SessionStartupFailure")
SERVICE_OPENED = blpapi.Name("ServiceOpened")
SERVICE_OPEN_FAILURE = blpapi.Name("ServiceOpenFailure")
ERROR_INFO = blpapi.Name("ErrorInfo")
GET_FILLS_RESPONSE = blpapi.Name("GetFillsResponse")
d_service="//blp/emsx.history"
d_host="localhost"
d_port=8194
bEnd=False
class SessionEventHandler():
def processEvent(self, event, session):
try:
if event.eventType() == blpapi.Event.SESSION_STATUS:
self.processSessionStatusEvent(event,session)
elif event.eventType() == blpapi.Event.SERVICE_STATUS:
self.processServiceStatusEvent(event,session)
elif event.eventType() == blpapi.Event.RESPONSE:
self.processResponseEvent(event)
else:
self.processMiscEvents(event)
except:
print ("Exception: %s" % sys.exc_info()[0])
return False
def processSessionStatusEvent(self,event,session):
print ("Processing SESSION_STATUS event")
for msg in event:
pass
def processServiceStatusEvent(self,event,session):
print ("Processing SERVICE_STATUS event")
for msg in event:
pass
def processResponseEvent(self, event):
print ("Processing RESPONSE event")
for msg in event:
global bEnd
bEnd = True
def processMiscEvents(self, event):
print ("Processing " + event.eventType() + " event")
for msg in event:
print ("MESSAGE: %s" % (msg.tostring()))
def main():
sessionOptions = blpapi.SessionOptions()
sessionOptions.setServerHost(d_host)
sessionOptions.setServerPort(d_port)
print ("Connecting to %s:%d" % (d_host,d_port))
eventHandler = SessionEventHandler()
session = blpapi.Session(sessionOptions, eventHandler.processEvent)
if not session.startAsync():
print ("Failed to start session.")
return
global bEnd
while bEnd==False:
pass
session.stop()
I can follow the code up to here:
session = blpapi.Session(sessionOptions, eventHandler.processEvent)
Here, I see I'm calling "Session" from the blpapi library, and passing it some options as well as my eventHandler.processEvent. Here is where I get lost. I look at that particular function, and see:
def processEvent(self, event, session):
try:
if event.eventType() == blpapi.Event.SESSION_STATUS:
self.processSessionStatusEvent(event,session)
elif event.eventType() == blpapi.Event.SERVICE_STATUS:
self.processServiceStatusEvent(event,session)
elif event.eventType() == blpapi.Event.RESPONSE:
self.processResponseEvent(event)
else:
self.processMiscEvents(event)
except:
print ("Exception: %s" % sys.exc_info()[0])
return False
I see that the function is attempting to discern what type of event has been passed in, and will execute a different function within the class depending on that event type. The trouble is, I can't figure out where the event is ever specified! Where does "event" come from? I see it as an argument in that particular function, but no event argument was passed to:
session = blpapi.Session(sessionOptions, eventHandler.processEvent)
So how does it know what to do at this point? How did this "event" object magically appear?
Thanks for entertaining my dumb questions
session = blpapi.Session(sessionOptions, eventHandler.processEvent)
Note that processEvent here lacks parentheses () after it. This means you are passing the function itself as a parameter to the Session class. This class will later call processEvent with appropriate parameters.
Side Note:
I'm still having trouble understanding functional programming
"Functional programming" has a very specific definition and this example isn't it. If you are interested, you can google "functional programming" or read the Wikipedia article to find out more. However, this isn't really important at this stage in your learning process.

Python functions and calling args

I'm creating my first python tool, if you want to call it that. (I work in IT Security, btw)
It was going well until I tried to call a function from the main function. I'm sure it's something simple that I'm missing :(. Could someone point me in the right direction? Then feel free to point and laugh.
#!/usr/bin/python
import sys, getopt, socket
def usage():
print "-h --help: help\n"
print "-f --file: File to read bruteforce domain list from.\n"
print "-p --proxy: Proxy address and port. e.g http://192.168.1.64:8080\n"
print "-d --domain: Domain to bruteforce.\n"
print "-e: Turn debug on.\n"
sys.exit()
def main(argv):
file = None
proxy = None
domain = None
try:
opts, argv =getopt.getopt(argv, "h:f:p:d:e",["help", "file=", "proxy=", "domain="])
except getopt.GetoptError as err:
print str(err)
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit()
elif opt in ("-f", "--file"):
file = arg
elif opt in ("-p", "--proxy"):
proxy = arg
elif opt in ("-d", "--domain"):
domain = arg
elif opt in '-e':
global _debug
_debug = 1
else:
assert Flase, "Unhandled option"
print fread.flist
def fread(file, *args):
flist = open(file).readlines()
return
if __name__ == "__main__":
main(sys.argv[1:])
The issue is with your statement print fread.flist. You can't access variables assigned inside functions this way. Instead, change your fread() function to the following:
def fread(file, *args):
flist = open(file).readlines()
return flist
and change the statement above to
print fread(file)
where file is the file you want to access.

Detect and print if no command line argument is provided

This is the program I have:
from sys import argv
script, arg1 = argv
def program(usr_input, arg1):
if(usr_input == arg1):
print "CLI argument and user input are identical"
else:
print "CLI argument and user input aren't identical"
if arg1 != "":
usr_input = raw_input("enter something: ")
program(usr_input, arg1)
else:
print "You have not entered a CLI argument at all."
I get:
Traceback (most recent call last):
File "filename.py", line 3, in <module>
script, arg1 = argv
ValueError: need more than 1 value to unpack
How can I detect the lack of command line argument and throw an error/exception instead of receiving this error?
I would recommend just checking the program args in the __main__ location of your script, as an entry point to the entire application.
import sys
import os
def program(*args):
# do whatever
pass
if __name__ == "__main__":
try:
arg1 = sys.argv[1]
except IndexError:
print "Usage: " + os.path.basename(__file__) + " <arg1>"
sys.exit(1)
# start the program
program(arg1)
You can handle the exception:
In [6]: def program(argv):
try:
script, argv1 = argv
except ValueError:
print("value error handled")
...:
In [7]: program(argv)
value error handled
try this:
script = argv[0]
try:
arg1 = argv[1]
except:
arg1 = ''
You could use a try statement there:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import sys
class MyError(Exception):
def __init__(self, value):
self.error_string = value
def __str__(self):
return eval(repr(self.error_string))
try:
script, arg1 = sys.argv
except ValueError:
raise MyError, "Not enough arguments"
Seeing that sys.argv is a list you should check the length of the list to make sure it is what you wish it to be. Your script with minor changes to check the length:
from sys import argv
def program(usr_input, arg1):
if(usr_input == arg1):
print "CLI argument and user input are identical"
else:
print "CLI argument and user input aren't identical"
if len(argv)== 2:
arg1 = argv[1]
usr_input = raw_input("enter something: ")
program(usr_input, arg1)
else:
print "You have not entered a CLI argument at all."

Add SMTP AUTH support to Python smtpd library... can't override the method?

So, I wanted to extend the Python smtpd SMTPServer class so that it could handle SMTP AUTH connections. Seemed simple enough...
So, it looked like I could just start like this:
def smtp_EHLO(self, arg):
print 'got in arg: ', arg
# do stuff here...
But for some reason, that never gets called. The Python smtpd library calls other similar methods like this:
method = None
i = line.find(' ')
if i < 0:
command = line.upper()
arg = None
else:
command = line[:i].upper()
arg = line[i+1:].strip()
method = getattr(self, 'smtp_' + command, None)
Why won't it call my method?
After that, I thought that I could probably just override the entire found_terminator(self): method, but that doesn't seem to work either.
def found_terminator(self):
# I add this to my child class and it never gets called...
Am I doing something stupid or...? Maybe I just haven't woken up fully yet today...
import smtpd
import asyncore
class CustomSMTPServer(smtpd.SMTPServer):
def smtp_EHLO(self, arg):
print 'got in arg: ', arg
def process_message(self, peer, mailfrom, rcpttos, data):
print 'Receiving message from:', peer
print 'Message addressed from:', mailfrom
print 'Message addressed to :', rcpttos
print 'Message length :', len(data)
print 'HERE WE ARE MAN!'
return
# Implementation of base class abstract method
def found_terminator(self):
print 'THIS GOT CALLED RIGHT HERE!'
line = EMPTYSTRING.join(self.__line)
print >> DEBUGSTREAM, 'Data:', repr(line)
self.__line = []
if self.__state == self.COMMAND:
if not line:
self.push('500 Error: bad syntax')
return
method = None
i = line.find(' ')
if i < 0:
command = line.upper()
arg = None
else:
command = line[:i].upper()
arg = line[i+1:].strip()
method = getattr(self, 'smtp_' + command, None)
print 'looking for: ', command
print 'method is: ', method
if not method:
self.push('502 Error: command "%s" not implemented' % command)
return
method(arg)
return
else:
if self.__state != self.DATA:
self.push('451 Internal confusion')
return
# Remove extraneous carriage returns and de-transparency according
# to RFC 821, Section 4.5.2.
data = []
for text in line.split('\r\n'):
if text and text[0] == '.':
data.append(text[1:])
else:
data.append(text)
self.__data = NEWLINE.join(data)
status = self.__server.process_message(self.__peer,
self.__mailfrom,
self.__rcpttos,
self.__data)
self.__rcpttos = []
self.__mailfrom = None
self.__state = self.COMMAND
self.set_terminator('\r\n')
if not status:
self.push('250 Ok')
else:
self.push(status)
server = CustomSMTPServer(('127.0.0.1', 1025), None)
asyncore.loop()
You need to extend SMTPChannel -- that's where the smtp_verb methods are implemented; your extension of SMTPServer just needs to return your own subclass of the channel.
TL&DR: To add additional functionality to SMTPChannel you just need to declare a function, and then add it directly to smtpd.SMTPChannel
Explanation:
The SMTPChannel class is designed to respond to the commands that are entered by the user on the open port (typically port 25). The way it searches for which commands it can answer is based off 'Introspection' where it examines all the available attributes of the function.
Take note that the functions within SMTPChannel need to start with the "smtp_". For Example, if you wanted to respond to HELP you would create smtpd.SMTPChannel.smtp_HELP.
The Function below is from the source-code that details the introspection
class SMTPChannel(asynchat.async_chat):
method = getattr(self, 'smtp_' + command, None)
CodeThatWorks
Step 1: Declare a FUNCTION that will be called
def smtp_HELP(self,arg):
self.push("[8675309] GPT Answers to HELP")
Step 2: Add the following function to smtpd.SMTPChannel
class FakeSMTPServer(smtpd.SMTPServer):
"""A Fake smtp server"""
smtpd.SMTPChannel.smtp_HELP = smtp_HELP
Step 3: Telnet to localhost 25 and test out
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 vics-imac.fios-router.home ESMTP Sendmail 6.7.4 Sunday 17 March 2019
HELP
[8675309] GPT Answers to HELP

Categories