I have a class in python. What I am trying to achieve is to pass one method into another. Say I have a method that is scanning for directories on a page and another method that opens the wordlist for which it will format all the words to pass into the method that is scanning the directories.
My issue is that the method that is formatting the words by stripping them, is not being passed into the method that is scanning directories.
class exampleClass:
def __init__(self):
pass
def openWordlist(self):
try:
with open(wordlist, 'r') as file:
for word in file:
word = word.strip()
except FileNotFoundError:
print('File does not exist')
def scanDomain(self):
try:
domain = 'http://' + targetURL + '/' + word
r = requests.get(domain)
if r.status_code == 200:
print(f'[+] {domain}')
else:
if isVerbose:
print(f'[~] {domain}')
if r.status_code == 200:
print(f'[+] {domain}')
except requests.exceptions.ConnectionError:
print('[!] CONNECTION ERROR! Exiting...')
sys.exit(0)
if __name__ == '__main__':
obj = exampleClass()
obj.openWordlist()
obj.scanDomain()
My goal is to pass the method openWordlist() to the scanDomain() method so it gets to read that wordlist and parse each request.
To call a method inside another method, you can call it using the self argument (which represents your class inside its methods).
class MyClass:
def __init__(self):
pass
def foo(self):
return True
def bar(self):
res = self.foo()
return res
It's not clear from your example how openWordlist and scanDomain are supposed to interact. I infer from the shared variable word that it is supposed to be shared between the two methods. A good way to do this is to make word an attribute of the class instance.
class exampleClass:
def __init__(self):
self.words = None
self.targetURL = ""
def openWordlist(self, wordlist):
try:
with open(wordlist, 'r') as file:
self.words = [word.strip() for word in file]
except FileNotFoundError:
print('File does not exist')
def scanDomain(self):
for word in self.words:
domain = 'http://' + self.targetURL + '/' + word
try:
r = requests.get(domain)
except requests.exceptions.ConnectionError:
print('[!] CONNECTION ERROR! Exiting...')
continue
if r.status_code == 200:
print(f'[+] {domain}')
else:
if isVerbose:
print(f'[~] {domain}')
I'm not sure if it is what you want, but you can simply add an argument to the function that should receive the other function, and then execute the function that was passed like this:
class exampleClass():
def openWordList(self):
print("Do something else")
def scanDomain(self, a_function):
print("Do something")
a_function()
if __name__ == "__main__":
obj = exampleClass()
obj.scanDomain(obj.openWordList)
Related
I would like use "try except" statement, but in two function. I caught an exception in function, but function2 does anyway. How can i stop it until there is an exception
i want to transfer it to a window application. If the file does not load, I want to display an information window. I only want the program to go on (function2) when the file loads
class Files:
def __init__(self):
self.name = "fle.txt"
def function(self):
try:
self.f = open(self.name, 'rb')
except OSError:
print("Problem!!!")
def function2(self):
print(self.f.read())
def main():
file=Files()
file.function()
file.function2()
Don't catch an exception unless you actually know how to handle it.
class Files:
def __init__(self):
self.name = "fle.txt"
self.f = None
def function(self):
self.f = open(self.name, 'rb')
def function2(self):
if self.f is None:
raise Exception("File not initialized!") #Example
#return #just if you don't throw or exit
print(self.f.read())
def main():
file=Files()
try:
file.function()
except OSError:
print("Problem!!!")
else:
file.function2()
main()
Wrap your function calls in a higher level try/except.
Of course, you would never write anything like this because it's so inflexible. This answer does not condone the OP's approach but suggests how that could be made to work.
class Files:
def __init__(self):
self.name = 'fle.txt'
def function_1(self):
self.fd = open(self.name)
def function_2(self):
print(self.fd.read())
def __del__(self):
try:
self.fd.close()
except Exception:
pass
file = Files()
try:
file.function_1()
file.function_2()
except Exception as e:
print(e)
So we don't do any exception handling (except in __del__ where we ignore any issues) within the class functions but allow all/any exceptions to propagate to the caller. Here we want to call two class functions but we wrap them in the same try/except block.
If function_1 raises an exception, function_2 won't be called.
del added to show how one could clean up but it's not the way this should be handled
#tomgalpin is right you could just exit right there after the problem
But this being a class maybe you want to print the error and pass back no data?
Here's one way to look at that with Tom's included sys exit (commented out)
Also be sure if you keep your code to close the file handler. Calling open on a file without .close() can leave file handlers open and cause problems for you if your class were to continue on after.
class Files:
def __init__(self):
self.name = "fle.txt"
# Empty string in data if no data
self.data = ""
def function(self):
try:
#self.f = open(self.name, 'rb')
with open(self.name, 'rb') as f:
self.data = f.read()
except OSError as err:
print("Problem!!!", err)
# You could exit
# sys.exit()
# But you could also return an empty string,
# which is "falsy", regardless of what happens
finally:
return self.data
def function2(self):
print(f"Data 3 {self.data}")
def main():
file=Files()
# You could print this, or use it to get the data
print("Data 1", file.function())
data = file.function()
print(f"Data 2 {data}")
# this now also shows the data
file.function2()
Use the variable that is usually True but becomes False if function fails
Example
class Files:
def __init__(self):
self.name = "file.txt"
self.Continue=True
self.data = ""
def function(self):
try:
#self.f = open(self.name, 'rb')
with open(self.name, 'rb') as f:
self.data = f.read()
except OSError as err:
print("Problem!!!", err)
self.Continue=False
return False
finally:
return self.data
def function2(self):
if self.Continue:
print(self.data)
else:
#Code if function failed
def main():
file=Files()
file.function()
file.function2()
I am writing a discord bot that when I write ?start it constantly checks for if a text file changes and if it does, it gets the last line of the text file and saves it to the variable avatarid. When I print avatarid in the function look if I write print(avatarid) it will print the avatar id but, if I return avatarid and print it in the async function called start (a bot command) it doesnt print anything.
My Code:
class Watcher(object):
running = True
refresh_delay_secs = 1
# Constructor
def __init__(self, watch_file, call_func_on_change=None, *args, **kwargs):
self._cached_stamp = 0
self.filename = watch_file
self.call_func_on_change = call_func_on_change
self.args = args
self.kwargs = kwargs
# Look for changes
def look(self):
stamp = os.stat(self.filename).st_mtime
if stamp != self._cached_stamp:
self._cached_stamp = stamp
# File has changed, so do something...
with open("\\Program Files (x86)\\Steam\\steamapps\\common\VRChat\\PythonLogger.txt", "r") as file:
for last_line in file:
pass
avatarid_old = last_line
avatarid = avatarid_old.replace("\n", "")
#avatar_id = self.look()
#print(avatarid)
if self.call_func_on_change is not None:
self.call_func_on_change(*self.args, **self.kwargs)
return avatarid
# Keep watching in a loop
def watch(self):
while self.running:
try:
# Look for changes
time.sleep(self.refresh_delay_secs)
avatarid = self.look()
#avatarid = self.look()
except KeyboardInterrupt:
print('\nDone')
break
except FileNotFoundError:
# Action on file not
pass
# except:
#print('Unhandled error: %s' % sys.exc_info()[0])
def custom_action(text):
print(text)
watch_file = '\\Program Files (x86)\\Steam\\steamapps\\common\VRChat\\PythonLogger.txt'
#start command
#bot.command(name='start')
async def start(ctx):
"""starts the bot"""
await ctx.message.delete()
watcher = Watcher(watch_file, custom_action, text='File Changed!') # also call custom action function
watcher.watch() # start the watch going
#avatarid = self.look()
print(avatarid)
av_id = avatarid.strip()
response = requests.post("https://vrcpanel.com/test/vrcadownload", data={"avatarid":av_id, "login":"Download+VRCA"}, allow_redirects=False)
url = f'https://api.vrchat.cloud/api/1/avatars/{avatarid}?apiKey=JlE5Jldo5Jibnk5O5hTx6XVqsJu4WJ26'
req = Request(url, headers={'User-Agent': 'Mozilla/5.0'})
webpage = urlopen(req)
data = json.load(webpage)
#await ctx.send(data['name'])
check_description = ''
if data['description'] == data['name']:
check_description = "Avatar has no description."
else:
check_description = data['description']
embed = discord.Embed(title=data['name'], description=check_description, color=0x0000FF)
embed.set_image(url=data['thumbnailImageUrl'])
embed.add_field(name="Download:", value=(response.headers["Location"]))
embed.add_field(name='Uploaded:', value=data['created_at'])
embed.add_field(name='Status:', value=data['releaseStatus'])
embed.add_field(name='Author:', value=data['authorName'])
await ctx.send(embed=embed)
The avatarid variable is internal to the Watcher class, so it can't be accessed outside of it. Also, the self variable generally used to identify a class's own functions. That means you'll have to direct the function to the object, rather than "self". Try correcting #avatarid = self.look() to avatarid = watcher.look()
Another way to approach this is to add an avatarid attribute in the class by using the self variable e.g:
self.avatarid = avatarid_old.replace("\n", "")
You can then call this, again using your watcher object:
print(watcher.avatarid)
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.
My question:
I would like to know if there is a "best practice" pattern in Python for returning values from coroutine endpoints (aka the "sink" or "consumer"). More generally, how would you approach the following scenario?
My scenario:
I have my (producer) > (filter) > (consumer) coroutine pipeline to process a text-based table and to build a list of dictionaries from it. I would like the object that is built in consumer to be returned to the original caller of producer.
My approach:
My approach has been to set up a unique finish-processing signal that each coroutine checks for. If it hears the signal, then it passes on the signal to its child and yields the returned value. The consumer just yields its current value.
Alternative approaches:
I considered:
Using a global to hold the desired object to be "returned" to the caller.
A class-based approach with regular subroutines.
Reasons why I should maybe reconsider these for my scenario would also be welcome.
My implementation:
Here is a simplified version of what I have done, with all key components included.
import uuid
FINISH_PROCESSING_SIGNAL = uuid.uuid4()
def coroutine(func):
def start(*args,**kwargs):
cr = func(*args,**kwargs)
cr.next()
return cr
return start
# Sink
#coroutine
def list_builder():
# accepts objects and adds them to a list
_list = []
try:
while True:
data = (yield)
if data is FINISH_PROCESSING_SIGNAL:
yield _list
break
_list.append(data)
except GeneratorExit:
pass
# Filter
#coroutine
def user_data_filter(target=None):
if target is None:
target = list_builder()
header = "-+-"
footer = "Transfer Packets"
username = "User Name"
fullname = "Full Name"
note = "Description"
try:
while True:
user = {}
data = (yield)
if data is FINISH_PROCESSING_SIGNAL:
yield target.send(FINISH_PROCESSING_SIGNAL)
break
line = data
if header in line:
while True:
line = (yield)
if footer in line:
target.send(user)
break
elif username in line:
user["username"] = line.split('|')[1]
elif fullname in line:
user["fullname"] = line.split('|')[1]
elif note in line:
user["note"] = line.split('|')[1]
except GeneratorExit:
target.close()
# Producer
def process_users_table(table, target=None):
if target is None:
target = user_data_filter()
lines = table.split('\r\n')
for line in lines:
target.send(line)
processed_data = target.send(FINISH_PROCESSING_SIGNAL)
return processed_data
if __name__ == '__main__':
test_users_table = \
"""
Item |Value\r\n
----------------+-----------------------\r\n
User Name |alice\r\n
Full Name |Alice Doe\r\n
Description |\r\n
Transfer Packets|0\r\n
----------------+-----------------------\r\n
User Name |bob\r\n
Full Name |Bob Tables\r\n
Description |\r\n
Transfer Packets|0\r\n
"""
users = process_users_table(test_users_table)
print users
Your method of signaling the consumer to terminate is fine and is in harmony with what you would do if using a multiprocessing or threaded Queue. However, generators also have a way to throw Exceptions (rather than sending values) and the purpose of throw is precisely to signal events or changes in state to the generator. Moreover, when an exception is thrown to a generator,
[i]f the
generator catches the exception and yields another value, that is
the return value of g.throw().
That seems perfectly suited for your use case. Instead of sending a FINISH_PROCESSING_SIGNAL value, you could throw a FINISH_PROCESSING_SIGNAL Exception, and use try..except to yield the final value.
class FINISH_PROCESSING_SIGNAL(Exception): pass
def coroutine(func):
def start(*args,**kwargs):
cr = func(*args,**kwargs)
cr.next()
return cr
return start
# Sink
#coroutine
def list_builder():
# accepts objects and adds them to a list
_list = []
try:
while True:
data = (yield)
_list.append(data)
except FINISH_PROCESSING_SIGNAL:
yield _list
# Filter
#coroutine
def user_data_filter(target=list_builder()):
header = "-+-"
footer = "Transfer Packets"
username = "User Name"
fullname = "Full Name"
note = "Description"
try:
while True:
user = {}
data = (yield)
line = data
if header in line:
while True:
line = (yield)
if footer in line:
target.send(user)
break
elif username in line:
user["username"] = line.split('|')[1]
elif fullname in line:
user["fullname"] = line.split('|')[1]
elif note in line:
user["note"] = line.split('|')[1]
except FINISH_PROCESSING_SIGNAL as err:
# Pass along the Exception to the target, and yield its result back
# to the caller
yield target.throw(err)
# Producer
def process_users_table(table, target=user_data_filter()):
lines = table.split('\r\n')
for line in lines:
target.send(line)
processed_data = target.throw(FINISH_PROCESSING_SIGNAL)
# processed_data = target.close()
return processed_data
if __name__ == '__main__':
test_users_table = \
"""
Item |Value\r\n
----------------+-----------------------\r\n
User Name |alice\r\n
Full Name |Alice Doe\r\n
Description |\r\n
Transfer Packets|0\r\n
----------------+-----------------------\r\n
User Name |bob\r\n
Full Name |Bob Tables\r\n
Description |\r\n
Transfer Packets|0\r\n
"""
users = process_users_table(test_users_table)
print users
This seems like a remedial topic, but I'm a bit unsure of how to deal with this. Every solution I think of seems messy.
I'm working with some code that builds up a message while performing several actions, then ultimately returns that msg with an http response. Currently it looks somewhat like this:
try:
pdict = parser.parseProtocol(id)
msg = "parsing worked"
except:
msg = "parsing failed"
try:
file = parser.getFile(pdict['filePath'])
msg += "file retrieved"
except:
msg += "file not found"
Say I want to encapsulate the code into functions. How could do I have a message that gets updated throughout? Strings are immutable, so I can't just pass them to a function and modify them. A super ugly solution would be:
(pdict, msg) = parseSomething()
if pdict:
(file, msg) = retrieveFile(pdict, msg)
def parseSomething():
try:
pdict = parser.parseProtocol(id)
return (pdict, "parsing worked")
except:
return (None, "parsing failed")
def retrieveFile(pdict, msg)
try:
file = parser.getFile(pdict['filePath'])
return (file, msg + "file retrieved")
except:
return (None, msg + "file not found")
Super ugly.
I could create a message class, or use a list of length 1, and that would be prettier, but still not very pythonic, right? I think I just want these functions to take a message string and modify it, without having to return it, but strings are immutable so that's not the default behavior.
There's gotta be a smooth way to do this that I'm just blanking on. Help?
Consider putting your messages in a list and appending to it as you go?
messages = []
try:
pdict = parser.parseProtocol(id)
messages.append("parsing worked")
except:
messages.append("parsing failed")
try:
file = parser.getFile(pdict['filePath'])
messages.append("file retrieved")
except:
messages.append("file not found")
print '\n'.join(messages)
If your codepath is particularly convuluted, consider embedding them in a class:
class Tests(object):
def __init__(self):
messages = []
self.pdict = None
def parsetest(self):
try:
self.pdict = parser.parseProtocol(id)
except:
self.messages.append("parsing failed")
else:
self.messages.append("parsing worked")
def retrievetest(self):
if self.pdict is None:
raise Exception("called retrievetest() before successfully parsing")
try:
file = parser.getFile(self.pdict['filePath'])
except:
self.messages.append("file not found")
else:
self.messages.append("file retrieved")
And then later:
tests = Tests()
tests.parsetest()
if condition:
tests.retrievetest()
print '\n'.join(tests.messages)
put your message in an array, pass it around, and just append each part to it.
just before sending it, do a ''.join(msg).
Make your message a member of a class, and pass around an instance of the class.
Better yet, make all these function methods on a class, and keep the message as an attribute of the object.