Mercurial na web com apache e fastcgi

01/06/2008

Um efeito interessante do padrão WSGI é que ele pode tornar a vida dos sysadmins mais fácil. Por exemplo, publicar uma aplicação web em Python, com WSGI consiste apenas de:

  1. Descobrir como instanciar essa aplicação (específico de aplicação pra aplicação)
  2. Transformá-la em um cliente/middleware WSGI
  3. Publicá-la, usando a forma desejada.

Abaixo, segue um exemplo de uma publicação do mercurial, no apache, usando fastcgi.

#!/usr/bin/env python2.5
#
# An example CGI script to export multiple hgweb repos, edit as necessary
import site
import sys
site.addpackage('/home/usuario/lib/python2.5/site-packages/','easy-install.pth',set(sys.path))

# enable importing on demand to reduce startup time
from mercurial import demandimport; demandimport.enable()

# If you'd like to serve pages with UTF-8 instead of your default
# locale charset, you can do so by uncommenting the following lines.
# Note that this will cause your .hgrc files to be interpreted in
# UTF-8 and all your repo files to be displayed using UTF-8.
#
#import os
#os.environ["HGENCODING"] = "UTF-8"

from mercurial.hgweb.hgwebdir_mod import hgwebdir
import mercurial.hgweb.wsgicgi as wsgicgi
from flup.server.fcgi import WSGIServer

application = hgwebdir('hgweb.config')
WSGIServer(application, debug = True).run()

E o hgweb.config:

[paths]
repositorio1 = /home/usuario/hg/repositorio1
repositorio2 = /home/usuario/hg/repositorio2

Compare com o deploy de Pylons via fastcgi, por exemplo. Depois de termos instanciado a aplicação (e isso varia de framework ou aplicativo), a forma de executar como fastcgi no apache é a mesma, usando o flup. E isso serviria para qualquer aplicação que disponibilizasse uma 'saída' WSGI. Prático não?


Email por Walter Cruz em Python
Tags: fastcgi, mercurial, web, wsgi

Deploy simplificado de Pylons via FastCGI

30/03/2008

Em um pequeno projeto que fiz com Pylons, o arquivo a ser executado pelo FastCGI era como o seguinte:


#!/usr/bin/env python2.5
import os, sys
lib_path = "/home/usuario/lib/python2.5/site-packages/"
sys.path.append(lib_path)
sys.path.append('/home/usuario/projects_pylons/project/')
from pkg_resources import require
require("Pylons")
require('python-openid')
require("AuthKit")
require("Elixir")
require("flup")
require('docutils')
require("pygments")
from paste.deploy import loadapp
wsgi_app = loadapp('config:/home/usuario/projects_pylons/project/server.ini')
from flup.server.fcgi import WSGIServer
WSGIServer(wsgi_app, debug = True).run()
 

Mas qual a razão de todos esses requires? A questão é que todos essas bibliotecas são eggs instaladas no diretório $HOME do usuario. Numa sessão normal do interpretador python, ao ser iniciado, ele detecta todos os eggs disponíveis em PYTHONPATH e os adiciona ao sys.path. Assim, ao fazer o import de algo que está em um egg, ele consegue encontrar a versão correta. Você pode até mesmo fazer um pequeno teste: execute o interpretador python, importe o módulo sys e imprima o sys.path. Você vai ver uma lista de todos os paths disponíveis, inclusive os seus eggs lá.

