Mostrando postagens com marcador WSGI. Mostrar todas as postagens
Mostrando postagens com marcador WSGI. Mostrar todas as postagens

sábado, 27 de novembro de 2010

Flask

Flask Há diversos frameworks em Python para Web, Django, Zope, web2py, Pyramid e TurboGears e Pylons.

Venho aqui para falar de um microframework chamado Flask.

Simples, flexível e poderoso, é capaz de manter desde o projeto mais simples até CMS no estilo Django ou grandes aplicações como em Pylons.

A instalação é também extremamente simples, já que se encontra no PyPI:
bash$ easy_install Flask


Como exemplo vou mostrar uma aplicação ao estilo Flask, registrando as URLs com decorador route, mas para aplicações mais complexas sugiro criar um arquivo url_rules.py que importe o objeto aplicação e use o método add_url_rule em vez do decorador.

Nossa aplicação simples exibirá o conteúdo dos arquivos em /proc/ dos sistemas Unix (por falta de ideia melhor).

Podemos começar importanto os recursos necessários:
from flask import Flask, make_response


  • Flask: classe da aplicação
  • make_response: função capaz de criar um objeto de resposta HTTP


Para a leitura dos arquivos e diretórios vamos precisar do módulo os:
import os


Vamos agora criar duas funções, uma que retorne a listagem de arquivos para um diretório e outra que retorne o conteúdo de um arquivo:
def list_dir(path):
filelist = os.listdir(path)
filelist.sort()
return '\n'.join(filelist)


def read_file(path):
data = 'NO DATA'
with open(path, 'r') as fd:
data = fd.read()
return data


Agora é possível criar a aplicação:
app = Flask(__name__)
app.debug = True


Podemos então criar uma função que receba o caminho do arquivo/diretório a ser lido e retorne para o navegador.

Caso seja necessário editar os cabeçalhos ou lidar com qualquer peculiaridade do objeto de resposta HTTP, é possível instanciá-lo manualmente. Caso contrário, retornar uma simples string já faz com que ela seja entendida como o conteúdo do objeto.

Se uma tupla for retornada, o primeiro valor será o conteúdo e o segundo o status de retorno.

Sabendo disso, podemos definir a função:
@app.route('/<path:filename>/')
def read_proc(filename):
real_path = os.path.join('/proc', filename)
data = 'NO DATA'

try:
if os.path.isfile(real_path):
data = read_file(real_path)

elif os.path.isdir(real_path):
data = list_dir(real_path)

else:
return 'NOT FOUND', 404

# Criando HTTP response apenas para editar headers
response = make_response(data)
response.headers['Content-Type'] = 'text/plain'
return response

except IOError:
# Você não pode ler este arquivo/diretório!
return 'BAD REQUEST', 400


A rota indica que o argumento filename receberá como parâmetro toda a URL passada (path: indica uma string com /).

Para a raiz da aplicação, poderíamos usar as funções redirect e url_for, por exemplo:
@app.route('/')
def index():
return redirect(url_for('read_proc', filename='cpuinfo'))


O que redirecionaria para a URL referente à função read_proc, passando 'cpuinfo' como parâmetro, mas faz mais sentido retornar o resultado da função:
@app.route('/')
def index():
return read_proc('')


Agora só falta colocar a aplicação para rodar:
if __name__ == '__main__':
app.run(host='0.0.0.0')


Execute o script e acesse no navegador: http://localhost:5000/ – você verá a listagem do diretório /proc/.

Acesse no navegador: http://localhost:5000/cpuinfo/ e você verá o conteúdo do arquivo /proc/cpuinfo.

Pretendo em uma próxima oportunidade demonstrar com construir uma estrutura mais complexa usando um arquivo com roteamente em vez de decorador.

Para mais diversão, leia a documentação e fascine-se também com a quantidade de vezes que a expressão «you don’t have to deal with that» se repete.

[]’s
Cacilhας, La Batalema

terça-feira, 3 de julho de 2007

Pylons

Esse texto é baseado em um e-mail que eu mandei para a lista PythonBrasil, porém mais completo que o e-mail.


Pylons é uma das opções que o desenvolvedor Python tem dentro dos frameworks para desenvolvimento web.

Um dos seus diferenciais é que ele é todo centrado em WSGI - Web Server Gateway Interface, que é uma PEP que descreve como os aplicativos devem se comunicar com o servidor web. Qual a vantagem disso? Uma modularização razoavelmente padronizada que é totalmente interessante.


Suporta SQLObject e SQLAlchemy (a maioria atualmente esteja dando preferência ao último). Embora o SQL Alchemy use o padrão de projeto DataMapper é possível transformá-lo em um ActiveRecord usando o Elixir. Isso com certeza irá agradar os usuários do rails.


