Skip to content

Commit

Permalink
some readme fixes; add module aliases; some code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy Landy committed Nov 16, 2024
1 parent a330a93 commit cc13189
Show file tree
Hide file tree
Showing 17 changed files with 171 additions and 48 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
- Fully compatible with 2.0.4
- Add short names for frequently used things like `a` and `fmt`
- Add unified `activate_by_import` to be used both for Jupyter and regular Python
- Add rel ellipsis pos for strings like `x=['some', ...long', 'list']`
- Add object detailed printout, useful for non-dataclass classes
- Add relative ellipsis position for strings like `x=['some', ...long', 'list']`
- Add detailed object printout, useful for non-dataclass classes
- Add protection against acidental mistyping in format attributes
- Fixed some bugs, e.g.
- cli not working in Python 3.12+
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<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://github.com/andy-landy/traceback_with_variables/blob/master/.github/workflows/dev-test.yml#L59"><img title="code tests coverage is 100%" alt="code tests coverage is 100%" src="https://img.shields.io/badge/coverage-100%25-brightgreen.svg"></a>
<a href="https://github.com/andy-landy/traceback_with_variables/blob/master/.github/workflows/master-test.yml#L59"><img title="code tests coverage is 100%" alt="code tests coverage is 100%" src="https://img.shields.io/badge/coverage-100%25-brightgreen.svg"></a>
<a href="https://github.com/andy-landy/traceback_with_variables/tree/master/LICENSE"><img alt="License: MIT" src="https://img.shields.io/github/license/andy-landy/traceback_with_variables?color=informational"></a>
<a href="https://pepy.tech/project/traceback-with-variables"><img alt="Downloads" src="https://static.pepy.tech/badge/traceback-with-variables"></a>
<a href="https://pypi.org/project/traceback-with-variables"><img alt="PyPI" src="https://img.shields.io/pypi/v/traceback-with-variables"></a>
Expand Down Expand Up @@ -47,10 +47,10 @@ _Contents:_ **[Installation](#installation)** | **[🚀 Quick Start](#-quick-sta
### Installation

```
pip install traceback-with-variables==2.1.0
pip install traceback-with-variables==2.1.1
```
```
conda install -c conda-forge traceback-with-variables=2.1.0
conda install -c conda-forge traceback-with-variables=2.1.1
```

### 🚀 Quick Start
Expand Down
15 changes: 9 additions & 6 deletions README.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<p align="center">
<a href="{{ repo_url }}/actions"><img alt="Actions Status" src="{{ repo_url }}/workflows/tests/badge.svg"></a>
<a href="{{ repo_url }}/blob/master/.github/workflows/dev-test.yml#L59"><img title="code tests coverage is 100%" alt="code tests coverage is 100%" src="https://img.shields.io/badge/coverage-100%25-brightgreen.svg"></a>
<a href="{{ repo_url }}/blob/master/.github/workflows/master-test.yml#L59"><img title="code tests coverage is 100%" alt="code tests coverage is 100%" src="https://img.shields.io/badge/coverage-100%25-brightgreen.svg"></a>
<a href="{{ code_url }}/LICENSE"><img alt="License: MIT" src="https://img.shields.io/github/license/{{ user_repo_name }}?color=informational"></a>
<a href="https://pepy.tech/project/traceback-with-variables"><img alt="Downloads" src="https://static.pepy.tech/badge/traceback-with-variables"></a>
<a href="{{ pypi_url }}"><img alt="PyPI" src="https://img.shields.io/pypi/v/{{ package_name }}"></a>
Expand Down Expand Up @@ -53,24 +53,27 @@ pip install traceback-with-variables=={{ version }}
conda install -c conda-forge traceback-with-variables={{ version }}
```

to use shorter `tb` alias in interactive mode call this once:
```
python3 -c 'from traceback_with_variables.tb_alias import create_tb_alias as c; c()'
```

### 🚀 Quick Start

Using without code editing, <a href="{{ examples_code_url }}/external_script.sh">running your script/command/module</a>:
```
traceback-with-variables tested_script.py ...srcipt's args...
```

<a href="{{ examples_code_url }}/simple.py">Simplest usage in regular Python</a>, for the whole program:
<a href="{{ examples_code_url }}/simple.py">Simplest usage</a>, for the whole program:
```python
from {{ import_name }} import activate_by_import
```

<a href="{{ examples_code_url }}/simple_jupyter.py">Simplest usage in Jupyter or IPython</a>, for the whole program:
or just (if you added an alias by the above command)
```python
from {{ import_name }} import activate_in_ipython_by_import
import tb.a
```


<a href="{{ examples_code_url }}/print_for_function.py">Decorator</a>, for a single function:
```python
@prints_exc
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
'rollable. Debug reasons of exceptions by logging or pretty printing color'
'ful variable contexts for each frame in a stacktrace, showing every value'
'. Dump locals environments after errors to console, files, and loggers. W'
'orks with Jupiter and IPython.',
'orks with Jupyter and IPython.',
long_description=long_description,
long_description_content_type="text/markdown",
url='https://github.com/andy-landy/traceback_with_variables',
Expand All @@ -23,7 +23,7 @@
'variables', 'python3', 'stacktrace', 'arguments', 'errors',
'error-handling', 'dump', 'exception-handling', 'exceptions',
'pretty', 'pretty-print', 'frame', 'simple',
'colors', 'jupyer', 'jupyer-notebook', 'ipython', 'customize'],
'colors', 'jupyter', 'jupyter-notebook', 'ipython', 'customize'],
classifiers=[
'Programming Language :: Python :: 3',
'License :: OSI Approved :: MIT License',
Expand Down
4 changes: 2 additions & 2 deletions tests/dumps/test_core.after_100_.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ Traceback with variables (most recent call last):
. fmt.skip_files_except = []
. fmt.brief_files_except = []
. fmt.custom_var_printers = []
. with pytest.raises(AttributeError):
. with pytest.raises(AttributeError) as e:
. fmt.max_val_str_len = 1
. assert str(e.value) == "'Format' object has no attribute 'max_val_str_len'"
.
.
. def test_default(check):
Expand Down Expand Up @@ -88,7 +89,6 @@ Traceback with variables (most recent call last):
. def test_objects_details(tb_reg, obj, objects_details):
. try:
. 1/0
. except:
kwargs = {'fmt': <traceback_with_variables.core.Format object at 0x...omitted for tests only...>}
tb_reg = <bound method Reg.match_tb_text of <tests.test_utils.Reg object at 0x...omitted for tests only...>>
File "...omitted for tests only.../dummies.py", line...omitted for tests only..., in f
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Traceback (most recent call last):
File "...omitted for tests only.../code.py", line...omitted for tests only..., in <module>
from traceback_with_variables import activate_in_ipython_by_import
File "...omitted for tests only.../activate_in_ipython_by_import.py", line...omitted for tests only..., in <module>
default_global_print_exc_in_ipython()
File "...omitted for tests only.../default_global_hooks.py", line...omitted for tests only..., in default_global_print_exc_in_ipython
global_print_exc_in_ipython()
File "...omitted for tests only.../global_hooks.py", line...omitted for tests only..., in global_print_exc_in_ipython
raise ValueError("IPython not found")
Expand Down
3 changes: 2 additions & 1 deletion tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ def test_setattr():
fmt.skip_files_except = []
fmt.brief_files_except = []
fmt.custom_var_printers = []
with pytest.raises(AttributeError):
with pytest.raises(AttributeError) as e:
fmt.max_val_str_len = 1
assert str(e.value) == "'Format' object has no attribute 'max_val_str_len'"


def test_default(check):
Expand Down
62 changes: 62 additions & 0 deletions tests/test_module_alias.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import importlib
import os

import pytest

import traceback_with_variabless as twv
from traceback_with_variables.module_alias import (
create_alias,
rm_alias,
module_name_to_path,
Path,
NoModuleError,
)


ROOT_PATH = Path(twv.__file__).parent
TWV = 'traceback_with_variables'

def test_module_name_to_path():
assert module_name_to_path('os') == Path(os.__file__)
assert module_name_to_path(TWV) = ROOT_PATH / TWV
with pytest.raises(NoModuleError):
module_name_to_path('nonexistant_module')


def test_create_and_rm_alias():
with pytest.raised(ValueError) as e:
create_alias('', TWV)
assert e.value == 'the alias must be non-empty')
with pytest.raises(ValueError) as e:
create_alias('bad name', TWV)
assert e.value == 'the alias must have only ascii lowecases, digits and underscores'
with pytest.raises(NoModuleError):
create_alias('alias1', 'nonexistant_module')
with pytest.raises(ValueError) as e:
create_alias('os', TWV)
assert e.value == 'a module with the alias name already exists'

