Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.0.9 #9

Merged
merged 34 commits into from
Mar 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
bf8e612
now you can pass an exceptions list before the list
pomponchik Mar 1, 2024
f2bd325
ellipsis support
pomponchik Mar 1, 2024
4600fd3
no extra fs for strings in the tests
pomponchik Mar 1, 2024
9a556a9
run ruff in CI
pomponchik Mar 1, 2024
345966e
+1 test
pomponchik Mar 2, 2024
f12a801
parametrize
pomponchik Mar 2, 2024
074c222
more tests
pomponchik Mar 2, 2024
5bb4341
more tests
pomponchik Mar 2, 2024
2208986
mypy ignore comment
pomponchik Mar 2, 2024
f62ded0
mypy ignore comment
pomponchik Mar 2, 2024
0bb5b05
rename exception
pomponchik Mar 2, 2024
5ad0168
move the tests to an own directory
pomponchik Mar 2, 2024
de1fc9e
import fix
pomponchik Mar 2, 2024
1a96212
+1 classifier
pomponchik Mar 2, 2024
cf44b31
run mypy for tests in the CI
pomponchik Mar 2, 2024
8677533
job name
pomponchik Mar 2, 2024
749ce22
type hints
pomponchik Mar 2, 2024
068bad3
readme
pomponchik Mar 2, 2024
e2d54b4
readme
pomponchik Mar 2, 2024
2c12b43
readme
pomponchik Mar 2, 2024
cfdfa06
readme
pomponchik Mar 2, 2024
7b0547b
no extra import
pomponchik Mar 2, 2024
758d88e
fix test
pomponchik Mar 2, 2024
acabdb1
readme
pomponchik Mar 2, 2024
2bc1652
new tests
pomponchik Mar 2, 2024
18f938b
new version tag
pomponchik Mar 2, 2024
b58cfae
pragma comments
pomponchik Mar 2, 2024
4664627
no extra imports
pomponchik Mar 2, 2024
6a35fb3
logos
pomponchik Mar 2, 2024
be3dbcf
logos
pomponchik Mar 2, 2024
9fb0e9b
logos
pomponchik Mar 2, 2024
b611fb1
logos
pomponchik Mar 2, 2024
d60e859
logos
pomponchik Mar 2, 2024
9828774
logos
pomponchik Mar 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ jobs:
shell: bash
run: mypy escape --strict

- name: Run mypy for tests
shell: bash
run: mypy tests

- name: Run ruff
shell: bash
run: ruff escape

