# optimize-later [![Build Status](https://img.shields.io/travis/quantum5/optimize-later.svg)](https://travis-ci.org/quantum5/optimize-later) [![Coverage](https://img.shields.io/codecov/c/gh/quantum5/optimize-later.svg)](https://codecov.io/gh/quantum5/optimize-later) > Premature optimization is the root of all evil (or at least most of it) in programming. > > -- Donald Knuth Wouldn't it be nice to have something to tell you when optimization is really necessary? Enter `optimize-later`. Instead of trying to guess what code ought to be optimized, `optimize-later` times potentially slow blocks of code for you, and calls a user-specified function when it exceeds the specified time limit. This way, you only have to optimize code when speed becomes a problem. ## Usage ```python from optimize_later import optimize_later ### Basic usage. These examples will call your global callback. with optimize_later('test_block', 0.2): # potentially slow block of code... time.sleep(1) # Automatic block names from file and source line (slightly slow). with optimize_later(0.2): # potentially slow block of code... time.sleep(1) # Always warn. Good for exceptional cases that you suspect should not happen. with optimize_later(): # potentially slow block of code... time.sleep(1) # Also available as a decorator. @optimize_later('bad-function', 0.2) def function_name(): # potentially slow function... time.sleep(1) # Will use module:function as block name, if you do not specify a name. # There is no performance penalty this way, as the function name can be easily detected. @optimize_later(0.2) def function_name(): # potentially slow function... time.sleep(1) ### Blocks. with optimize_later() as o: with o.block('block 1'): # When the time limit of whole block is exceeded, your report will contain # a detailed breakdown by sub-blocks executed. This allows you to pinpoint # which exact block is the culprit. time.sleep(1) # optimize-later will automatically generate a block name for you from file and # line number, with a slightly performance penalty. with o.block() as b: # You can also nest blocks. with b.block(): pass ### Callbacks. from optimize_later import register_callback, deregister_callback, optimize_context @register_callback def my_report_function(report): # Short one line description. print(report.short()) # Long description with breakdown based on blocks. print(report.long()) # Details available in: # - report.name: block name # - report.limit: time limit # - report.delta: time consumed # - report.blocks: breakdown by blocks # - report.start, report.end: start and end time with an unspecified timer: # useful for building a relative timeline with blocks. deregister_callback(my_report_function) with optimize_context(): # Register a callback here. register_callback(my_report_function) # Callback is not available here. @optimize_context def function(): # This callback will be available for the duration of this function. register_callback(my_report_function) # Remove global callbacks for this block. with optimize_context(renew=True): pass # or... @optimize_context(renew=True) def function(): pass # Shortcut registration syntax. with optimize_context(my_report_function): pass @optimize_context(my_report_function, renew=True) def function(): pass ``` A sample short report: ```Block 'tests.py@152' took 0.011565s (+0.011565s over limit)``` A sample long report: ``` Block 'tests.py@152' took 0.011565s (+0.011565s over limit), children: - Block 'tests.py@153' took 0.006662s, children: - Block 'tests.py@154' took 0.000002s - Block 'tests.py@156' took 0.000002s - Block 'tests.py@159' took 0.000001s ``` ## Installation First, install the module with: ``` $ pip install optimize-later ``` Or if you want the latest bleeding edge version: ``` $ pip install -e git://github.com/quantum5/optimize-later.git ``` That's it! ### Django If you are using Django, you might want to configure `optimize-later` in `settings.py` instead of adding callbacks directly. You have to add `'optimize-later'` to `INSTALLED_APPS`. Then, the list of callbacks as dot-separated import paths can be specified in `'OPTIMIZE_LATER_CALLBACKS'` in `settings.py`. For example: ```python OPTIMIZE_LATER_CALLBACKS = [ 'myapp.optimize.report', 'otherapp.optimize.report', ] ```