with pytest.raises(NoModuleError):
rm_alias('alias1')
with pytest.raises(ValueError) as e:
rm_alias(TWV)
assert e.value == 'the module is not an alias'

create_alias('alias1', TWV)
with pytest.raises(ValueError) as e:
create_alias('alias1', TWV)
assert e.value == 'a module with the alias name already exists'
with pytest.raises(ValueError) as e:
create_alias('alias1', 'os')
assert e.value == 'a module with the alias name already exists'

rm_alias('alias1')
with pytest.raises(NoModuleError):
rm_alias('alias1')

os.symlink(str(ROOT_PATH / TWV), str(ROOT_PATH / 'alias1'))
with pytest.raises(ValueError) as e:
create_alias('alias1', 'os')
assert e.value == 'the needed file system location already occupied'
os.remove(str(ROOT_PATH / 'alias1'))

8 changes: 0 additions & 8 deletions tox.ini

This file was deleted.

4 changes: 2 additions & 2 deletions traceback_with_variables/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

from .color import ColorScheme, ColorSchemes, supports_ansi # noqa
from .core import Format, format_exc, iter_exc_lines, format_cur_tb, iter_cur_tb_lines, default_format # noqa
from .print import print_exc, print_cur_tb, printing_exc, prints_exc, LoggerAsFile # noqa
from .global_hooks import global_print_exc, global_print_exc_in_ipython, is_ipython_global # noqa
from .print import print_exc, print_cur_tb, printing_exc, prints_exc, LoggerAsFile # noqa


