Skip to content

Commit 58b95c8

Browse files
author
Arjan
committed
Updated error handling example
1 parent b421854 commit 58b95c8

18 files changed

+320
-48
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import logging
2+
from functools import wraps
3+
4+
# Example from: https://www.geeksforgeeks.org/create-an-exception-logging-decorator-in-python/
5+
6+
def create_logger():
7+
8+
# create a logger object
9+
logger = logging.getLogger('exc_logger')
10+
logger.setLevel(logging.INFO)
11+
12+
#c reate a file to store all the
13+
# logged exceptions
14+
logfile = logging.FileHandler('exc_logger.log')
15+
16+
fmt = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
17+
formatter = logging.Formatter(fmt)
18+
19+
logfile.setFormatter(formatter)
20+
logger.addHandler(logfile)
21+
22+
return logger
23+
24+
logger = create_logger()
25+
26+
# you will find a log file
27+
# created in a given path
28+
print(logger)
29+
30+
def exception(logger):
31+
def decorator(func):
32+
@wraps(func)
33+
def wrapper(*args, **kwargs):
34+
try:
35+
return func(*args, **kwargs)
36+
except:
37+
issue = "exception in "+func.__name__+"\n"
38+
issue = issue+"=============\n"
39+
logger.exception(issue)
40+
raise
41+
return wrapper
42+
return decorator
43+
44+
45+
@exception(logger)
46+
def divideByZero():
47+
return 12/0
48+
49+
# Driver Code
50+
if __name__ == '__main__':
51+
divideByZero()
52+
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import time
2+
import math
3+
from functools import wraps
4+
5+
def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
6+
"""Retry calling the decorated function using an exponential backoff.
7+
8+
http://www.saltycrane.com/blog/2009/11/trying-out-retry-decorator-python/
9+
original from: http://wiki.python.org/moin/PythonDecoratorLibrary#Retry
10+
11+
:param ExceptionToCheck: the exception to check. may be a tuple of
12+
exceptions to check
13+
:type ExceptionToCheck: Exception or tuple
14+
:param tries: number of times to try (not retry) before giving up
15+
:type tries: int
16+
:param delay: initial delay between retries in seconds
17+
:type delay: int
18+
:param backoff: backoff multiplier e.g. value of 2 will double the delay
19+
each retry
20+
:type backoff: int
21+
:param logger: logger to use. If None, print
22+
:type logger: logging.Logger instance
23+
"""
24+
def deco_retry(f):
25+
26+
@wraps(f)
27+
def f_retry(*args, **kwargs):
28+
mtries, mdelay = tries, delay
29+
while mtries > 1:
30+
try:
31+
return f(*args, **kwargs)
32+
except ExceptionToCheck as e:
33+
msg = "%s, Retrying in %d seconds..." % (str(e), mdelay)
34+
if logger:
35+
logger.warning(msg)
36+
else:
37+
print(msg)
38+
time.sleep(mdelay)
39+
mtries -= 1
40+
mdelay *= backoff
41+
return f(*args, **kwargs)
42+
43+
return f_retry # true decorator
44+
45+
return deco_retry
46+
47+
@retry(Exception, tries=4)
48+
def test_fail(text):
49+
raise Exception("Fail")
50+
51+
test_fail("it works!")
Binary file not shown.
Binary file not shown.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import sqlite3
2+
3+
class SQLite():
4+
def __init__(self, file='application.db'):
5+
self.file=file
6+
def __enter__(self):
7+
self.conn = sqlite3.connect(self.file)
8+
return self.conn.cursor()
9+
def __exit__(self, type, value, traceback):
10+
print("Closing the connection")
11+
self.conn.close()
12+
13+
class NotFoundError(Exception):
14+
pass
15+
16+
class NotAuthorizedError(Exception):
17+
pass
18+
19+
def blog_lst_to_json(item):
20+
return {
21+
'id': item[0],
22+
'published': item[1],
23+
'title': item[2],
24+
'content': item[3],
25+
'public': bool(item[4])
26+
}
27+
28+
def fetch_blogs():
29+
try:
30+
with SQLite('application.db') as cur:
31+
32+
# execute the query
33+
cur.execute('SELECT * FROM blogs where public=1')
34+
35+
# fetch the data and turn into a dict
36+
return list(map(blog_lst_to_json, cur.fetchall()))
37+
except Exception as e:
38+
print(e)
39+
return []
40+
41+
def fetch_blog(id: str):
42+
try:
43+
with SQLite('application.db') as cur:
44+
45+
# execute the query and fetch the data
46+
cur.execute(f"SELECT * FROM blogs where id='{id}'")
47+
result = cur.fetchone()
48+
49+
# return the result or raise an error
50+
if result is None:
51+
raise NotFoundError(f'Unable to find blog with id {id}.')
52+
53+
data = blog_lst_to_json(result)
54+
if not data['public']:
55+
raise NotAuthorizedError(f'You are not allowed to access blog with id {id}.')
56+
return data
57+
except sqlite3.OperationalError:
58+
raise NotFoundError(f'Unable to find blog with id {id}.')
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import sqlite3
2+
3+
class SQLite():
4+
def __init__(self, file='application.db'):
5+
self.file=file
6+
def __enter__(self):
7+
self.conn = sqlite3.connect(self.file)
8+
return self.conn.cursor()
9+
def __exit__(self, type, value, traceback):
10+
self.conn.close()

8 - dealing with errors/error-handling.py renamed to 8 - dealing with errors/after-context/error-handling.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from flask import Flask, jsonify, abort
2-
import sqlite3
3-
from db import fetch_blogs, fetch_blog, NotFoundError
2+
from db import fetch_blogs, fetch_blog, NotFoundError, NotAuthorizedError
43

54
app = Flask(__name__)
65

@@ -18,3 +17,5 @@ def get_blog(id):
1817
return jsonify(fetch_blog(id))
1918
except NotFoundError:
2019
abort(404, description="Resource not found")
20+
except NotAuthorizedError:
21+
abort(403, description="Access denied")
12 KB
Binary file not shown.

0 commit comments

Comments
 (0)