Skip to content

Commit

Permalink
* Add some badges
Browse files Browse the repository at this point in the history
* Add tests workflow

* Add code coverage

* Add examples

* Update readme

* Add num_context_lines to some funcs

* Add some tests
  • Loading branch information
andy-landy committed Nov 3, 2020
1 parent 0be1995 commit fa030be
Show file tree
Hide file tree
Showing 20 changed files with 286 additions and 72 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Tests
on:
pull_request:
branches:
- 'master'
push:
branches:
- 'master'
jobs:
unit-tests:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 3.9]
steps:
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest-cov
- name: Checkout code
uses: actions/checkout@v2

- name: Lint with flake8
run: |
flake8 traceback_with_variables --count --show-source --statistics --max-line-length=127
- name: Test with pytest
run: |
python -m pytest --cov=./traceback_with_variables --cov-report=xml
- name: Upload Codecov
uses: codecov/codecov-action@v1
with:
file: ./coverage.xml
113 changes: 53 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,58 @@
## Python traceback (stacktrace) printing variables.
![Example](https://raw.githubusercontent.com/andy-landy/traceback_with_variables/master/header.png)

Very simple to use, but versatile when needed.
<h2 align="center">Python Traceback (Error Message) Printing Variables</h2>
<p align="center">Very simple to use, but versatile when needed.</p>
<br/>
<p align="center">
<a href="https://github.com/andy-landy/traceback_with_variables/actions"><img alt="Actions Status" src="https://github.com/andy-landy/traceback_with_variables/workflows/Tests/badge.svg"></a>
<a href="https://codecov.io/gh/andy-landy/traceback_with_variables"><img alt="Codecov" src="https://codecov.io/gh/andy-landy/traceback_with_variables/branch/master/graph/badge.svg"></a>
<a href="https://github.com/andy-landy/traceback_with_variables/blob/master/LICENSE"><img alt="License: MIT" src="https://img.shields.io/github/license/andy-landy/traceback_with_variables?color=informational"></a>
<a href="https://pypi.org/project/traceback_with_variables/"><img alt="PyPI" src="https://img.shields.io/pypi/v/traceback_with_variables"></a>
<a href="https://pypi.org/project/traceback_with_variables/"><img alt="PyPI" src="https://img.shields.io/badge/python-3.5+-blue.svg"></a>
<!--
<a href="https://pepy.tech/project/traceback_with_variables"><img alt="Downloads" src="https://pepy.tech/badge/traceback_with_variables"></a>
<a href="https://anaconda.org/conda-forge/traceback_with_variables/"><img alt="conda-forge" src="https://img.shields.io/conda/dn/conda-forge/traceback_with_variables.svg?label=conda-forge"></a>
-->
</p>

> “It is useless work that darkens the heart.”
> <em>– Ursula K. Le Guin</em>
Tired of useless job of putting all your variables into debug exception messages? Just stop it.
Automate it and clean your code. Once and for all.

---

![Example](https://raw.githubusercontent.com/andy-landy/traceback_with_variables/master/header.png)
_Contents:_ **[Quick Start](#quick-start)** | **[Installation](#installation)**
| **[How does it save my time?](#how-does-it-save-my-time)** |
**[Examples and recipes](#examples-and-recipes)** | **[Reference](#reference)**

---

###
###
###

### Quick Start

Simplest usage:
<a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/simple.py">Simplest usage</a>, for the whole program:
```python
from traceback_with_variables import activate_by_import
```

Decorator:
<a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/print_for_function.py">Decorator</a>, for a single function:
```python
@prints_tb
# def main(): or def some_func(...):
```

Context:
<a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/print_for_code_block.py">Context</a>, for a single code block:
```python
with printing_tb():
```

Work with traceback lines:
<a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/work_with_traceback_lines.py">Work with traceback lines</a> in a custom manner:
```python
return '\n'.join(iter_tb_lines(e))
```

Using a logger:
Using a logger [<a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/log_for_function.py">with a decorator</a>, <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/log_for_code_block.py">with a context</a>]:
```python
with printing_tb(file_=LoggerAsFile(logger)):
# or
Expand All @@ -48,9 +65,9 @@ Using a logger:
pip install traceback-with-variables
```

### Rationale
### How does it save my time?

* Tired of putting all your variables in debug exception messages? Just stop it. Go clean your code:
* Turn a code totally covered by debug formatting from this:

```diff
def main():
Expand Down Expand Up @@ -82,7 +99,7 @@ pip install traceback-with-variables
- # or
- raise MyToolException(f'something happened :(, width = {width}, height = {height}')
```
Must become this:
into this (zero debug code):

```diff
+ from traceback_with_variables import activate_by_import
Expand All @@ -99,7 +116,7 @@ pip install traceback-with-variables
return height / width
```

To produce:
And obtain total debug info spending 0 lines of code:

```
Traceback with variables (most recent call last):
Expand All @@ -126,7 +143,7 @@ pip install traceback-with-variables
builtins.ZeroDivisionError: division by zero
```

* Make automated logging easier:
* Automate your logging too:

```python
logger = logging.getLogger('main')
Expand Down Expand Up @@ -184,9 +201,20 @@ pip install traceback-with-variables
step 6: Erase all recently added printouts, logging and exception messages. \
step 7: Go back to step 1 once bugs appear.

### Reference
### Examples and recipes

---
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/simple.py">simple usage</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/change_how_traceback_looks.py">a bit more controlled usage</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/change_how_traceback_looks_customised.py">a bit more controlled usage, customised</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/print_for_function.py">working with a function</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/print_for_function_customised.py">working with a function, customised</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/log_for_function.py">working with a function, logging</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/print_for_code_block.py">working with a code block</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/print_for_code_block_customised.py">working with a code block, customised</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/log_for_code_block.py">working with a code block, logging</a>
* <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/examples/work_with_traceback_lines.py">get traceback lines for custom things</a>

### Reference

#### All functions have output customization
* `max_value_str_len` max length of each variable string
Expand All @@ -197,15 +225,15 @@ pip install traceback-with-variables

---

#### `activate_by_import`
#### <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/traceback_with_variables/activate_by_import.py">`activate_by_import`</a>
Just import it. No arguments, for real quick use.
```python
from traceback_with_variables import activate_by_import
```

---

#### `override_print_tb`
#### <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/traceback_with_variables/override.py">`override_print_tb`</a>
Call once in the beginning of your program, to change how traceback after an uncaught exception looks.
```python
def main():
Expand All @@ -214,7 +242,7 @@ def main():

---

#### `prints_tb`
#### <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/traceback_with_variables/print.py">`prints_tb`</a>
Function decorator, used for logging or simple printing of scoped tracebacks with variables. I.e. traceback is shorter as it includes only frames inside the function call. Program exiting due to unhandled exception still prints a usual traceback.
```python
@prints_tb
Expand All @@ -226,57 +254,22 @@ def f(...):

---

#### `printing_tb`
#### <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/traceback_with_variables/print.py">`printing_tb`</a>
Context manager (i.e. `with ...`), used for logging or simple printing of scoped tracebacks with variables. I.e. traceback is shorter as it includes only frames inside the `with` scope. Program exiting due to unhandled exception still prints a usual traceback.
```python
with printing_tb(...):
```

---

#### `LoggerAsFile`
#### <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/traceback_with_variables/print.py">`LoggerAsFile`</a>
A logger-to-file wrapper, to pass a logger to print tools as a file.

---

#### `iter_tb_lines`
#### <a href="https://github.com/andy-landy/traceback_with_variables/tree/master/traceback_with_variables/core.py">`iter_tb_lines`</a>
Iterates the lines, which are usually printed one-by-one in terminal.

### Recipes

#### Simplest usage
```python
from traceback_with_variables import activate_by_import
```

#### Override standard traceback if env variable X is set
```python
def main():
override_print_tb(activate_by_env_var='X')
```

#### Override standard traceback unless env variable Y is set
```python
def main():
override_print_tb(deactivate_by_env_var='Y')
```

#### Log traceback for a block of code, exclude external frames
```python
logger = logging.getLogger(__name__)
...
with printing_tb(file_=LoggerAsFile(logger)):
```

#### Log traceback for a function, exclude external frames
```python
logger = logging.getLogger(__name__)
...
@prints_tb(file_=LoggerAsFile(logger))
def f(...):
```

#### Print traceback for inner frames
```python
with printing_tb():
```
11 changes: 11 additions & 0 deletions examples/change_how_traceback_looks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from traceback_with_variables import override_print_tb


def main():
override_print_tb()

n = 0
print(1 / n)


main()
18 changes: 18 additions & 0 deletions examples/change_how_traceback_looks_customised.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from traceback_with_variables import override_print_tb


def main():
override_print_tb(
num_context_lines=3,
max_value_str_len=100,
max_exc_str_len=1000,
ellipsis_='...',
activate_by_env_var='PY_PRINT_VARS',
deactivate_by_env_var='PY_DONT_PRINT_VARS'
)

n = 0
print(1 / n)


main()
20 changes: 20 additions & 0 deletions examples/log_for_code_block.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import logging

from traceback_with_variables import printing_tb, LoggerAsFile


logging.basicConfig(format='%(asctime)-15s %(name)s %(levelname)s %(message)s')
logger = logging.getLogger(__name__)


def f(n):
print(1 / n)


def main():
with printing_tb(file_=LoggerAsFile(logger)):
x = 1
f(x - 1)


main()
19 changes: 19 additions & 0 deletions examples/log_for_function.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import logging

from traceback_with_variables import prints_tb, LoggerAsFile


logging.basicConfig(format='%(asctime)-15s %(name)s %(levelname)s %(message)s')
logger = logging.getLogger(__name__)


@prints_tb(file_=LoggerAsFile(logger))
def f(n):
print(1 / n)


def main():
f(0)


main()
14 changes: 14 additions & 0 deletions examples/print_for_code_block.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from traceback_with_variables import printing_tb


def f(n):
print(1 / n)


def main():
with printing_tb():
x = 1
f(x - 1)


main()
21 changes: 21 additions & 0 deletions examples/print_for_code_block_customised.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from traceback_with_variables import printing_tb


def f(n):
print(1 / n)


def main():
with printing_tb(
num_context_lines=3,
max_value_str_len=100,
max_exc_str_len=1000,
ellipsis_='...',
skip_cur_frame=True, # e.g. no info about 'x'
reraise=False, # i.e. program won't fail, exceptions stay inside
):
x = 1
f(x - 1)


main()
13 changes: 13 additions & 0 deletions examples/print_for_function.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from traceback_with_variables import prints_tb


@prints_tb
def f(n):
print(1 / n)


def main():
f(0)


main()
Loading

0 comments on commit fa030be

Please sign in to comment.