__version__ = '2.1.0'
__version__ = '2.1.1'

# shorter names for swifter interactive usage
fmt = default_format # noqa
13 changes: 2 additions & 11 deletions traceback_with_variables/activate_by_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,7 @@
For the simplest usage possible. Just import it. Handles all environments.
"""

from traceback_with_variables.color import ColorSchemes
from traceback_with_variables.global_hooks import global_print_exc_in_ipython, global_print_exc, is_ipython_global, in_ipython
from traceback_with_variables import default_format
from traceback_with_variables.default_global_hooks import default_global_print_exc_in_all


if in_ipython():
default_format.custom_var_printers = [(is_ipython_global, lambda v: None)]
default_format.color_scheme = ColorSchemes.common
global_print_exc_in_ipython()

else:
default_format.custom_var_printers = [((lambda n, t, fn, is_global: is_global), lambda v: None)]
global_print_exc()
default_global_print_exc_in_all()
8 changes: 2 additions & 6 deletions traceback_with_variables/activate_in_ipython_by_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
For the simplest usage possible. Jupyter or IPython. Just import it
"""

from traceback_with_variables.color import ColorSchemes
from traceback_with_variables.global_hooks import global_print_exc_in_ipython, is_ipython_global
from traceback_with_variables import default_format
from traceback_with_variables.default_global_hooks import default_global_print_exc_in_ipython


default_format.custom_var_printers = [(is_ipython_global, lambda v: None)]
default_format.color_scheme = ColorSchemes.common
global_print_exc_in_ipython()
default_global_print_exc_in_ipython()
6 changes: 2 additions & 4 deletions traceback_with_variables/activate_in_python_by_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
For the simplest usage possible. Just import it. For 'python3' command usage, not for Jupyter or IPython
"""

from traceback_with_variables.global_hooks import global_print_exc
from traceback_with_variables import default_format
from traceback_with_variables.default_global_hooks import default_global_print_exc


default_format.custom_var_printers = [((lambda n, t, fn, is_global: is_global), lambda v: None)]
global_print_exc()
default_global_print_exc()
2 changes: 1 addition & 1 deletion traceback_with_variables/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def __init__(

def __setattr__(self, name, value):
if (not getattr(self, '_can_grow', True)) and (name not in dir(self)) or (name in dir(type(self))):
raise AttributeError("'Format' object has no attribute '{name}'")
raise AttributeError(f"'Format' object has no attribute '{name}'")
super().__setattr__(name, value)

@classmethod
Expand Down
18 changes: 18 additions & 0 deletions traceback_with_variables/default_global_hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from traceback_with_variables.color import ColorSchemes
from traceback_with_variables.global_hooks import global_print_exc_in_ipython, global_print_exc, is_ipython_global, in_ipython
from traceback_with_variables import default_format


def default_global_print_exc():
default_format.custom_var_printers = [((lambda n, t, fn, is_global: is_global), lambda v: None)]
global_print_exc()


def default_global_print_exc_in_ipython():
default_format.custom_var_printers = [(is_ipython_global, lambda v: None)]
default_format.color_scheme = ColorSchemes.common
global_print_exc_in_ipython()


def default_global_print_exc_in_all():
(default_global_print_exc_in_ipython if in_ipython() else default_global_print_exc)()
51 changes: 51 additions & 0 deletions traceback_with_variables/module_alias.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""Potentially evil magic to speed up the interactive commands"""

import importlib
import os
import string
from pathlib import Path


VALID_CHARS = set(string.ascii_lowercase + string.digits + '_')


class NoModuleError(ValueError):
pass


def module_name_to_path(name: str) -> Path:
spec = importlib.util.find_spec(name)
if spec is None:
raise NoModuleError(name)
path = Path(spec.origin)
return path.parent if path.name == '__init__.py' else path


def module_exists(name: str) -> bool:
try:
module_name_to_path(name)
except NoModuleError:
return False
return True


def create_alias(alias: str, module_name: str) -> None:
if not name:
raise ValueError('alias must be non-empty')
if any(c not in VALID_CHARS for c in name):
raise ValueError('the alias must have only ascii lowecases, digits and underscores')
if module_exists(alias):
raise ValueError('a module with the alias name already exists')
module_path = module_name_to_path(module_name)

try:
os.symlink(str(module_path), str(module_path.parent / name))
except FileExistsError as e:
raise ValueError('the needed file system location already occupied')


def rm_alias(alias: str) -> None:
module_path = module_name_to_path(alias)
if not module_path.is_symlink():
raise ValueError(f'the module is not an alias')
os.remove(str(module_path))
9 changes: 9 additions & 0 deletions traceback_with_variables/tb_alias.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from traceback_with_variables.module_alias import create_alias, rm_alias


def create_tb_alias() -> None:
create_alias(alias='tb', module_name='traceback_with_variables')


def rm_tb_alias() -> None:
rm_alias(alias='tb')

0 comments on commit cc13189

Please sign in to comment.