Não só isso – a integração com JavaScript é feita à la Rails, incluindo os helpers com suporte a Prototype e Scriptaculous e o sistema de despacho do Pylons é baseado no do Ruby (Routes).


Usando os mecanismos do WSGI, a autenticação pode ser feita por um middleware, o AuthKit. Para algo ultra-simples, um cadastro que apenas um usuário vá usar, é possível gerar um formulário de login usando apenas as configurações do middleware. Simples e funcional.


Quais seriam as vantagens desses middlewares e do amplo suporte a WSGI? Um exemplo simples: você tem uma aplicação com o Pylons, e precisa adicionar um wiki a ela. É fácil desenvolver um, mas que tal usar o MoinMoin? Mas e a base de usuários, terei de duplicar? Bom, como o MoinMoin também implementa interfaces pra WSGI, você embute ele em um controlador e usa a própria autenticação do AuthKit. Interessante não?


Para modelos, o Pylons usa o Buffet, que é uma API de intercambiabilidade de motores de modelo. No cardápio, Myghty, Mako, Genshi e Kid e Cheetah (por enquanto).

Dos três principais frameworks pra web em Python (Django[2003-2004],TurboGears[início de 2005] e Pylons[fim de 2005]), o Pylons é o mais novo. Mas nem por isso deixa de surpreender: a movimentação para o TurboGears 2.0 é que ele seja implementado em cima do Pylons! Só por esse tipo de notícia já vale a pena colocar o Pylons na sua lista de coisas a testar!

sábado, 23 de junho de 2007

LuaWsgi

Lua/Python Como eu havia prometido nas Reflexões de Monte Gasppa e Giulia C., aqui está o artigo sobre LuaWsgi.

Histórico


Eu ia contar aqui a história de como surgiu o LuaWsgi, mas decidi não fazer isso.

Basta dizer que envolve intriga, maus entendidos e até uma certa dose de má fé.

Mas também gostaria de dizer que desenvolvi o primeiro protótipo funcional em apenas um domingo de diversão.

Outra coisa que é importante dizer é que LuaWsgi nasceu como uma terapia e resolvi publicá-lo para ser meu trabalho de conclusão de curso.

O que é WSGI?


WSGI é uma proposta formal de melhoria para Python, PEP, que sugere uma nova abordagem para o desenvolvimento web mais simpática para programadores.

A forma original como páginas web foram concebidas é muito interessante para não-programadores, pois o HTTP era apenas uma extensão do FTP voltada para a visualização.

Usando HTML, uma linguagem de marcação, era possível criar páginas atraentes com pouco ou nenhum conhecimento de programação.

Porém «marcação» não permite muitos recursos usados na programação. Para suprir essa necessidade, foram criados o CGI as páginas dinâmicas, que são geradas por um programa.

Depois criaram os servlets.

Até aqui, no entanto, o formato continuava desconfortável para programadores – apesar de «arrastadores de componentes» (component drag-n-droppers) se sentirem verdadeiros programadores assim e de alguns servlets serem bastante amigáveis.

Então Phillip J. Eby sugeriu uma API mais interessante para Python: WSGI.

E WSGI é ainda mais! A proposta foi tão bem feita que pode ser implementada em quase qualquer linguagem de programação, quase como um protocolo!

Para saber mais leia a PEP 333.

O que é Lua?


Lua é uma linguagem de programação livre projetada e implementada em 1993 por uma equipe no Lablua da PUC-Rio.

Atualmente se encontra na versão 5.1.2.

É uma linguagem estruturada, orientada a tabelas e com suporte a orientação a objetos.

Sua tipagem é dinâmica, como Python. Não é tão forte quanto a tipagem de Python, mas possui sete tipos bem definidos e de conversão simplificada quando possível.

Para saber mais, leia o livro do Roberto Ierusalimschy.

O que é LuaWsgi?


É uma implementação de WSGI para linguagem de programação Lua da forma mais precisa possível.

Dependências


Para instalar LuaWsgi você precisa instalar antes:


Mas há um jeito mais fácil…

Você pode simplesmente instalar o Projeto Kepler, que já traz todos os módulos que vamos precisar.

Até agora – o momento em que escrevo – não há uma versão final do Kepler 1.1. Se quando você for baixar houver, baixe-a. Se não, baixe o último snapshot.

Obs.: para instalar Kepler 1.1, você precisa ter instalado Expat, ZZipLib, algum SGBD e GNU Readline (você provavelmente possui algum ou todas as dependências, mas é bom verificar).

Não siga as instruções de instalação de Kepler. Faça o seguinte:

Desempacote o tarball (tar xzvf kepler-*.tar.gz). Isso irá gerar um diretório kepler-1.1/. Acesse-o.

