rapid, puternic, ușor de folosit
configurare, utilitare, dispeceri
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""CherryPy - Motivație"""
import cherrypy
class Motivatie(object):
"""CherryPy oferă dezvoltatorilor posibilitatea de a construi o aplicație
web în aceeași manieră în care ar construi orice altă aplicație folosind
programarea obiectuală."""
@cherrypy.expose
@cherrypy.tools.json_out()
def index(self):
"""Câteva avantaje aduse de CherryPy."""
return {"avantaje": ["ușor de folosit", "foarte puternic",
"multe resurse", "dimensiuni mici",
"modificări în timp real"]}
if __name__ == "__main__":
# Pornim aplicațua
cherrypy.quickstart(Motivatie())
# Putem adăuga setări folosind update
cherrypy.config.update({
"server.socket_host": "127.0.0.1",
"server.socket_port": 80,
"log.error_file": "/tmp/logs/applicatia_mea/error.logs",
"request.show_tracebacks": False,
"environment": "production"
})
# Sau putem încărca setările dintr-un fișier de configurare.
# Argumentul poate fi numele fișierului de configurare sau un fișier deschis
cherrypy.config.update(configurare
)
[global]
server.socket_host: "0.0.0.0"
server.socket_port: 80
log.error_file: "/tmp/logs/applicatia_mea/error.logs"
request.show_tracebacks: False
environment: "production"
[/]
tools.trailing_slash.on = False
request.dispatch: cherrypy.dispatch.MethodDispatcher()
[/forum]
methods_with_bodies = ("POST", "PUT", "PROPPATCH")
# Putem adăuga setări pentru tot arborele de aplicații
config = {'/':{
'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
'tools.trailing_slash.on': False}}
cherrypy.tree.mount(Root(), config=config)
# Sau putem specifica pentru fiecare aplicație în parte setările dorite
cherrypy.tree.mount(root1, "", appconf1)
cherrypy.tree.mount(root2, "/forum", appconf2)
cherrypy.tree.mount(root3, "/blog", appconf3)
# Putem activa/dezactiva o unealtă folosind setările
[/exemplu]
tools.staticdir.on: True
tools.staticdir.root: "/path/to/app"
tools.staticdir.dir: "static"
# Putem activa și configura uneltele pentru fiecare aplicație
class Exemplu(object):
_cp_config = {"tools.staticdir.on": True,
"tools.staticdir.root": "/path/to/app",
"tools.staticdir.dir": "static"}
class Exemplu(object):
# Putem folosi unealta ca și decorator
@tools.staticdir(root="/path/to/app", dir='static')
def page(self):
# ...
class MentorValid(cherrypy.Tool):
"""Verificăm dacă membrul este valid"""
def __init__(self):
cherrypy.Tool.__init__(self, 'before_handler',
self.check, priority=10)
def check(self, mentori=None):
"""Verificăm dacă parametrul mentor este în lista primită"""
mentor = cherrypy.request.params.get('mentor', None)
if (mentor and mentori) and mentor not in mentori:
raise cherrypy.HTTPError(400, "Mentorul nu exista")
cherrypy.tools.mentor_valid = MentorValid()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cherrypy
def adauga_antete():
"""Adăugăm antetele recomandate pentru sporirea securității
https://www.owasp.org/index.php/List_of_useful_HTTP_headers
"""
headers = cherrypy.response.headers
headers['X-Frame-Options'] = 'DENY'
headers['X-XSS-Protection'] = '1; mode=block'
headers['Content-Security-Policy'] = "default-src='self'"
cherrypy.tools.adauga_antete = cherrypy.Tool('before_finalize', adauga_antete,
priority=60)
import cherrypy
def protect(users):
if cherrypy.request.login not in users:
raise cherrypy.HTTPError("401 Unauthorized")
cherrypy.tools.protect = Tool('on_start_resource', protect)
@cherrypy.expose
@cherrypy.tools.protect(users=['alex', 'claudiu', 'cmin'])
def resource(self):
return "Bine ai venit, {}!".format(cherrypy.request.login)
on_start_resource | primul punct de legătură |
before_request_body | înainte de a se procesa corpul cererii |
before_handler | înainte de a fi apelată o funcție ce procesează această cerere (funcție expusă) |
before_finalize | imediat după ce pagina a fost procesată și imediat înainte ca CherryPy să formateze răspunsul pentru client |
on_end_resource | procesarea s-a încheiat răspunsul este gata pentru a fi trimis spre client |
before_error_response | inainte de a se răspunde cu un cod de eroare |
after_error_response | imediat după ce s-a răspuns cu un cod de eroare |
on_end_request | răspunsul a fost trimis către server |
root = cherrypy.Application.root()
root.index = RoPython()
root.membri = Membri(["Alex", "Claudiu", "Cosmin"])
root.contact = Contact("contact@ropython.org")
root.evenimente = Evenimente(["workshop"])
root.evenimente.workshop = Workshop("Python pentru web")
class Membri(object):
def __init__(self, membri):
self.membri = membri
@cherrypy.expose
def index(self):
return "Echipa noastra {}".format(", ".join(self.membri))
class RoPython(object):
membri = Membri(["Alex", "Claudiu", "Cosmin"])
@cherrypy.expose
def index(self):
return "Grupul pasionaților de Python din România !"
class Student(object):
def __init__(self, nume):
self.nume, self.note = nume, {}
@cherrypy.expose
def index(self, **kargs):
mesaj = ["Notele elevului {} sunt".format(self.nume), str(kargs)]
for materie in self.note:
mesaj.append("{}: {}".format(materie, self.note[materie]))
return "".join(mesaj)
@cherrypy.expose
def update(self, materie, nota):
self.note[materie] = nota
return "OK"
dispecer = cherrypy.dispatch.RoutesDispatcher()
dispecer.connect(name='alex', route='/alex', controller=Student('Alex'),
action='index', conditions=dict(method=['GET']))
dispecer.mapper.connect('alex', controller='alex',
action='update', conditions=dict(method=['POST']))
cherrypy.tree.mount(root=None, config={'/': {'request.dispatch': dispecer}})
cherrypy.engine.start()
cherrypy.engine.block()
import cherrypy
from cherrypy._cpdispatch import Dispatcher
class Aplicatie(object):
@cherrypy.expose
def salut(self, length=8):
return "Salut !"
class URLAmuzant(Dispatcher):
def __call__(self, path_info):
return Dispatcher.__call__(self, path_info.lower())
if __name__ == '__main__':
conf = {'/': {'request.dispatch': URLAmuzant()}}
cherrypy.quickstart(Aplicatie(), '/', conf)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cherrypy
class Aplicatie(object):
def index(self):
"""Prima pagina"""
return "Bine ați venit !"
def default(self, *args, **kargs):
"""În cazul în care nu a fost găsită nici o potrivire"""
return "Resursa căutata nu este implementată! "
index.exposed = True
despre.exposed = True
default.exposed = True
cherrypy.quickstart(Aplicatie())
@cherrypy.popargs('organizatie')
class Organizatie(object):
def __init__(self):
self.evenimente = Evenimente()
@cherrypy.expose
def index(self, organizatie):
return "Bine ai venit pe: {}".format("organizatie")
@cherrypy.popargs('eveniment')
class Evenimente(object):
@cherrypy.expose
def index(self, organizatie, eveniment):
return ("Despre evenimentul {} organizat de {}"
.format(eveniment, organizatie))
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import random
import string
import cherrypy
class CodPin(object):
exposed = True
def GET(self):
return cherrypy.session['cod_pin']
def POST(self, lungime=4):
cherrypy.session['cod_pin'] = ''.join(random.sample(string.hexdigits,
int(lungime)))
return ""
def PUT(self, cod_pin):
cherrypy.session['cod_pin'] = cod_pin
def DELETE(self):
cherrypy.session.pop('cod_pin', None)
if __name__ == '__main__':
conf = {
'/': {
'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
'tools.sessions.on': True,
'tools.response_headers.on': True,
'tools.response_headers.headers': [('Content-Type', 'text/plain')],
}
}
cherrypy.quickstart(CodPin(), '/', conf)
>>> import requests
>>> sesiune = requests.Session()
>>> sesiune.post("http://127.0.0.1:8080", {"lungime": 8})
Response [200]
>>> sesiune.get("http://127.0.0.1:8080")
Response [200]
>>> sesiune.get("http://127.0.0.1:8080").text
u'8EAa94bd'
>>> sesiune.put("http://127.0.0.1:8080", {"cod_pin": "123456789"})
Response [200]
>>> sesiune.get("http://127.0.0.1:8080").text
u'123456789'
>>> sesiune.delete("http://127.0.0.1:8080")
Response [200]
class Rezervare(object):
exposed = True
def __init__(self):
self.mentor = {"Alex": [], "Claudiu": [], "Cosmin": []}
@cherrypy.tools.json_out(content_type='application/json')
@cherrypy.tools.mentor_valid(mentori=["Alex", "Claudiu", "Cosmin"])
def GET(self, mentor=None):
"""Request de tip GET - Afișăm informațiile"""
if mentor in self.mentor:
return self.mentor[mentor]
return self.mentor
@cherrypy.tools.json_out(content_type='application/json')
@cherrypy.tools.mentor_valid(mentori=["Alex", "Claudiu", "Cosmin"])
def POST(self, mentor, echipa):
"""Request de tip POST - Adăugăm o resursă"""
if not mentor in self.mentor:
raise cherrypy.HTTPError(404)
if self.mentor[mentor]:
raise cherrypy.HTTPError(409)
return self.mentor[mentor].append(echipa)
@cherrypy.tools.mentor_valid(mentori=["Alex", "Claudiu", "Cosmin"])
def DELETE(self, mentor):
"""Request de tip DELETE - Ștergem o resursă"""
if not self.mentor[mentor]:
raise cherrypy.HTTPError(404)
return self.mentor[mentor].pop()
if __name__ == '__main__':
conf = {'/': {'request.dispatch': cherrypy.dispatch.MethodDispatcher()}}
cherrypy.quickstart(Rezervare(), '/', conf)
>>> requests.post("http://127.0.0.1:8080/", {"mentor": "Alex", "echipa": "RoPython"})
Response [200]
>>> requests.get("http://127.0.0.1:8080/")
Response [200]
>>> requests.get("http://127.0.0.1:8080/").text
u'{"Claudiu": [], "Alex": ["RoPython"], "Cosmin": []}'
>>> requests.delete("http://127.0.0.1:8080/Alex")
Response [200]
>>> requests.get("http://127.0.0.1:8080/")
Response [200]
>>> requests.get("http://127.0.0.1:8080/").text
u'{"Claudiu": [], "Alex": [], "Cosmin": []}'
>>> requests.delete("http://127.0.0.1:8080/Alex")
Response [404]
class Echo(object):
"""Aplicatie care va returna mesajul primit"""
@cherrypy.expose
def index(self):
"""Prima pagină"""
return "Bine ați venit."
@cherrypy.expose
def echo(self, mesaj=None):
"""Va returna valoarea parametrului message"""
if not mesaj:
raise cherrypy.HTTPError(404, "Lipseste paramentrul mesaj!")
return mesaj
# -*- coding: utf-8 -*-
import cherrypy
from cherrypy.test import helper
class RootTest(helper.CPWebCase):
"""Suita de teste pentru aplicația Echo"""
@staticmethod
def setup_server():
"""Setarile pentru applicatie"""
cherrypy.tree.mount(Echo())
def test_mesaj_valid(self):
"""Trimitem un mesaj valid și verificăm răspunsul aplicației"""
self.getPage("/echo?mesaj=Workshop%20RoPython%20pentru%20Web")
self.assertStatus('200 OK')
self.assertHeader('Content-Type', 'text/html;charset=utf-8')
self.assertBody('Workshop RoPython pentru Web')
def test_lipsa_mesaj(self):
"""Nu trimitem parametrul referitor la mesaj"""
self.getPage("/echo")
self.assertStatus(404)