A Python library to make debugging with print statements simpler and more effective.
PyScribe.com for full documentation. (Work in progress)
Warning: This project is currently in a pre-release state. Open to contributions and collaborators.
To install pyscribe:
$ pip install pyscribeIt may be necessary to have root privileges, in which case:
$ sudo pip install pyscribeTo uninstall:
$ pip uninstall pyscribe- Include
from pyscribe import pyscribeat the top of the files you are debugging. - Initialize a variable of your choice to
pyscribe.Scriber()(E.g.:ps = pyscribe.Scriber()) - Make API calls as needed. (E.g.:
ps.p(x)) - Run one of the following commands
$ pyscribe myfile.pyThis is the equivalent of running $ python myfile.py with all calls desugared.
$ pyscribe myfile.py --extraargs "-u asdf"This is the equivalent of running $ python myfile.py -u asdf with all calls desugared.
$ pyscribe myfile.py --desugaredThis does not run anything, but rather outputs a myfile_desugared.py, which is intended to be run to debug.
--extraargs-- Arguments intended to be passed to Python file when run. Must be called with --run set--clean-- Produce a clean version of the file with all references to PyScribe removed--desugared-- Produce a desugared version of the file with all API calls replaced with valid Python.--log-- Save logs to a pyscribe_log.txt file along with timestamp.
pyscribe.Scriber(labels=[])-- Initialize PyScribe. If you're scribing values with labels, you can filter by labels by passing in a list of the labels as strings.pyscribe.p(object, label=None)-- Print the object value with relevant info dependent on typepyscribe.iterscribe(object)-- Log the object value from inside a for or while loop which prints current iterationpyscribe.watch(object)-- Log the object whenever its value changespyscribe.d(object, unit="*")-- Distinguish the log with a clear separator defined by the unit
pyscribe.values(object)-- Log the internal values of lists and dictionaries in a pretty waypyscribe.props(object)-- Log the fields of an object and their values- Add configurations for the logging messages. e.g.
Line 9: x is 4instead ofFrom line 9: x is the int 4.
Test modules are in the tests directory. Specific test cases are in these modules in the form of testcase.py, and the test runner compares these with testcase_correct. Run the tests with ./run_tests.
#####test.py:
from pyscribe import pyscribe
def main():
ps = pyscribe.Scriber()
x = 5
ps.p(x)
bar = "foo"
for i in xrange(5):
bar += str(i)
ps.iterscribe(bar)
y = "hello"
ps.p(y)
ps.watch(y)
y = "world"
foo = 1234
ps.d(foo)
ps.d(foo, unit="^")
synonyms = {"clerk": "secretary", "student": "apprentice", "ground": "floor"}
ps.p(synonyms)
if __name__ == "__main__":
main()####pyscribe_logs.txt:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Log saved at 2014-12-31 22:03:48
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
From line 9: x is the int 5
----------------------------------------
bar is the str foo at beginning of for loop at line 12
From line 14: In iteration 0, bar changed to foo0
From line 14: In iteration 1, bar changed to foo01
From line 14: In iteration 2, bar changed to foo012
From line 14: In iteration 3, bar changed to foo0123
From line 14: In iteration 4, bar changed to foo01234
From line 17: y is the str hello
From line 18: Watching variable y, currently str hello
From line 20: y changed to world
From line 23:
----------------------------------------
foo is the int 1234
----------------------------------------
From line 24:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
foo is the int 1234
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
From line 27: synonyms is the dict {'clerk': 'secretary', 'student': 'apprentice', 'ground': 'floor'}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
End of log
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%This log comes from running the desugared version of test.py:
import re
import pprint
import datetime
#from pyscribe import pyscribe
def main():
pyscribe_log = open('pyscribe_logs.txt', 'w')
pyscribe_log.write('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\nLog saved at ' + str(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + '\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n')
x = 5
pyscribe_log.write('From line 9: x is the ' + re.search(r'\'[a-zA-Z]*\'', str(type(x))).group()[1:-1] + ' ' + str(x)+ '\n')
bar = "foo"
NAICKSHMWL = -1
pyscribe_log.write('----------------------------------------\n' + 'bar is the ' + re.search(r'\'[a-zA-Z]*\'', str(type(bar))).group()[1:-1] + ' ' + str(bar) + ' at beginning of for loop at line 12' + '\n')
for i in xrange(5):
bar += str(i)
NAICKSHMWL += 1
pyscribe_log.write('From line 14: In iteration ' + str(NAICKSHMWL) + ', bar changed to ' + str(bar) + '\n')
y = "hello"
pyscribe_log.write('From line 17: y is the ' + re.search(r'\'[a-zA-Z]*\'', str(type(y))).group()[1:-1] + ' ' + str(y)+ '\n')
pyscribe_log.write('From line 18: Watching variable y, currently ' + re.search(r'\'[a-zA-Z]*\'', str(type(y))).group()[1:-1] + ' ' + str(y)+ '\n')
y = "world"
pyscribe_log.write('From line 20: y changed to ' + str(y)+ '\n')
foo = 1234
pyscribe_log.write('From line 23: \n----------------------------------------\nfoo is the ' + re.search(r'\'[a-zA-Z]*\'', str(type(foo))).group()[1:-1] + ' ' + str(foo) + '\n----------------------------------------\n'+ '\n')
pyscribe_log.write('From line 24: \n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nfoo is the ' + re.search(r'\'[a-zA-Z]*\'', str(type(foo))).group()[1:-1] + ' ' + str(foo) + '\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'+ '\n')
synonyms = {"clerk": "secretary", "student": "apprentice", "ground": "floor"}
pyscribe_log.write('From line 27: synonyms is the ' + re.search(r'\'[a-zA-Z]*\'', str(type(synonyms))).group()[1:-1] + ' ' + str(synonyms)+ '\n')
pyscribe_log.write('\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\nEnd of log\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n')
pyscribe_log.close()
if __name__ == "__main__":
main()