Então execute o ./configure com as seguintes opções:
bash$ ./configure --prefix=/usr \
--sysconfdir=/etc \
--lua-suffix='' \
--kepler-web=/var/xavante \
--with-optional=lualogging,luasql,luaexpat,luazip,md5 \
--enable-lua


O que estamos fazendo é dizendo para o configurador onde o instalador deve colocar os arquivos, que módulos queremos usar (todos) e para instalar Lua também.

Você também pode usar a opção --with-luasql-driver= para especificar qual SGBD você está usando. Para obter informações tente:
bash$ ./configure --help


Se tudo correr bem, o resto é instalação padrão:
bash$ make
bash$ sudo make install


Se não houver problemas, você já terá todos os módulos que precisará instalados – e mais alguns úteis. Se quiser testar o servidor web Xavante, ele também estará instalado – mas aí já é outro assunto.

Opa! Falta ainda instalar o lua-unistd!

Você tem duas escolhas: 1baixar o fonte e compilá-lo ou 2baixar o binário pré-compilado.

Acredito que o binário seja suficiente, mas se você tiver problemas, para compilar o fonte o comando é:
bash$ gcc -c -fPIC -O3 -Wall unistd.c
bash$ ld -shared -lm -lcrypt unistd.o -o libunistd.so.1.0.1


Mova a biblioteca para /usr/lib/lua/5.1/ e crie neste mesmo diretório uma ligação (link) simbólica chamada unistd.so:
bash# ln -s libunistd.so.1.0.1 unistd.so


Configurando o sistema


Apesar de Kepler não precisar de variáveis de ambiente, LuaWsgi precisa. Crie as seguintes variáveis:
export LUA_PATH=?.lua;?/?.lua;/usr/share/lua/5.1/?.lua;/usr/share/lua/5.1/?/?.lua


Se estiver difícil de visualizar no navegador, trata-se da seguinte sequência, trocando as mudanças de linha por ponto-e-vírgula:
?.lua
?/?.lua
/usr/share/lua/5.1/?.lua
/usr/share/lua/5.1/?/?.lua


A outra variável é:
export LUA_CPATH=?.so;l?.so;/usr/lib/lua/5.1/?.so;/usr/lib/lua/5.1/?/?.so


Idem acima:
?.so
l?.so
/usr/lib/lua/5.1/?.so
/usr/lib/lua/5.1/?/?.so


Aconselho colocar esses comandos em /etc/profile

Agora, para testar, execute o seguinte:
bash$ lua
Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
> require "unistd"


Se nenhum erro ocorrer, você já está com o ambiente configurado! ;)

Finalmente: instalando LuaWsgi


Essa parte é complicada… =D hehehehehe

Baixe o pacote mais recente da página de arquivos (a versão mais recente no momento em que escrevo é a 7.06.1).

Desempacote o tarball em /usr/share/lua/5.1/:
bash# tar xzvf luawsgi-*.tar.gz -C /usr/share/lua/5.1/


E pronto!

Primeiro exemplo


Crie um arquivo (pode ser em seu homedir) chamado teste.lua:
require "wsgi"
require "wsgi.session"
require "middleware.auth"


local function authhandler(user, pass)
return user == "eu" and pass == "senha"
end


local function app(environ, start_response)
-- Cria ambiente de sessão
local session = wsgi.session(environ, start_response)

-- Se não houver um login, lê de POST
if not session.login then
print "Criando login com dados de POST"
session.login = environ.params.login
end
print("Usuário: " .. session.login)

-- Configura status e cabeçalho (não envia)
start_response { "200 OK";
["Content-Type"] = "text/html; charset=utf-8",
}

-- Encerra retornando o corpo da página
return {
"<html>\n",
"<head>\n",
"<title>Ola ",
(environ.params.login or ""),
"</title>\n",
"</head>\n",
"<body>\n",
'<form action="" method="POST">\n',
'<input type="text" id="login" ',
'name="login" />\n',
'<input type="submit" />\n',
"</body>\n",
"</html>\n",
}
end


-- Este middleware garante autenticação
app = middleware.auth(app, authhandler)
wsgi.serve { app; host="*", port=8001 }


O submódulo wsgi.session permite um acesso fácil a sessão e o submódulo middleware.auth oferece recursos para autenticação.

Salve execute:
bash$ lua teste.lua


E acesse no navegador http://localhost:8001. Veja na função authhandler() que o usuário é «eu» e a senha é «senha».

Descendo o rio… AJAX


Vamos usar AJAX? Para isso temos o submódulo wsgi.ajax. Crie testeDeAjax.lua:
require "wsgi"
require "wsgi.ajax"


