-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* New python lesson, how to handle exceptions. Code + tests * Add exceptions docs * Add logging lesson
- Loading branch information
Showing
16 changed files
with
571 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,5 +7,6 @@ defaultdict | |
getsizeof | ||
kwargs | ||
levelname | ||
loguru | ||
repr | ||
timeit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Exceptions | ||
|
||
Exceptions are a mechanism for handling errors in Python (and most programming | ||
language). When an error occurs when running your code, Python raises an | ||
exception. There are multiple types of exceptions. Each exception has a name and | ||
a message. | ||
|
||
If the exception is not caught, the program will terminate immediately, raising | ||
the corresponding exception. | ||
|
||
::: src.intermediate.exceptions.exception_uncontrolled | ||
|
||
## Controlling exceptions | ||
|
||
Exceptions can be caught and handled using a `try` block. You can catch the | ||
exception, do something (like logging), and continue running the program. | ||
|
||
::: src.intermediate.exceptions.exception_controlled | ||
|
||
You can catch the exception, logging and raise the same exception to terminate | ||
the execution. | ||
|
||
::: src.intermediate.exceptions.exception_controlled_raise_exception | ||
|
||
Similar way, ou can catch the exception, logging and raise another type of | ||
exception. You can terminate the execution of a running program by raising an | ||
exception at any time. | ||
|
||
::: src.intermediate.exceptions.exception_controlled_raise_custom_exception | ||
|
||
With the finally block, you can run code that will always run, regardless if the | ||
code in the try block raises an exception. It will be always executed. | ||
|
||
::: src.intermediate.exceptions.exception_controlled_raise_custom_exception | ||
|
||
## References | ||
|
||
- [Concrete exceptions](https://docs.python.org/3/library/exceptions.html#concrete-exceptions) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Logging | ||
|
||
Logging is a very important part of any application. It allows you to track the | ||
code execution and to debug the application. Python has a built-in logging | ||
module that allows you to log messages to the console, to a file, or to a remote | ||
server. In contrast to the `print` function, the logging module is more | ||
complete, allowing you to configure the log level, the log format, and the log | ||
destination. | ||
|
||
Logging is based in handlers. A handler is an object that receives the log | ||
messages and decides what to do with them. The logging module has several | ||
built-in handlers, such as `StreamHandler`, `FileHandler`, `RotatingFileHandler` | ||
or `TimedRotatingFileHandler`. But you can create your own handler by inherit | ||
the `Handler` class. [Notifiers](https://github.com/liiight/notifiers) is a 3pp | ||
library that provides with extra handlers with the ability to send notifications | ||
to different services. | ||
|
||
## Best practices | ||
|
||
- Set different log levels for different environments. For example, you may set | ||
`DEBUG` level in development and `ERROR` level in production. | ||
- Set a specific format for the log messages, including the timestamp or the log | ||
level. Using a standard format makes it easier to read the log messages. Use | ||
the `extra` parameter to pass the data to the log message. | ||
- Use pipelines `|` to separate the different parts of the log message. It can be | ||
useful to filter the log messages, or even to parse them. | ||
- To include variables in your log message, don't use `format` or `f-string` in | ||
the log call, instead use the `%s`, like `logger.info('Variable: %s', value)`. | ||
- Use `logging.exception` to log an exception message and the stack trace. | ||
- Set the different logger instance you are going to use with | ||
`logging.getLogger`. This way you can configure the logger in one place and | ||
use it in different modules. | ||
|
||
## logging library | ||
|
||
This is the built-in Python logging library. It is very flexible and allows you | ||
to configure the log level, the log format, and the log destination. | ||
|
||
Each logger has a name, and the loggers are organized in a tree-like structure. | ||
The root logger is the top-level logger, and all other loggers are children of | ||
the root logger. | ||
|
||
::: src.intermediate.logging.default_logging | ||
|
||
::: src.intermediate.logging.custom_logging_format | ||
|
||
## loguru library | ||
|
||
Loguru is a third-party library that simplifies the logging configuration to the | ||
bare minimum, such as log level and log format. But you can also can configure | ||
much more easily, such as: | ||
|
||
- color customization. | ||
- log rotation, retention and compression. | ||
- custom log levels. | ||
- lazy evaluation of log messages. | ||
|
||
:::src.intermediate.logging.default_loguru | ||
|
||
::: src.intermediate.logging.custom_loguru_format_and_level | ||
|
||
## References | ||
|
||
- [Python logging module](https://docs.python.org/3/library/logging.html) | ||
- [Loguru repository](https://github.com/Delgan/loguru) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
"""Module to show how to handle exceptions. | ||
This module contains different methods to handle exceptions. | ||
""" | ||
|
||
from .custom_exceptions import CustomError # noqa: F401 | ||
from .exceptions import ( | ||
exception_controlled, # noqa: F401 | ||
exception_controlled_raise_custom_exception, # noqa: F401 | ||
exception_controlled_raise_exception, # noqa: F401 | ||
exception_uncontrolled, # noqa: F401 | ||
exception_with_finally, # noqa: F401 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
"""Module with a sample CustomError class. | ||
This class is just an example of a CustomError class. | ||
""" | ||
|
||
|
||
class CustomError(Exception): | ||
"""Custom error class.""" | ||
|
||
message = str | ||
exception = Exception | ||
|
||
def __init__(self, **kwargs): | ||
"""Init CustomError exception.""" | ||
self.message = kwargs["message"] | ||
self.exception = kwargs["exception"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
"""Module to show how to handle exceptions. | ||
This module contains different methods to handle exceptions. | ||
""" | ||
|
||
import logging | ||
|
||
from .custom_exceptions import CustomError | ||
|
||
logging.basicConfig(name=__name__, format="%(message)s", level=logging.DEBUG) | ||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def exception_uncontrolled() -> None: | ||
"""Method that raises an exception that is not handled correctly. | ||
Raises: | ||
TypeError: cannot sum int&string types | ||
""" | ||
number = 1 | ||
char = "a" | ||
number + char # raise TypeError, cannot sum int&string types | ||
|
||
|
||
def exception_controlled() -> None: | ||
"""Method that control the exception, no raise.""" | ||
number = 1 | ||
char = "a" | ||
try: | ||
number + char # raise TypeError, cannot sum int&string types | ||
except TypeError: | ||
logger.warning("Cannot sum int + string. Continue.") | ||
pass | ||
|
||
|
||
def exception_controlled_raise_exception() -> None: | ||
"""Method that control the exception, raising the same exception. | ||
Raises: | ||
TypeError: cannot sum int&string types | ||
""" | ||
number = 1 | ||
char = "a" | ||
try: | ||
number + char # raise TypeError, cannot sum int&string types | ||
except TypeError as exc: | ||
logger.error("Cannot sum int + string. Raising TypeError.") | ||
raise exc | ||
|
||
|
||
def exception_controlled_raise_custom_exception() -> None: | ||
"""Method that control the exception, raising custom exception. | ||
Raises: | ||
TypeError: cannot sum int&string types | ||
""" | ||
number = 1 | ||
char = "a" | ||
try: | ||
number + char # raise TypeError, cannot sum int&string types | ||
except TypeError as exc: | ||
logger.error("Cannot sum int + string. Raising CustomError.") | ||
raise CustomError( | ||
message="Controlled TypeError", | ||
exception=exc, | ||
) | ||
|
||
|
||
def exception_with_finally(raise_exception: bool) -> None: | ||
"""Method that control the exception, raising custom exception. | ||
Arguments: | ||
raise_exception (bool): flag to raise exception or not | ||
Raises: | ||
TypeError: cannot sum int&string types | ||
""" | ||
number = 1 | ||
char = "a" | ||
try: | ||
if raise_exception: | ||
number + char # raise TypeError, cannot sum int&string types | ||
else: | ||
number + 10 | ||
except TypeError as exc: | ||
logger.error("Cannot sum int + string. Raising TypeError.") | ||
raise exc | ||
finally: | ||
logger.debug("Finally is executed.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
"""Module to show the use of logging libraries. | ||
This module contains different logging libraries, how to initialize, configure | ||
and use. | ||
""" | ||
|
||
from .logging import ( | ||
custom_logging_format, # noqa: F401 | ||
custom_loguru_format_and_level, # noqa: F401 | ||
default_logging, # noqa: F401 | ||
default_loguru, # noqa: F401 | ||
) |
Oops, something went wrong.