To open the browser when Gramex starts, use --browser. To prevent opening the
browser on startup, use --browser=false.
If gramex.yaml is missing in the directory from where Gramex is run, Gramex will report an error.
You can also press Ctrl+B on the Gramex console at any point to start the
browser.
To start the browser at a specific URL, use --browser=url. The URL need not be
a local URL.
To save this setting locally, use gramex run <appname> --target=. --browser.
The next time you run gramex run <appname>, the setting will be saved. To
disable the --browser option, use --browser= (note the = at the end.)
You can add it to gramex.yaml under app as browser: true,
browser: url or browser: false.
Configurations auto-reload. By default, Gramex auto-reloads gramex.yaml
configurations (including any imported files). If you have a
FunctionHandler defined as:
url:
pattern: /$YAMLURL/func/
handler: FunctionHandler
kwargs:
function: yourmodule.run
When yourmodule.py is reloaded, the FunctionHandler automatically recompiles
the new function (Gramex 1.19 onwards.)
Modules can auto-reload. If you are manually importing any functions via an
import statement in Python or template code, call
gramex.cache.reload_module. This ensures that modules
are reloaded if required. For example:
import yourmodule1
import yourmodule2
import gramex.cache
gramex.cache.reload_module(yourmodule1, yourmodule2)
Files can auto-reload. When using FileHandler, files and modules are always auto-reloaded. So are Login templates, DataHandler templates, QueryHandler templates, etc.
When your code loads files, use gramex.cache.open. This auto-reloads files if they have changed.
Queries can auto-reload. For SQL data, use gramex.cache.query. This re-runs the query if state has changed.
Press Ctrl+D on the console to start the Python debugger
inside Gramex at any time.
Run gramex --settings.debug to trigger the debug mode.
When any template or Python file changes, the application will reload.
On Windows, you need to run python -m gramex --settings.debug instead,
due to a Tornado issue.
The Python debugger lets you stop, inspect and step through code line-by-line. You can learn more from this video tutorial on pdb and this detailed talk.
There are many ways to start the debugger:
breakpoint() to your code. Python will
run until this line and start the debugger.Ctrl+D on the console at any time. Python
will start the debugger.gramex --settings.debug. When there’s an exception, Python will start
the debugger at the line before the error. (This was called debug_exception
in Gramex 1.0.7 and debug.exception in Gramex 1.0.8. It is not merged into
settings.debug.)python -m pdb /path/to/gramex/__main__.py.v1.88. You can replace the default Python debugger pdb by setting the
PYTHONBREAKPOINT environment variable:
PYTHONBREAKPOINT=ipdb.set_trace - IPython-enabled pdbPYTHONBREAKPOINT=pdbpp.set_trace - a drop-in replacement for pdbPYTHONBREAKPOINT=pudb.set_trace - a full-screen console-based debuggerPYTHONBREAKPOINT=wdb.set_trace - a web debuggerPYTHONBREAKPOINT=webpdb.set_trace - a web UI for pdbHere are some useful things you can do on the debugger:
b <function>, then run by typing c.import(<module>); reload(<module>)import gramex, yaml; p yaml.dump(gramex.conf.url)Useful commands you can use on the debugger:
c # Continue running the program
pp value # Pretty-print value
!<python-code> # Run the Python code in the current context
b function # Set a breakpoint at a function
b file:line # Set a breakpoint at file, on line
clear function # Clear breakpoint at a function
s or step # Step into the current line's function
n or next # Next line (without entering the current function)
l or list # List the code
h or help # Help -- list available commands
gramex.debug.print() is an improved print function for debugging. For example:
from gramex.debug import print
def run():
print('we are here')
… will print: d:/path/to/module.py(7).run: we are here
It’s better to use keyword arguments – this also prints variable names:
>>> val = [10, 20]
>>> print(val=val)
<stdin>(1).<module>:
.. val = [10, 20]
It pretty-prints complex variables. For example:
>>> print(val=['This is a long sentence, repeated thrice. '] * 3)
<stdin>(1).<module>:
.. val = [ 'This is a long sentence, repeated thrice. ',
.. 'This is a long sentence, repeated thrice. ',
.. 'This is a long sentence, repeated thrice. ']
Remember to remove all print statements before committing your code.
Add the @gramex.debug.trace() decorator before any function to print every line
it executes. For example:
from gramex.debug import trace
@trace()
def run():
x = 1
y = 2
return x + y
… will print:
--- modulename: module, funcname: run
module.py(5): x = 1
module.py(6): y = 2
module.py(7): return x + y
Remember to remove all trace statements before committing your code.
gramex.debug provides support for timing and line profiling via timer,
Timer and lineprofile.
timer() prints the time since last called. For example:
from gramex.debug import timer
def function(handler):
timer('start')
some_code()
timer('ran some_code()')
prints this log message:
I 05-May 08:16:38 debug:54 0.102s start [module.function:56]
I 05-May 08:16:38 debug:54 0.012s ran some_code() [module.function:58]
The log message includes the time taken to get to the line (e.g. 0.102s), the
message logged, and the module.function:line-number from where the timer()
was called.
Timer() is similar to timer(), but shows the time for an block of code. For
example:
from gramex.debug import Timer
def function(handler):
with Timer('run some_code()'):
some_code()
prints this log message:
I 05-May 08:16:38 debug:54 0.012s run some_code() [module.function:56]
The log message includes the time taken to get to the line (e.g. 0.102s), the
message logged, and the module.function:line-number from where the Timer()
was called.
lineprofile is a decorator that prints the time taken for each line of a
function every time it is called. This example prints each line’s performance:
import pandas as pd
from gramex.debug import lineprofile
@lineprofile
def calc():
data = pd.Series([x*x for x in range(1000)])
diff = data.diff()
acf = data.autocorr()
return acf
Running calc() prints this result:
Timer unit: 3.52616e-07 s
Total time: 0.00198735 s
File: <ipython-input-8-af6a7bd543d9>
Function: calc at line 4
Line # Hits Time Per Hit % Time Line Contents
==============================================================
4 @lineprofile
5 def calc():
6 1001 3023 3.0 53.6 data = pd.Series([x*x for x in range(1000)])
7 1 613 613.0 10.9 diff = data.diff()
8 1 1998 1998.0 35.5 acf = data.autocorr()
9 1 2 2.0 0.0 return acf
The % time columns is noteworthy. This tells us that more than 50% of the time is going into constructing the series in line 6.
This requires the line_profiler module.
Run conda install line_profiler to install it.