local function app(environ, start_response)
-- Cria ambiente AJAX
local ajax = wsgi.ajax(environ, start_response)

ajax.export("som", function (x, y) return x + y end)
ajax.export("sub", function (x, y) return x - y end)
ajax.export("mul", function (x, y) return x * y end)
ajax.export("div", function (x, y) return x / y end)

-- Descomente para depuração
--ajax.setdebug()

-- Responde AJAX
if ajax.handle then
return ajax.handle()
end

-- Configura status e cabeçalho
start_response{ "200 OK";
["Content-Type"] = "text/html; charset=utf-8",
["Cache-Control"] = "no-cache, must-revalidate",
["Pragma"] = "no-cache",
}

-- Retorna o corpo da página (recheado de JavaScript!)
return {[[<html>
<head>
<title>Teste de AJAX</title>
<script language="javascript"><!--
]],
ajax.get_js(),
[[
function set_x(x) {
document.getElementById('x').value = x;
document.getElementById('y').value = '';
}

function som() {
var x, y;
x = document.getElementById('x').value;
y = document.getElementById('y').value;
ajax_som(x, y, set_x);
document.getElementById('y').focus();
return true;
}

function sub() {
var x, y;
x = document.getElementById('x').value;
y = document.getElementById('y').value;
ajax_sub(x, y, set_x);
document.getElementById('y').focus();
return true;
}

function mul() {
var x, y;
x = document.getElementById('x').value;
y = document.getElementById('y').value;
ajax_mul(x, y, set_x);
document.getElementById('y').focus();
return true;
}

function div() {
var x, y;
x = document.getElementById('x').value;
y = document.getElementById('y').value;
ajax_div(x, y, set_x);
document.getElementById('y').focus();
return true;
}
//--></script>
<style rel="stylesheet"><!--
body {
font-size: 14pt;
text-align: center;
}
--></style>
</head>
<body onLoad="document.getElementById('x').focus(); return true;">
<input type="txt" id="x" value="2" />
?
<input type="txt" id="y" value="3" />
<br />
<input type="button" value="+" onClick="som()" />
<input type="button" value="-" onClick="sub()" />
<input type="button" value="×" onClick="mul()" />
<input type="button" value="÷" onClick="div()" />
</body>
</html>
]]
}
end

wsgi.serve { app; host="*", port=8001 }


Execute:
bash$ lua testeDeAjax.lua


Agora acesse: http://localhost:8001.

Uma brincadeira com JSON


Fala-se muito atualmente em XML atualmente, que é um recurso interessante e até eficiente para o que se propõe.

Mas é um descaramento afirmar que XML seja pau pra toda obra. Quem diz isso ou está iludido ou está querendo enganar alguém.

Por exemplo, para transferência de dados em tempo real, XML é altamente ineficiente.

Para tanto temos JSON.

Além de LuaWsgi trazer integrado JSON4Lua, o submódulo wsgi.ajax possui uma função que adapta o comportamento de uma função para trabalhar com JSON.

Vamos ao exemplo testeDeJson.lua:
require "wsgi"
require "wsgi.ajax"

local function dobro(t)
print(t.val)
return { val = t.val * 2 }
end

local function app(environ, start_response)
local ajax = wsgi.ajax(environ, start_response)

-- Esta é a função JSON-import → jsonport ;)
ajax.jsonport("nada", dobro)

if ajax.handle then
return ajax.handle()
end

start_response{ "200 OK";
["Content-Type"] = "text/html; charset=utf-8",
["Cache-Control"] = "no-cache, must-revalidate",
["Pragma"] = "no-cache",
}

return {[[<html>
<head>
<title>Teste de AJAX</title>
<script
type="text/javascript"
src="http://www.json.org/json.js"
></script>
<script language="javascript"><!--
]],
ajax.get_js(),
[[
function set_x(x) {
var e = x.parseJSON();
document.getElementById("x").value = e.val;
return true;
}

function nada() {
var o = { "val": document.getElementById("x").value };
ajax_nada(o.toJSONString(), set_x);
return true;
}
//--></script>
<style rel="stylesheet"><!--
body {
font-size: 14pt;
text-align: center;
}
--></style>
</head>
<body>
<input type="text" id="x" value=" " />
<input type="button" value="Vai!" onClick="nada()" />
</body>
</html>
]]
}
end

wsgi.serve { app; host="*", port=8001 }


Mesmo esquema!

Conclusão


Ainda há mais o que ver sobre LuaWsgi, como o middleware publicador (middleware.publisher) e mais algumas coisinhas interessantes, mas este artigo já se tornou extenso demais. =(

Estão todos convidados a experimentar LuaWsgi e, mais importante, a participar de seu desenvolvimento!

[]'s
Rodrigo Cacilhas