Difference between revisions of "Short Notes on Python"
(→Decorators) |
|||
Line 78: | Line 78: | ||
** of course, create link in ''/etc/nginx/sites-enabled/'', and restart nginx, | ** of course, create link in ''/etc/nginx/sites-enabled/'', and restart nginx, | ||
− | === Run uWSGI daemon on boot === | + | === Run uWSGI daemon on boot - supervisor === |
+ | |||
+ | * install <tt>supervisor</tt> | ||
+ | apt-get install supervisor | ||
+ | * add/edit <tt>/etc/supervisord.conf</tt> with content like this: | ||
+ | <pre>[unix_http_server] | ||
+ | file=/run/supervisor.sock | ||
+ | |||
+ | [supervisord] | ||
+ | logfile=/var/log/supervisord.log | ||
+ | logfile_maxbytes=1MB | ||
+ | logfile_backups=1 | ||
+ | loglevel=info ; (others: warn,debug,trace) | ||
+ | pidfile=/run/supervisord.pid | ||
+ | nodaemon=false | ||
+ | minfds=1024 | ||
+ | minprocs=200 | ||
+ | |||
+ | [supervisorctl] | ||
+ | serverurl=unix:///run/supervisor.sock | ||
+ | |||
+ | [program:your app] | ||
+ | directory=/path/to/app | ||
+ | command=/usr/bin/uwsgi --ini wsgi.ini | ||
+ | autostart=true | ||
+ | autorestart=true | ||
+ | stdout_logfile=/var/log/uwsgi.log | ||
+ | redirect_stderr=true | ||
+ | stopsignal=QUIT</pre> | ||
+ | |||
+ | === Run uWSGI daemon on boot - systemd === | ||
* create ''systemd'' file for uWSGI, ''/etc/systemd/system/uwsgi-app.service'': | * create ''systemd'' file for uWSGI, ''/etc/systemd/system/uwsgi-app.service'': |
Revision as of 09:46, 18 October 2016
Contents
Timing, and memory, on Linux
Timing
On Linux, it's safer to use time.time()
import time t = time.time() # do some stuff print "stuff took %1.3f", time.time() - t, "seconds"
On Windows, AFAIK, it's safer to use time.clock()
Memory
For me, the following does a good job getting memory usage (in kB) on Linux:
import resource print resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
Since resource is standard package, it should work on Windows too, but I don't know if it does, or what units are used if it works.
Importing Files
If you need to import a file '../mylib/commons.py', you can use the following snippet:
import sys, os fld = os.path.realpath(os.path.abspath(os.path.join('..', 'mylib'))) if fld not in sys.path: sys.path.insert(0, fld) import commons # use your commons.py module now... commons.super_function()
uWSGI, nginx, Flask
- install uwsgi (incl. uwsgi python plugin), python flask, and nginx,
Setting Up uWSGI
- create main.py file that will hold the server logic, for instance:
from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "hello there!"
- create uwsgi config file, wsgi.ini (minimal version here; read uwsgi docs for head-spinning array of configurables):
[uwsgi] module = main:app master = true processes = 5 socket = 127.0.0.1:8000 protocol = http plugin = python
- run uwsgi
uwsgi --ini wsgi.ini
- check that all works on http://localhost:8000/
Adding nginx Layer
- remove the "protocol" directive from wsgi.ini, and add "die-on-term":
[uwsgi] module = main:app master = true processes = 5 socket = 127.0.0.1:8000 plugin = python die-on-term = true
- add a new vhost to nginx - /etc/nginx/sites-available/app.nginx:
server { listen 80; server_name my.awesome.domain; location / { include uwsgi_params; uwsgi_pass 127.0.0.1:8000; } }
- communication through socket is also possible (see socket, chmod-socket, vacuum and other directives for uWSGI)
- of course, create link in /etc/nginx/sites-enabled/, and restart nginx,
Run uWSGI daemon on boot - supervisor
- install supervisor
apt-get install supervisor
- add/edit /etc/supervisord.conf with content like this:
[unix_http_server] file=/run/supervisor.sock [supervisord] logfile=/var/log/supervisord.log logfile_maxbytes=1MB logfile_backups=1 loglevel=info ; (others: warn,debug,trace) pidfile=/run/supervisord.pid nodaemon=false minfds=1024 minprocs=200 [supervisorctl] serverurl=unix:///run/supervisor.sock [program:your app] directory=/path/to/app command=/usr/bin/uwsgi --ini wsgi.ini autostart=true autorestart=true stdout_logfile=/var/log/uwsgi.log redirect_stderr=true stopsignal=QUIT
Run uWSGI daemon on boot - systemd
- create systemd file for uWSGI, /etc/systemd/system/uwsgi-app.service:
[Unit] Description=Job that runs the uWSGI app [Service] Type=simple WorkingDirectory=/home/project/flask-test/ ExecStart=/usr/bin/uwsgi --ini wsgi.ini [Install] WantedBy=multi-user.target
Then you can start and stop the uwsgi service using:
# systemctl start uwsgi-app.service # systemctl stop uwsgi-app.service
Once you're happy with the settings, enable the daemon to be run on boot:
# systemctl enable uwsgi-app.service
Decorators
Decorators are simple and expressive way to modify function without editing the source of the function itself. Or, the other way around, to modify multiple functions in the same way, without code duplication (DRY).
Decorators can be spotted in the code by starting with @ character. Decorator is a function (or class) that can do some additional work before or after the call to the decorated function. It can even call the decorated function multiple times, or not at all.
Decorators can be implemented as closures (my fave), or as classes; the following approaches are equivalent:
# using a function (closure) as a decorator def beforeAndAfter(f): def decorated_fn(): print("Before", f.__name__) f() print("After", f.__name__) return decorated_fn @entryExit def func(): print "func() is in da' house!" func()
# using a class as a decorator class beforeAndAfter(object): def __init__(self, f): self.f = f def __call__(self): print("Before", self.f.__name__) self.f() print("After", self.f.__name__) @beforeAndAfter def func(): print "func() is in da' house!" func()
Note that in functional decorator, anything outside the body of decorated_fn() is equivalent to content of the __init__() constructor of the class-based decorator. This code is run during the initialization, only once for each decorated function, regardless of whether the decorated function is ever called in the code - you should avoid any heavy lifting there.
Decorators can also accept arguments, and (obviously should) forward arguments to the decorated function:
def beforeAndAfter(p1, p2): def wrap(f): def wrapped_f(*args, **kwargs): print "Decorator arguments:", p1, p2 print("Before", f.__name__) f(*args, **kwargs) print("After", f.__name__) return wrapped_f return wrap @beforeAndAfter("hello", "world") def func(a, b=2): print "func() is in da' house,", a, b func(1)