Mastering Python Second Edition Release Code

This commit is contained in:
Rick van Hattem
2022-05-05 18:25:55 +02:00
commit 3223a43fe3
454 changed files with 20230 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
Chapter 11, Debugging
##############################################################################
| Solving bugs demonstrates several methods of hunting down bugs using tracing, logging and interactive debugging.
@@ -0,0 +1,30 @@
import os
import inspect
import linecache
def print_code():
while True:
info = inspect.stack()[1]
lineno = info.lineno
function = info.function
# Strip the path from the filename
filename = os.path.split(info.filename)[-1]
# Fetch the next line of code
code = linecache.getline(info.filename, lineno + 1)
print(f'{filename}:{lineno}:{function}: {code.strip()}')
yield
# Always prime the generator
print_code = print_code()
def some_test_function(a, b):
next(print_code)
c = a + b
next(print_code)
return c
some_test_function('a', 'b')
@@ -0,0 +1,56 @@
>>> def hiding_generator():
... print('a')
... yield 'first value'
... print('b')
... yield 'second value'
... print('c')
>>> generator = hiding_generator()
>>> next(generator)
a
'first value'
>>> next(generator)
b
'second value'
>>> next(generator)
Traceback (most recent call last):
...
StopIteration
##############################################################################
>>> import os
>>> import inspect
>>> import linecache
>>> def print_code():
... while True:
... info = inspect.stack()[1]
... lineno = info.lineno + 1
... function = info.function
... # Fetch the next line of code
... code = linecache.getline(info.filename, lineno)
... print(f'{lineno:03d} {function}: {code.strip()}')
... yield
# Always prime the generator
>>> print_code = print_code()
>>> def some_test_function(a, b):
... next(print_code)
... c = a + b
... next(print_code)
... return c
>>> some_test_function('a', 'b')
003 some_test_function: c = a + b
005 some_test_function: return c
'ab'
+6
View File
@@ -0,0 +1,6 @@
def some_test_function(a, b):
c = a + b
return c
print(some_test_function('a', 'b'))
+10
View File
@@ -0,0 +1,10 @@
--- modulename: T_02_selective_trace, funcname: some_test_function
0.00 T_02_selective_trace.py(19): c = a + b
0.00 T_02_selective_trace.py(20): return c
ab
--- modulename: contextlib, funcname: __exit__
0.00 contextlib.py(...): if typ... is None:
0.00 contextlib.py(...): try:
0.00 contextlib.py(...): next(self.gen)
--- modulename: T_02_selective_trace, funcname: trace
0.00 T_02_selective_trace.py(12): sys.settrace(None)
+24
View File
@@ -0,0 +1,24 @@
import sys
import trace as trace_module
import contextlib
@contextlib.contextmanager
def trace(count=False, trace=True, timing=True):
tracer = trace_module.Trace(
count=count, trace=trace, timing=timing)
sys.settrace(tracer.globaltrace)
yield tracer
sys.settrace(None)
result = tracer.results()
result.write_results(show_missing=False, summary=True)
def some_test_function(a, b):
c = a + b
return c
with trace():
print(some_test_function('a', 'b'))
+8
View File
@@ -0,0 +1,8 @@
--- modulename: T_03_filename_trace, funcname: some_test_function
T_03_filename_trace.py(27): c = a + b
T_03_filename_trace.py(28): return c
ab
--- modulename: T_03_filename_trace, funcname: trace
T_03_filename_trace.py(20): sys.settrace(None)
lines cov% module (path)
3 100% T_03_filename_trace (/CH_11_debugging/T_03_filename_trace.py)
+33
View File
@@ -0,0 +1,33 @@
import sys
import trace as trace_module
import contextlib
@contextlib.contextmanager
def trace(filename):
tracer = trace_module.Trace()
def custom_trace(frame, event, arg):
# Only trace for the given filename
if filename != frame.f_code.co_filename:
return custom_trace
# Let globaltrace handle the rest
return tracer.globaltrace(frame, event, arg)
sys.settrace(custom_trace)
yield tracer
sys.settrace(None)
result = tracer.results()
result.write_results(show_missing=False, summary=True)
def some_test_function(a, b):
c = a + b
return c
# Pass our current filename as `__file__`
with trace(filename=__file__):
print(some_test_function('a', 'b'))
+3
View File
@@ -0,0 +1,3 @@
DEBUG:root:add(a=1, b=123): 124
DEBUG:root:add(a=1, b=456): 457
DEBUG:root:add(a=456, b=1): 457
+43
View File
@@ -0,0 +1,43 @@
import pprint
import inspect
import logging
import functools
def debug(function):
@functools.wraps(function)
def _debug(*args, **kwargs):
# Make sure `result` is always defined
result = None
try:
result = function(*args, **kwargs)
return result
finally:
# Extract the signature from the function
signature = inspect.signature(function)
# Fill the arguments
arguments = signature.bind(*args, **kwargs)
# NOTE: This only works for Python 3.5 and up!
arguments.apply_defaults()
logging.debug('%s(%s): %s' % (
function.__qualname__,
', '.join('%s=%r' % (k, v) for k, v in
arguments.arguments.items()),
pprint.pformat(result),
))
return _debug
@debug
def add(a, b=123):
return a + b
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
add(1)
add(1, 456)
add(b=1, a=456)
+3
View File
@@ -0,0 +1,3 @@
[DEBUG] T_05_logging_config.py:20:_debug: add(a=1, b=123): 124
[DEBUG] T_05_logging_config.py:20:_debug: add(a=1, b=456): 457
[DEBUG] T_05_logging_config.py:20:_debug: add(a=456, b=1): 457
+45
View File
@@ -0,0 +1,45 @@
import pprint
import inspect
import logging
import functools
def debug(function):
@functools.wraps(function)
def _debug(*args, **kwargs):
try:
result = function(*args, **kwargs)
finally:
# Extract the signature from the function
signature = inspect.signature(function)
# Fill the arguments
arguments = signature.bind(*args, **kwargs)
# NOTE: This only works for Python 3.5 and up!
arguments.apply_defaults()
logging.debug('%s(%s): %s' % (
function.__qualname__,
', '.join('%s=%r' % (k, v) for k, v in
arguments.arguments.items()),
pprint.pformat(result),
))
return _debug
@debug
def add(a, b=123):
return a + b
if __name__ == '__main__':
log_format = (
# Removed %(relativeCreated)d because of test unstability
'[%(levelname)s] '
'%(filename)s:%(lineno)d:%(funcName)s: %(message)s'
)
logging.basicConfig(level=logging.DEBUG, format=log_format)
add(1)
add(1, 456)
add(b=1, a=456)
+24
View File
@@ -0,0 +1,24 @@
import traceback
class ShowMyStack:
def run(self, limit=None):
print('Before stack print')
traceback.print_stack(limit=limit)
print('After stack print')
class InheritShowMyStack(ShowMyStack):
pass
if __name__ == '__main__':
show_stack = InheritShowMyStack()
print('Stack without limit')
show_stack.run()
print()
print('Stack with limit 1')
show_stack.run(1)
+4
View File
@@ -0,0 +1,4 @@
import ctypes
# Get memory address 0, your kernel shouldn't allow this:
ctypes.string_at(0)
@@ -0,0 +1,7 @@
import ctypes
try:
# Get memory address 0, your kernel shouldn't allow this:
ctypes.string_at(0)
except Exception as e:
print('Got exception:', e)
@@ -0,0 +1,7 @@
import ctypes
import faulthandler
faulthandler.enable()
# Get memory address 0, your kernel shouldn't allow this:
ctypes.string_at(0)
+12
View File
@@ -0,0 +1,12 @@
import code
def start_console():
some_variable = 123
print(f'Launching console, some_variable: {some_variable}')
code.interact(banner='console:', local=locals())
print(f'Exited console, some_variable: {some_variable}')
if __name__ == '__main__':
start_console()
+12
View File
@@ -0,0 +1,12 @@
import pdb
def go_to_debugger():
some_variable = 123
print('Starting pdb trace')
pdb.set_trace()
print(f'Finished pdb, some_variable: {some_variable}')
if __name__ == '__main__':
go_to_debugger()
+11
View File
@@ -0,0 +1,11 @@
import pdb
def print_value(value):
print('value:', value)
if __name__ == '__main__':
pdb.set_trace()
for i in range(5):
print_value(i)
@@ -0,0 +1,3 @@
print('This still works')
1 / 0
print('We will never reach this')
+6
View File
@@ -0,0 +1,6 @@
def do_nothing(i):
pass
for i in range(10):
do_nothing(i)
+7
View File
@@ -0,0 +1,7 @@
def print_value(value):
print('value:', value)
if __name__ == '__main__':
for i in range(5):
print_value(i)
View File