Mas executando num ambiente fastcgi, a variável PYTHONPATH não estava definida, e essa pequena magia de adicionar os módulos em eggs no sys.path acontece na hora da inicialização do interpretador. Por isso o require: depois que eu adicionei o /home/usuario/lib/python2.5/site-packages/ ao sys.path, cada chamada ao pkg_resources.require irá procurar o egg correspondente, inclusive nesse path. Mas observe que são sete linhas apenas com require (e isso porque o require do Elixir já trouxe o SQLAlchemy de brinde, se não teria sido mais uma. Provavelmente uma boa saída teria sido fazer uma instalação completa do python no meu $HOME, ou usar algo como o virtualenv, mas não era da forma como eu queria.

Minha primeira idéia foi usar o módulo glob, procurar por todos os eggs e adicionar no meu sys.path Isso funcionaria, exceto por um inconveniente: ao instalar uma nova versão do pacote, o easy_install não apaga o egg anterior. E se houvessem mais de uma versão do pacote nos eggs, qual ele usuaria, a primeira versão encontrada na lista? Era hammeragem o bastante. Após alguma pesquisa, consegui enxugar o código para:


#!/usr/bin/env python2.5
import sys
sys.path.append('home/usuario/projects_pylons/project')
import site
site.addpackage('/home/usuario/lib/python2.5/site-packages/','easy-install.pth',set(sys.path))
from paste.deploy import loadapp
wsgi_app = loadapp('config:/home/usuario/projects_pylons/project/server.ini')
from flup.server.fcgi import WSGIServer
WSGIServer(wsgi_app, debug = True).run()
 

O segredo todo estava no módulo site. Com isso, todos os eggs disponíveis em home/usuario/projects_pylons/project estão disponíveis para importação!


Email por Walter Cruz em Python, Pylons
Tags: deploy, fastcgi, flup, paste, pylons, python, wsgi

Pylons, WSGI, Frameworks Ruby e Templates Engines

26/06/2007
Esse fim de semana eu estava mexendo como Pylons, mais exatamente tentando fazer o deployment de uma micro-aplicação feita com ele. Como me enrolei todo com o FastCGI, eu acabei tendo tempo de ler um pouco sobre WSGI.

WSGI é uma especificação de comunicação entre servidores web e servidores de aplicação. Pondo de forma grotesca: é como o seu aplicativo em TurboGears ou Pylons se comunica com o Apache, Lighttpd ou qualquer outro servidor. O Cacilhas fez uma implementação de WSGI pra Lua. Na trilha disso, eu dei uma pesquisada e achei o Rack - uma especificação semelhante para o Ruby.

Christian Neukirchen fez um post introdutório sobre o rack onde ele menciona dois frameworks, o Camping e o Ramaze, que já suportam o rack. Como vocês podem ver, o Camping é mais um produto do why the lucky stiff, famoso pelo Poignant Guide to Ruby.

Não cheguei a ver os frameworks - deixo esse trabalho a vocês. Mas vi pelo menos uma coisa interessante:

O Camping usa Ruby pra gerar os templates! Um exemplo, retirado do próprio site do projeto:


   def layout

     html do
       title { 'My HomePage' }
       body { self << yield }
     end
   end

 

Esquisito? É porque vocês não viram o HAML ainda.

Eu não imaginava que a selva de templates tivesse chegado ao mundo Ruby, mas a página do Ramaze diz que ele suporta 7 templates engines. E não devem ser todas que existem! Será que já existe ZPT pra Ruby? O jeito é continuar com o bom e velho Erb.

Voltando ao Pylons, eu acabei conseguindo me virar com o CGI/FastCGI na segunda-feira. E com ele também não falta opção de escolha: o sistema de templates padrão é o Myghty, mas em breve será trocado para o Mako.

Talvez eu escreva um tutorial sobre Pylons, mas não estou prometendo nada. Mas acho que já testei o suficiente pra dizer que dos frameworks disponíveis pra Python, o que eu achei mais interessante foi ele.


Email por Walter Cruz em Python, Programação, Ruby
Tags: apache, fastcgi, frameworks, lighttpd, lua, pylons, rails, ruby, templates, wsgi, yaml

TurboGears no fim de semana

05/06/2007

Há duas semanas, eu publiquei um texto chamado 'Django no fim de semana', relatando uma pequena experiência que fiz com o Django.

Na sexta-feira, o Torcato publicou um artigo chamado SQLALchemy no TurboGears. Resolvi tirar o sábado para testar o tutorial.

Usei o PostgreSQL no lugar do MySQL, o que me causou um pouco de dor de cabeça, não por causa do PostgreSQL em si, mas por causa do conector psycopg. Estou usando o Ubuntu Feisty Fawn, que vem com Python 2.5. Eu tinha instalada duas cersões do conector: psycopg e psycopg2. Ao iniciar o servidor do TurboGears com ambas as versões instaladas, ele morria no meio do caminho com core dump. Resolvi remove o psycopg2, e passou a iniciar. Mas não sem problemas: os SQL estavam sendo gerados de forma incorreta (mais especificamente, sem aspas nos campos string). Resolvi fazer o teste com o Python 2.4, reinstalei o psycopg2 e pra minha surpresa funcionou perfeitamente. Pelo visto, coisa está meio bichada na combinação python2.5 e psycopg2. Uma pena.

Se alguém resolver testar, eis o script de criação da tabela, versão PostgreSQL:

CREATE TABLE categories (

    id serial,
    name varchar(100)   NOT NULL DEFAULT '',
    PRIMARY KEY(id)
)

CREATE TABLE recipes ( id serial,
     category_id int NOT NULL,
     title varchar(100)   NOT NULL DEFAULT '',
     description varchar(255)   NULL,
     date  date NULL,
     instructions text  NULL,
     constraint fk_recipes_categories FOREIGN KEY (category_id) REFERENCES categories(id),
     PRIMARY KEY(id)
);
 

Alguns pontos:

  • O TurboGears provê uma ferramenta chamada toolbox, que inclui algumas coisas legais como um interpretador de python para a web (usando ajax), o Model Designer para criar os models e o CatWalk, para o CRUD dos modelos e o WidgetBrowser(mais sobre ele à seguir), entre outros. O Django inclui o admin no seu pacote contrib, porém o admin é voltado ao usuário, enquanto o CatWalk é voltado ao desenvolvedor. Porém, o CatWalk e o ModelDesigner ainda não funcionam com o SQLAlchemy. Um pequeno preço a pagar por sair do padrão :)
  • Gostei do sistema de templates Kid. Os zopistas vão se sentir familiares com ele, e suas construções py:content e py:replace. Você pode querer dar uma olhada no que eles tem em comum.
  • Como o tutorial do Torcato foi bem sucinto, resolvi brincar um pouco alêm dele. Baixei o tgcrud no http://www.turbogears.org/cogbin/ . Porém, me senti como se tivesse sido iludido por uma propaganda enganosa: ele não faz a introspecção para saber as colunas do seu objeto. Ele gera o esqueleto do CRUD, porém ele não sai funcionando antes de você dar uma modificada. Na verdade, a propaganda não foi enganosa: ela diz que é dessa forma que funciona. Apenas minha expectativas que eram muitas.
  • Achei o código dos controladores parecidos com os do rails. (Eu não cheguei a mexer muito com as views[controllers] do Django, então não posso dizer exatamente como foi essa parte).
  • Uma das idéias que eu achei interessante no desenvolvimento Plone+Archetypes são os widgets. Com widgets, você não precisa escrever o HTML para o seu formulário. Você pega o seu modelo, declara que o campo nome é do tipo TextWidget ou algo assim e o template já renderiza. Pode não ser a forma mais flexível de todas, mas é prático.
  • No geral, encontrei pouca documentação do TurboGears, e menos ainda sobre a combinação SQL+Alchemy e TurboGears. Para vocês terem idéia, a página que vem em primeiro lugar na busca do google é a própria página do Torcato. Tente você mesmo!
  • Eu não conseguiria fazer o deploy da aplicação com o TurboGears no meu site, devido à versão do meu apache e mod_python. Poderia tentar usando FastCGI e ver se eu não fico frustrado como esse cara.

Resumindo: foi um pouco mais difícil mexer com o TurboGears que com o Django, mas note-se que eu fui muito mais 'raso' no Django - não cheguei a escrever praticamente nenhum template, e os aplicativos em si eram diferentes. Achei pouca documentação do TurboGears. Dei uma olhada por alto no SQLAlchemy e fui com a cara do mesmo - dá pra usar DataMapper ou ActiveRecord com ele. Eu diria que no geral o TurboGears ficou com um pontinho a menos que o Django.


Email por Walter Cruz em Python, Programação, Ruby, Django, Frameworks
Tags: crud, django, elixir, fastcgi, pylons, python, sqlalchemy, turbogears

1 2 >>