0

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.

papelr
  • 468
  • 1
  • 11
  • 42
  • your `scrape_status` seems totally useless. It will run `try/except` too late - after error hapends - so it can't catch it. You would have to rather send function's name (without `()` ) into `scrape_status` and use it with `()` to execute it inside `try/except` - and then it can catch it. OR simply you have to run `scraper_file.pic_scrape(scrape_object)` inside `try/except` and it would be simpler if you use `try/except` directly inside `scraper_file.pic_scrape(scrape_object)` instead of creating universal function `scrape_Status()` for `this` – furas Apr 01 '21 at 18:02
  • code in yoiur first works because function `input()` was moved from outside `error_handler` into inside `error_handler` and you would have to do the same with `scraper_file.pic_scrape(scrape_object)` - you have to move it into `scrape_status` but you can't do this using `scraper_file.pic_scrape(scrape_object)` because it runs it outside `scrape_status`. All your idea is overcomplicated. Better put all code in one file and don't try to create universal function `scrape_status` – furas Apr 01 '21 at 18:06

1 Answers1

1

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.

furas
  • 134,197
  • 12
  • 106
  • 148
  • Gotcha - I agree, does look totally useless. Will try this out after work! – papelr Apr 01 '21 at 18:30
  • maybe it could be more readable with some decorator like in answers for [General decorator to wrap try except in python?](https://stackoverflow.com/questions/15572288/general-decorator-to-wrap-try-except-in-python). Or maybe there is module for this – furas Apr 01 '21 at 18:36
  • I created code using decorator from question ` General decorator to wrap try except in python?.` and now code is nice and readable. – furas Apr 01 '21 at 18:49