<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog do Robson Dantas &#187; Python</title>
	<atom:link href="http://blogdodantas.dxs.com.br/category/tecnologia_informatica/desenvolvimento-de-software/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://blogdodantas.dxs.com.br</link>
	<description>Tecnologia, segurança, cotidiano, pesca esportiva e inutilidades</description>
	<lastBuildDate>Tue, 31 Jan 2012 02:31:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.3</generator>
		<item>
		<title>AppEngine Python &#8211; Webservices através de ProtoRPC</title>
		<link>http://blogdodantas.dxs.com.br/2011/04/20/appengine-python-webservices-atraves-de-protorpc/</link>
		<comments>http://blogdodantas.dxs.com.br/2011/04/20/appengine-python-webservices-atraves-de-protorpc/#comments</comments>
		<pubDate>Wed, 20 Apr 2011 19:56:41 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Desenvolvimento de software]]></category>
		<category><![CDATA[Google AppEngine]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[appengine]]></category>
		<category><![CDATA[webservices]]></category>

		<guid isPermaLink="false">http://blogdodantas.dxs.com.br/?p=530</guid>
		<description><![CDATA[Consegui dar uma parada para dar uma lida nos feeds e algo interessante chamou a atenção no blog do Google AppEngine: lançamento de uma api para webservices, chamada ProtoRPC . Havia dado alguns passos usando o django-nonrel e um projeto para expor funcionalidades via REST, porém, esse esquema facilita e muito as coisas, principalmente ao [...]]]></description>
			<content:encoded><![CDATA[<p>Consegui dar uma parada para dar uma lida nos feeds e algo interessante chamou a atenção no blog do<a href="http://googleappengine.blogspot.com/" onclick="javascript:pageTracker._trackPageview('out/googleappengine.blogspot.com');" target="_blank"> Google AppEngine</a>: lançamento de uma api para webservices, chamada <a href="http://googleappengine.blogspot.com/2011/04/introducing-protorpc-for-writing-app.html" onclick="javascript:pageTracker._trackPageview('out/googleappengine.blogspot.com');" target="_blank">ProtoRPC</a> .</p>
<p>Havia dado alguns passos usando o<a href="http://www.allbuttonspressed.com/projects/django-nonrel" onclick="javascript:pageTracker._trackPageview('out/www.allbuttonspressed.com');" target="_blank"> django-nonrel</a> e um projeto para expor funcionalidades via <a href="http://pt.wikipedia.org/wiki/REST" onclick="javascript:pageTracker._trackPageview('out/pt.wikipedia.org');" target="_blank">REST</a>, porém, esse esquema facilita e muito as coisas, principalmente ao expor simples serviços, como chamadas ajax, por exemplo.</p>
<p>Basicamente, você tem 3 passos:</p>
<ul>
<li>Uma classe de request, que deriva de messages.Message;</li>
<li>Uma classe de respose, que também deriva de messages.Message;</li>
<li>Uma classe de serviço, que deriva de remote.Service, e que expõe os métodos;</li>
</ul>
<p>Feito isso, só mapear sua aplicação para uma URL apontando a classe de serviço, e chamar o método. O <a href="https://docs.google.com/document/d/1QJBVWnbtYoiTFHIyqcBdnv5u4C1zYvDzFFGBIun35Ro/edit?hl=pt_BR&amp;ndplr=1#" onclick="javascript:pageTracker._trackPageview('out/docs.google.com');" target="_blank">exemplo completo pode ser visto aqui</a>.</p>
<p>Nota: Por enquanto disponível somente para Python, mas em breve a versão Java será liberada.</p>
<p>Boa, Google!</p>
<p class="bookmark-me">Bookmarks<a title="technorati.com" href="http://www.technorati.com/faves?add=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F20%2Fappengine-python-webservices-atraves-de-protorpc%2F" onclick="javascript:pageTracker._trackPageview('out/www.technorati.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/technorati.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="del.icio.us" href="http://del.icio.us/post?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F20%2Fappengine-python-webservices-atraves-de-protorpc%2F&amp;title=AppEngine+Python+%26%238211%3B+Webservices+atrav%C3%A9s+de+ProtoRPC" onclick="javascript:pageTracker._trackPageview('out/del.icio.us');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/delicious.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="digg.com" href="http://digg.com/submit?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F20%2Fappengine-python-webservices-atraves-de-protorpc%2F&amp;title=AppEngine+Python+%26%238211%3B+Webservices+atrav%C3%A9s+de+ProtoRPC" onclick="javascript:pageTracker._trackPageview('out/digg.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/digg.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.facebook.com" href="http://www.facebook.com/share.php?u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F20%2Fappengine-python-webservices-atraves-de-protorpc%2F&amp;t=AppEngine+Python+%26%238211%3B+Webservices+atrav%C3%A9s+de+ProtoRPC" onclick="javascript:pageTracker._trackPageview('out/www.facebook.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/facebook.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="bookmarks.yahoo.com" href="http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F20%2Fappengine-python-webservices-atraves-de-protorpc%2F" onclick="javascript:pageTracker._trackPageview('out/bookmarks.yahoo.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/yahoo.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.google.com" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F20%2Fappengine-python-webservices-atraves-de-protorpc%2F&amp;title=AppEngine+Python+%26%238211%3B+Webservices+atrav%C3%A9s+de+ProtoRPC" onclick="javascript:pageTracker._trackPageview('out/www.google.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/google.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> </p><p><script type="text/javascript"><!--
google_ad_client = "pub-3400408440819022";
/* 468x60, criado 02/11/10 */
google_ad_slot = "1718761682";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>]]></content:encoded>
			<wfw:commentRss>http://blogdodantas.dxs.com.br/2011/04/20/appengine-python-webservices-atraves-de-protorpc/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Como modificar a data da criação de uma foto usando a data que a fotografia foi tirada</title>
		<link>http://blogdodantas.dxs.com.br/2011/04/04/como-modificar-a-data-da-criacao-de-uma-foto-usando-a-data-que-a-fotografia-foi-tirada/</link>
		<comments>http://blogdodantas.dxs.com.br/2011/04/04/como-modificar-a-data-da-criacao-de-uma-foto-usando-a-data-que-a-fotografia-foi-tirada/#comments</comments>
		<pubDate>Mon, 04 Apr 2011 19:21:39 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Desenvolvimento de software]]></category>
		<category><![CDATA[Gambiarras]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[alterar data de foto]]></category>
		<category><![CDATA[exif]]></category>
		<category><![CDATA[exif .net]]></category>
		<category><![CDATA[exif python]]></category>

		<guid isPermaLink="false">http://blogdodantas.dxs.com.br/?p=516</guid>
		<description><![CDATA[O título parece meio confuso, mas vou tentar explicar uma situação: Imagine que você tirou várias fotos, e que as mesmas estavam na sua máquina fotográfica. Você decide, então, mover para um computador e mais para frente, fazer uma simples montagem em um programa estilo Sony Vegas, Adobe Premiere, etc. Ao jogar as suas fotos [...]]]></description>
			<content:encoded><![CDATA[<p>O título parece meio confuso, mas vou tentar explicar uma situação: Imagine que você tirou várias fotos, e que as mesmas estavam na sua máquina fotográfica. Você decide, então, mover para um computador e mais para frente, fazer uma simples montagem em um programa estilo <a href="http://www.sonycreativesoftware.com/vegassoftware" onclick="javascript:pageTracker._trackPageview('out/www.sonycreativesoftware.com');" target="_blank">Sony Vegas</a>, <a href="http://www.adobe.com/br/products/premiere/" onclick="javascript:pageTracker._trackPageview('out/www.adobe.com');" target="_blank">Adobe Premiere</a>, etc.</p>
<p>Ao jogar as suas fotos na timeline, pode ser que a ordem em que as mesmas foram tiradas (e que você gostaria de manter), estejam lá. Mas pode ser, que por algum motivo você andou movendo suas fotos para um backup externo, depois movendo para o PC de volta e assim por diante. O que vai acontecer nesse caso ? Sim, a data da criação do arquivo não irá refletir a data em que necessariamente foi tirada, e você pode perder a ordem das mesmas. Além disso, você pode misturar fotos de diversos diretórios e aí a bagunça fica sem tamanho.</p>
<p>Há alguns softwares no mercado que tomam conta de todo seu acervo digital, porém, decidi pensar em uma forma de acertar as datas de criação das fotos de forma automática, até que modifiquei um simples código python, que implementa o seguinte fluxo:</p>
<ul>
<li>Dado um diretório, listar todos os arquivos .jpg;</li>
<li>Para cada arquivo .jpg, extrair as informações <a href="http://pt.wikipedia.org/wiki/Exif" onclick="javascript:pageTracker._trackPageview('out/pt.wikipedia.org');" target="_blank">EXIF</a>, e localizar a entrada em que a fotografia foi tirada (DateTimeDigitized);</li>
<li>Alterar a data de criação do arquivo;</li>
<li>Fim do fluxo;</li>
</ul>
<p>Para fazer isso em Python, você precisará da biblioteca <a href="http://www.pythonware.com/products/pil/" onclick="javascript:pageTracker._trackPageview('out/www.pythonware.com');" target="_blank">PIL </a>(Python Imaging Library), e de outras libs nativas, como a &#8216;os&#8217; para modificar a data.</p>
<p>O script final, utilizei com base em <a href="http://www.litster.org/blog/2010/05/30/python-and-exif-metadata-theres-more-than-one-way-to-do-it/" onclick="javascript:pageTracker._trackPageview('out/www.litster.org');" target="_blank">outro que estava na internet</a>, bugado, o qual corrigi e estou publicando aqui para download. Também encaminhei o patch ao autor.</p>
<p><a href="http://www.dxs.com.br/wordpress/wp-content/uploads/2011/04/filedate.zip"  target="_blank">Faça download aqui da versão Python.</a></p>
<p>Também fiz uma versão em .NET usando uma biblioteca chamada <a href="http://www.codeproject.com/KB/graphics/exiftagcol.aspx" onclick="javascript:pageTracker._trackPageview('out/www.codeproject.com');" target="_blank">ExifTagCollection</a>, disponível no CodeProject. Falta finalizar algumas coisas antes de publicar, mas abaixo um pequeno pedaço que código que mostra como alterar a data de um arquivo:</p>
<pre>                        string folder=@"path_to_folder";
                        ExifTagCollection exif = new ExifTagCollection(folder);
			System.Collections.Hashtable h = new System.Collections.Hashtable();

			foreach(ExifTag t in exif)
				h[t.FieldName] = t.Value;

			if( h.ContainsKey("DateTimeDigitized") ) {
				System.IO.FileInfo f =new System.IO.FileInfo(folder);
				f.CreationTime = DateTime.Parse(h["DateTimeDigitized"]);
			}</pre>
<p>Espero que seja útil!</p>
<p>Um abraço</p>
<p>Robson</p>
<p class="bookmark-me">Bookmarks<a title="technorati.com" href="http://www.technorati.com/faves?add=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F04%2Fcomo-modificar-a-data-da-criacao-de-uma-foto-usando-a-data-que-a-fotografia-foi-tirada%2F" onclick="javascript:pageTracker._trackPageview('out/www.technorati.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/technorati.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="del.icio.us" href="http://del.icio.us/post?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F04%2Fcomo-modificar-a-data-da-criacao-de-uma-foto-usando-a-data-que-a-fotografia-foi-tirada%2F&amp;title=Como+modificar+a+data+da+cria%C3%A7%C3%A3o+de+uma+foto+usando+a+data+que+a+fotografia+foi+tirada" onclick="javascript:pageTracker._trackPageview('out/del.icio.us');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/delicious.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="digg.com" href="http://digg.com/submit?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F04%2Fcomo-modificar-a-data-da-criacao-de-uma-foto-usando-a-data-que-a-fotografia-foi-tirada%2F&amp;title=Como+modificar+a+data+da+cria%C3%A7%C3%A3o+de+uma+foto+usando+a+data+que+a+fotografia+foi+tirada" onclick="javascript:pageTracker._trackPageview('out/digg.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/digg.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.facebook.com" href="http://www.facebook.com/share.php?u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F04%2Fcomo-modificar-a-data-da-criacao-de-uma-foto-usando-a-data-que-a-fotografia-foi-tirada%2F&amp;t=Como+modificar+a+data+da+cria%C3%A7%C3%A3o+de+uma+foto+usando+a+data+que+a+fotografia+foi+tirada" onclick="javascript:pageTracker._trackPageview('out/www.facebook.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/facebook.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="bookmarks.yahoo.com" href="http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F04%2Fcomo-modificar-a-data-da-criacao-de-uma-foto-usando-a-data-que-a-fotografia-foi-tirada%2F" onclick="javascript:pageTracker._trackPageview('out/bookmarks.yahoo.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/yahoo.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.google.com" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2011%2F04%2F04%2Fcomo-modificar-a-data-da-criacao-de-uma-foto-usando-a-data-que-a-fotografia-foi-tirada%2F&amp;title=Como+modificar+a+data+da+cria%C3%A7%C3%A3o+de+uma+foto+usando+a+data+que+a+fotografia+foi+tirada" onclick="javascript:pageTracker._trackPageview('out/www.google.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/google.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://blogdodantas.dxs.com.br/2011/04/04/como-modificar-a-data-da-criacao-de-uma-foto-usando-a-data-que-a-fotografia-foi-tirada/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>PyQuery &#8211; jQuery like library para Python</title>
		<link>http://blogdodantas.dxs.com.br/2010/12/07/pyquery-jquery-like-library-para-python/</link>
		<comments>http://blogdodantas.dxs.com.br/2010/12/07/pyquery-jquery-like-library-para-python/#comments</comments>
		<pubDate>Tue, 07 Dec 2010 18:51:34 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[pyquery]]></category>
		<category><![CDATA[python bot]]></category>
		<category><![CDATA[scrapping]]></category>

		<guid isPermaLink="false">http://blogdodantas.dxs.com.br/?p=472</guid>
		<description><![CDATA[Se há algo que eu gosto de fazer, é criar robôs para extrair dados de sites e recarregá-los em um formato simples. Há alguns dias atrás, postei aqui no blog sobre um scrapper que eu fiz usando PHP e phpQuery para monitorar as vagas que o Google abre no Brasil. Eu gosto do PHP por [...]]]></description>
			<content:encoded><![CDATA[<p>Se há algo que eu gosto de fazer, é criar robôs para extrair dados de sites e recarregá-los em um formato simples. Há alguns dias atrás, postei aqui no blog sobre um scrapper que eu fiz usando PHP e phpQuery para <a href="http://blogdodantas.dxs.com.br/2010/11/29/quer-trabalhar-no-google-confira-as-vagas/"  target="_blank">monitorar as vagas que o Google abre no Brasil</a>.</p>
<p>Eu gosto do PHP por causa da facilidade em criar coisas rápidas, mas ultimamente tenho gostado mais de Python. E como um profundo admirador, usuário e colaborador de tecnologias opensource, resolvi pesquisar algo que fosse tão poderoso quanto o phpQuery, mas para Python.</p>
<p>Em um passado não muito distante, usei um framework Python chamado <a href="http://www.python.org.br/wiki/BeautifulSoup" onclick="javascript:pageTracker._trackPageview('out/www.python.org.br');" target="_blank">BeautifulSoup</a> que fazia o trabalho de uma forma decente, mas não era algo que fosse intuitivo igual a sintaxe do jQuery &#8211; também usada pelo phpQuery.</p>
<p>Ontem achei o <a href="http://packages.python.org/pyquery/" onclick="javascript:pageTracker._trackPageview('out/packages.python.org');" target="_blank">pyQuery</a>, e fiquei feliz com o resultado. Além de ser um pacote que está incorporado ao packages.python, escrevi uma rotina que tenho usado bastante, com 45 linhas de código.</p>
<p><strong>Dicionário offline de phrasal verbs</strong></p>
<p>O uso do inglês é constante em uma multinacional, e depois de um certo nível de fluência, você começa a querer melhorar alguns detalhes &#8211; no meu especificamente os <a href="http://en.wikipedia.org/wiki/Phrasal_verb" onclick="javascript:pageTracker._trackPageview('out/en.wikipedia.org');" target="_blank">phrasal verbs</a>.</p>
<p>Não vou entrar muito no mérito, mas phrasal verbs podem ter um significado muito diferente do que você imagina, dentro de uma frase ou de uma situação &#8211; um site que eu sempre uso para aprender novas palavras é o <a href="http://www.usingenglish.com/reference/phrasal-verbs/" onclick="javascript:pageTracker._trackPageview('out/www.usingenglish.com');" target="_blank">Using English</a>, que possui um dicionário online bem rico. Mas nem sempre consigo estar conectado, e ficar navegando entre palavras consome um tempo desnecessário.</p>
<p>Aproveitei essa possibilidade para colocar em prática um bot que consolida todas as palavras e todos os significados em uma única página, offline, onde posso usar CTRL+F a vontade. Não vou disponibilizar o arquivo para download, mas vou colocar o código fonte python em breve para você fazer uso a seu critério. Abaixo um print do resultado:</p>
<div id="attachment_473" class="wp-caption alignnone" style="width: 607px"><a href="http://www.dxs.com.br/wordpress/wp-content/uploads/2010/12/scrapping-phrasal.png" ><img class="size-full wp-image-473" title="Phrasal Verbs - offline" src="http://www.dxs.com.br/wordpress/wp-content/uploads/2010/12/scrapping-phrasal.png" alt="Phrasal Verbs - offline" width="597" height="439" /></a><p class="wp-caption-text">Phrasal Verbs - offline</p></div>
<p class="bookmark-me">Bookmarks<a title="technorati.com" href="http://www.technorati.com/faves?add=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F12%2F07%2Fpyquery-jquery-like-library-para-python%2F" onclick="javascript:pageTracker._trackPageview('out/www.technorati.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/technorati.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="del.icio.us" href="http://del.icio.us/post?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F12%2F07%2Fpyquery-jquery-like-library-para-python%2F&amp;title=PyQuery+%26%238211%3B+jQuery+like+library+para+Python" onclick="javascript:pageTracker._trackPageview('out/del.icio.us');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/delicious.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="digg.com" href="http://digg.com/submit?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F12%2F07%2Fpyquery-jquery-like-library-para-python%2F&amp;title=PyQuery+%26%238211%3B+jQuery+like+library+para+Python" onclick="javascript:pageTracker._trackPageview('out/digg.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/digg.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.facebook.com" href="http://www.facebook.com/share.php?u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F12%2F07%2Fpyquery-jquery-like-library-para-python%2F&amp;t=PyQuery+%26%238211%3B+jQuery+like+library+para+Python" onclick="javascript:pageTracker._trackPageview('out/www.facebook.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/facebook.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="bookmarks.yahoo.com" href="http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F12%2F07%2Fpyquery-jquery-like-library-para-python%2F" onclick="javascript:pageTracker._trackPageview('out/bookmarks.yahoo.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/yahoo.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.google.com" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F12%2F07%2Fpyquery-jquery-like-library-para-python%2F&amp;title=PyQuery+%26%238211%3B+jQuery+like+library+para+Python" onclick="javascript:pageTracker._trackPageview('out/www.google.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/google.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://blogdodantas.dxs.com.br/2010/12/07/pyquery-jquery-like-library-para-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Semáforos e condições de corrida com memcache e python &#8211; lock em registros</title>
		<link>http://blogdodantas.dxs.com.br/2010/02/22/semaforos-e-condicoes-de-corrida-com-memcache-e-python-lock-em-registros/</link>
		<comments>http://blogdodantas.dxs.com.br/2010/02/22/semaforos-e-condicoes-de-corrida-com-memcache-e-python-lock-em-registros/#comments</comments>
		<pubDate>Mon, 22 Feb 2010 16:20:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[memcache condição de corrida]]></category>
		<category><![CDATA[memcache lock]]></category>
		<category><![CDATA[memcache semáforo]]></category>

		<guid isPermaLink="false">http://blogdodantas.dxs.com.br/?p=387</guid>
		<description><![CDATA[No post anterior, falei de performance em aplicações web e coloquei um ponto importante em relação ao processo caro de ficar acessando o banco de dados constantemente. Muitas empresas utilizam soluções de cache que são muito mais rápidas e eficientes, e entre as opções disponíveis, eu gostaria de destacar o memcached. Empresas como Facebook, Google, [...]]]></description>
			<content:encoded><![CDATA[<p>No post anterior, falei de performance em aplicações web e coloquei um ponto importante em relação ao processo caro de ficar acessando o banco de dados constantemente.</p>
<p>Muitas empresas utilizam soluções de cache que são muito mais rápidas e eficientes, e entre as opções disponíveis, eu gostaria de destacar o <a href="http://memcached.org/" onclick="javascript:pageTracker._trackPageview('out/memcached.org');" target="_blank">memcached</a>. Empresas como Facebook, Google, Wikipedia fazem uso bem intenso dessa ferramenta e ela é bem otimizada para uso em larga escala.</p>
<p>Apesar de ser projetado para Linux, <a href="http://jehiah.cz/projects/memcached-win32/" onclick="javascript:pageTracker._trackPageview('out/jehiah.cz');" target="_blank">há um port para windows no qual eu uso para testes</a> ( nunca testado em ambiente de produção). Basicamente sua função é armazenar coleções em memória, servindo os dados via socket para os clientes que conectarem ao servidor.  Usa UDP como protocolo de comunicação e um mecanismo muito eficiente para gerenciamento de dados.</p>
<p>Um exemplo prático de como seria usado o mecanismo de cache:</p>
<ul>
<li>Usuário A chama uma página e requisita cidades do estado de SP e a mesma não está em cache;</li>
<li>Aplicação chama consulta no banco de dados, adiciona a chave ao cache: cache.set(&#8220;cidades&#8221;,coleção);</li>
<li>Usuário B chama a aplicação e verifica que os dados estão no cache. Aplicação consulta cache e retorna os dados para serem tratados: cache.get(&#8220;cidades&#8221;);</li>
</ul>
<p>Se não tenha ficado claro, um pseudo-código pode ajudar:</p>
<ul>
<li>se existir cache.get(&#8220;cidade&#8221;) então:<br />
-&gt; popular controles com essa coleção</li>
<li>caso contrário:<br />
-&gt; buscar dados de cidade do banco;<br />
-&gt; setar cache cache.set(&#8220;cidade&#8221;, dados_do_banco);<br />
-&gt; popular controles com essa coleção;</li>
</ul>
<p><strong>Problemas de um cenário real:</strong></p>
<p>Na teoria parece muito simples, certo ? Se você estiver pensando em um ambiente que não haja restrição por condições de corrida ( usuários simultâneos realizando a mesma operação ), então é realmente simples.</p>
<p>Mas imagine um momento em que você precisa incrementar um registro no cache, e esse registro só pode ser incrementado se ninguém mais estiver fazendo o processo. Como você resolveria essa questão ?</p>
<p>Pesquisando um pouco, acabei lembrando dos <a href="http://pt.wikipedia.org/wiki/Regi%C3%A3o_cr%C3%ADtica" onclick="javascript:pageTracker._trackPageview('out/pt.wikipedia.org');" target="_blank">mecanismos de semáforo e de entrada em região crítica</a>, o que me levou a criar um modelo que tenta fazer algo parecido. Só para lembrar o processo de região crítica (retirado do link acima da wikipedia):</p>
<blockquote><p>Para entrar numa região crítica, uma linha de execução deve obter um semáforo, que será descartado na saída da região crítica. Cada recurso compartilhado, ou um conjunto de recursos compartilhados em comum, possui um semáforo próprio. Qualquer outra linha de execução deverá esperar para entrar numa região crítica em uso, mas poderá usar a CPU para executar qualquer outro código, incluindo regiões críticas protegidas por outro semáforo.</p></blockquote>
<p>Logo abaixo, postei o exemplo criado em Python, porém estou escrevendo um pseudo-código que pode ser facilmente migrado para qualquer linguagem:</p>
<ol>
<li>Conectar no memcache;</li>
<li>Tentar adicionar a chave(&#8220;lock&#8221;);</li>
<li>Se adicionar, então não tem ninguém esperando &#8211; incremente o registro que você precisa, remova a chave lock;</li>
<li>Caso tenha a chave, tente esperar alguns micro-segundos, e executar a operação &#8220;N&#8221; vezes. Se &#8220;N&#8221; for atingido, retornar erro, caso contrário, basta executar o procedimento anterior;</li>
<li>Desconectar do memcache;</li>
</ol>
<pre>import memcache
import time

def lock_update(key):

    # parametrizacoes, todo passar para um cfg
    m = memcache.Client(['127.0.0.1:11211'], debug=0)
    lock = "lock_" + key
    max_tries = 5 #tenta 5 vezes
    tries = 0
    expiration = 60 #segundos
    got_lock = False
    number = -1
    wait_time_between_tries = 101 #microsegundos

    # teste inicial, apenas para colocar algo na chave, caso não tenha no cache
    if m.get(key) is None:
        m.set(key,0)

    if(m):
        # roda o numero de tentativas para adquirir o lock
        for tries in range(0, max_tries):
            # se conseguir adicionar, adquire o lock
            if(m.add(lock, 1, expiration)):
                got_lock = True
                break

            # se nao conseguiu, espera um pouco
            time.sleep(wait_time_between_tries / 1000000.0)

        # consegui adquirir o lock
        if(got_lock):
            number = m.incr(key)
            m.delete(lock, 0)

        # retorna o valor
        return number

# só para teste pela linha de comando
if __name__=="__main__":
    print lock_update("teste")</pre>
<p><em>Simples</em>, não ?</p>
<p>Espero que ajude <img src='http://www.dxs.com.br/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>abs</p>
<p>Robson Dantas</p>
<p class="bookmark-me">Bookmarks<a title="technorati.com" href="http://www.technorati.com/faves?add=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F02%2F22%2Fsemaforos-e-condicoes-de-corrida-com-memcache-e-python-lock-em-registros%2F" onclick="javascript:pageTracker._trackPageview('out/www.technorati.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/technorati.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="del.icio.us" href="http://del.icio.us/post?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F02%2F22%2Fsemaforos-e-condicoes-de-corrida-com-memcache-e-python-lock-em-registros%2F&amp;title=Sem%C3%A1foros+e+condi%C3%A7%C3%B5es+de+corrida+com+memcache+e+python+%26%238211%3B+lock+em+registros" onclick="javascript:pageTracker._trackPageview('out/del.icio.us');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/delicious.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="digg.com" href="http://digg.com/submit?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F02%2F22%2Fsemaforos-e-condicoes-de-corrida-com-memcache-e-python-lock-em-registros%2F&amp;title=Sem%C3%A1foros+e+condi%C3%A7%C3%B5es+de+corrida+com+memcache+e+python+%26%238211%3B+lock+em+registros" onclick="javascript:pageTracker._trackPageview('out/digg.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/digg.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.facebook.com" href="http://www.facebook.com/share.php?u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F02%2F22%2Fsemaforos-e-condicoes-de-corrida-com-memcache-e-python-lock-em-registros%2F&amp;t=Sem%C3%A1foros+e+condi%C3%A7%C3%B5es+de+corrida+com+memcache+e+python+%26%238211%3B+lock+em+registros" onclick="javascript:pageTracker._trackPageview('out/www.facebook.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/facebook.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="bookmarks.yahoo.com" href="http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F02%2F22%2Fsemaforos-e-condicoes-de-corrida-com-memcache-e-python-lock-em-registros%2F" onclick="javascript:pageTracker._trackPageview('out/bookmarks.yahoo.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/yahoo.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.google.com" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2010%2F02%2F22%2Fsemaforos-e-condicoes-de-corrida-com-memcache-e-python-lock-em-registros%2F&amp;title=Sem%C3%A1foros+e+condi%C3%A7%C3%B5es+de+corrida+com+memcache+e+python+%26%238211%3B+lock+em+registros" onclick="javascript:pageTracker._trackPageview('out/www.google.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/google.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://blogdodantas.dxs.com.br/2010/02/22/semaforos-e-condicoes-de-corrida-com-memcache-e-python-lock-em-registros/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Patching WordPress xmlrpc to filter post using categories</title>
		<link>http://blogdodantas.dxs.com.br/2009/03/18/patching-wordpress-xmlrpc-to-filter-post-using-categories/</link>
		<comments>http://blogdodantas.dxs.com.br/2009/03/18/patching-wordpress-xmlrpc-to-filter-post-using-categories/#comments</comments>
		<pubDate>Wed, 18 Mar 2009 15:34:18 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Desenvolvimento de software]]></category>
		<category><![CDATA[Google AppEngine]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Wordpress - PHP]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wordpress filter post by category]]></category>
		<category><![CDATA[wordpress hack]]></category>
		<category><![CDATA[xmlrpc wordpress]]></category>

		<guid isPermaLink="false">http://blogdodantas.dxs.com.br/?p=238</guid>
		<description><![CDATA[I´m building an application to integrate data between some blog apps (WordPress and Blogger for example) and then faced a problem when I was trying to filter some posts using a specific category. My app is AppEngine based and I´m algo using xmlrpclib and wordpress-library to make web calls. After playing a while with wordpress-library, [...]]]></description>
			<content:encoded><![CDATA[<p>I´m building an application to integrate data between some blog apps (WordPress and Blogger for example) and then faced a problem when I was trying to filter some posts using a specific category.</p>
<p>My app is AppEngine based and I´m algo using xmlrpclib and wordpress-library to make web calls. After playing a while with wordpress-library, I got some things missing and started to patch to make it work for me.</p>
<p>Basically I´ve added some stuff like post status, custom fields and filter posts by categories. I dont know why WordPress don´t give a simple wrapper function inside xmlrpc.php to make things generic, allowing other users to extend functionalities. Anyway, I did it and will suggest to add support for it, because makes easier to give some maitenance.</p>
<p>To make the patch, you must understand the <em>get_post</em> function, exposed on <em>wp-includes/post.php</em>. Looking inside, the function body is:</p>
<pre>function get_posts($args = null) {
    $defaults = array(
                             'numberposts' =&gt; 5, 'offset' =&gt; 0,
                             'category' =&gt; 0, 'orderby' =&gt; 'post_date',
                             'order' =&gt; 'DESC', 'include' =&gt; '',
                             'exclude' =&gt; '', 'meta_key' =&gt; '',
                             'meta_value' =&gt;'', 'post_type' =&gt; 'post',
                             'suppress_filters' =&gt; true
                             );</pre>
<p><em>&#8230;. continue</em></p>
<p>Based on that function, it becomes easier to make your on function on xmlrpc.php:</p>
<p><span style="text-decoration: underline;">First</span>:  Include your function entrypoint on $this-&gt;methods array. My implementation is <em>&#8216;wp.getPostsByCategory&#8217;   =&gt; &#8216;this:wp_getPostsByCategory&#8217;</em>. I decided to use this name, because it´s a specific function for wordpress, not a MetaWebLog structure.</p>
<p><span style="text-decoration: underline;">Second</span>: Change <em>mw_wp_get_recent_posts</em> to receive other args and change the call <em>wp_get_recent_posts($num_posts)</em> to use <em>get_posts</em> . You´ll also need to change the ways that arrays are accessed, because get_posts function returns an Object, instead of array. Example: <em>$entry['ID']</em> becomes <em>$entry-&gt;ID</em>.</p>
<p>After that, just make your call to <em>wp.getPostsByCategory</em>, passing username, password and categoryId. Like magic <img src='http://www.dxs.com.br/wordpress/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<p>Just to finish, a simple python example using xmlrpclib to call a server method:</p>
<pre>import xmlrpclib

server = xmlrpclib.ServerProxy("http://www.mywebsite.com/xmlrpc.php")
posts = server.wp.getPostsByCategory(categoryId, 'user', 'password')

for post in posts:
   print post['post_title']</pre>
<p>.<br />
Piece of cake ! If you have any doubt, leave a comment here.</p>
<p class="bookmark-me">Bookmarks<a title="technorati.com" href="http://www.technorati.com/faves?add=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F03%2F18%2Fpatching-wordpress-xmlrpc-to-filter-post-using-categories%2F" onclick="javascript:pageTracker._trackPageview('out/www.technorati.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/technorati.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="del.icio.us" href="http://del.icio.us/post?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F03%2F18%2Fpatching-wordpress-xmlrpc-to-filter-post-using-categories%2F&amp;title=Patching+WordPress+xmlrpc+to+filter+post+using+categories" onclick="javascript:pageTracker._trackPageview('out/del.icio.us');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/delicious.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="digg.com" href="http://digg.com/submit?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F03%2F18%2Fpatching-wordpress-xmlrpc-to-filter-post-using-categories%2F&amp;title=Patching+WordPress+xmlrpc+to+filter+post+using+categories" onclick="javascript:pageTracker._trackPageview('out/digg.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/digg.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.facebook.com" href="http://www.facebook.com/share.php?u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F03%2F18%2Fpatching-wordpress-xmlrpc-to-filter-post-using-categories%2F&amp;t=Patching+WordPress+xmlrpc+to+filter+post+using+categories" onclick="javascript:pageTracker._trackPageview('out/www.facebook.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/facebook.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="bookmarks.yahoo.com" href="http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F03%2F18%2Fpatching-wordpress-xmlrpc-to-filter-post-using-categories%2F" onclick="javascript:pageTracker._trackPageview('out/bookmarks.yahoo.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/yahoo.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.google.com" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F03%2F18%2Fpatching-wordpress-xmlrpc-to-filter-post-using-categories%2F&amp;title=Patching+WordPress+xmlrpc+to+filter+post+using+categories" onclick="javascript:pageTracker._trackPageview('out/www.google.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/google.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://blogdodantas.dxs.com.br/2009/03/18/patching-wordpress-xmlrpc-to-filter-post-using-categories/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Instalando mod_python no Apache &#8211; Python e web</title>
		<link>http://blogdodantas.dxs.com.br/2009/02/19/instalando-mod_python-no-apache-python-e-web/</link>
		<comments>http://blogdodantas.dxs.com.br/2009/02/19/instalando-mod_python-no-apache-python-e-web/#comments</comments>
		<pubDate>Thu, 19 Feb 2009 14:45:28 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Desenvolvimento de software]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[apache mod_python]]></category>
		<category><![CDATA[python com django]]></category>
		<category><![CDATA[python web]]></category>

		<guid isPermaLink="false">http://blogdodantas.dxs.com.br/?p=223</guid>
		<description><![CDATA[Depois de começar a brincar com o Google AppEngine, decidi realmente levar a sério o Python. Cheguei à uma conclusão do motivo pelo qual a Google vem investindo tanto no Python: realmente a linguagem é fantástica. Vou começar uma série de artigos sobre o desenvolvimento de aplicações WEB usando Python com o Django, um poderoso [...]]]></description>
			<content:encoded><![CDATA[<p>Depois de começar a brincar com o Google AppEngine, decidi realmente levar a sério o Python. Cheguei à uma conclusão do motivo pelo qual a Google vem investindo tanto no Python: realmente a linguagem é fantástica.</p>
<p>Vou começar uma série de artigos sobre o desenvolvimento de aplicações WEB usando Python com o Django, um poderoso framework web, no qual eu comecei a respeitar, tanto quanto a comunidade Ruby respeita o Ruby on Rails.</p>
<p>Antes de entrar nos detalhes do modelo de implementação do Django com Python, estou postando um simples tutorial de como configurar o Apache e o mod_python para que você possa desenvolver aplicações.</p>
<p>Para o meu tutorial, eu usei o Apache 2.2 para Windows e a mesma versão para o Ubuntu. Caso queira ver a lista dos pré-requisitos, sugiro que acesse a página do mod_python pois a versão do módulo só funciona com a versão certa do apache. Veja:  <a href="http://www.modpython.org/live/current/doc-html/inst-prerequisites.html" onclick="javascript:pageTracker._trackPageview('out/www.modpython.org');" target="_blank">Requisitos para o mod_python</a></p>
<h2><strong>Passo 1:</strong></h2>
<p>Verifique a versão do Python que você possui instalado na sua máquina. Para poder rodar o mod_python, você precisa do python 2.5.x, pois por alguns problemas relativos à compilação, o mod_python ainda não suporta o python 2.6 .</p>
<p>Para fazer isso, entre num prompt do dos e digite <em>python &#8211;version</em> . Se estiver tudo certo, verificará algo como &#8220;Python 2.5.xx&#8221; .</p>
<p>Caso apresente um erro que o executável não foi encontrado, certifique-se que a pasta do Python está no seu path.</p>
<h2><strong><br />
Passo 2:</strong></h2>
<p>Faça <a href="http://httpd.apache.org/modules/python-download.cgi" onclick="javascript:pageTracker._trackPageview('out/httpd.apache.org');" target="_blank">download do mod_python</a> . No momento em que esse tutorial foi escrito, a versão era (ou é) a 3.3 . Para windows, existe um instalador e basta seguir o processo NNF (next, next, finish).</p>
<p>Para *Nix, é necessário baixar os fontes e compilar na mão. Verifique se a sua distribuição não oferece o pacote pronto, assim você economiza tempo e CPU <img src='http://www.dxs.com.br/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  . Antes da compilação, caso você opte por fazer na mão, precisa decidir como quer carregar o módulo: por DSO ( Dynamic Shared Object) ou estáticamente. Se for pra linha do estático, vai precisar recompilar o Apache.</p>
<p>Eu escolhi compilar usando DSO. Só para deixar claro, o utilitário que faz o processo da carga dinâmica de módulos é chamado de APXS  Verifique se o mesmo está no seu path!</p>
<p>Rodei um configure bem simples: <em>./configure &#8211;with-apxs=/usr/local/apache/bin/apxs</em></p>
<p>Depois disso, os famosos comandos <em>make</em> e depois<em> make install</em>. Lembre-se que para rodar o make install você precisa estar logado como <span style="text-decoration: underline;">root</span>, pois ele copiará a biblioteca para o seu <em>libexec</em>.</p>
<h2><strong><br />
Passo 3:</strong></h2>
<p>Depois disso tudo, vem o truque necessário para o Python rodar no Apache. Eu apanhei algumas vezes pois as documentações além de desatualizadas, estão cheias de erro.</p>
<p>Para fazer rodar você precisa editar o arquivo <em>httpd.conf</em>. No windows, está na pasta &#8220;<em>conf</em>&#8221; e nos linux, normalmente fica em /etc/httpd.conf .</p>
<p>Abra o arquivo no seu editor favorito e procure por linhas que comecem por &#8220;LoadModule&#8221;. Você vai achar várias linhas, uma embaixo da outra, com um monte de módulos. Essas linhas falam ao Apx para carregar o módulo e depois da última, inclua uma nova linha:</p>
<p><em>LoadModule python_module modules/mod_python.so</em></p>
<p>Só garanta que a pasta que o módulo está, foi configurada corretamente. É possível colocar o caminho completo por lá também.</p>
<p>Depois de carregado o módulo, é necessário configurar um diretório para que os scripts python seja interpretados. Procure por linhas que comecem por <em>&#8220;&lt;Directory &#8220;</em> no httpd.conf e inclua uma nova, com o seguinte formato:</p>
<p>Para windows:</p>
<pre>&lt;Directory "c:/diretorio_apache/www/py/"&gt;
        SetHandler mod_python
        PythonHandler mptest
        PythonDebug On
&lt;/Directory&gt;</pre>
<p>Para Linux:</p>
<pre>&lt;Directory "/pasta/diretorioapache/www/py/"&gt;
        SetHandler mod_python
        PythonHandler mptest
        PythonDebug On
&lt;/Directory&gt;</pre>
<p>Pronto! Depois desse processo, salve o arquivo e reinicie seu apache. Verifique nos arquivos de log se não ocorreu nenhum erro com a carga do módulo e passe para a etapa seguinte.</p>
<h2><strong><br />
Passo 4:</strong></h2>
<p>Vamos gerar um arquivo de teste, para que seja executado pelo navegador. Abra um editor qualquer e digite o seguinte conteúdo:</p>
<pre>from mod_python import apache

def handler(req):
	req.content_type = 'text/plain'
	req.write("Funcionou. Minha aplicacao python esta ok.")
	return apache.OK</pre>
<p>Salve o arquivo na pasta py que você criou no arquivo de configuração do apache e chame-o através do browser. Ex: http://localhost/py/teste.py . Se tudo ocorreu bem, você deve ver &#8220;Funcionou. Minha aplicacao python esta ok&#8221;.</p>
<p>É isso. O segredo está no &#8220;SetHandler&#8221;, que muitas documentações passam outra forma.</p>
<p>Caso tenha alguma dúvida, faça um comentário e consulte também a <a href="http://www.modpython.org/live/current/doc-html/inst-installing.html" onclick="javascript:pageTracker._trackPageview('out/www.modpython.org');" target="_blank">documentação no site do mod_python</a>.</p>
<p>Até a próxima com Django.</p>
<p class="bookmark-me">Bookmarks<a title="technorati.com" href="http://www.technorati.com/faves?add=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F02%2F19%2Finstalando-mod_python-no-apache-python-e-web%2F" onclick="javascript:pageTracker._trackPageview('out/www.technorati.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/technorati.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="del.icio.us" href="http://del.icio.us/post?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F02%2F19%2Finstalando-mod_python-no-apache-python-e-web%2F&amp;title=Instalando+mod_python+no+Apache+%26%238211%3B+Python+e+web" onclick="javascript:pageTracker._trackPageview('out/del.icio.us');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/delicious.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="digg.com" href="http://digg.com/submit?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F02%2F19%2Finstalando-mod_python-no-apache-python-e-web%2F&amp;title=Instalando+mod_python+no+Apache+%26%238211%3B+Python+e+web" onclick="javascript:pageTracker._trackPageview('out/digg.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/digg.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.facebook.com" href="http://www.facebook.com/share.php?u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F02%2F19%2Finstalando-mod_python-no-apache-python-e-web%2F&amp;t=Instalando+mod_python+no+Apache+%26%238211%3B+Python+e+web" onclick="javascript:pageTracker._trackPageview('out/www.facebook.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/facebook.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="bookmarks.yahoo.com" href="http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F02%2F19%2Finstalando-mod_python-no-apache-python-e-web%2F" onclick="javascript:pageTracker._trackPageview('out/bookmarks.yahoo.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/yahoo.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.google.com" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F02%2F19%2Finstalando-mod_python-no-apache-python-e-web%2F&amp;title=Instalando+mod_python+no+Apache+%26%238211%3B+Python+e+web" onclick="javascript:pageTracker._trackPageview('out/www.google.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/google.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://blogdodantas.dxs.com.br/2009/02/19/instalando-mod_python-no-apache-python-e-web/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Chamadas ajax em outro domínio no Google appengine (crossdomain ajax)</title>
		<link>http://blogdodantas.dxs.com.br/2009/01/28/chamadas-ajax-em-outro-dominio-no-google-appengine-crossdomain-ajax/</link>
		<comments>http://blogdodantas.dxs.com.br/2009/01/28/chamadas-ajax-em-outro-dominio-no-google-appengine-crossdomain-ajax/#comments</comments>
		<pubDate>Wed, 28 Jan 2009 18:29:34 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Desenvolvimento de software]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Tecnologia e informática]]></category>
		<category><![CDATA[appengine ajax outro dominio]]></category>
		<category><![CDATA[crossdomain javascript]]></category>
		<category><![CDATA[google appengine]]></category>
		<category><![CDATA[javascript ajax dominio externo]]></category>

		<guid isPermaLink="false">http://blogdodantas.dxs.com.br/?p=189</guid>
		<description><![CDATA[Bom, comecei a brincar com o Google App Engine há algumas semanas para hospedar um projeto pessoal que estou desenvolvendo e fiquei muito satisfeito com o progresso pelos seguintes motivos: 1- Estou hospedando meu site de graça, em uma estrutura da Google. Apenas registrei meu domínio no registro.br, usei um serviço de DNS GRATUITO &#8211; [...]]]></description>
			<content:encoded><![CDATA[<p>Bom, comecei a brincar com o Google App Engine há algumas semanas para hospedar um projeto pessoal que estou desenvolvendo e fiquei muito satisfeito com o progresso pelos seguintes motivos:</p>
<p>1- Estou hospedando meu site de graça, em uma estrutura da Google. Apenas registrei meu domínio no registro.br, usei um serviço de DNS GRATUITO &#8211; nesse caso o Zoneedit (zoneedit.com), me cadastrei no Google Applications (google.com/a) e alterei as entradas CNAME para o Google;</p>
<p>2- O Google App Engine fornece uma estrutura de CDN (content delivery network), onde o seu site fica dentro de uma estrutura com balanceamento de carga e um algoritmo determina a melhor rota para servir uma página, fazendo com que o mecanismo fique muito mais rápido;</p>
<p>3- Além de fornecer tudo isso, permite hospedagens de páginas Python de uma maneira bem simples: basta editar um arquivo .yaml e rodar um programa python que o processo de upload está feito;</p>
<p>Se quiser mais detalhes disso que estou falando, tem um post interessante no 24 ways:  http://24ways.org/2008/using-google-app-engine-as-your-own-cdn</p>
<p>Enfim&#8230; o assunto principal aqui não é como subir o seu CDN e sim como habilitar chamadas AJAX em domínios externos. A solução, é bem simples por sinal: subir um proxy escrito em python que redirecione as requisições de GET e POST para um servidor final, lendo e imprimindo os resultados.</p>
<p>Como é de conhecimento de muitos, os browsers não permitem requisição HTTP fora do domínio e apresentam erros como &#8220;Security error&#8221;, óbvio.  Para resolver isso, siga a minha receita de bolo&#8230;</p>
<p>a) Edite o arquivo app.yaml e inclua as seguintes linhas dentro de handlers:</p>
<p>- url: /xpto<br />
script: x.py</p>
<p>O resultado do meu arquivo app.yaml é algo do tipo:</p>
<p><em>application: meuapp<br />
version: 1<br />
runtime: python<br />
api_version: 1</em></p>
<p><em>handlers:<br />
- url: /<br />
static_files: assets/*.html<br />
upload: assets/index.html</em></p>
<p><em>- url: /xpto<br />
script: x.py</em></p>
<p><em>- url: /<br />
static_dir: assets</em></p>
<p>Esse parâmetro diz para redirecionar todas as requisições http que tem como destino a pasta &#8220;xpto&#8221;, para o script x.py. Depois disso precisamos criar nosso script python para fazer o proxy. Estou dando o exemplo apenas com o método GET:</p>
<div><em># -*- coding: utf-8 -*-<br />
import cgi<br />
import urllib<br />
import httplib<br />
from google.appengine.ext import webapp<br />
from google.appengine.api import urlfetch<br />
from google.appengine.ext.webapp.util import run_wsgi_app</em></div>
<div><em>class ProxyController(webapp.RequestHandler):</em></div>
<div><em> def get(self):<br />
 <br />
  p = self.request.str_GET<br />
  saida=&#8221;<br />
  page = self.response.out<br />
  <br />
  if p.get(&#8216;a&#8217;,&#8221;) == &#8221;:<br />
   page.write(&#8220;pagina nao existe&#8221;)<br />
  else:<br />
   saida = p['a'] + &#8216;.php&#8217;<br />
   p['a']=&#8221;<br />
  <br />
   params=urllib.urlencode(p)<br />
   saida+=&#8217;?'+params<br />
   resultado = urlfetch.fetch(url = &#8220;<a href="http://www.dxs.com.br/app/" >http://www.dxs.com.br/app/</a>&#8221; + saida,<br />
         method= urlfetch.GET)<br />
         <br />
   self.response.out.write(resultado.content)</em></div>
<div><em>application = webapp.WSGIApplication([('/xpto', ProxyController)],debug=True)</em></div>
<div><em>def main():<br />
 run_wsgi_app(application)<br />
 <br />
if __name__ == &#8220;__main__&#8221;:<br />
 main()</em></div>
<div><em></em></div>
<p><em> </p>
<p></em></p>
<p><em><br />
</em><br />
Salve na pasta raiz e depois disso, com o jQuery faça um teste&#8230;</p>
<p><em>$.get(&#8220;/xpto&#8221;,{campo1: &#8220;aaa&#8221;, campo2: &#8220;bbb&#8221;}, function(data){</em></p>
<p><em>alert(data);<br />
</em></p>
<p><em>});</em></p>
<p>Embora muita gente defenda o uso de JSONP, acredito que o modelo de proxy seja mais eficiente. A implementação do POST fica por sua conta, basta seguir a lógica <img src='http://www.dxs.com.br/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Dúvida, comentário, sugestão ? Utilize o formulário aqui do blog.</p>
<p>&#8211;Robson</p>
<p class="bookmark-me">Bookmarks<a title="technorati.com" href="http://www.technorati.com/faves?add=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F01%2F28%2Fchamadas-ajax-em-outro-dominio-no-google-appengine-crossdomain-ajax%2F" onclick="javascript:pageTracker._trackPageview('out/www.technorati.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/technorati.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="del.icio.us" href="http://del.icio.us/post?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F01%2F28%2Fchamadas-ajax-em-outro-dominio-no-google-appengine-crossdomain-ajax%2F&amp;title=Chamadas+ajax+em+outro+dom%C3%ADnio+no+Google+appengine+%28crossdomain+ajax%29" onclick="javascript:pageTracker._trackPageview('out/del.icio.us');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/delicious.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="digg.com" href="http://digg.com/submit?url=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F01%2F28%2Fchamadas-ajax-em-outro-dominio-no-google-appengine-crossdomain-ajax%2F&amp;title=Chamadas+ajax+em+outro+dom%C3%ADnio+no+Google+appengine+%28crossdomain+ajax%29" onclick="javascript:pageTracker._trackPageview('out/digg.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/digg.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.facebook.com" href="http://www.facebook.com/share.php?u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F01%2F28%2Fchamadas-ajax-em-outro-dominio-no-google-appengine-crossdomain-ajax%2F&amp;t=Chamadas+ajax+em+outro+dom%C3%ADnio+no+Google+appengine+%28crossdomain+ajax%29" onclick="javascript:pageTracker._trackPageview('out/www.facebook.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/facebook.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="bookmarks.yahoo.com" href="http://bookmarks.yahoo.com/toolbar/savebm?opener=tb&amp;u=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F01%2F28%2Fchamadas-ajax-em-outro-dominio-no-google-appengine-crossdomain-ajax%2F" onclick="javascript:pageTracker._trackPageview('out/bookmarks.yahoo.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/yahoo.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> <a title="www.google.com" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fblogdodantas.dxs.com.br%2F2009%2F01%2F28%2Fchamadas-ajax-em-outro-dominio-no-google-appengine-crossdomain-ajax%2F&amp;title=Chamadas+ajax+em+outro+dom%C3%ADnio+no+Google+appengine+%28crossdomain+ajax%29" onclick="javascript:pageTracker._trackPageview('out/www.google.com');" target="_blank" rel="nofollow"><img src="http://www.dxs.com.br/wordpress/wp-content/plugins/bookmark-me/images/google.png" style="margin:0;border:0;padding:0" alt="bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://blogdodantas.dxs.com.br/2009/01/28/chamadas-ajax-em-outro-dominio-no-google-appengine-crossdomain-ajax/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

