Skip to content

Commit 259b242

Browse files
authored
Return args (#87)
* return the args of debug() * test for generators * adding docs for returning * linting
1 parent fda133f commit 259b242

File tree

5 files changed

+81
-15
lines changed

5 files changed

+81
-15
lines changed

devtools/debug.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
MYPY = False
1111
if MYPY:
1212
from types import FrameType
13-
from typing import Generator, List, Optional
14-
13+
from typing import Any, Generator, List, Optional
1514

1615
pformat = PrettyFormat(
1716
indent_step=int(os.getenv('PY_DEVTOOLS_INDENT', 4)),
@@ -107,10 +106,16 @@ def __init__(self, *, warnings: 'Optional[bool]' = None, highlight: 'Optional[bo
107106
self._show_warnings = env_bool(warnings, 'PY_DEVTOOLS_WARNINGS', True)
108107
self._highlight = highlight
109108

110-
def __call__(self, *args, file_=None, flush_=True, **kwargs) -> None:
109+
def __call__(self, *args, file_=None, flush_=True, **kwargs) -> 'Any':
111110
d_out = self._process(args, kwargs)
112111
s = d_out.str(use_highlight(self._highlight, file_))
113112
print(s, file=file_, flush=flush_)
113+
if kwargs:
114+
return (*args, kwargs)
115+
elif len(args) == 1:
116+
return args[0]
117+
else:
118+
return args
114119

115120
def format(self, *args, **kwargs) -> DebugOutput:
116121
return self._process(args, kwargs)

docs/examples/return_args.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from devtools import debug
2+
3+
assert debug('foo') == 'foo'
4+
assert debug('foo', 'bar') == ('foo', 'bar')
5+
assert debug('foo', 'bar', spam=123) == ('foo', 'bar', {'spam': 123})
6+
assert debug(spam=123) == ({'spam': 123},)

docs/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@
1515
```
1616

1717
{!examples/example.html!}
18+
19+
Python devtools can do much more, see [Usage](./usage.md) for examples.

docs/usage.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,22 @@ A more complex example of `debug` shows more of what it can do.
2626

2727
{!examples/complex.html!}
2828

29+
### Returning the arguments
30+
31+
`debug` will return the arguments passed to it meaning you can insert `debug(...)` into code.
32+
33+
The returned arguments work as follows:
34+
35+
* if one non-keyword argument is passed to `debug()`, it is returned as-is
36+
* if multiple arguments are passed to `debug()`, they are returned as a tuple
37+
* if keyword arguments are passed to `debug()`, the `kwargs` dictionary is added to the returned tuple
38+
39+
```py
40+
{!examples/return_args.py!}
41+
```
42+
43+
{!examples/return_args.html!}
44+
2945
## Other debug tools
3046

3147
The debug namespace includes a number of other useful functions:

tests/test_main.py

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import re
22
import sys
3+
from collections.abc import Generator
34
from pathlib import Path
45
from subprocess import PIPE, run
56

@@ -8,12 +9,13 @@
89
from devtools import Debug, debug
910
from devtools.ansi import strip_ansi
1011

12+
pytestmark = pytest.mark.xfail(sys.platform == 'win32', reason='as yet unknown windows problem')
13+
1114

12-
@pytest.mark.xfail(sys.platform == 'win32', reason='yet unknown windows problem')
1315
def test_print(capsys):
1416
a = 1
1517
b = 2
16-
debug(a, b)
18+
result = debug(a, b)
1719
stdout, stderr = capsys.readouterr()
1820
print(stdout)
1921
assert re.sub(r':\d{2,}', ':<line no>', stdout) == (
@@ -22,9 +24,44 @@ def test_print(capsys):
2224
' b: 2 (int)\n'
2325
)
2426
assert stderr == ''
27+
assert result == (1, 2)
28+
29+
30+
def test_print_kwargs(capsys):
31+
a = 1
32+
b = 2
33+
result = debug(a, b, foo=[1, 2, 3])
34+
stdout, stderr = capsys.readouterr()
35+
print(stdout)
36+
assert re.sub(r':\d{2,}', ':<line no>', stdout) == (
37+
'tests/test_main.py:<line no> test_print_kwargs\n'
38+
' a: 1 (int)\n'
39+
' b: 2 (int)\n'
40+
' foo: [1, 2, 3] (list) len=3\n'
41+
)
42+
assert stderr == ''
43+
assert result == (1, 2, {'foo': [1, 2, 3]})
44+
45+
46+
def test_print_generator(capsys):
47+
gen = (i for i in [1, 2])
48+
49+
result = debug(gen)
50+
stdout, stderr = capsys.readouterr()
51+
print(stdout)
52+
assert re.sub(r':\d{2,}', ':<line no>', stdout) == (
53+
'tests/test_main.py:<line no> test_print_generator\n'
54+
' gen: (\n'
55+
' 1,\n'
56+
' 2,\n'
57+
' ) (generator)\n'
58+
)
59+
assert stderr == ''
60+
assert isinstance(result, Generator)
61+
# the generator got evaluated and is now empty, that's correct currently
62+
assert list(result) == []
2563

2664

27-
@pytest.mark.xfail(sys.platform == 'win32', reason='yet unknown windows problem')
2865
def test_format():
2966
a = b'i might bite'
3067
b = "hello this is a test"
@@ -38,7 +75,6 @@ def test_format():
3875
)
3976

4077

41-
@pytest.mark.xfail(sys.platform == 'win32', reason='yet unknown windows problem')
4278
def test_print_subprocess(tmpdir):
4379
f = tmpdir.join('test.py')
4480
f.write("""\
@@ -68,7 +104,6 @@ def test_func(v):
68104
)
69105

70106

71-
@pytest.mark.xfail(sys.platform == 'win32', reason='yet unknown windows problem')
72107
def test_odd_path(mocker):
73108
# all valid calls
74109
mocked_relative_to = mocker.patch('pathlib.Path.relative_to')
@@ -92,7 +127,6 @@ def test_small_call_frame():
92127
)
93128

94129

95-
@pytest.mark.xfail(sys.platform == 'win32', reason='yet unknown windows problem')
96130
def test_small_call_frame_warning():
97131
debug_ = Debug()
98132
v = debug_.format(
@@ -109,7 +143,6 @@ def test_small_call_frame_warning():
109143
)
110144

111145

112-
@pytest.mark.xfail(sys.platform == 'win32', reason='yet unknown windows problem')
113146
@pytest.mark.skipif(sys.version_info < (3, 6), reason='kwarg order is not guaranteed for 3.5')
114147
def test_kwargs():
115148
a = 'variable'
@@ -123,7 +156,6 @@ def test_kwargs():
123156
)
124157

125158

126-
@pytest.mark.xfail(sys.platform == 'win32', reason='yet unknown windows problem')
127159
def test_kwargs_orderless():
128160
# for python3.5
129161
a = 'variable'
@@ -136,7 +168,6 @@ def test_kwargs_orderless():
136168
}
137169

138170

139-
@pytest.mark.xfail(sys.platform == 'win32', reason='yet unknown windows problem')
140171
def test_simple_vars():
141172
v = debug.format('test', 1, 2)
142173
s = re.sub(r':\d{2,}', ':<line no>', str(v))
@@ -206,7 +237,6 @@ def test_exec(capsys):
206237
assert stderr == ''
207238

208239

209-
@pytest.mark.xfail(sys.platform == 'win32', reason='yet unknown windows problem')
210240
def test_colours():
211241
v = debug.format(range(6))
212242
s = re.sub(r':\d{2,}', ':<line no>', v.str(True))
@@ -240,7 +270,6 @@ def test_breakpoint(mocker):
240270
assert mocked_set_trace.called
241271

242272

243-
@pytest.mark.xfail(sys.platform == 'win32', reason='yet unknown windows problem')
244273
def test_starred_kwargs():
245274
v = {'foo': 1, 'bar': 2}
246275
v = debug.format(**v)
@@ -252,7 +281,6 @@ def test_starred_kwargs():
252281
}
253282

254283

255-
@pytest.mark.xfail(sys.platform == 'win32', reason='yet unknown windows problem')
256284
@pytest.mark.skipif(sys.version_info < (3, 7), reason='error repr different before 3.7')
257285
def test_pretty_error():
258286
class BadPretty:
@@ -279,3 +307,12 @@ def test_multiple_debugs():
279307
'tests/test_main.py:<line no> test_multiple_debugs\n'
280308
' [i * 2 for i in range(2)]: [0, 2] (list) len=2'
281309
)
310+
311+
312+
def test_return_args(capsys):
313+
assert debug('foo') == 'foo'
314+
assert debug('foo', 'bar') == ('foo', 'bar')
315+
assert debug('foo', 'bar', spam=123) == ('foo', 'bar', {'spam': 123})
316+
assert debug(spam=123) == ({'spam': 123},)
317+
stdout, stderr = capsys.readouterr()
318+
print(stdout)

0 commit comments

Comments
 (0)