- name: Run ruff for tests
shell: bash
run: ruff tests
98 changes: 53 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# exception_escaping
![logo](https://raw.githubusercontent.com/pomponchik/exception_escaping/develop/docs/assets/logo_9.svg)

[![Downloads](https://static.pepy.tech/badge/exception_escaping/month)](https://pepy.tech/project/exception_escaping)
[![Downloads](https://static.pepy.tech/badge/exception_escaping)](https://pepy.tech/project/exception_escaping)
Expand All @@ -20,7 +20,6 @@ If you've just confessed and you can't wait to sin again, try this package. It w
- [**Quick start**](#quick-start)
- [**Decorator mode**](#decorator-mode)
- [**Context manager mode**](#context-manager-mode)
- [**Which exceptions are escaped?**](#which-exceptions-are-escaped)
- [**Logging**](#logging)


Expand Down Expand Up @@ -49,92 +48,101 @@ Read about other library features below.

## Decorator mode

You can hang the `escape` decorator on any function, including a coroutine one. Exceptions that occur internally will be suppressed.

An example with a regular function:
The `@escape` decorator suppresses exceptions in a wrapped function (including a coroutine one), which are passed in parentheses. In this way, you can pass any number of exceptions, for example:

```python
@escape
import asyncio
import escape

@escape(ValueError, ZeroDivisionError)
def function():
raise ValueError
```
raise ValueError('oh!')

And with coroutine one:
@escape(ValueError, ZeroDivisionError)
async def async_function():
raise ZeroDivisionError('oh!')

```python
@escape
async def coroutine_function():
raise ValueError
function() # Silence.
asyncio.run(async_function()) # Silence.
```

The decorator will work both with and without brackets:
If you use `@escape` with parentheses but do not pass any exception types, no exceptions will be suppressed:

```python
@escape() # This will work too.
@escape()
def function():
...
raise ValueError('oh!')

function()
# > ValueError: oh!
```

If an exception occurred inside the function wrapped by the decorator, it will return the default value - `None`. You can specify your own default value:

```python
@escape(default='some value')
@escape(ValueError, default='some value')
def function():
raise ValueError

assert function() == 'some value' # It's going to work.
```

Finally, you can use `@escape` as a decorator without parentheses.

## Context manager mode
```python
@escape
def function():
raise ValueError

You can use `escape` as a context manager. It works almost the same way as [`contextlib.suppress`](https://docs.python.org/3/library/contextlib.html#contextlib.suppress) from the standard library. However, in this case, you can choose whether to use the context manager with or without brackets:
function() # Silence still.
```

```python
# Both options work the same way.
In this mode, not all exceptions from the [hierarchy](https://docs.python.org/3/library/exceptions.html#exception-hierarchy) are suppressed, but only those that can be expected in the user code. [`Exception`](https://docs.python.org/3/library/exceptions.html#Exception) and all its descendants are suppressed, as well as, starting with `Python 3.11`, [groups of exceptions](https://docs.python.org/3/library/exceptions.html#exception-groups). However, exceptions [`GeneratorExit`](https://docs.python.org/3/library/exceptions.html#GeneratorExit), [`KeyboardInterrupt`](https://docs.python.org/3/library/exceptions.html#KeyboardInterrupt) and [`SystemExit`](https://docs.python.org/3/library/exceptions.html#SystemExit) are not escaped in this mode. This is due to the fact that in most programs none of them is part of the semantics of the program, but is used exclusively for system needs. For example, if `KeyboardInterrupt` was blocked, you would not be able to stop your program using the `Control-C` keyboard shortcut.

with escape:
You can also use the same set of exceptions in parenthesis mode as without parentheses. To do this, use the [`Ellipsis`](https://docs.python.org/dev/library/constants.html#Ellipsis) (three dots):

```python
@escape(...)
def function_1():
raise ValueError

with escape():
@escape
def function_2():
raise ValueError

function_1() # These two functions are completely equivalent.
function_2() # These two functions are completely equivalent.
```

However, as you should understand, the default value cannot be specified in this case. If you try to specify a default value for the context manager, get ready to face an exception:
`Ellipsis` can also be used in enumeration, along with other exceptions:

```python
with escape(default='some value'):
...

# escape.errors.SetDefaultReturnValueForDecoratorError: You cannot set a default value for the context manager. This is only possible for the decorator.
@escape(GeneratorExit, ...)
```

## Which exceptions are escaped?

By default, not all exceptions from the [hierarchy](https://docs.python.org/3/library/exceptions.html#exception-hierarchy) are escaped. This only applies to [`Exception`](https://docs.python.org/3/library/exceptions.html#Exception) and all its descendants. Starting with Python 3.11, [groups of exceptions](https://docs.python.org/3/library/exceptions.html#exception-groups) appear - and they are also escaped by default. However, exceptions [`GeneratorExit`](https://docs.python.org/3/library/exceptions.html#GeneratorExit), [`KeyboardInterrupt`](https://docs.python.org/3/library/exceptions.html#KeyboardInterrupt) and [`SystemExit`](https://docs.python.org/3/library/exceptions.html#SystemExit) are not escaped by default. This is due to the fact that in most programs none of them is part of the semantics of the program, but is used exclusively for system needs. For example, if `KeyboardInterrupt` was blocked, you would not be able to stop your program using the `Control-C` keyboard shortcut.

If you want to expand or narrow the range of escaped exceptions, use the `exceptions` argument. You must pass a list or tuple of exception types.
## Context manager mode

It works for the [decorator mode](#decorator-mode):
You can use `escape` as a context manager, which escapes exceptions in the code block wrapped by it. You can call it according to the same rules as the [decorator](#decorator-mode) - pass exceptions or ellipsis there. It also works almost the same way as [`contextlib.suppress`](https://docs.python.org/3/library/contextlib.html#contextlib.suppress) from the standard library, but with a bit more opportunities. Some examples:

```python
@escape(exceptions=[ValueError]):
def function():
raise ValueError # It will be suppressed.
with escape(ValueError):
raise ValueError

@escape(exceptions=[ValueError]):
def function():
raise KeyError # And this is not.
with escape:
raise ValueError

with escape(...):
raise ValueError
```

... and for the [context manager mode](#context-manager-mode):
However, as you should understand, the default value cannot be specified in this case. If you try to specify a default value for the context manager, get ready to face an exception:

```python
with escape(exceptions=[ValueError]):
raise ValueError # It will be suppressed.
with escape(default='some value'):
...

with escape(exceptions=[ValueError]):
raise KeyError # And this is not.
# > escape.errors.SetDefaultReturnValueForContextManagerError: You cannot set a default value for the context manager. This is only possible for the decorator.
```


Expand All @@ -156,7 +164,7 @@ logging.basicConfig(

logger = logging.getLogger('logger_name')

with escape(logger=logger):
with escape(..., logger=logger):
1/0

# You will see a description of the error in the console.
Expand Down
Binary file added docs/assets/logo_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading