I have a script, main.py, that runs a few functions from other scripts in the directory. I had the very unoriginal idea to send myself Slack notifications if specific functions ran correctly or failed, i.e. error handling. How would I use an error handling function located in a separate script - call the file slack_notifications.py - in my main.py script? This linked question starts to get at the answer, but it doesn't get to the calling the error function from somewhere else.
main.py script:
import scraper_file
import slack_notifications
# picture scrape variable
scrape_object = 'Barack Obama'
# scraper function called
scraped_image = scraper_file.pic_scrape(scrape_object)
# error handling?
slack_notifications.scrape_status(scrape_object)
I have tried embedding the called scraper function into the scrape_status() function, like this: scraped_image = (slack_notifications.scrape_status(scraper_file.pic_scrape(scrape_object))) and a few other ways, but that doesn't really tell you if it ran successfully, right?
slack_notifications.py script:
testing = "dunderhead"
def scrape_status(x):
# if this function gets a positive return from the scrape function
# if this function gets any error from the scrape function
try:
x
print(x + ' worked!')
except:
print(x + ' failed!')
if __name__ == '__main__':
scrape_status(testing)
Is there a way to do this? I have been going off these instructions, too.
Code in your first link works because function input() was moved from outside error_handler() into inside error_handler() and it is executed inside `try/except.
Your code always runs function outside error handler scrape_status() and it sends only result from executed function - so it never runs it inside try/except.
You would have to send separatelly function's name (without () and arguments) and separatelly arguments - and then it can run it inside try/except
def scrape_status(function, *args):
try:
function(*args)
print(function.__name__ + ' worked!')
except:
print(function.__name__ + ' failed!')
But it means you have to send function as
scrape_status(scraper_file.pic_scrape, scrape_object)
instead of
scrape_status( scraper_file.pic_scrape(scrape_object) )
and this is not readable - so I don't know if it is good idea to create universal error handler.
Minimal working example
def scrape_status(function, *args, **kwargs):
try:
result = function(*args, **kwargs) # some functions may return result
print(function.__name__ + ' worked!')
return result
except:
print(function.__name__ + ' failed!')
# ----
# this function needs `arg1, arg2` to work correctly
def testing(arg1, arg2):
print(arg1, arg2)
# --- main ---
print('--- test 1 ---')
# send funciton's name `testing` and argument(s) `'hello', 'world'`
scrape_status(testing, 'hello', 'world') # OK
print('--- test 2 ---')
# send funciton's name `testing` without argument(s)
scrape_status(testing) # ERROR
Result:
--- test 1 ---
hello world
testing worked!
--- test 2 ---
testing failed!
EDIT:
I created new example using decorator based on answers in question General decorator to wrap try except in python?. Now code use readableand it needs to use decorator #scrape_status('') only when function is defined
#scrape_status('')
def testing(arg1, arg2):
print(arg1, arg2)
Minimal working code:
def scrape_status():
def decorate(function):
def applicator(*args, **kwargs):
try:
result = function(*args, **kwargs)
print(function.__name__ + ' worked!')
return result
except:
print(function.__name__ + ' failed!')
return applicator
return decorate
# ----
# this function needs `arg1, arg2` to work correctly
#scrape_status()
def testing(arg1, arg2):
print(arg1, arg2)
# --- main ---
print('--- test 1 ---')
# send function's name `testing` and argument(s) `'hello', 'world'`
testing('hello', 'world') # OK
print('--- test 2 ---')
# send function's name `testing` without argument(s)
testing() # ERROR
As I remeber there could be some module(s) with more complex decorators - ie. one decorator could repeate function 3 times if it was raising error. It could be uses to repeate question in input() if answer was wrong, or repeate downloading file if there was problem to download it.
Related
say I have a test file with the following content:
def a():
print('this is a')
def b(x):
print(x)
and also a main file:
import test
def try_cmd(cmd, params):
try:
getattr(functions, cmd)(params)
except Exception as error:
print(error)
while True:
cmd = input('Enter cmd')
params = input('Enter params')
do_command(cmd, params)
The purpose of the code should be to try to call a function from a different file, with the user giving the function name and if needed params for it to take.
What happens is if the value of cmd is 'a' and parmas is a random string do_command will not work because function a doesn't take params. However if cmd will be 'b' and params will be say '5' it will work. How do I get around that without forcing a to take params and not actually using it.
As in my comment on your question, you should write your functions to accept *args and **kwargs, but if you insist on not using this convention, try this:
def try_cmd(cmd, params):
func = getattr(functions, cmd)
try:
func(params)
except TypeError:
func()
except Exception as error:
print(error)
In my opinion, accepting *args and **kwargs is the better practice compared to using exception handling to manage branching.
If you're already importing your "test" file, you can look at locals() and globals(), for example:
getattr(locals()['test'],'a')()
When i run a simple app (producer / consumer) - all is working. aka connecting to rabbitmq, consuming msgs etc.
when I run the below code inside a class (in order not to block the flask app) --> the callback not being called.
I added some prints and it seems that all is fine during the connection initialization.
The msgs are consumed (the queue is is being clean) --> but the callback is not even being called.
Any idea ?
TIA
here is the code:
currentprices = ({"1":5.5, "2":3.5})
def initialparams(): #being called from outside
print('S-init')
RMQ = RMQPriceListener()
RMQ.create_currentprices_channel()
print('F-init')
class RMQPriceListener():
def create_currentprices_channel(self):
try:
credential_params = pika.PlainCredentials('un', 'pw')
connection_params = pika.ConnectionParameters(
host='127.0.0.1',port=5555,
credentials=credential_params) # i use port 5555
connection = pika.BlockingConnection(connection_params)
channel = connection.channel()
channel.queue_declare(queue='formatedrates')
print('c0') # being printed
channel.basic_consume(queue='formatedrates',
on_message_callback=self.callback,
auto_ack=True) # without this (above) self - the app
# is stuck here (which is logical)
print('c1') # being printed
channel.start_consuming() # working good and cleaning the queue
return ('lost connection to RMQ')
except:
return ('No connection to RMQ')
** the problematic func that works good on regular app but here inside the class not**
def callback(ch, method, properties,msg):
print(f'msg={msg}') # never printed
global currentprices # has an initial value and being call from the below
getcurrentrates method and never change its value
currentprices = msg # never being updated
print(currentprices) # never printed
def getcurrentrates():
print('get' + str(currentprices)) # printed
print(type(currentprices)) # printed - ' dict '
return currentprices # returned with initial value
Since you define the on_message_callback=self.callback, you have to define the callback function as a class method with self as first function parameter as below
def callback(self, ch, method, properties, msg):
....
I have some blocks of code which need to be wrapped by function.
try:
if config.DEVELOPMENT == True:
# do_some_stuff
except:
logger.info("Config is not set for development")
Then I'll do again:
try:
if config.DEVELOPMENT == True:
# do_some_another_stuff
except:
logger.info("Config is not set for development")
So, how can I wrap this "do_some_stuff" and "do_some_another_stuff"?
I'm trying to write function with contextmanager:
#contextmanager
def try_dev_config(name):
try:
if name is not None:
yield
except Exception as e:
print "not dev config"
with try_dev_config("config.DEVELOPMENT"):
# do_some_stuff
And I got an error:
RuntimeError: generator didn't yield
You could pass in a function.
boolean = True
def pass_this_in():
print("I just did some stuff")
def the_try_except_bit(function):
try:
if boolean:
function()
except:
print("Excepted")
# Calling the above code
the_try_except_bit(pass_this_in)
If you want to reduce the "pass_this_in" definition bit, then you can use lambda function definitions:
pass_this_in = lambda : print("I just did some stuff")
I am not sure that a context manager is the good method to achieve what you want. The context manager goal is to provide a mecanism to open/instantiate a resource, give access to it (or not) and close/clean it automatically when you no more need it.
IMHO, what you need is a decorator.
A decorator aims at executing code around a function call. It would force you to put each block of code in a function but I don't think it is so difficult. You can implement it like this:
class Config(object):
"""for demonstration purpose only: used to have a config.DEVELOPMENT value"""
DEVELOPMENT = True
class Logger(object):
"""for demonstration purpose only: used to have a logger.info method"""
#staticmethod
def info(msg):
print("Logged: {}".format(msg))
def check_dev_config(config, logger):
def dev_config_checker(func):
def wrapper(*args, **kwargs):
try:
if config.DEVELOPMENT:
func(*args, **kwargs)
except Exception as err:
logger.info(
"Config is not set for developpement: {}".format(err))
return wrapper
return dev_config_checker
#check_dev_config(Config, Logger)
def do_stuff_1():
print("stuff 1 done")
#check_dev_config(Config, Logger)
def do_stuff_2():
raise Exception("stuff 2 failed")
do_stuff_1()
do_stuff_2()
This code prints
stuff 1 done
Logged: Config is not set for developpement: stuff 2 failed
Explanations:
The check_dev_config function is actually a decorator generator which accepts the config and the logger as arguments.
It returns the dev_config_checker function which is an actual (and parameterised) decorator, and which accepts a function to decorate as argument.
This decorator returns a wrapper function which will actually run code around the decorated function call. In this function, the decorated function is called inside a try/except structure and only if the config.DEVELOPMENT is evaluated to True. In case of exception, the logger is used to log an information.
Each block of code to decorate is put into a function (do_stuff_1, do_stuff_2 and decorated with the check_dev_config decorator generator, giving it the config and the logger.
When decorated functions are called, they are called via their decorator and not directly. As you can see, the do_stuff_2 exception has been catched and the a message has been logged.
I have a scenario where I'm dynamically running functions at run-time and need to keep track of a "localized" scope. In the example below, "startScope" and "endScope" would actually be creating levels of "nesting" (in reality, the stuff contained in this localized scope isn't print statements...it's function calls that send data elsewhere and the nesting is tracked there. startScope / endScope just set control flags that are used to start / end the current nesting depth).
This all works fine for tracking the nested data, however, exceptions are another matter. Ideally, an exception would result in "falling out" of the current localized scope and not end the entire function (myFunction in the example below).
def startScope():
#Increment our control object's (not included in this example) nesting depth
control.incrementNestingDepth()
def endScope():
#Decrement our control object's (not included in this example) nesting depth
control.decrementNestingDepth()
def myFunction():
print "A"
print "B"
startScope()
print "C"
raise Exception
print "D"
print "This print statement and the previous one won't get printed"
endScope()
print "E"
def main():
try:
myFunction()
except:
print "Error!"
Running this would (theoretically) output the following:
>>> main()
A
B
C
Error!
E
>>>
I'm quite certain this isn't possible as I've written it above - I just wanted to paint a picture of the sort of end-result I'm trying to achieve.
Is something like this possible in Python?
Edit: A more relevant (albeit lengthy) example of how this is actually being used:
class Log(object):
"""
Log class
"""
def __init__(self):
#DataModel is defined elsewhere and contains a bunch of data structures / handles nested data / etc...
self.model = DataModel()
def Warning(self, text):
self.model.put("warning", text)
def ToDo(self, text):
self.model.put("todo", text)
def Info(self, text):
self.model.put("info", text)
def StartAdvanced(self):
self.model.put("startadvanced")
def EndAdvanced(self):
self.model.put("endadvanced")
def AddDataPoint(self, data):
self.model.put("data", data)
def StartTest(self):
self.model.put("starttest")
def EndTest(self):
self.model.put("endtest")
def Error(self, text):
self.model.put("error", text)
#myScript.py
from Logger import Log
def test_alpha():
"""
Crazy contrived example
In this example, there are 2 levels of nesting...everything up to StartAdvanced(),
and after EndAdvanced() is included in the top level...everything between the two is
contained in a separate level.
"""
Log.Warning("Better be careful here!")
Log.AddDataPoint(fancyMath()[0])
data = getSerialData()
if data:
Log.Info("Got data, let's continue with an advanced test...")
Log.StartAdvanced()
#NOTE: If something breaks in one of the following methods, then GOTO (***)
operateOnData(data)
doSomethingCrazy(data)
Log.ToDo("Fill in some more stuff here later...")
Log.AddDataPoint(data)
Log.EndAdvanced()
#(***) Ideally, we would resume here if an exception is raised in the above localized scope
Log.Info("All done! Log some data and wrap everything up!")
Log.AddDataPoint({"data": "blah"})
#Done
#framework.py
import inspect
from Logger import Log
class Framework(object):
def __init__(self):
print "Framework init!"
self.tests = []
def loadTests(self, file):
"""
Simplifying this for the sake of clarity
"""
for test in file:
self.tests.append(test)
def runTests(self):
"""
Simplifying this for the sake of clarity
"""
#test_alpha() as well as any other user tests will be run here
for test in self.tests:
Log.StartTest()
try:
test()
except Exception,e :
Log.Error(str(e))
Log.EndTest()
#End
You can achieve a similar effect with a context manager using a with statement. Here I use the contextlib.contextmanager decorator:
#contextlib.contextmanager
def swallower():
try:
yield
except ZeroDivisionError:
print("We stopped zero division error")
def foo():
print("This error will be trapped")
with swallower():
print("Here comes error")
1/0
print("This will never be reached")
print("Merrily on our way")
with swallower():
print("This error will propagate")
nonexistentName
print("This won't be reached")
>>> foo()
This error will be trapped
Here comes error
We stopped zero division error
Merrily on our way
This error will propagate
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
foo()
File "<pyshell#3>", line 10, in foo
nonexistentName
NameError: global name 'nonexistentName' is not defined
It cannot be done with an ordinary function call as in your example. In your example, the function startScope returns before the rest of the body of myFunction executes, so startScope can't have any effect on it. To handle exceptions, you need some kind of explicit structure (either a with statement or a regular try/except) inside myFunction; there's no way to make a simple function call magically intercept exceptions that are raised in its caller.
You should read up on context managers as they seem to fit what you're trying to do. The __enter__ and __exit__ methods of the context manager would correspond to your startScope and endScope. Whether it will do exactly what you want depends on exactly what you want those "manager" functions to do, but you will probably have more luck doing it with a context manager than trying to do it with simple function calls.
I have the following program statement (program1.py)
I have a program 1:
try:
except:
I have another program 2 (program2.py):
def something:
print hello
is there a way when program 1 is imported into program 2 , that program 1 wraps around program 2, so the program should be
try:
def something:
print hello # all program 2 components
except:
I am confused on how to do this and any pointers would be appreciated
The way I would suggest going about this is with a decorator:
def tryit(fn):
def wraps(*args, **kwargs):
try:
fn(*args, **kwargs)
except Exception, e:
print e
return wraps
def doStuff(x, y):
return x / y
#tryit
def main(arg1, arg2):
print doStuff(arg1, arg2)
if __name__ == "__main__":
main(1, 10.0)
main(100, 0)
OUTPUT
0.1
integer division or modulo by zero
Your logic might need to be reworked, but I think it would be worth it in the end.
In program1.py, you need to call the something function. Thereby, it would wrap the new function (by function call) into try-except block. I suggest, you understand inter-module program flow handling from basic information on net. You must not view it as simple parse but as a function call.
HTH.
Below links will help you to understand.
Modules in python and integration.
Similar stackoverflow question.
You could use a import
program1.py:
from program2 import something
try:
something()
exception:
# Some more code
program2.py:
def something:
print 'Hello, World!'
program2.py:
from contextlib import contextmanager
#contextmanager
def tryer():
try:
yield # code within with statement runs here
except:
print "Failed!
program1.py:
from program2 import tryer
with tryer():
print 'Hello, World!'