Planeta PythonBrasil

May 21, 2013

Aprenda Python

Diferenças entre Django e Web2py

Uma pergunta recorrente na lista Python Brasil é: "qual é o melhor framework web para Python?". Existe quase que um consenso a respeito da qualidade dos frameworks web em Python: eles vão resolver o seu problema. Cada um com seu estilo, mas você não vai ficar na mão. Eles estão sendo atualizados e suas comunidades são bem ativas. Mas o que seria uma boa notícia, traz um inconveniente: se todos

por Vinicius Assef (noreply@blogger.com) em 21 de May de 2013 às 01:28

May 20, 2013

Devlog

Usando ckeditor e jquery validate juntos

Mais simples impossível:

$('#form1').validate({
			ignore: [],
			rules: {
				corpo : {
					required: function()
					{
						CKEDITOR.instances.corpo.updateElement();
					}
				}
			}
		})

por waltercruz em 20 de May de 2013 às 14:19

May 15, 2013

Aprenda Python

Mutirão Python março, abril e maio/2013

Dando continuidade ao projeto Mutirão Python, a PyCursos promoveu em março, abril e maio de 2013, mais palestras sobre Python e seu ecossistema, mostrando que Python pode ser usada não só para desenvolver aplicações web. Abaixo, os links das aulas, divididos por mês. Março 12/03/2013: Tornado - mais do que um framework bonitinho (Marcel Nicolay) 20/03/2013: Entendendo Metaclasses (João

por Vinicius Assef (noreply@blogger.com) em 15 de May de 2013 às 20:48

Palestras gratuitas e atualizadas (2013)

Quero dar os parabéns ao pessoal da Pycursos pelo Mutirão Python. Foi uma iniciativa que movimentou voluntários da comunidade Python brasileira em fevereiro/2013, oferecendo palestras sobre algum assunto relacionado à linguagem. Tivemos palestras com conteúdo atualizado, realizadas por quem conhece os assuntos. Recomendo assistir a todas elas, se possível. Algumas delas foram apresentadas na

por Vinicius Assef (noreply@blogger.com) em 15 de May de 2013 às 20:47

May 14, 2013

Henrique Bastos

Começando um Podcast

As melhores discussões que me lembro, aconteceram em uma mesa de bar. O único inconveniente é que aquelas conversas fantásticas, ficavam restritas àquele espaço e tempo.

Como levá-las adiante? Como incluir até quem não estava presente? Como permitir a colaboração daquele amigo próximo que mora em Cuiabá, em Brasília, em Belém ou até em Orlando?

Já tentamos gravar as conversas para jogar na internet, mas o barulho do ambiente não permitiu e acabamos deixando isso de lado.

Recentemente levantei essa questão novamente durante um Pós-Dojo, com a ideia de gravar um podcast. O Diego Dukão que já toca o sensacional Mobilidade.fm, providenciou o empurrão que faltava.

Qual o objetivo do podcast?

O podcast em si não tem objetivo específico, além de discutir o que parece interessante. Em vez nós definirmos previamente as coisas, faz muito mais sentido deixar a galera interagir e ver o que acontece.

Mas como funciona?

A ideia até então é um bate-papo via Hangout ou Skype, despretensioso, preferencialmente regado à alguma cerveja.

E quais assuntos serão abordados?

Ideias não faltam, mas queremos saber a sua.

Eu, pessoalmente, ando interessado em autonomia e no uso da tecnologia para viver mais simples.

Mas isso sou eu. E você? O que quer você quer discutir?

Alguns assuntos emergiram no bar sem ordem específica:

  • Money que é good e nóis num have: Mexendo com dinheiro sem burocracia.
  • Programe ou seja programado: Saber programar é o novo saber escrever.
  • A Morte da Profissão.
  • A filosofia por trás do Test Driven Development.
  • Empreendedorismo sem “empresarialismo”.
  • Agile sem frescura: eliminando gargalos em processos.
  • Blogueiro por necessidade: A importância de botar a cara na internet e compartilhar o que você tem à dizer.
  • Empreendendo na Internet: Emita a 1a nota fiscal sem nem escrever uma linha de código.
  • Negócios em Rede: O que são e como funcionam.
  • Escritório Ubíquo: Organizando o dia à dia para poder morar numa mochila.
  • Vender não é enganar: Discutindo o tabu da venda.
  • Filho, como funciona a internet? Como você explicaria para os seus pais?
  • A história do Design.
  • Gestalt e a compreensão do ser humano sobre si mesmo.
  • Serviços não escalam, mas amplificam.

Para este primeiro experimento, o Dukão ficou animado de começarmos falando sobre grana. Sobre como podemos nos organizar para levar uma vida mais alinhada com o que desejamos, tendo mais tempo para nós mesmos.

Aceitamos sugestões até a hora da gravação, que acontecerá nesta quarta-feira às 23h.

Gostou da ideia? Tem alguma sugestão? Quer participar? Fale livremente aí nos comentários que a gente vai batendo bola.

[]‘s, HB!

por Henrique Bastos em 14 de May de 2013 às 19:36

May 12, 2013

Andrews Medina

referências para quem quer aprender go

Esse post tem como objetivo ser um guia com alguns links para quem que aprender a linguagem go.

Visão geral sobre a linguagem

Go Tour

Instalando e configurando um ambiente de desenvolvimento

Getting started

How to Write Go Code

Aprendendo sobre a linguagem

Effective Go

Apresentações

Let's go

A linguagem de programação go

Livros

An introduction to programming in go

Programming in go

Learning go

The way to go

Novidades

http://www.reddit.com/r/golang

E para dúvidas, tem a lista de e-mail golang-nuts.

Espero que gostem :)

por andrewsmedina@gmail.com (Andrews Medina) em 12 de May de 2013 às 20:30

Henrique Bastos

Ainda Somos Tão Jovens

O filme “Somos Tão Jovens” retrata o processo do Renato virar Russo, com todos os seus dilemas e complexidades. Gostei tanto do filme que decidi escrever este artigo.

Como entendedor de cinema, eu sou um ótimo jogador de purrinha. Então vou me limitar às reflexões que o filme me provocou.

“Deve ser difícil viver na sua cabeça.”

Essa é uma frase que costumo ouvir bastante em casa quando converso sobre minhas ideias e visões “incomuns”.

Então se você é dessas pessoas que tem a mente agitada, assistir ao filme vai lhe proporcionar uma certa paz, pois devia ser ainda mais difícil viver na cabeça do Renato Russo.

Brincadeiras à parte, as tensões de se lançar em busca da percepção do que se deseja ficam muito bem retratadas no filme. O ator consegue transmitir com muita sensibilidade as ondas de tédio, dúvidas e os impulsos que motivam ações incompreendidas, mas muito necessárias.

Singularidade

Como diria Sílvio Meira, o futuro vem do futuro.

Quem diria que de um grupo de adolescentes que não tinham mais o que fazer surgiriam diversas bandas que trilhariam o caminho que hoje conhecemos?

Ninguém! O sucesso como instituído e vendido socialmente é improvável, por isso é tão importante construir sua própria definição de sucesso.

É muito interessante a trajetória caótica de sucessivos nascimentos, mortes e ressurreições de bandas.

Esse grau de liberdade é importante para que se continue fazendo, tentando, mesmo com o desconforto de não compreender antecipadamente o que se faz.

Em uma cena em especial, os integrantes do Legião Urbana estão discutindo: “e se não der certo?”; E o Renato afirma: “Eu não quero nem pensar em alternativa.”

Essa é a virada de chave. Uma decisão a despeito das circunstâncias.

O Nativo e o Outsider

O filme tem muitas cenas interessantes que retratam “maluquices” cotidianas.

Todos temos as nossas. Mas quando expostas ao social, a reação padrão é de estranheza seguida pelo julgamento: “Esse cara é maluco”.

Atitudes como perder um show para meditar sobre a morte do John Lennon porque a Yoko Ono pediu.

Julgar o que não se compreende está na raiz da intolerância. O outsider, que não compreende o comportamento e as motivações do nativo, julga, deixando de reconhecer o outro como alguém, e o reduzindo à alguma coisa.

O remédio para este comportamento é a “observação participativa”, um conceito antropológico que enfatiza: observar sem interagir não proporciona compreensão.

Julgar sem compreender nos leva a ignorar que é possível haver sentido, por mais que não se perceba lógica.

Em algum momento a gente esqueceu que sentido vem de sentir e não de racionalizar. O resultado desse esquecimento? Um monte de outsiders julgando nativos e divulgando seus veredictos vazios no Facebook, sem compreender que de alguma forma, todos somos nativos e outsiders em diferentes situações.

Homofobia

Como mencionado pelo Pablo Villaça, o filme demonstra covardia ao abordar os dilemas sexuais do protagonista.

O filme já vinha tratando do tema sexualidade, até que Renato conhece Carlinhos e se segue uma cena bonita e muito humana, retratando duas pessoas se conhecendo e se reconhecendo.

Mas uma parte da platéia pareceu não estar vendo o mesmo filme que eu. Logo quando os personagens se conhecem, a platéia reage em coro com murmurinhos e risos.

Me senti extremamente constrangido, ofendido e em seguida, profundamente triste.

Acho que aprendi o que é homofobia. A homofobia velada. É uma coisa mínima, uma sutileza que passa despercebida, mas que ofende profundamente e não permite defesa.

Fiquei triste ao constatar que a homofobia e as demais fobias sociais, não se resumem a intolerância. Mais do que intolerância, há uma incapacidade de apreciação das diferenças. As pessoas estão incapazes de reconhecer o afeto, o amor, a humanidade na relação entre duas pessoas quaisquer.

Quanto tempo são 30 anos?

Pra mim, que tenho essa idade, é tudo. Mas parece que culturalmente 30 anos são 30 segundos.

A contemporaneidade das letras do Renato Russo é assustadora. Aquelas músicas poderiam ter sido escritas hoje pela manhã.

Saí do cinema com a sensação de que não se passaram 30 anos no Brasil. Ainda nos falta sensibilidade para nos reconhecermos uns nos outros. Essa falta de empatia, consequentemente, gera falta de engajamento para fazermos as mudanças por nós mesmos.

Ainda não conseguimos ler além do que está literalmente escrito, nem ver além do que está explícito na cena. Precisamos de óculos melhores para lermos as entrelinhas das questões, das notícias, das inúmeras distrações que nos empurram para a ignorância.

Não, isso não é uma reclamação. É um ato de conscientização. Um lembrete de que ainda tem chão pela frente. De que ainda não estamos onde queremos. Ao menos eu ainda não estou.

por Henrique Bastos em 12 de May de 2013 às 03:27

May 07, 2013

Rodrigo Amaral

Matheus apresenta introdução ao Django

Resumo do 1º Encontro de Usuários Python de SergipeNo último dia 30 de abril, aproveitamos a realização da quarta edição do World Plone Day em Aracaju para realizar o primeiro Encontro de Usuários Python de Sergipe. O evento aconteceu na Universidade Tiradentes e contou com a expressiva participação de cerca de 40 pessoas, que aproveitaram a oportunidade para conhecer um pouco mais sobre Plone e Python, além de entrar em contato com outros interessados na plataforma.

Inicialmente, apresentei uma rápida palestra institucional sobre o Python User Group de Sergipe (PUG-SE), explicando a motivação por trás do uso de Python e suas tecnologias, e a importância de ter um grupo de usuários local atuante.

Em seguida, foi a vez da palestra do World Plone Day, ministrada por Davi Lima. Foi apresentada uma visão geral sobre o CMS Plone e seu ecossistema: características, vantagens competitivas, oportunidades de mercado, comunidade, perspectivas e etc. Os participantes aproveitaram para tirar várias dúvidas sobre aplicações do Plone, casos indicados de uso da plataforma, entre outras.

A terceira palestra da noite foi sobre o uso do Git para controle de versões, apresentada por Onezino Gabriel Moreira. Conversamos sobre o funcionamento do workflow do Git, boas práticas para gerenciamento de repositórios por parte de equipes em diversos cenários de uso, comandos úteis, etc.

A palestra seguinte foi uma rápida Introdução ao Django, ministrada por Matheus Lima. O grupo demonstrou muito interesse e participou bastante, tanto que decidimos, de comum acordo, deixar a palestra sobre Criação de plugins para Sublime Text que seria apresentada em seguida para o próximo encontro.

Por fim, realizamos um sorteio dos brindes gentilmente cedidos por nossos patrocinadores PyCursos e Treinamentos.mobi. Além deles, gostaríamos de agradecer à Universidade Tiradentes pela total disponibilidade e apoio ao evento, inclusive incentivando os alunos interessados a participar.

logo-pycursos

logo-treinamentos.mobi

Em breve teremos mais uma edição do Encontro do PUG-SE! Para ficar por dentro, assine a nossa lista de discussão.


por Rodrigo Amaral em 07 de May de 2013 às 20:48

May 01, 2013

Aprenda Python

Fazer com que uma função seja membro de uma instância

Neste post eu uso o Web2py como exemplo, mas a ideia de atribuir uma função dinamicamente a uma instância de classe é genérica e eu peguei da Python Decorator Library, que trata só de decorators. Diferente do Django, não é necessário criar classes para definir modelos, no Web2py. Uma desvantagem é que não existe a figura dos managers, como no Django. Assim, fica ruim associar métodos às tabelas,

por Vinicius Assef (noreply@blogger.com) em 01 de May de 2013 às 17:50

April 30, 2013

Aprenda Python

Um ambiente Web2py novo a cada projeto

A virtualização veio pra ficar no mundo do desenvolvimento de software. Se você programa em Python e ainda não usa virtualenv, sugiro dar uma pesquisada e começar a usar agora mesmo. O maior benefício dele é isolar os ambientes, de modo que cada projeto seu não seja afetado pelo outro. Trocando em miúdos, cada ambiente virtual tem seu próprio conjunto de bibliotecas (site-packages) independente

por Vinicius Assef (noreply@blogger.com) em 30 de April de 2013 às 18:08

April 28, 2013

Gustavo Niemeyer

Porting 6700 lines of C to Go

A few years ago, when I started pondering about the possibility of porting juju to the Go language, one of the first pieces of the puzzle that were put in place was goyaml: a Go package to parse and serialize a yaml document. This was just an experiment and, as a sane route to get started, a Go layer that does all the language-specific handling was written on top of the libyaml C scanner, parser, and serializer library.

This was a good initial plan, but for a number of reasons the end goal was always to have a pure Go implementation. Having a C layer in a Go program slows down builds significantly due to the time taken to build the C code, makes compiling in other platforms and cross-compiling harder, has certain runtime penalties, and also forces the application to drop the memory safety guarantees offered by Go.

For these reasons, over the last couple of weeks I took a few hours a day to port the C backend to Go. The total time, considering full time work days, would be equivalent to about a week worth of work.

The work started on the scanner and parser side of the library. This took most of the time, not only because it encompassed more than half of the code base, but also because the shared logic had to be ported too, and there was a need to understand which patterns were used in the old code and how they would be converted across in a reasonable way.

The whole scanner and parser plus header files, or around 5000 code lines of C, were ported over in a single shot without intermediate runs. To steer the process in a sane direction, gofmt was called often to reformat the converted code, and then the project was compiled every once in a while to make sure that the pieces were hanging together properly enough.

It’s worth highlighting how useful gofmt was in that process. The C code was converted in the most convenient way to type it, and then gofmt would quickly put it all together in a familiar form for analysis. Not rarely, it would also point out trivial syntactic issues. A double win.

After the scanner and parser were finally converted completely, the pre-existing Go unmarshaling logic was shifted to the new pure implementation, and the reading side of the test suite could run as-is. Naturally, though, it didn’t work out of the box.

To quickly pick up the errors in the new implementation, the C logic and the Go port were put side-by-side to run the same tests, and tracing was introduced in strategic points of the scanner and parser. With that, it was easy to spot where they diverged and pinpoint the human errors.

It took about two hours to get the full suite to run successfully, with a handful of bugs uncovered. Out of curiosity, the issues were:

  • An improperly dropped parenthesis affected the precedence of an expression
  • A slice was being iterated with copying semantics where a reference was necessary
  • A pointer arithmetic conversion missed the base where there was base+offset addressing
  • An inner scoped variable improperly shadowed the outer scope

The same process of porting and test-fixing was then repeated on the the serializing side of the project, in a much shorter time frame for the reasons cited.

The resulting code isn’t yet idiomatic Go. There are several signs in it that it was ported over from C: the name conventions, the use of custom solutions for buffering and reader/writer abstractions, the excessive copying of data due to the need of tracking data ownership so the simple deallocating destructors don’t double-free, etc. It’s also been deoptimized, due to changes such as the removal of macros and in many cases its inlining, and the direct expansion of large unions which causes some core objects to grow significantly.

At this point, though, it’s easy to gradually move the code base towards the common idiom in small increments and as time permits, and cleaning up those artifacts that were left behind.

This code will be made public over the next few days via a new goyaml release. Meanwhile, some quick facts about the process and outcome follows.

Lines of code

According to cloc, there was a total of 7070 lines of C code in .c and .h files. Of those, 6727 were ported, and 342 were 12 functions that were left unconverted as being unnecessary right now. Those 6727 lines of C became 5039 lines of Go code in a mostly one-to-one dumb translation.

That difference comes mainly from garbage collection, lack of forward declarations, standard helpers such as append, range-based for loops, first class slice type with length and capacity, internal OOM handling, and so on.

Future work code can easily increase the difference further by replacing some of the logic ported with more sensible options available in Go, such as standard abstractions for readers and writers, buffered writing support as availalbe in the standard library, etc.

Code clarity and safety

In the specific context of the work done, which is of a scanner, parser and serializer, the slice abstraction is responsible for noticeable clarity gains in the code, when compared to the equivalent logic based on pointer arithmetic. It also gives a much more comforting guarantee of correctness of the written code due to bound-checking.

Performance

While curious, this shouldn’t be taken as a performance comparison between the two languages, as it is comparing a fine tuned C implementation with something that is worse than a direct one-to-one port: not only it hasn’t seen any time at all on preventing waste, but the original logic was deoptimized due to changes such as the removal of inlining macros and the expansion of large unions. There are many obvious changes to be done for improving performance.

With that out of the way, in a simple decoding benchmark the C-backed decoder runs on about 37% of the time taken by the out-of-the-box deoptimized Go port.

Output size

The previous goyaml.a Go package file had 1463kb. The new one has 1016kb. This difference includes glue code generated for the integration.

Considering only the .c and .h files involved in the port, the C object code generated with the standard flags used by the go build tool (-g -O2) sums up to 789kb. The equivalent Go code with the standard settings compiles to 664kb. The 12 functions not ported are also part of that difference, so the difference is pretty much negligible.

Build time

Building the 8 .c files alone takes 3.6 seconds with the standard flags used by the go build tool (-g -O2). After the port, building the entire Go project with the standard settings takes 0.3 seconds.

Mechanical changes

Many of the mechanical changes were done using regular expressions. Excluding the trivial ones, about a dozen regular expressions were used to swap variable and type names, drop parenthesis, place brackets in the right locations, convert function declarations, and so on.

por niemeyer em 28 de April de 2013 às 13:50

Inno::Blog

O Saltador, o Consultor e os Levianos

Em 14 de Outubro de 2012, Felix Baumgartner, um paraquedista austríaco, concluiu o objetivo do projeto Red Bull Stratos e realizou um salto de 39 mil metros, sendo o salto mais alto de todos os tempos, partindo nada mais nada menos que da estratosfera no qual ele chegou através de um balão especialmente preparado para tal feito. E este não foi o único cuidado, pois para se conquistar tal feito, ele passou por uma preparação minunciosa, tomando assim vários cuidados como por exemplo empregando telemetrias adequada e altamente calibradas,  fazer Felix respirar oxigênio puro para eliminar o nitrogênio de seus sangue, que poderia se expandir em alturas elevadas e com isto ameaçar sua saúde.

O staff do projeto contava com especialistas altamente qualificados e  entre eles estava Joe Kittinger na categoria de consultor especial, detentor do recorde anterior que havia sido estabelecido em 1960. Vendo um documentário sobre o tal feito, houve algo que Joe comentou que me chamou muito a atenção:

“Teve muita gente falando sobre como as ondas de choque da barreira de som poderiam partí-lo ao meio” o que deixou Joe muito triste e frustrado, pois “aqueles que insistiam em afirmar estas coisas, não consultaram a equipe Stratos para saber os cuidados que eles estavam tomando, não eram especialistas no assunto e não possuíam nenhuma fundamentação e realizavam tais afirmações apenas porque eles podiam”.

Bom, Joe deveria estar mais acostumado com esta situação pois esta é um das constantes da humanidade.  Independente das motivações, *parece* que ser leviano é regra e não exceção. Além disto há a “recursividade dos sem noção“, onde sem argumentos racionais o imprudente critica o insensato que acredita e potencializa os delírios do leviano. E há quem afirme que o segredo do sucesso é saber conviver com tudo isto, convencer e ser articulado para sobreviver.

Mas sou muito solidário ao Joe, eu entendo totalmente o desconforto dele.

Num dos muitos contextos que posso citar, é muito comum vermos discussões em foruns e listas baseadas em artigos equivocados ou baseado em pesquisas de caráter duvidoso, algumas vezes as imprecisões logo vem a tona pela análise de seus integrantes, mas sempre há (quando não são maioria) os simpatizantes dos levianos por razões simples, tanto o autor quanto seus simpatizantes estão falando aquilo que eles desejam que seja verdade e não a realidade ou simplesmente são analistas imprudentes.

A algum tempo, me foi solicitado uma consultoria de  performance, security testing e verificação de SIMRAV compliace de um sistema, sendo-se que o SIMRAV tem um workflow, processos, protocolos  e mensageria padrão.  No primeiro contato com os desenvolvedores, me foi comentado que possivelmente eu não encontraria muita coisa, pois o Scrum Master do projeto havia orientado todo o processo de TDD (Test Driven Development), todos os módulos possuíam testes unitários, funcionais, de integração e que a arquitetura era excepcional, etc, etc, etc…  E quanto a capacidade de processamento ele realmente era impecável,  mas além de ter segurança tendendo a zero, ele havia falhas conceituais, que eu achei impressionante.

Quando fiz a introdução da apresentação do meu parecer, chegaram a me perguntar se eu tinha certeza do que eu estava falando,  chegaram a insinuar (na brincadeira) que eu estava sendo leviano e que tal apresentação era para conquistar mais horas de consultoria, da forma que foi feito confesso que me senti ofendido. Mas relevei, e já imaginando por isto, em minha apresentação dissequei alguns bits, datagramas, assim como fluxos incorretos e as páginas dos manuais que evidenciava as falhas. Nem preciso dizer que os diretores técnico e de produto, assim como os gerentes de produto, desenvolvimento e segurança  não ficaram nada felizes, mas ali não encontrei ninguém na equipe que dominasse de SIMRAV. E então fiquei pensando, como poderia? Para um sistema tão específico não possuir alguém que dominasse as regras de negócio? Na hora lembrei de uma das máximas do livro Code Complete do Steve McConnell:

Testing by itself does not improve software quality. Test results are an indicator of quality, but in and of themselves, they don’t improve it. Trying to improve software quality by increasing the amount of testing is like trying to lose weight by weighing yourself more often. What you eat before you step onto the scale determines how much you will weigh, and the software development techniques you use determine how many errors testing will find. If you want to lose weight, don’t buy a new scale; change your diet. If you want to improve your software, don’t test more; develop better.”

E neste caso, para desenvolver melhor, era necessário de um especialista nas regras de negócio. Pois técnicas eles possuíam de sobra. E o mais surpreendente foi ouvir do diretor que num outro sistema eles haviam cometido a mesma falha.

Acidentes acontecem, ninguém é perfeito, todos estão propensos ao erro e o alvo de minha crítica é ao cerne de cada uma das iniciativas. É a insistência e a recorrência que classifica o indivíduo.

Namastê!


por leptoniando em 28 de April de 2013 às 01:50

April 23, 2013

Rodrigo Amaral

Gustavo Niemeyer

Exceptional crashes

Last week I was part of a rant with a couple of coworkers around the fact Go handles errors for expected scenarios by returning an error value instead of using exceptions or a similar mechanism. This is a rather controversial topic because people have grown used to having errors out of their way via exceptions, and Go brings back an improved version of a well known pattern previously adopted by a number of languages — including C — where errors are communicated via return values. This means that errors are in the programmer’s face and have to be dealt with all the time. In addition, the controversy extends towards the fact that, in languages with exceptions, every unadorned error comes with a full traceback of what happened and where, which in some cases is convenient.

All this convenience has a cost, though, which is rather simple to summarize:

Exceptions teach developers to not care about errors.

A sad corollary is that this is relevant even if you are a brilliant developer, as you’ll be affected by the world around you being lenient towards error handling. The problem will show up in the libraries that you import, in the applications that are sitting in your desktop, and in the servers that back your data as well.

Raymond Chen described the issue back in 2004 as:

Writing correct code in the exception-throwing model is in a sense harder than in an error-code model, since anything can fail, and you have to be ready for it. In an error-code model, it’s obvious when you have to check for errors: When you get an error code. In an exception model, you just have to know that errors can occur anywhere.

In other words, in an error-code model, it is obvious when somebody failed to handle an error: They didn’t check the error code. But in an exception-throwing model, it is not obvious from looking at the code whether somebody handled the error, since the error is not explicit.
(…)
When you’re writing code, do you think about what the consequences of an exception would be if it were raised by each line of code? You have to do this if you intend to write correct code.

That’s exactly right. Every line that may raise an exception holds a hidden “else” branch for the error scenario that is very easy to forget about. Even if it sounds like a pointless repetitive task to be entering that error handling code, the exercise of writing it down forces developers to keep the alternative scenario in mind, and pretty often it doesn’t end up empty.

It isn’t the first time I write about that, and given the controversy that surrounds these claims, I generally try to find one or two examples that bring the issue home. So here is the best example I could find today, within the pty module of Python’s 3.3 standard library:

def spawn(argv, master_read=_read, stdin_read=_read):
    """Create a spawned process."""
    if type(argv) == type(''):
        argv = (argv,)
    pid, master_fd = fork()
    if pid == CHILD:
        os.execlp(argv[0], *argv)
    (...)

Every time someone calls this logic with an improper executable in argv there will be a new Python process lying around, uncollected, and unknown to the application, because execlp will fail, and the process just forked will be disregarded. It doesn’t matter if a client of that module catches that exception or not. It’s too late. The local duty wasn’t done. Of course, the bug is trivial to fix by adding a try/except within the spawn function itself. The problem, though, is that this logic looked fine for everybody that ever looked at that function since 1994 when Guido van Rossum first committed it!

Here is another interesting one:

$ make clean
Sorry, command-not-found has crashed! Please file a bug report at:

https://bugs.launchpad.net/command-not-found/+filebug

Please include the following information with the report:

command-not-found version: 0.3
Python version: 3.2.3 final 0
Distributor ID: Ubuntu
Description:    Ubuntu 13.04
Release:        13.04
Codename:       raring
Exception information:

unsupported locale setting
Traceback (most recent call last):
  File "/.../CommandNotFound/util.py", line 24, in crash_guard
    callback()
  File "/usr/lib/command-not-found", line 69, in main
    enable_i18n()
  File "/usr/lib/command-not-found", line 40, in enable_i18n
    locale.setlocale(locale.LC_ALL, '')
  File "/usr/lib/python3.2/locale.py", line 541, in setlocale
    return _setlocale(category, locale)
locale.Error: unsupported locale setting

That’s a pretty harsh crash for the lack of locale data in a system-level application that is, ironically, supposed to tell users what packages to install when commands are missing. Note that at the top of the stack there’s a reference to crash_guard. This function has the intent of catching all exceptions right at the edge of the call stack, and displaying a detailed system specification and traceback to aid in fixing the problem.

Such “parachute catching” is a fairly common pattern in exception-oriented programming and tends to give developers the false sense of having good error handling within the application. Rather than actually guarding the application, though, it’s just a useful way to crash. The proper thing to have done in the case above would be to print a warning, if at all, and then let the program run as usual. This would have been achieved by simply wrapping that one line as in:

try:
    locale.setlocale(locale.LC_ALL, '')
except Exception as e:
    print("Cannot change locale:", e)

Clearly, it was easy to handle that one. The problem, again, is that it was very natural to not do it in the first place. In fact, it’s more than natural: it actually feels good to not be looking at the error path. It’s less code, more linear, and what’s left is the most desired outcome.

The consequence, unfortunately, is that we’re immersing ourselves in a world of brittle software and pretty whales. Although more verbose, the error result style builds the correct mindset: does that function or method have a possible error outcome? How is it being handled? Is that system-interacting function not returning an error? What is being done with the problem that, of course, can happen?

A surprising number of crashes and plain misbehavior is a result of such unconscious negligence.

por niemeyer em 23 de April de 2013 às 08:35

Andrews Medina

a diferença entre atributos de classe e de instância

"Qual a diferença entre atributos de classe e de instância em Python?"

Essa é uma dúvida muito comum e bem simples de ser respondida. Mas, antes de repondê-la vou demonstrar o que é um atributo de classe e de instância.

atributo de classe

São atributos que são definidos diretamente a classe.

atributo de instância

São atributos definidos a instância, geralmente através do "self", que representa a instância de uma classe.

Qual a diferença entre eles?

A diferença é que atributos de classes são compartilhados por todas as instâncias daquela classe. Atributos de instancia são únicos para cada instância.

Por exemplo, todas as modificações feitas na lista "l" da classe "C" afetara a lista para todas as instâncias de "C" pois "l" é um atributo da classe.

Já com as instâncias da classe "D" isso não ocorre pois "l" é um atributo de instância, sendo único para cada instância de "D":

É importante conhecer esse comportamento para não ter resultados inesperados ao construir uma classe.

por andrewsmedina@gmail.com (Andrews Medina) em 23 de April de 2013 às 00:58

April 16, 2013

Elcio Luiz Ferreira

April 15, 2013

Artificial Intelligence in Motion

Review of the book Learning Scipy for Numerical and Scientific Computing


Hi all,

I've finished reading the book "Learning Scipy for Numerical and Scientific Computing".  This book comes to the scientific python series that PacktPub are bringing to the Python Developers! Congratulations!  As the title informs: it includes Scipy, Numpy and Matplotlib.  I only missed some further information about IPython, but it wasn't the goal of the book, so it goes well even leaved out.





It covers several important topics that are not as commonly covered, specially with several snippets illustrating special functions presented at Scipy library. For the developers it will be another great reference book to complement the native docs that comes with the library.  I enjoyed the author focused more on numerical analysis functions, it is one of the most used functions at the library.  

The bool also brings chapters on more specific applications: signal processing, data mining and computational geometry.  There is an extra chapter about the integration with another languages, but I found it not dense enough to explain those integrations. I really missed more start-off examples showing how to install the f2py or how to use Scipy with C/C++. 

Overall the Learning Scipy for Numerical and Scientific Computing book is a good book on Scipy covering  lots of mathematics with examples in Python. The book has a good size and it helps the scientists and scientific developers (by the way the non-developers will face some difficulties due to the heavy math that comes with the examples) to have a good overview on the library before exploring the reference material.


Thanks Kenny for the invitation to review this book, and congratulations to Francisco for bringing one more technical book for scientific python computing to the series!

Regards,

Marcel Caraciolo


por Marcel Caraciolo (noreply@blogger.com) em 15 de April de 2013 às 18:20

Gustavo Niemeyer

Unix-like pipelines for Go

This weekend the proper environment settled out for sorting a pet peeve that shows up every once in a while when coding: writing logic that interacts with other applications in the system via their stdin and stdout streams is often more involved than it should be, which seems pretty ironic when sitting in front of a Unix-like system.

Rather than going over the trouble of setting up pipes and hooking them up in a custom way, often applications end up just delegating the job to /bin/sh, which is not ideal for a number of reasons: argument formatting isn’t straightforward, injecting custom application-defined logic is hard, which means even simple tasks that might be easily achieved by the language end up shelling out to further external applications, and so on.

In an attempt to address that, I’ve spent some time working on an experimental Go package that is being released today: pipe.

I hope you like it as well, and please drop me a note if you find any issues.

por niemeyer em 15 de April de 2013 às 08:52

April 12, 2013

Andrews Medina

try.tsuru.io

Nós da equipe do PaaS da globo.com estamos lançando o try.tsuru.io como private beta com o objetivo de ser uma maneira fácil das pessoas conhecerem e experimentarem o tsuru.

Com o tsuru, times e desenvolvedores não precisam se preocupar com servidores ou em como executar o deploy, eles podem focar no mais importante: a aplicação.

Com ele é possível escrever aplicações na linguagem da sua escolha, usar serviços como banco de dados SQL ou NoSQl, memcacehd, redis e plugá-los a sua app.

Você gerencia sua app usando a linha de comando ou uma interface web e faz o deploy via git. Tudo isso sendo executado pela infra estruturua do tsuru.

O tsuru é um projeto open source se você quiser conhecer o código, montar seu próprio Paas usando o tsuru, contribuir ou sugerir features/reportar bugs sinta-se a vontade.

por andrewsmedina@gmail.com (Andrews Medina) em 12 de April de 2013 às 14:38

April 11, 2013

Francisco Souza

Try out Tsuru: announcing limited preview

A few days ago, Tsuru got some attention in the news. After reading about Tsuru, and seeing some of its capabilities, people started asking for a way to try Tsuru. Well, your claims were attended! We're preparing a public cloud that will be freely available for beta testers.

TL;DR: go to tsuru.io/try, signup for beta testing and get ready to start deploying Python, Ruby, Go and Java applications in the cloud.

What is Tsuru?

Tsuru is an open source platform as a service that allows developers to automatically deploy and manage web applications written in many different platforms (like Python, Ruby and Go). It aims to provide a solution for cloud computing platforms that is extensible, flexible and component based.

You can run your own public or private cloud using Tsuru. Or you can try it in the public cloud that Globo.com is building.

What is Tsuru public cloud? What does "beta availability" means?

Tsuru public cloud will be a public, freely available, installation of Tsuru, provided by Globo.com. "Beta availability" means that it will not be available for the general Internet public.

People will need to subscribe for the beta testing and wait for the confirmation, so they can start deploying web applications on Tsuru public cloud.

Which development platforms are going to be available?

Tsuru already supports Ruby, Python, Java and Go, so it is very likely that these platforms will be available for all beta users.

It's important to notice that adding new platforms to Tsuru is a straightforward task: each development platform is based on Juju Charms, so one can adapt charms available at Charm Store and send a patch.

How limited is it going to be?

We don't know what's the proper answer for this question yet, but don't worry about numbers now. There will be some kind of per-user quota, but it has not been defined yet.

People interested in running applications in the Tsuru public cloud that get to use the beta version will have access a functional environment where they will be able to deploy at least one web application.

When will it be available?

We're working hard to make it available as soon as possible, and you can help us get it done! If you want to contribute, please take a look at Tsuru repository, chose an issue, discuss your solution and send your patches. We are going to be very happy helping you out.

What if I don't want to wait?

If you want an unlimited, fully manageable and customized installation of Tsuru, you can have it today. Check out Tsuru's documentation and, in case of doubts, don't hesitate in contacting the newborn Tsuru community.

por Francisco Souza (noreply@blogger.com) em 11 de April de 2013 às 22:47

April 08, 2013

Osvaldo Santana Neto

Filtros bolha e a diversidade de opinião

Nos últimos dias tenho feito algumas experiências e estou tentando viver sem o Google. Sério… é bem difícil e tem algumas coisas que eles fazem que estão se provando insubstituíveis.

A razão para eu tentar me livrar do Google é o temor de ficar tão dependente de um serviço deles e eles simplesmente resolverem descontinuar como fizeram com o Code Search, Reader, entre outros. É muito mais uma questão de confiabilidade do que privacidade, monopólio, etc.

Uma das coisas difíceis de se substituir é o Google Search. Principal produto da empresa. Para essa tarefa eu escalei o DuckDuckGo que, apesar do nome inusitado, já havia se motrado um excelente buscador em testes que eu havia feito anteriormente.

O DuckDuckGo tem duas “funcionalidades” interessantes. Uma delas é um respeito maior à privacidade de seus usuários. A outra é a ausência de filtros bolha.

Quando fui avaliar melhor a questão relacionada a filtros bolhas meu cérebro tomou uma linha de raciocínio que seguiu em direção à diversidade de opinião e a tolerância que temos à essa diversidade.

Vou tentar usar fatos atuais para ilustrar a minha linha de raciocínio e para isso terei que trabalhar com assuntos polêmicos relacionados à amor, ódio, religião, ateísmo, homossexualismo, etc.

Também vou partir da premissa de que todo mundo na internet, hoje, tem opiniões fortes sobre todos os assuntos. Dos royalties do petróleo ao dinheiro gasto para mandar a Curiosity para Marte.

O conceito de “filtro bolha” que o Google Search implementa faz com que assuntos que tenham mais relação com o seu histórico de pesquisa tenha um ranking melhor do que algo que não “combine” com você.

O resultado desse comportamento é que o Google Search vai sempre lhe oferecer “mais do mesmo” ao longo do tempo e aquilo que diverge das suas opiniões vai simplesmente sumindo dos resultados criando uma “bolha protetora” de opiniões.

Nas redes sociais isso também acontece mas de uma maneira mais explícita: você oculta as opiniões divergentes, o sistema ‘aprende’ que você não gosta daquilo e nunca mais te manda informações daquele tipo (ou daquela pessoa).

Frequentemente me pego “censurando” alguns posts nas minhas timelines quase que de modo inconsequente.

Sou ateu (mesmo) e acho que todos podem crer ou, como no meu caso, não-crer, no que lhes deixam felizes.

Sou heterossexual mas entendo o homossexualismo sob o aspecto cientifico dos estudos que dizem que as pessoas são homossexuais e não se tornam homossexuais por opção (ou com o passar dos anos).

No espectro político eu piso um pouco mais à esquerda do que à direita e tenho vínculo com um partido político que representa essa posição. Apesar disso sei que existem virtudes na “direita” e pessoas extremamente inteligentes que trafegam nessa vertente.

A minha linha-mestra de pensamento: se você está feliz e não está me tornando infeliz você pode fazer e acreditar no que achar melhor.

Apesar disso sou humano e cometo erros de julgamento e avaliação.

Recentemente, com a chegada de um pastor evangélico fundamentalista à presidência da Comissão de Direitos Humanos da Câmara dos Deputados, as redes sociais estão fervendo com assuntos relacionados à cristianismo, laicismo, homossexualismo, racismo, e outros “ismos”.

Pra mim, na minha timeline, é um festival de surpresas e decepções com pessoas que fazem parte do meu “círculo virtual de amizades”. Até aí não tem nada de errado. O problema aparece é na escolha dos critérios que te fazem ficar surpreso ou se decepcionar.

Sendo ateu eu poderia me decepcionar com uma pessoa quando ela defende parcimoniosamente o discurso do tal pastor demonstrando trechos bíblicos que corroboram tais opiniões (mesmo sabendo que com trechos da bíblia é possível corroborar qualquer tese). Essa pessoa é crente e tem pra ela que esse livro é sagrado, logo, tem força maior que a “lei dos homens”.

Mas eu não posso me decepcionar com essa pessoa e censurá-la na minha timeline porque, com isso, estaria alimentando o meu filtro bolha e mandando a diversidade de opinião às favas. No lugar de censurá-la eu prefiro debater com essa pessoa ou simplesmente deixá-la com suas opiniões, afinal, ela deve ser feliz com aquele pensamento.

Agora vamos para outra hipótese: esse mesma pessoa que citou a bíblia me decepcionaria muito se usasse uma mentira, um estudo científico duvidoso, uma fonte de origem duvidosa, ou até mesmo usar desonestidade intelectual para, por exemplo, “provar que homossexualismo é errado”.

Eu tenho duas reações possíveis com pessoas que me decepcionam dessa forma. Se a pessoa é muito cara para mim eu rebato o post dela para tentar desmenti-lo. Se a pessoa “não cheira nem fede”, ela será censurada. Mas veja que eu censurei essa pessoa por ser desonesta e não por ser crente.

Qualquer tipo de censura cria o efeito “bolha” mas a bolha que eu criei é uma bolha de segurança para me proteger contra pessoas desonestas e não pra me privar da diversidade de opinião.

Além dessa censura aos desonestos eu também censuro, com menos frequencia, os “ativistas”. Censuro eles não pelo que pensam e defendem mas pelo excesso. É uma questão puramente prática: tenho um limite de tempo para ver a minhas timelines. Se elas estão monopolizadas pelos “ativistas” fica difícil ver os posts de todo mundo.

Além disso, ativistas, sejam felizes com o que pensam e defendem e me deixem ser feliz com o que penso e defendo. Parem de se comportar como Testemunhas de Jeová oferencendo a palavra do senhor.

Quanto ao caso do tal pastor: não acho que ele seja adequado para a tal comissão e acho que ele deveria sair de lá. Mas não devemos ser desonestos para atingir esse objetivo.

Não concordo com uma palavra do que dizes, mas defenderei até o ultimo instante seu direito de dizê-la.
Voltaire (ou não)

por osantana em 08 de April de 2013 às 15:00

April 07, 2013

Artificial Intelligence in Motion

Slides for Scientific Computing Meeting: Benchy and GeoMapper Visualization



Hi all,

Yesterday it happened the XXVI local meeting of the Python Users Group at Pernambuco (PUG-PE).  In the occasion I had the opportunity to present two talks about scientific computing with python.


The first one was the lightweight framework for benchmark analysis on Python Scripts called Benchy, which I developed for about one week to help me on checking performance of several algorithms that I developed in Python.  I covered the framework at my last post which can be found here.


Here are the slides for the presentation:




The second talk was about a new type of visualization that I developed for social network analysis in order to check the degree of connections between the users at the socialnetwork using their geolocation data to present in a map.

The result was beautiful plots using this new type of visualization.  Amazing!

The slides are available here:



I hope you enjoy the slides, any further information feel free to comment!

Regards,

Marcel Caraciolo

por Marcel Caraciolo (noreply@blogger.com) em 07 de April de 2013 às 06:43

April 03, 2013

Henrique Bastos

Cuidados importantes ao configurar i18n no Django

A Babilônia caiu não foi por acaso. Internacionalização (aka i18n) é trabalhoso por natureza, e quando você esbarra em sutilezas de configuração pode ser irritante.

Esta semana eu decidi finalmente adaptar o site do Small Acts Manifesto para outros idiomas, e no processo acabei caindo numa cilada de coincidências.

Para que você não cometa o mesmo erro, criei uma receitinha de bolo para configurar o projeto.

Começe pelo settings.py:

USE_I18N = True
LANGUAGES = (
    ('en', u'English'),
    ('pt-br', u'Português'),
)
LOCALE_PATHS = (PROJECT_DIR.child('locale'),)

É simples, mas temos alguns pontos de atenção:

  • O LANGUAGES é uma tupla de tuplas. O primeiro elemento das tuplas é o language code. Para português brasileiro o valor é pt-br, tudo minúsculo separado por hífen.
  • LOCALE_PATHS é escrito no plural e aceita vários diretórios, portanto é uma tupla contendo strings.
  • Se você não sabe o que é o PROJECT_DIR, veja nesta palestra.

Crie os arquivos .po

Cada idioma tem um “código fonte” da tradução.

O Django varre todo o código fonte e reúne as strings marcadas para tradução com o comando:

python manage.py makemessages -l en -l pt_BR

Atenção, o parâmetro deve ser pt_BR, com pt em minúsculo e BR em maiúsculo, separados por underscore. Esse formato é o locale name e este valor será usado para criar o diretório que conterá o arquivo django.po.

Usando as traduções

Depois de definir as traduções editando os arquivos .po, basta empacotar a tradução, compilando os .po em .mo para os idiomas disponíveis:

python manage.py compilemessages

Ao longo do projeto você vai usar várias vezes o makemessages e o compilemessages.

Se você for realizar traduções colaborativas, o Transifex pode ajudar bastante e é grátis para projetos open source.

Mas e a cilada?

Quando eu implementei conteúdo em português tudo funcionava bem no ambiente de desenvolvimento, mas no ambiente de stage o site só exibia o idioma padrão que é o inglês. Clássico caso de works on my machine. Como pode?

O problema era que eu estava desenvolvendo no Mac e o site está hospedado em Linux.

Por desatenção, eu executei o makemessages -l pt_br, em minúsculo.

Na minha máquina tudo funcionava, porque o filesystem do Mac não é case sensitive por padrão, logo conseguia encontrar o diretório. Já no Linux, era como se não existisse dicionário disponível em português.

Qual a moral da história?

Use vagrant mesmo em um site ridiculamente pequeno, e compartilhe seus tropeços para que outros possam rir de você, com você. :-P

[]‘s, HB!

por Henrique Bastos em 03 de April de 2013 às 21:10

April 01, 2013

Henrique Bastos

A importância do movimento DIY

Depois que retuitei a frase do Vini Braga:

“As pessoas precisam entender de uma vez por todas, a busca da “invisibilidade da tecnologia” é um dos pilares do totalitarismo vigente.”

O Luis Soeiro perguntou se eu poderia explicar melhor…

Tecnologia é conhecimento aplicado. Basicamente, com a ciência conhecemos a natureza e com a engenharia criamos ferramentas a partir destes conhecimentos.

No início, uma nova tecnologia encanta, mas logo a gente se acostuma com ela e a incorpora na nossa rotina. Com o tempo, tecnologia vira mágica, no sentido de que todos apreciam, alguns sabem como ela funciona, poucos sabem como implementá-la e uma restrita minoria detém o direito de reproduzí-la.

Tecnologia existe para expandir a capacidade do ser humano. Mas se nossas capacidades são tão ampliadas com tecnologias, por qual razão temos cada vez menos tempo? Por que estamos cada vez correndo mais?

Porque não dominamos as tecnologias. Apenas as usamos para obtermos um resultado. E a cultura do “foco no resultado” dispensa o acesso a como as coisas funcionam, apesar de dependermos cada vez mais destas ferramentas.

Isso acontece em todos os âmbitos. Pegue a programação web, por exemplo. Quantos profissionais repousam na mais alta camada de abstração do framework de sua preferência? Quantos compreendem como e porque o framework funciona e quantos seriam capazes de implementar o seu?

Não estou sugerindo que cada programador tenha que implementar o seu próprio framework. Mas penso que devam ter esta capacidade.

Essa é a essência do movimento Do It Yourself. A busca pelo conhecimento tácito para realizar a mágica e não apenas permanecer como espectador ou como mágico teórico.

Sem essa busca, a mesma tecnologia que poderia libertar, acaba se tornando invisível, reduzindo o homem à escravo ignorante do seu aluguel. Afinal, se você depende, mas não possui, terá que pagar pelo acesso. Sempre!

[]‘s, HB!

por Henrique Bastos em 01 de April de 2013 às 02:27

March 28, 2013

Gustavo Niemeyer

Synchronicity: threads vs. events

There are a number of common misconceptions in software development surrounding the idea of concurrency. This has been coming for decades, and some of the issues have just been reinforced one more time in an otherwise interesting post in LinkedIn’s engineering blog that recommends their development framework.

Such issues may be observed throughout the post, but can be elucidated via this short paragraph:

As we saw with the Scala and JavaScript examples above, for very simple cases, the Evented (asynchronous) code is generally more complicated than Threaded (synchronous) code. However, in most real-world scenarios, you’ll have to make several I/O calls, and to make them fast, you’ll need to do them in parallel.

At a glance, this may look like a sane proposition. There’s agreement that an asynchronous API or framework is one that does not block the flow of execution when faced with a task that has a long or non-predictable deadline, and this coding style is harder for human beings to get right. For example, if you see code such as:

data = read(filename)

There’s less brain work to process and build on it than so called asynchronous logic such as:

read(filename, callback)

It’s also true that there are important interfaces that follow the asynchronous style to prevent resource waste. Some of these exist in the kernel I/O API.

So what’s the issue, then?

There are a few. The first one is the statement that to make I/O scale you have to do it in parallel. That’s clearly not true. Scalable I/O requires your program to not waste an irresponsible amount of memory and CPU per operation. This may be achieved with simple concurrent techniques, and concurrency is not parallelism.

This drives to the next point, which is the strong association between synchronous programming and threads. You can have synchronous programming, and its simplified mental model, without operating system threads. This can be done by having a compiler and runtime that is mindful about performance and resource consumption, building on the efficient interfaces to implement its abstractions.

These ideas have also been covered in this paper from 2003, including benchmark results that debunk the performance myth. What seems most interesting about this paper is that it theorizes such a compiler and runtime that would allow “overcom[ing] limitations in current threads packages and improv[ing] safety, programmer productivity, and performance”, by using techniques such as dynamic stack growth, stack moving, cheaper synchronization, and compile-time data race detection.

That exact mix, including all of the properties described in the paper, are available today in the Go language. You can have synchronous programming, concurrency, parallelism, and performance. We live in the future.

por niemeyer em 28 de March de 2013 às 10:56

March 22, 2013

Artificial Intelligence in Motion

Performing runtime benchmarks with Python Monitoring Tool Benchy


Hi all,

I've been working on in the last weeks at a little project that I developed called benchy.  The goal of benchy is answer some trivial questions about which code is faster ?  Or which algorithm consumes more memory ?  I know that there are several tools suitable for this task, but I would like to create some performance reports  by myself using Python.   

Why did I create it ?  Since the beginning of the year I decided to rewrite all the code at Crab, a python framework for building recommender systems.  And one of the main components that required some refactoring was the pairwise metrics such as cosine, pearson, euclidean, etc.  I needed to unit test the performance of several versions of code for those functions. But doing this manually ? It's boring. That's why benchy came for!


What benchy can do ?

Benchy is a lightweight Python library for running performance benchmarks over alternative versions of code.  How can we use it ?

Let's see the cosine function, a popular pairwise function for comparing the similarity between two vectors and matrices in recommender systems.




Let's define the benchmarks to test:



With all benchmarks created, we could test a simple benchmark by calling the method run:


The dict associated to the key memory represents the memory performance results. It gives you the number of calls repeat to the statement, the average consumption usage in units . In addition, the key 'runtime' indicates the runtime performance in timing results. It presents the number of calls repeat following the average time to execute it timing in units.

Do you want see a more presentable output ? It is possible calling the method to_rst with the results as parameter:


Benchmark setup
import numpy
X = numpy.random.uniform(1,5,(1000,))

import scipy.spatial.distance as ssd
X = X.reshape(-1,1)
def cosine_distances(X, Y):
return 1. - ssd.cdist(X, Y, 'cosine')
Benchmark statement
cosine_distances(X, X)
namerepeattimingloopsunits
scipy.spatial 0.8.0318.3610ms


Now let's check which one is faster and which one consumes less memory. Let's create a BenchmarkSuite. It is referred as a container for benchmarks.:

Finally, let's run all the benchmarks together with the BenchmarkRunner. This class can load all the benchmarks from the suite and run each individual analysis and print out interesting reports:



Next, we will plot the relative timings. It is important to measure how faster the other benchmarks are compared to reference one. By calling the method plot_relative:




As you can see the graph aboe the scipy.spatial.distance function is 2129x slower and the sklearn approach is 19x. The best one is the numpy approach. Let's see the absolute timings. Just call the method plot_absolute:



You may notice besides the bar representing the timings, the line plot representing the memory consumption for each statement. The one who consumes the less memory is the nltk.cluster approach!

Finally, benchy also provides a full repport for all benchmarks by calling the method to_rst:




Performance Benchmarks

These historical benchmark graphs were produced with benchy.
Produced on a machine with
  • Intel Core i5 950 processor
  • Mac Os 10.6
  • Python 2.6.5 64-bit
  • NumPy 1.6.1

scipy.spatial 0.8.0

Benchmark setup
import numpy
X = numpy.random.uniform(1,5,(1000,))

import scipy.spatial.distance as ssd
X = X.reshape(-1,1)
def cosine_distances(X, Y):
return 1. - ssd.cdist(X, Y, 'cosine')
Benchmark statement
cosine_distances(X, X)
namerepeattimingloopsunits
scipy.spatial 0.8.0319.1910ms

sklearn 0.13.1

Benchmark setup
import numpy
X = numpy.random.uniform(1,5,(1000,))

from sklearn.metrics.pairwise import cosine_similarity as cosine_distances
Benchmark statement
cosine_distances(X, X)
namerepeattimingloopsunits
sklearn 0.13.130.18121000ms

nltk.cluster

Benchmark setup
import numpy
X = numpy.random.uniform(1,5,(1000,))

from nltk import cluster
def cosine_distances(X, Y):
return 1. - cluster.util.cosine_distance(X, Y)
Benchmark statement
cosine_distances(X, X)
namerepeattimingloopsunits
nltk.cluster30.010241e+04ms

numpy

Benchmark setup
import numpy
X = numpy.random.uniform(1,5,(1000,))

import numpy, math
def cosine_distances(X, Y):
return 1. - numpy.dot(X, Y) / (math.sqrt(numpy.dot(X, X)) *
math.sqrt(numpy.dot(Y, Y)))
Benchmark statement
cosine_distances(X, X)
namerepeattimingloopsunits
numpy30.0093391e+05ms

Final Results

namerepeattimingloopsunitstimeBaselines
scipy.spatial 0.8.0319.1910ms2055
sklearn 0.13.130.18121000ms19.41
nltk.cluster30.010241e+04ms1.097
numpy30.0093391e+05ms1

Final code!

I might say this micro-project is still a prototype, however  I tried to build it to be easily extensible. I have several ideas to extend it, but feel free to fork it and send suggestions and bug fixes.  This project was inspired by the open-source project vbench, a framework for performance benchmarks over your source repository's history. I recommend!

For me, benchy will assist me to test several pairwise alternative functions in Crab. :)  Soon I will publish the performance results that we got with the pairwise functions that we built for Crab :)

I hope you enjoyed,

Regards,

Marcel Caraciolo

por Marcel Caraciolo (noreply@blogger.com) em 22 de March de 2013 às 09:52

March 20, 2013

Rodrigo Amaral

Guia para os atalhos de teclado do Sublime Text

Guia para os atalhos de teclado do Sublime TextTodo mundo que usa o computador para trabalhar durante muitas horas por dia já deve ter notado que um dos segredos para ser mais produtivo é tirar as mãos do teclado o menos possível. Aprender a digitar direito, eliminando alguns vícios adquiridos ao longo dos anos, também ajuda bastante.

Quando falamos do Sublime Text, então, a importância de aprender a usar os atalhos de teclado, ao invés de perder tempo alcançando o mouse, fica ainda mais evidente. O Sublime Text tem atalhos de teclado para quase tudo mas, quando se está iniciando, às vezes é um pouco difícil descobri-los e memorizá-los. Para facilitar a tarefa, seguem algumas dicas:

Dedique alguns minutos para explorar os menus

Vasculhar os menus quando não se está procurando por nenhum comando específico é muito útil para descobrir novos recursos. Em muitos casos, os atalhos de teclado são mostrados ao lado de cada item. Algo que também costumo fazer quando quero aprender os atalhos de alguma ferramenta é me forçar a procurar pelo comando desejado no menu, usando o mouse – para me lembrar de quanto é inconveniente, e por isso tenho que aprender o atalho o quanto antes – ver qual é o atalho e depois fechar o menu e usar o teclado. Faço isso toda vez que preciso executar o comando, até memorizar.

Utilize a Command Palette

Após se familarizar com os menus, comece a usar a Command Palette (Ctrl+Shift+P) para tudo. Com ela você poderá ter acesso a quase todos os comandos sem precisar alcançar o mouse, mesmo se não lembrar o atalho. Ao chamar a Command Palette, aparecerá uma lista de seleção com o recurso de autocompletar. Depois é só começar a digitar algumas letras da descrição do comando até encontrá-lo e pressionar Enter. Lembrando que, em muitos casos, o atalho específico de cada comando também aparece na Command Palette.

Vasculhe os arquivos de configuração

Se ainda não achou o atalho que você queria, nem nos menus, nem na Command Palette, não se desespere. O pulo do gato nesse caso é “partir pra ignorância” e ir fuçar nos arquivos de configuração do Sublime Text:

  1. Clique no… (oops!) Ative a Command Palette e digite “keybindings default” para abrir o arquivo de configuração de atalhos padrão para seu sistema operacional. Lá são definidos todos os atalhos de teclado padrão.
  2. Procure por um trecho de alguma palavra que descreva o comando desejado. Como não existem descrições textuais de cada ação, pode não ser tão simples encontrar na primeira tentativa, mas se um atalho existe, ele estará lá.

Por exemplo, quando precisamos achar o atalho para duplicar uma linha, basta começar a procurar (Ctrl+F) no arquivo de configuração por “duplicate” e logo aparece a linha:

{ "keys": ["ctrl+shift+d"], "command": "duplicate_line" },

E eis aí nosso atalho: Ctrl+Shift+D.

E os atalhos para comandos dos plugins instalados?

Os comandos dos plugins muitas vezes não aparecem no menu nem na Command Palette. Descobri-los vai exigir um pouco do seu Sherlock Holmes interior, mas não é nenhum bicho de sete cabeças. Como todos os atalhos de teclados estão definidos em arquivos no formato JSON de fácil leitura, você vai precisar fazer o seguinte:

  1. Abrir a Command Palette.
  2. Digitar “Browse Packages”.
  3. Procurar e abrir a pasta com o nome do plugin cujo atalho para o comando você quer descobrir.
  4. Procurar e abrir o arquivo de configuração de atalhos, que possui a extensão sublime-keymap. Lá estão todos os atalhos do plugin, é só procurar pelo que você precisa.

Conhece alguma outra dica de atalho do Sublime Text? Compartilhe com a gente nos comentários.

Referência: dicas de Josh Earl, autor de Sublime Productivity


por Rodrigo Amaral em 20 de March de 2013 às 21:51

March 17, 2013

Elcio Luiz Ferreira

Pare, pense, e faça alguma coisa!

Este é um blog sobre tecnologia e desenvolvimento, e eu tenho sido muito criterioso em evitar posts sobre outros assuntos. Mas dessa vez eu não me aguentei. Hoje li esses posts:

Se você ainda não os leu, por favor, leia agora. Depois você volta aqui e continua a ler o meu.

Não levou a sério? Cara, vai lá, lê os dois posts, você vai perder um minutinho só em cada um. Vale a pena.

Leu? Bom queria falar de 3 assuntos: carros, bicicletas e trabalho.

O primeiro texto é sobre carros. Os outros dois sairão nos próximos domingos.

Tenho um sedã popular. Comprei novo, há três anos. Está na hora de trocar. Não amo meu carro, embora goste muito do conforto e comodidade que ele traz a minha família. Já me disseram para trocar meu carro por um “melhor”, mas “melhor”, nesse caso, significa mais caro, mais imponente ou maior. Nenhum desses três adjetivos significa melhor para mim. Não é raro que eu deixe o carro na garagem e vá de transporte público a alguma reunião. Não é raro também, ver nas pessoas cara de espanto ao saber que eu cheguei até ali sem um carro. “Está tudo bem? Quer uma carona? O que houve com seu carro?” São as reações mais comuns.

Por quê? Claro, por uma série de motivos, incluindo o fato de que tem muita gente que realmente te julga pelo carro em que você anda. Mas há um outro motivo, que talvez seja mais doloroso: não ter um carro, em São Paulo, é muito ruim. Dependendo do seu caminho, andar de transporte público é desumano.

Fiz uma experiência simples. Escolhi quatro shopping centers, cada um em uma zona da cidade, e tracei as rotas no Google Maps da minha casa até lá agora:

Lugar de carro de transporte público
Zona Oeste 0:23 1:25
Zona Leste 0:30 1:20
Zona Norte 0:23 1:20
Zona Sul 0:33 1:10

Está certo, é domingo. Se seu trajeto puder ser feito de Metrô e for hora do rush, o carro perde feio. Dependendo do trajeto, é melhor até ir andando a pé pela rua do que de carro. Você olhou bem para a tabela acima? Se eu for a um shopping agora com minha família, de carro, em qualquer lugar da cidade vou gastar cerca de uma hora em deslocamento, ida e volta. Se formos de transporte público, levarei duas horas e meia, se der sorte.

Qual o resultado disso? Simples, quem puder vai andar de carro, sempre que puder. O jovem de classe baixa arruma o primeiro emprego e começa a se planejar para comprar um carro, para se livrar do ônibus, mesmo que o carro custe mais de um ano de salário. São Paulo tem 11 milhões de habitantes e 6 milhões de carros. Não cabem 6 milhões de carros nas ruas.

A matemática é simples. São Paulo tem cerca de 14 mil quilômetros de ruas e avenidas. Se todos os 6 milhões de veículos da cidade forem colocados em fila, encostados um no outro, a fila terá quase 27 mil quilômetros. Mesmo a cidade tendo centenas de avenidas com várias pistas, é fácil ver o que acontece.

A solução não é fazer mais avenidas. Nosso modelo de cidade feliz não pode ser um lugar onde todos tenham bons carros e possam dirigi-los livremente. Não porque eu ache que pessoas de determinada classe social, cor da pele, religião ou time de futebol não mereçam ter um bonito SUV de oito lugares. Simplesmente não cabe, não há espaço para isso. Nós precisamos de outro modelo de felicidade. Precisamos de uma cidade em que sair de carro seja apenas uma das boas opções.

Enquanto continuarmos achando que quem tem um carro é mais importante do que quem anda à pé, deixando de dar preferência ao mais frágil no trânsito, xingando o sujeito que teve a coragem de fazer alguma coisa ao deixar o carro em casa e sair de bicicleta, buzinando para o motorista que parou antes de uma esquina para o pedestre passar, vamos estar transmitindo uma mensagem a toda a sociedade: importante é quem tem carro. Nossas crianças estão ouvindo a mensagem. Nossos governantes também.

Isso tem muito a ver com você, que não sairia de casa sem carro nem que estivesse em Londres. Não estou dizendo que você precisa deixar de andar de carro, que isso é crime. O que estou dizendo é que, se você não quer ser obrigado a deixar o carro em casa, você precisa parar de pensar em avenidas e viadutos, e começar a pensar em tornar a cidade boa para todos. Ao votar, ao escrever, ao conversar, você deveria fazer o que estiver ao seu alcance para que São Paulo tenha transporte público excepcional, e que andar a pé, de bicicleta, de moto ou de Pogobol seja maravilhoso. É o único jeito de cabermos todos aqui.

por elcio em 17 de March de 2013 às 20:37

March 15, 2013

PUG - PE

Inline image 1

Olá a todos,

Com grande satisfação que convidamos a todos para submeterem propostas de palestras para o nosso I Encontro Nordestino de Python (PythonNordeste). Com muita dedicação e esforço das comunidades locais estamos lançando a chamada das palestras em conjunto com a nossa página oficial: http://pythonnordeste.org

Inline image 1

O evento será realizado nos dias 24 e 25 de maio de 2013 em Fortaleza, Ceará. As células do Nordeste estão organizando este evento, lideradas pelo PUG-CE, PUG-AL, PUG-PE e o PUG-SE.  O evento já tem 4 keynotes confirmadas com presenças de referências em Python no cenário brasileiro como Luciano Ramalho, Alvaro Justen e Henrirque Bastos.  O I Lote já se encontra à venda com preço promocional até o final de março!

Quaisquer pessoas podem submeter palestras desde que atendam os pré-requisitos: a) ser algum assunto relacionado a uso direto ou indireto da plataforma Python b) ter disponibilidade de comparecer no dia do evento na data e horário para apresentação e c) palestras terem com duração máxima de 25 minutos com 5 minutos para perguntas.

Link para submissão de palestras:    http://pythonnordeste.org/callforpapers

A chamada estará aberta até o dia 30 de março  com trilhas de Python Core, Frameworks, Enterprise e Gestão, Web, Mobile, Multimídia, Science e outros. Para aqueles que pretendem submeter palestras no PythonBrasil este ano em Brasília, eis uma excelente oportunidade de apresentar previamente para um público selecionado e interessado em programação e Python. O resultado da seleção deve sair até o dia 15 de abril.

Todos estão convidados, para mais informações entrem em contato conosco pelo site:  http://pythonnordeste.org/#contato

Divulguem a todos seus colegas e amigos! E nos vemos em Fortaleza, Ceará!

Atenciosamente,

Equipe PythonNordeste


por marcelcaraciolo em 15 de March de 2013 às 18:31

Aprenda Python

Rapidinha - strings em Python

"Rapidinha Python" é uma série de posts que demonstram a praticidade de Python. Você pode encontrar outros posts da série, identificadas com a tag "rapidinha". Iniciamos a série com esse post falando de strings em Python. Rapidinha Python é direto ao assunto. Então, show me the code! Preenchido ou vazio? >>> s = 'abcd' >>> if s: ... print('tem conteudo') ... tem conteudo >>> s = '' >>> if

por Vinicius Assef (noreply@blogger.com) em 15 de March de 2013 às 14:04

March 12, 2013

Rodrigo Amaral

Não é magia, é o módulo itertools da biblioteca padrão do Python

Não é magia, é o módulo itertools da biblioteca padrão do PythonQuem ouve falar que Python vem com baterias incluídas, geralmente não imagina que elas estão mais próximas de uma usina nuclear do que de um par de pilhas Rayovale (sim, existe!). Nunca me canso de ficar surpreso toda vez que lembro que existem módulos como o itertools, por exemplo. Passeando pela documentação, é fácil encontrar funcionalidades poderosas, pérolas que podem salvar o dia em alguns minutos quando o seu problema é um desses:

Percorrer os elementos de várias sequências de uma só vez

Com a função chain(), basta fazer:

>>> import itertools
>>> a = [100, 200, 300]
>>> b = ('Newton', 'Einstein', 'Hawking', 'Cooper')
>>> c = 'Python'
>>> for item in itertools.chain(a, b, c):
...     print item
...
100
200
300
Newton
Einstein
Hawking
Cooper
P
y
t
h
o
n

Calcular a soma acumulada a cada passo da iteração

Vamos supor que uma criança guarda parte de sua mesada num cofrinho todo mês. Com a função accumulate() (Python 3) é possível calcular o valor economizado mês a mês:

>>> import itertools
>>> cofrinho = [10, 12, 15, 5, 7, 0, 20, 13, 9, 0, 1, 16]
>>> for mes, valor_guardado in enumerate(list(itertools.accumulate(cofrinho)), start=1):
...    print(mes, '= R$', valor_guardado)
...
1 = R$ 10
2 = R$ 22
3 = R$ 37
4 = R$ 42
5 = R$ 49
6 = R$ 49
7 = R$ 69
8 = R$ 82
9 = R$ 91
10 = R$ 91
11 = R$ 92
12 = R$ 108

Na verdade essa é apenas a funcionalidade mais básica da função accumulate(). É possível passar qual a função que será usada no lugar da soma, permitindo fazer operações muito mais complexas envolvendo séries de elementos. Mais detalhes podem ser vistos na documentação oficial.

Encontrar todas as possíveis combinações entre os elementos de um conjunto

Lembra de análise combinatória na escola? Uma entre as funções do módulo itertools que poderiam nos ajudar na hora do aperto é a permutations(). Um problema clássico da análise combinatória é encontrar todos os anagramas de uma palavra:

>>> import itertools
>>> [''.join(anagrama) for anagrama in itertools.permutations('gato')]
['gato', 'gaot', 'gtao', 'gtoa', 'goat', 'gota', 'agto', 'agot', 'atgo', 'atog', 'aogt', 'aotg', 'tgao', 'tgoa', 'tago', 'taog', 'toga', 'toag', 'ogat', 'ogta', 'oagt', 'oatg', 'otga', 'otag']

Esse é só um aperitivo das possibilidades do módulo itertools. A documentação oficial traz, além da referência de todas as funções do módulo, uma seção só com receitas do que se pode construir a partir da combinação das funções. Vale dar uma olhada, pois nunca se sabe quando vai ser necessário usar algo parecido.

Referência


por Rodrigo Amaral em 12 de March de 2013 às 22:22

March 10, 2013

Aprenda Python

Dicionários na sequência de criação

Os dicionários em Python são estruturas muito poderosas e rápidas. Mas uma característica ruim deles é que a ordem das chaves não é garantida. Isso significa que ao criar um dicionário você pode ver algo assim: >>> d = {'ac': 'Acre', 'ce': 'Ceará', 'pi': 'Piauí'} >>> print(d) {'ac': 'Acre', 'pi': 'Piauí', 'ce': 'Ceará'} >>> Viu? Fora de ordem. Isso atrapalha quando queremos manter a ordem dos

por Vinicius Assef (noreply@blogger.com) em 10 de March de 2013 às 11:05

March 06, 2013

Rodrigo Amaral

Comandos Python em uma linha

Comandos Python em uma linhaJá se vão mais de 15 anos desde que a última edição da saudosa revista Micro Sistemas foi publicada. Naquela época pré-internet, os curiosos que tentavam aprender como obrigar o computador a fazer exatamente o que eles queriam – vulgo programar – não tinham outra alternativa a não ser garimpar livros e revistas sobre o assunto. Uma das minhas seções preferidas da Micro Sistemas era a dos jogos one-liner em BASIC e suas variantes. Meu primeiro contato com programação foi justamente a tentativa de copiar aquele emaranhado mágico e incompreensível de letras e números que vinha publicado na revista e tentar fazer aquilo funcionar.

Hoje a informação é muito mais acessível e qualquer um pode aprender praticamente qualquer assunto, sobre qualquer ramo do conhecimento humano, desde que tenha disciplina para se dedicar o suficiente. Uma dentre as milhões de coisas bastante úteis de se aprender é o uso das opções de linha de comando do interpretador Python (finalmente cheguei onde queria!). Com elas é possível realizar vários tipos de tarefas em apenas 1 (uma) linha, direto do shell, sem sequer precisar editar um arquivo de código-fonte.

A opção -c <comando>

Executa o código Python passado como argumento em comando, que pode ser uma ou mais declarações separados por indicadores de nova linha, no caso o ponto-e-vírgula (;). Vale lembrar que, assim como no código Python normal, espaços em branco no começo de cada linha são significativos. Portanto, cuidado.

A opção -m <nome-do-módulo>

Procura no sys.path pelo nome-do-módulo e executa seu conteúdo como o módulo principal (__main__). Como o argumento é o nome de um módulo, você não deve passar a extensão (.py). O nome-do-módulo deveria ser um nome de módulo válido para o Python, mas pode ser que a implementação não force esse comportamento (ex.: pode permitir que você use um nome que contenha hífen).

Exemplos de uso

Com essas duas opções e um pouco de criatividade, é possível fazer coisas como:

Imprimir o caminho de busca por módulos Python formatado

Usando os módulos sys e pprint:

$ python -c 'import sys, pprint; pprint.pprint(sys.path)'

Iniciar um servidor HTTP

Este exemplo cria um servidor HTTP que serve o conteúdo do diretório corrente na porta 8081 usando o módulo SimpleHTTPServer :

$ python -m SimpleHTTPServer 8081

Obter lista dos releases disponíveis de um módulo do PyPI

Usando o módulo xmlrpclib:

$ python -c 'import xmlrpclib; print xmlrpclib.Server("http://pypi.python.org/pypi").package_releases("Django")'
['1.5', '1.4.5', '1.4.4', '1.4.3', '1.3.7', '1.3.6', '1.3.5', '1.2.7', '1.1.4', '1.0.4']

Medir o tempo de execução de um trecho de código

Usando o módulo timeit para descobrir qual implementação é mais rápida:

$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 35.3 usec per loop
$ python -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 3: 30.2 usec per loop

Conhece alguma outra aplicação útil das opções de linha de comando do Python? Compartilhe nos comentários!

Referências


por Rodrigo Amaral em 06 de March de 2013 às 00:51

March 04, 2013

Aprenda Python

Named Tuples ao invés de classes ou dicionários

O Python 2.6 introduziu uma nova estrutura de dados, chamada namedtuple(), que pode ajudar a eliminar classes ou a deixar de usar dicionários aonde eles não deveriam ser usados. As named tuples são objetos imutáveis, assim como as tuplas e a grande novidade é que agora os campos têm um nome, lembrando uma struct da linguagem C, mas tendo a mesma facilidade de interação das tuplas do Python.

por Vinicius Assef (noreply@blogger.com) em 04 de March de 2013 às 19:38

March 02, 2013

Thiago Avelino

Chromium as the default browser

Logo ChromiumThe code of Google Chrome is based on Chromium, all the feature implemented in Chromium comes in Google Chrome.

What do you think of being one of the first to test new feature of Google Chrome? Interesting huh!

Download a bleeding-edge build of Chromium for Mac!

Chromium does not update automatically, for this reason I wrote a shell script which updates the Chromium on Mac:

#!/bin/sh
#
# Note, this will remove /Applications/Chromium.app
#

echo '..'
rm -f chrome-mac.zip chrome-mac
export CHROME_VERSION=`curl http://commondatastorage.googleapis.com/chromium-browser-continuous/Mac/LAST_CHANGE`
echo "   latest version: $CHROME_VERSION"
echo '..'
export CHROME_OLD_VERSION=`cat ~/dotfile/CHROME_VERSION`
if [ $CHROME_VERSION == $CHROME_OLD_VERSION ]; then
  echo '   latest version!'
  echo '..'
  exit 2
fi
echo $CHROME_VERSION > ~/doestfile/CHROME_VERSION
echo "   save latest version: $CHROME_VERSION"
echo '..'
echo "   get latest version: $CHROME_VERSION"
echo '..'
wget http://commondatastorage.googleapis.com/chromium-browser-continuous/Mac/$CHROME_VERSION/chrome-mac.zip
echo "   compile latest version: $CHROME_VERSION"
echo '..'
unzip chrome-mac.zip
rm -rf /Applications/Chromium.app
echo "   install latest version: $CHROME_VERSION"
echo '..'
mv chrome-mac/Chromium.app /Applications/Chromium.app
rm -rf chrome-mac chrome-mac.zip
killall -9 Chromium
open /Applications/Chromium.app
echo 'DONE'

base source: https://github.com/avelino/dotfile/blob/master/chromium_update.sh

por avelino em 02 de March de 2013 às 00:18

March 01, 2013

Artificial Intelligence in Motion

Graph Based Recommendations using "How-To" Guides Dataset


Hi all,

In this post I'd like to introduce another approach for recommender engines using graph concepts to recommend novel and interesting items. I will build a graph-based how-to tutorials recommender engine using the data available on the website SnapGuide (By the way I am a huge fan and user of this tutorials website), the graph database Neo4J and the graph traversal language Gremlin.

What is SnapGuide ?

Snapguide is a web service for anyone who wants to create and share step-by-step "how to guides".  It is available on the web and IOS app. There you can find several tutorials with easy visual instructions for a wide array of topics including cooking, gardening, crafts, projects, fashion tips and more.  It is free  and anyone is invitide to submit guides in order to share their passions and expertise with the community.  I have extracted from their website for only research purposes the corpus of tutorials likes. Several users may like the tutorial and this signal can be quite useful to recommend similar tutorials based on what other users liked.  Unfortunately I can't provide the dataset for download but the code you can follow below for your own data set.

Snapguide 



Getting Started with Neo4J


To create your own graph with Neo4J you will need to use Java/Groovy to explore it.  I found Bulbflow, it is a open-source Python ORM  for graph databases and supports puggable backends using Blueprints standards.  In this post I used it to connect to Neo4j Servers.  The snippet code below is a simple example of Bulbflow in action by creating some edges and vertexes.


>>> from people import Person, Knows
>>> from bulbs.neo4jserver import Graph
>>> g = Graph()
>>> g.add_proxy("people", Person)
>>> g.add_proxy("knows", Knows)
>>> james = g.people.create(name="James")
>>> julie = g.people.create(name="Julie")
>>> g.knows.create(james, julie)

Generating our tutorials Graph


I decided to define my graph schema in order to map the raw data into a property graph so the traversals required to get recommendations of which tutorials to check could be natural as possible.


SnapGuide Graph Schema


The data will be inserted into the graph database Neo4J  The code belows creates a new Neo4J graph with all the data set.

#-*- coding: utf-8 -*-
from bulbs.neo4jserver import Graph
from nltk.tag.hunpos import HunposTagger
from nltk.tokenize import word_tokenize

ht = HunposTagger('en_wsj.model')

likes = open('likes.csv')
tutorials = open('tutorials.csv')
users = open('users.csv')
g = Graph()
def filter_nouns(words):
return [word.lower() for word, cat in words if cat in ['NN', 'NNP', 'NNPS']]
#Loading tutorials and categories
for tutorial in tutorials:
tutorial = tutorial.strip()
try:
ID, title, likes, category = tutorial.split(';')
except:
try:
ID, title, category = tutorial.split(';')
except:
t = tutorial.split(';')
ID, title, category = t[0], t[1].replace('&Yuml', ''), t[-1]

tut = g.vertices.create(type='Tutorial', tutorialId=int(ID), title=title)
keywords = filter_nouns(ht.tag(word_tokenize(tutorial.split(';')[1])))
keywords.append(category)

for keyword in keywords:
resp = g.vertices.index.lookup(category=keyword)
if resp is None:
ct = g.vertices.create(type='Category', category = keyword)
else:
ct = resp.next()
g.edges.create(tut,'hasCategory', ct)
#Loading user dataset.

for user in users:
user = user.strip()
username = user.split(';')[0]

user = g.vertices.create(type='User', userId=username)
#Loading the likes dataset.
for like in likes:
like = like.strip()
item_id, user_id = like.split(';')
p = g.vertices.index.lookup(tutorialId=int(item_id))
q = g.vertices.index.lookup(userId=user_id)
g.edges.create(q.next(), 'liked', p.next())
There are three input files: tutorials.dat, users.dat and likes.dat. The file tutorials.dat contains the list of  tutorials. Each row has 2 columns: tutorialId, title and category. The file users.dat contains the list of users.  Each row contains the columns:  userID, user name.  Finally  the likes.dat includes the tutorials that a user marked their interest. Each row of the raw file has : userId and movieId.

Given that there are more than 1 million likes, it will take some time to process all the data. An important note before going on. Don't forget to create the vertices indexes,  if you forget your queries it will take ages to proccess.


  1. //These indexes are a must, otherwise querying the graph database will take so looong
  2. g.createKeyIndex('userId',Vertex.class)
  3. g.createKeyIndex('tutorialId',Vertex.class)
  4. g.createKeyIndex('category',Vertex.class)
  5. g.createKeyIndex('title',Vertex.class)


Before moving on to recommender algorithms, let's make sure the graph is ok.

For instance,  what is the distribution of keywords amongst the tutorials repository ?

  1. //Distribution frequency of Categories
    def dist_categories(){
      m = [:]
     g.V.filter{it.getProperty('type')=='Tutorial'}.out('hasCategory').category.groupCount(m).iterate() 
    return m.sort{-it.value}
    }
>>> script = g.scripts.get('dist_categories')
>>> categories = g.gremlin.execute(script, params=None)
>>> sorted(categories.content.items(), key=lambda keyword: -keyword[1])[:10]
[(u'food', 4537), (u'make', 3840), (u'arts-crafts', 1609), (u'cook', 1362), (u'desserts', 1247), (u'beauty', 1108), (u'technology', 943), (u'drinks', 587), (u'home', 508), (u'chicken', 452)]

What about the average number of likes per tutorial ?

  1. //Get the average number of likes per tutorial
    def avg_likes(){
    return  
    g.V.filter{it.getProperty('type')=='Tutorial'}.transform{it.in('liked').count()}.mean() 
    }

>>> script = g.scripts.get('avg_likes')
>>>likes = g.gremlin.command(script, params=None)
>>>likes
111.089116326

Trasversing the Tutorials Graph

Now that the data is represented as graph, let's make some queries. Behind the scene what we make are some traversals.  In recommender systems  there are two general typs of recommendation approaches: the collaborative filtering and content-based one.

In collaborative, the liking behavior of users is correlated in order to recommend the favorites of one user to another, in this case let's find the similar user.

I like the tutorials Amanda preferred, what other tutorials does Amanda like that I haven't seen ?

Otherwise, the content-base strategy is based on the features of a recommendable item. So the attributes are analyzed in order to find other similar items with analogous features.

I  like food tutorials, what other food tutorials are there ?


Making Recommendations

Let's begin with collaborative filtering.  I will use some complex traversal queries at our graph.  Let's start with the tutorial: "How to Make Sous Vide Chicken at Home".  Yes,  I love chicken! :)

Great dish by the way!
Which users liked Make Sous Vide Chicken at Home ?
  1. //Get the users who liked a tutorial
    def users_liked(tutorial){
       v = g.V.filter{it.getPropery('title') == tutorial}
       return v.inE('liked').outV.userId[0..4]
    }
>>> tuts = g.vertices.index.lookup(title='Make Sous Vide Chicken at Home')
>>> tut = tuts.next()
>>> tut.title
Make Sous Vide Chicken at Home
>>> tut.tutorialId
11890
>>> tut.type
Tutorial
>>> script = g.scripts.get('n_users_liked')
>>> users_liked = g.gremlin.command(script, params={'tutorial': 'Make Sous Vide Chicken at Home'})
>>> users_liked
1000
This traversal doesn't provide us useful information, but we could put in action now the collaborative filtering with a extended query:

Which users liked Make Sous Vide Chicken at Home and what other tutorials did they liked most in common to ?


  1. //Get the users who liked the tutorial and what other tutorials did they like too ?
    def similar_tutorials(tutorial){
    v = g.V.filter{it.getProperty('title') == tutorial}
    return v.inE('liked').outV.outE('liked').inV.title[0..4]
    }


>>>> script = g.scripts.get('similar_tutorials')
>>>> similar_tutorials = g.gremlin.execute(script, params={'tutorial': 'Make Sous Vide Chicken at Home'})
>>> similar_tutorials.content
[u'Make Potato Latkes', u'Make Beeswax and Honey Lip Balm', u'Make Sous Vide Chicken at Home', u'Cook the Perfect & Simple Chicken Ramen Soup', u'Make a Simple (But Authentic) Paella on Your BBQ']

What is the query above express ?

It filters all users that liked the tutorial (inE('liked')) and find out what they liked (outV.outE('liked')), fetching the title of those tutorials (inV.title) . It returns the first five items ([0..4])

In recommendations we have to find the most-common purchased or liked itens.  Using Gremlin, we can work on a simple collaborative filtering algorithm by joining several steps together.

  1. //Get similar tutorials
    def topMatches(tutorial){
        m = [:]
    v = g.V.filter{it.getProperty('title') == tutorial}
    v.inE('liked').outV.outE('liked').inV.title.groupCount(m).iterate()
        return m.sort{-it.value}[0..9]

    }


>>> script = g.scripts.get('topMatches')
>>> topMatches = g.gremlin.execute(script, params={'tutorial': 'Make Sous Vide Chicken at Home'})
>>> sorted(topMatches.content.items(), key=lambda keyword: -keyword[1])[:10]
{u'Make Cake Pops!!': 75, u'Make Sous Vide Chicken at Home': 1000, u'Make Potato Latkes': 124, u'Make Incredible Beef Jerky at Home Easily!': 131, u'Cook the Perfect & Simple Chicken Ramen Soup': 96, u'Make Mint Juleps': 74, u"Solve a 3x3 Rubik's Cube": 89, u'Cook Lamb Shanks Moroccan Style': 74, u'Make Beeswax and Honey Lip Balm': 75, u'Make an Aerium': 74}

This traversal will return a list of tutorials.  But you may notice if you get all matches, ther are many duplicates. It happens because who like  How to Make sous Vide Chicken At Home also like many of the same other tutorials.  The similarity between users in represented at collaborative filtering algorithms.


How many of How to Make sous Vide Chicken At Home highly correlated tutorials are unique ?

  1. //Get the number of unique similar tutorials
    def n_similar_unique_tutorials(tutorial){
    v = g.V.filter{it.title == tutorial}
    return v.inE('liked').outV.outE('liked').inV.dedup.count()
    }

    //Get the number of similar tutorials
    def n_similar_tutorials(tutorial){
    v = g.V.filter{it.getProperty('title') == tutorial}
    return v.inE('liked').outV.outE('liked').inV.count()
    }

>>> script = g.scripts.get('n_similar_tutorials')
>>> similar_tutorials = g.gremlin.command(script, params={'tutorial': 'Make Sous Vide Chicken at Home'})
>>> similar_tutorials
37323
>>> script = g.scripts.get('n_similar_unique_tutorials')
>>> similar_tutorials = g.gremlin.command(script, params={'tutorial': 'Make Sous Vide Chicken at Home'})
>>> similar_tutorials
8766

There are 37323 paths from Make Sous Vide Chicken at Home to other tutorials and only  8766 of those tutorials are unique. Using this information we can use these duplications to build a ranking mechanism to build recommendations.

Which tutorials are most highly co-rated with How to Make Soous Vide Chicken ?


>>> script = g.scripts.get('topMatches')
>>> topMatches = g.gremlin.execute(script, params={'tutorial': 'Make Sous Vide Chicken at Home'})
>>> sorted(topMatches.content.items(), key=lambda keyword: -keyword[1])[:10]
[(u'Make Sous Vide Chicken at Home', 1000), (u'Make Incredible Beef Jerky at Home Easily!', 131), (u'Make Potato Latkes', 124), (u'Cook the Perfect & Simple Chicken Ramen Soup', 96), (u"Solve a 3x3 Rubik's Cube", 89), (u'Make Cake Pops!!', 75), (u'Make Beeswax and Honey Lip Balm', 75), (u'Make Mint Juleps', 74), (u'Cook Lamb Shanks Moroccan Style', 74), (u'Make an Aerium', 74)]

So we have the top similar tutorials. It means, people who like  Make Sous Vide Chicken at Home, also like Make Sous Viden Chicken at Home, oops! Let's remove these reflexive paths, by filtering out the Sous Viden Chicken.

  1. //Get similar tutorials
    def topUniqueMatches(tutorial){
        m = [:]
        v = g.V.filter{it.getProperty('title') == tutorial}
        possible_tutorials = v.inE('liked').outV.outE('liked').inV
        possible_tutorials.hasNot('title',tutorial).title.groupCount(m).iterate()
        return m.sort{-it.value}[0..9]
    }




>>>> script = g.scripts.get('topUniqueMatches')
>>>> topMatches = g.gremlin.execute(script, params={'tutorial': 'Make Sous Vide Chicken at Home'})
>>>
topMatches.content
[(u'Make Incredible Beef Jerky at Home Easily!', 131), (u'Make Potato Latkes', 124), (u'Cook the Perfect & Simple Chicken Ramen Soup', 96), (u"Solve a 3x3 Rubik's Cube", 89), (u'Make Cake Pops!!', 75), (u'Make Beeswax and Honey Lip Balm', 75), (u'Make Mint Juleps', 74), (u'Cook Lamb Shanks Moroccan Style', 74), (u'Make an Aerium', 74), (u'Make a Leather iPhone Flip Wallet', 73)]

The recommendation above starts from a particular tutorial (i.e. Make Sous Vide Chicken), not from a particular user. This collaborative filtering method is called item-based filtering.   

Given an tutorial that a user likes, who else like this tutorial, and from those what other tutorials do they like that are not already liked by the initial user.

And the recommendation for a particular user ?  That comes the user-based filtering.


Which tutorials that similar users liked are recommended given a specified user  ?


  1. def userRecommendations(user){
      m = [:]
      v = g.V.filter{it.getProperty('userId') == user}
     v.out('liked').aggregate(x).in('liked').dedup.out('liked').except(x).title.groupCount(m).iterate()
      return m.sort{-it.value}[0..9]
    }
>>>> script = g.scripts.get('topRecommendations')
>>>> recommendations = g.gremlin.execute(script, params={'user': 'emma-rushin'})
>>>
recommendations.content
[(u'Create a Real Fisheye Picture With Your iPhone', 1156), (u'Make a DIY Galaxy Print Tshirt', 933), (u'Make a Macro Lens for Free!', 932), (u'Make Glass Marble Magnets With Any Image', 932), (u'Make DIY Nail Decals', 932), (u'Make a Five Strand Braid', 929), (u'Create a Pendant Lamp From Coffee Filters', 928), (u'Make Avocado Toast', 926), (u'Make Instagram Magnets for Less Than $10', 923), (u'Make a Recycled Magazine Tree (Christmas Tree)', 923)]

Emma Rushin will really like art and crafts suggestions! :D

Ok, we have interesting recommendations, but if I desire to make another styles of chicken like Chicken Ramen Soup for my dinner, I probably do not want some tutorial of How to Solve a Rubik Cube 3x3.  To adapt to this situation, it is possible to mix collaborative filtering and content-based recommendation into a traversal so it would recommend similar chicken and food tutorials based on similar keywords.
Now let's play with content-based recommendation! 
Which tutorials are most highly correlated with Sous Vide Chicken that share the same category of food?

  1. //Top recommendations mixing content + collaborative sharing all categories.
    def topRecommendations(tutorial){
      m = [:]
      x = [] as Set
     v = g.V.filter{it.getProperty('title') == tutorial}
     tuts =v.out('hasCategory').aggregate(x).back(2).inE('liked').outV.outE('liked').inV
    tuts.hasNot('title',tutorial).out('hasCategory').retain(x).back(2).title.groupCount(m).iterate()
      return m.sort{-it.value}[0..9]
    }
>>>> script = g.scripts.get('topRecommendations')
>>>> recommendations = g.gremlin.execute(script, params={'tutorial': 'Make Sous Vide Chicken at Home'})
>>>
topMatches.content
[(u'Make Incredible Beef Jerky at Home Easily!', 131), (u'Make Potato Latkes', 124), (u'Cook the Perfect & Simple Chicken Ramen Soup', 96), (u'Make Cake Pops!!', 75), (u'Make Beeswax and Honey Lip Balm', 75), (u'Make Mint Juleps', 74), (u'Cook Lamb Shanks Moroccan Style', 74), (u'Cook an Egg in a Basket', 72), (u'Make Banana Fritters', 72), (u'Prepare Chicken With Peppers and Gorgonzola Cheese', 71)]

This rank makes sense, but it still has a flaw.  The tutorial like Make mint Juleps may not be interesting for me. How about only considering those tutorials that share the same keyword 'chicken' with Vide Chicken  ?

Which tutorials are most highly co-rated with Vide Chicken that share the same keyword 'chicken' with  Vide Chicken?
  1. //Top recommendations mixing content + collaborative sharing the chicken category.
    def topRecommendations(tutorial){
     m = [:]
     v = g.V.filter{it.getProperty('title') == tutorial}

     v.inE('liked').outV.outE('liked').inV.hasNot('title',tutorial).out('hasCategory').
     has('category' ,'chicken').back(2).title.groupCount(m).iterate()

     return m.sort{-it.value}[0..9]
    }

>>>> script = g.scripts.get('topRecommendations')
>>>> recommendations = g.gremlin.execute(script, params={'tutorial': 'Make Sous Vide Chicken at Home'})
>>> topMatches.content
{u'Make a Whole Chicken With Veggies in the Crockpot': 28, u'Bake Crispy Chicken With Doritos': 30, u'Cook Chicken Rollatini With Zucchini & Mozzarella': 28, u'Make Beer Can Chicken': 23, u'Roast a Chicken': 54, u'Cook the Perfect & Simple Chicken Ramen Soup': 96, u'Pesto Chicken Roll-Ups Recipe': 31, u'Cook Chicken in Roasting Bag': 23, u'Make Chicken Enchiladas': 29, u'Prepare Chicken With Peppers and Gorgonzola Cheese': 71}



Conclusions
In this post I presented one strategy for recommending items using graph concepts. What I explored here is the flexibility of the property graph data structure and the notion of derived and inferred relationships. This strategy could be further explored to use other features available at your dataset (I will be sure that SnapGuide has more rich information to use such as Age, sex and the category taxonomy).  I am working on a book for recommender systems and I will explain with more details about graph based recommendations, so stay tunned at my blog!

The performance ?  Ok, I didn't test in order to compare with the current solutions nowadays.  What I can say is that Neo4J can theoretically hold billions entities (vertices + edges) and the Gremlin makes possible advanced queries. I will perform some tests, but based on what I studied, depending on the complexity of the the graph structure, runtimes vary. 

I also would like to thank Marko Rodriguez with his help at the Grenlim-Users community with his post to inspire me to take a further look into Neo4J + Grenlim! It amazed me! :)

Regards,

Marcel Caraciolo

por Marcel Caraciolo (noreply@blogger.com) em 01 de March de 2013 às 22:08

Gustavo Niemeyer

12 years ago

These ancient entries were taken from my old Advogato diary, written in my early twenties, a year after I joined the development team of Conectiva Linux. I’m copying them for historic purposes, with the content untouched. It’s curious to look back and have such details of what was going on at the time, things that feel good, and things that feel awkward such as the “Dear Diary, …” style of writing, and the amount of exclamations!!


6 Feb 2002

Wow!! It has been a long time since my last diary entry.

I’ve left Linuxconf development team coordination in favor of the Conectiva Linux port to the S390 platform coordination (ok, I’m mostly coordinating myself now :-) . Most of the work is done. I have developed an acceptable installer (in Python!) and most of the packages are ported. We had some problems with IBM OCO modules (ick!), but we are already workarounding them (we gave up on some of our kernel patches, and I patched insmod to recognize OCO modules). Anyway, more information about this later (if I don’t disappear for another year.. ;-)

In the process of porting Conectiva Linux to S390 and PPC (Harald Welve started the PPC port, and I’m keeping it up to date and working on missing stuff) we are learning some lessons. We are trying to use those lessons to build a defacto package building system using the Python language. Unfortunately, we don’t have enough people here to develop it quickly, so we are trying a more realistic and evolutive approach this time. The first part of it is almost done. While devloping it, I’ve studied a little bit about process groups and extended python with a missing killpg() system call. I’ve also discovered that when python spawns a new thread, it blocks all signals. With this information in mind, I have also extended it with a new execv() syscall, that besides doing the usual work, unblocks every signal before the real call to execv(). I hope this project becomes real someday.

I’ve also been playing with Python optimization lately. There’s a big opportunity for somebody wanting to study and implement some concepts there. I’ve read some documentation about Stack Machine Optimization and made some tries (basically, optimizations around the inner loop and the Big Switch, stack caching, and other flavors of this joy). Today I found a paper from Skip Montanaro documenting some of the tries I’ve made (reading it first would save me a lot of time, but this knowledge will be useful anyway). You should have a look at his paper if you have any interest in the topic. Oh, don’t forget to get yourself a copy of Lemburg’s pybench to have a general idea of what you’re doing (don’t trust too much on it, it’s just a benchmark). I’ve written Skip a mail to discuss a little bit about what could be integrated into the interpreter. Let’s see where we get.

Oh… I must not forget to update the people I’ve certified in the past to reflect what they’ve been doing.

27 Jan 2001

I’ve just tested the patch floppy_cs on kernel 2.2.17 and it works just fine!!! I had no problems applying it. Now my Libretto 50CT has a floppy drive. Maybe Conectiva Linux can ship with this patch. The only drawback is that floppy support must be modular.

In the few last days, I’ve implemented support for Inputgrid into gnome-linuxconf. It allows one to define sensitive areas into a drawing area. Gurus are already working with it.

I’ve also created two new commands for Linuxconf’s gui protocol: Splash and Hidesplash. Linuxconf will send them while it is starting, and the graphic frontend is suposed to show a nice splash screen. Support in gnome-linuxconf has also been implemented with an image designed by Everaldo (thanks!!!).

Btw, yesterday I’ve fixed a bug in Python’s bsddb module. It was handling DB_RECNO databases with string keys. As the documentation says, these databases must use, in key’s “data” field, a pointer to a memory location holding a recno_t type.

My parents have arrived yesterday!! They’ll stay here until monday and then will go to Minas Gerais, visiting Raul and Lulude.

22 Jan 2001

Yesterday I’ve implemented a message signing module for Mailman. Darian (aka dmalloc), from openprojects.net has asked if I could do such module to use on lists.openprojects.net. (I said yes… ;-) . I’m going to ask the people here at Conectiva if they want to use this module in some of our lists.

Pybot has a few new features: CTCP handling/sending, timer module, unhandled messages hook, and something else I probably forgot.

About Linuxconf, I have spent the last days fixing a few simple bugs introduced in 1.24r2 and in the last modules developed by Conectiva. I hope to release a Linuxconf update to Conectiva 6.0 tomorrow.

gnome-linuxconf has won a home with screenshots and everything else at http://distro.conectiva.com/projetos/45. I’ve also published it at freshmeat and put files to download at SourceForge.

Oh, good news I forgot to tell: for those of you that are using wxxt-linuxconf, Jack (Jacques Gelinas) has implemented the Treemenu icons into this frontend as well.

16 Jan 2001

Today I’ve fixed a bug in the Pythonmod module of Linuxconf. Linuxconf has a default handler for the SIGCHLD signal that controls all of its child termination. This method has a few disadvantages. Before calling any external processes without using default Linuxconf methods, you must block this handler, otherwise Linuxconf will get on your way. Because of this, If a Pythonmod module tried to fork external processes, they were failing. Now Pythonmod is setting the SIGCHLD signal to SIG_DFL (POSIX doesn’t allow us to SIG_IGN it) before calling python code, and after returning from a few Linuxconf API functions that set the handler back. When the python code returns, popen_initsignal() is called, putting the Linuxconf handler back in place.

On the gnome-linuxconf side, I’ve implemented the drawing context command Defpen. Now we have colored lines and primitives!! (ok… not that good… ;-)

I’ve also spent a few hours in the last two days backing up and restoring data in my colocated machine. Now my personal emails are back online and the server has an updated kernel. I hope it doesn’t bother me for a long time.

Unfortunately, the server stuff didn’t let me work on Pybot, but I had time to implement dynamically loading, unloading and reloading of modules, before I started on the server. This will help a lot in the development, since I don’t have to reboot the bot everytime something is wrong. Anyway, now that the server is ok (I hope so), I’m planning to spend some of my spare time on the bot (yes, I still have some… ;-) .

11 Jan 2001

Today I’ve added the ability of using icons while in the Treemenu mode of Linuxconf. I have just changed some functions to pass the icon name around until it got into the treemenu module and then sent it to the GUI front-end. A little hack on gnome-linuxconf did the work at the front-end side. Following this line of improvements, I’m planning to add a splash screen or something like that soon. Icons would also be welcome in the web interface.

Besides that, I’m also playing with a Python IRC bot. It’s not meant to be a war or a channel control bot. I’m planning to implement useful modules to help making IRC even more useful as an information media (no it won’t be just another infobot clone). The core and a few modules are ready. I’ll post more information later… for now, I’ll just tell that it is a multi-channel, multi-server bot, and that I’m trying to make its commands with natural language (eg. forward messages from #blah on servername to #bloh on servername).

Happy birthday Diogo!!

16 Aug 2000

Created advogato account.

por niemeyer em 01 de March de 2013 às 01:40

February 28, 2013

Rodrigo Amaral

O que muda no Django 1.5

O que muda no Django 1.5No último dia 26 de fevereiro foi lançada a versão 1.5 do framework Django. Ainda não tive a oportunidade de instalar e testar todos os detalhes, mas de acordo com as informações das notas de versão, as principais novidades são as seguintes:

Modelo User configurável

A maior mudança nesta nova versão é a possibilidade de personalizar o modelo User do Django. Antes da versão 1.5, as aplicações que precisassem usar o framework de autenticação do Django eram forçadas a usar a sua definição de “usuário”. Agora é possível substituir o modelo User por outro escrito pelo desenvolvedor.

Algumas vantagens de poder criar seu próprio User são o fim da limitação de 30 caracteres para o atributo username e a possibilidade de criar mais atributos personalizados para o perfil do usuário, por exemplo.

Para facilitar a implementação, está disponível a classe AbstractBaseUser , que fornece a implementação do núcleo de um User customizado.

Também é necessário indicar para a aplicação qual a classe que representa o seu modelo User. Para isso, deve-se fornecer um valor para o atributo da configuração AUTH_USER_MODEL no settings.py. Por exemplo:

AUTH_USER_MODEL = 'myapp.MyUser'

Mais detalhes sobre a personalização do modelo User podem ser consultados na documentação oficial.

Suporte a Python 3

Outra novidade importante é o suporte a Python 3 (especificamente Python 3.2 e acima). Segundo os desenvolvedores, por enquanto este suporte deve ser considerado experimental, pois apesar de ter passado por testes automatizados extensivos, ainda não existiram muitas situações do “mundo real” para colocá-lo à prova. Além disso, alguns recursos não estão disponíveis para Python 3, tais como o backend para MySQL, o ImageField e o LiveServerTestCase. Isso se deve à dependência de componentes de software de terceiros (PIL, Selenium WebDriver etc.) que ainda não foram portados para Python 3.

Suporte a persistência de subconjuntos de campos de um modelo

Foi incluído o novo argumento update_fields no método Model.save(). Com ele é possível salvar apenas um subconjunto dos campos de um modelo. Esse recurso pode ser útil por motivos de desempenho ou para evitar sobrescrever mudanças concorrentes.

Instâncias de modelos relacionados passam a ficar em cache

O ORM do Django passa a evitar que uma nova consulta SQL seja disparada nos casos em que seja invocada uma instância de um modelo que possui relacionamento com outro que já foi recuperado do banco. Para exemplificar, na linha 3 do exemplo abaixo já não é mais necessária uma ida ao banco para recuperar first_choice.poll:

>>> first_poll = Poll.objects.all()[0]
>>> first_choice = first_poll.choice_set.all()[0]
>>> first_choice.poll is first_poll
True

Tag {% verbatim %}

Esta tag evita que o conteúdo do bloco seja renderizado. É útil nos casos em que, por exemplo, queremos evitar um trecho de código Javascript que conflita com a sintaxe do template seja renderizado.

{% verbatim %}
{{if dying}}Still alive.{{/if}}
{% endverbatim %}

Existem ainda muitas outras mudanças nessa nova versão do Django, incluindo algumas incompatibilidades com versões anteriores, para as quais vale a pena ficar atento antes de disponibilizar suas aplicações.

Referência: Django 1.5 release notes


por Rodrigo Amaral em 28 de February de 2013 às 13:04

February 27, 2013

PUG - PE

Gustavo apresentando o SimpleCV

Pessoal,

Realizamos o XXIV Encontro do Grupo de Usuários de Python de Pernambuco no auditório do Conecta.LA em Casa-Forte. Queremos agradecer a oportunidade ao Filipe Ximenes nos ceder o espaço para organização do encontro.

 

Abaixo seguem as apresentações realizadas durante o encontro:

Palestra de Gustavo Pinto sobre SimpleCV (Visão Computacional)

 

Palestra sobre Generic Views realizada por Gileno

https://github.com/gileno/talk-generic-views

Seguem algumas fotos:

2013-01-26 11.57.45Público presente no encontro do pug-pe

 

2013-01-26 10.26.50

 

2013-01-26 11.12.37

 

Parabenizar a Gileno e  Fernando Rocha pela organização deste encontro!

Atenciosamente,

Equipe PUG-PE

 


por marcelcaraciolo em 27 de February de 2013 às 00:23

February 23, 2013

Rodrigo Amaral

amaral

Extensão para Sublime Text com snippets para os trechos de código usados com mais frequência em Django. Traz atalhos que abrangem templates, models, forms e seus atributos.

Djaneiro: snippets do Sublime Text para Django


por Rodrigo Amaral em 23 de February de 2013 às 12:55

February 21, 2013

Rodrigo Amaral

python-doc-icon

python-doc-iconUma operação bastante comum em várias aplicações é a contagem da frequência da ocorrência de valores em uma determinada lista. Para facilitar nossa vida, o Python traz em sua biblioteca padrão a classe Counter, que é parte do módulo collections.

O uso de Counter é bastante simples: para instanciar a classe, passamos uma sequência qualquer como argumento para seu construtor. Vamos supor que queremos saber quantas vezes cada caractere aparece na frase “o rato roeu a roupa do rei de roma”. Como uma string é uma sequência, podemos fazer:

>>> from collections import Counter
>>> c = Counter('o rato roeu a roupa do rei de roma')
>>> c
Counter({' ': 8, 'o': 6, 'r': 5, 'a': 4, 'e': 3, 'd': 2, 'u': 2, 'i': 1, 'm': 1, 'p': 1, 't': 1})

Como podemos ver, o caractere mais frequente é ‘ ‘ (espaço), com 8 ocorrências, seguido por ‘o’ com 6, depois por ‘r’ com 5 e assim por diante.

Counter é uma subclasse de dict, portanto podemos acessar seus elementos por meio de índices, do mesmo jeito que fazemos com dicionários. Isso é útil quando queremos saber qual a contagem específica de um determinado elemento. Por exemplo, para saber a frequência apenas da letra ‘r’, fazemos:

>>> c['r']
5

Entre outros métodos, a classe Counter oferece o most_common([n]) que, como seu nome descreve, retorna as n ocorrências mais frequentes da sequência. Então para saber, por exemplo, quais foram os dois times com mais títulos da NBA nos últimos dez anos, bastaria fazer:

>>> nba = ['San Antonio Spurs', 'Detroit Pistons', 'San Antonio Spurs', 'Miami Heat', 'San Antonio Spurs', 'Boston Celtics', 'Los Angeles Lakers', 'Los Angeles Lakers', 'Dallas Mavericks', 'Miami Heat']
>>> Counter(nba).most_common(2)
[('San Antonio Spurs', 3), ('Los Angeles Lakers', 2)]

Note que, em caso de elementos com o mesmo número de ocorrências (“Los Angeles Lakers” e “Miami Heat”, nesse exemplo), a ordenação é aleatória.


por Rodrigo Amaral em 21 de February de 2013 às 13:03

February 20, 2013

Gustavo Niemeyer

Elcio Luiz Ferreira

Papo de Maluco

Hoje estava brincando com Requests e tive essa ideia maluca:

import requests
import re

def Ed(text):
  params=dict(server='0.0.0.0:8085',charset_post='utf-8',
  charset='utf-8',pure=1,js=0,tst=1,msg=text)
  return re.sub('[^>]*>','',re.sub(r'\n+$','',
    requests.get('http://www.ed.conpet.gov.br/mod_perl/bot_gateway.cgi',
      params=params).text))

def SeteZoom(text):
  params=dict(server='127.0.0.1:8088',pure=1,js=0,tst=1,msg=text)
  return re.sub(r'\n+$','',
    requests.get('http://bot.insite.com.br/cgi-bin/bot_gateway.cgi',
      params=params).text)

msg='Oi!'
while True:
  print 'SeteZoom: %s' % msg
  msg=Ed(msg)
  print 'Ed: %s' % msg
  msg=SeteZoom(msg)

Teste aí, o resultado às vezes é mais inteligente que muito chat entre seres humanos por aí…

por elcio em 20 de February de 2013 às 18:34

February 18, 2013

Aprenda Python

Como as variáveis funcionam em Python

Python tem alguns conceitos muito interessantes, que nos fazem pensar diferente em muitos casos. Um deles é o conceito de variável. A explicação mais didática que eu encontrei foi nesse artigo, de Fredrik Lundh: Python Objects. Eu achei o texto tão bom, que resolvi traduzí-lo na íntegra, abaixo. Introdução Esvazie seu cérebro. Objetos Todos os objetos Python têm isso: uma identidade única (

por Vinicius Assef (noreply@blogger.com) em 18 de February de 2013 às 16:35

Cálculos com dinheiro

Em Python, podemos encontrar alguns problemas de arredondamento se usarmos o tipo float, principalmente quando fazemos contas com valores monetários. Por exemplo: >>> 1.23 + 1.01 2.24 >>> n = 1.23 + 2.01 >>> print n # muitas casas decimais! 3.2399999999999998 >>> '{0:,.2f}'.format(n) # arredondou na hora de mostrar :-( 3.24 >>> Como fazer essa conta acima considerando apenas 2 casas decimais e

por Vinicius Assef (noreply@blogger.com) em 18 de February de 2013 às 14:18

February 15, 2013

Bruno Cezar Rocha

More web2py custom validators

# save this file in web2py/yourapp/modules/validators.py

# coding: utf-8

from gluon.validators import IS_EMAIL


class ANY(object):
    """
    Verifies if at least ONE validation is valid!
    Usage:
    from validators import ANY
    db.sometable.somefield.requires = ANY(IS_EMAIL(), IS_NOT_EMPTY(), ...)

    For testing on shell:
    >>> from validators import ANY
    >>> ANY(IS_IN_SET(('a','b')), IS_EMAIL())('foo')
    ('foo', 'value not allowed')
    >>> ANY([IS_IN_SET(['a','b']), IS_EMAIL()])('a')
    ('a', None)
    ANY([IS_IN_SET(['a','b']), IS_EMAIL()])('foo@bar.com')
    ('foo@bar.com', None)
    """

    def __init__(self, *validators):
        self.validators = validators

    def __call__(self, value):
        # validates the value against each validator
        results = [validator(value)[1] for validator in self.validators]
        # check if all validations are invalid
        if all(results):
            # invalid, so return the first error message
            return (value, results[0])
        else:
            # all valid
            return (value, None)



class CUSTOM(object):
    """
    you can use a function or a lambda
    to validate or/and transform the field in the way you want
    it is the same as "onvalidation" and "onsuccess" form callbacks
    but it can be used per field in models or controller level
    Usage:
    from validators import CUSTOM

    # the validate function should return the error_message or None
    def begins_with_a(value):
        if not value.startswith('a'):
            return "Should start with a"
        else:
            return None
     
     # the transform function should return a value
     def to_upper(value):
         return value.upper()

    db.define_table("foo", Field("bar"))
    db.foo.bar.requires = CUSTOM(begins_with_a, to_upper)
    
    >>> CUSTOM(begins_with_a, to_upper)('apple')
    ('APPLE', None)
    >>> CUSTOM(begins_with_a, to_upper)('orange')
    ('ORANGE', 'Should start with a')

    """
    def __init__(self, validate=lambda value: None, transform=lambda value: value):
        self.validate = validate
        self.transform = transform

    def __call__(self, value):
        return(self.transform(value), self.validate(value))

    
class IS_EMAIL_LIST(object):
    """
    To be used in textareas, users can include a comma
    or space or line separated list of emails
    Usage:
    from validators import IS_EMAIL_LIST
    db.define_table('emails',
        Field('email_list','text', requires=IS_EMAIL_LIST())
    )
    
    >>> IS_EMAIL_LIST()('item1, item2@gmail.com')
    ("item1", "Email Item1 is invalid")
    >>> IS_EMAIL_LIST()('item1@gmail.com, item2@gmail.com')
    ('item1@gmail.com, item2@gmail.com', None)
    
    Optionally you can return a Python List if your field
    is a list:string
    """
    def __init__(self, error_message="Email %s is invalid", sep=",", ret='str'):
        self.error_message = error_message
        self.sep = sep
        self.ret = 'str' or 'list'

    def __call__(self, value):
        emails = value.strip().replace('\n','').replace('\t','').split(self.sep)
        for email in emails:
            email = email.strip()
            if IS_EMAIL()(email)[1] != None:
                return (email, self.error_message % email)
        return (value if self.ret == 'str' else emails, None)
    
    
    
    

15 de February de 2013 às 03:18

February 10, 2013

Artificial Intelligence in Motion

Review about the book Numpy Cookbook!


Hi all,

This year I had the opportunity to review the book Numpy Cookbook by Ivan Idris and published by Pack Publishing. The goal of the book is to present the numpy library through several examples.  The author refers them as recipes.




For my first impression taking a right look into the bok before reading it I could say that the book is not only about Numpy but it also covers another related libraries such as Scipy, Scikit, Matplotlib, Cython, Pandas, Rpy, which I think for the book it's quite better.  Even the title is not well suited to it (it could be such as Scientific Python Cookbook for example), the book is a perfect book for scientific developers and for anyone not much familiar with the libraries, so it offers a fast way to explore it.

I believe the audience of this book if for people who knows how Python works and has some experience on scientific side.


Content


The book is well structured and generally easy to read and digest (congratulations to all Packt books that I read has this same organization).  I like the way the author introduces the examples by using IPython shell instead the regular one. The first experience with Scientific python with IPython must be presented for anyone who works in this field.

The first chapter covers the Ipython and the feature notebook.  It supports Matplotlib and it's a good way os sharing scripts between people.  Great points (even he didn't mention that) when the examples that he shows through the book runs on the Ipython Notebook! :)
The next two chapters he tackles the Numpy aspects: array indexing and several numpy functions.  I didn't like the little mess with different instalations of the packages. However I could install all the packages provided based on the links in the book.  The recipes were quite interesting and I liked the examples with trading stocks. For financial developers those examples are quite attractive!

The fourth chapter handles the Numpy comunication  with other Python modules and other programming languages.  There are several examples covering Matlab, octave, R, Java and even Google App Engine! All of them are simple recipes, so don't expect much of real action or deeper use (Unfortunately!).  You still need to read the docummentations of those interfaces to go beyond of the very basics provided in the book.
I'd like to give an extra credit for the author mentioning the picloud enviroment, a distributed cloud computing provider, which offers pre-installed Python software including numpy for distributed scientific  computing!

The next chapter covers audio and image signal processing and I think it's one of the best scientific recipes approached in the book. Even there's no in-depth details, but creating an audio filter was interesting! Some advanced functions covered in this chapter needs more details such as memmap, clip, etc.   
The Chapter 6 presents more special Numpy classes that can be useful such as masked arrays and recarrays. Those advanced structures can be quite useful in complex algorithms.

The main streams of the book are the next two chapters. Many scientists usually forget: profiling, debugging and quality insurance. The author covers all those topics showing several recipes using several tools ( I believe many of the examples uses nosetests - the author should mention it).  I really appreciate the BDD and the mock objects! I didn't know that!  My opinion for those chapters is that it worths the reading specially about those overlooked topics on scientific books covered in this book.

The chapter 9 gives some interesting recipes on optimizing your code with Cython. By the way it was excellent chapter since we don't have many books handling about those topics. Extra points for tackling a common problem with almost scientists: Call C functions with Python! However, it does not mention Fortran (Fpy) integration.

Finally the last chapter covers the scikit and pandas, that for me they are one of the best frameworks on top of numpy/scipy nowadays covering machine learning, image processing and statistics research fields! Although the recipes are not deeper you can have at a glance of how powerful each framework is and makes you curious to explore each one of them.

Conclusions

The book is well written and it's really easy to read digest. I liked the approach that the author uses by several examples familiar to scientists and scientific developers. It's not a book for Python beginners and it's focused on showing with recipes what the Scientific Python enviroment is capable of. And it does quite well!  I recommend this book for everyone looking to study profoundly with learning experiments the Numpy/Scipy/Matplotlib frameworks. I only miss some deeper explanations about some topics but it does not compromise the book.  Congratulations Packt and Ivan for this great contribution to the scientific python community!



Regards,

Marcel Caraciolo

por Marcel Caraciolo (noreply@blogger.com) em 10 de February de 2013 às 22:18

February 06, 2013

Gustavo Niemeyer

Ethics for code reviewers

In the previous post, I explored a bit how ephemeral most of the artifacts of software development processes are. One of these processes is code reviewing, which is arguably a major player in code quality, knowledge acquisition, and even team dynamics.

Even being so important, the outcome of the code review process — the review itself — tends to reach a very limited audience and have a short life time. It’ll be hard to change that picture given the nature of reviews: they are conversational, and address specific issues for the integration of a change in the project. At the same time, even if code reviews are not generally useful as permanent documentation, we can increase their value as reference material by improving the quality of those conversations. Having a good conversation has many other great side effects, of course.

As a small step in that direction, what follows are personal guidelines that I have been evolving empirically over the years as a software developer and code reviewer. They may not bring you fortune and fame, and are not always easy to apply, but hopefully they will help improving your experience as a member of your team and the value of those reviews.

Explain why

Unless the change is about an extremely obvious mistake, explain why you’re suggesting it. If the reasoning was natural to the author, he’d have done it in the first place. Good explanations also help avoiding the same mistake over and over again, and are much more rewarding to the listener. They also become a target for future references.

If you don’t have enough time to justify it and would rather provide the review sooner than later, one approach is to just recommend the change and invite the author for a conversation later if that would be helpful. That said, try to have that conversation over a media that may be shared with the rest of the team, or recollected whenever necessary.

Be respectful

Always keep in mind that there’s a person on the other side of the wire, not a machine, and that it’s hard to understand written words with little context. Avoid letting anger and frustration leak into the review, even if you feel it is justified. There’s no good outcome in those situations.

It doesn’t matter who broke it, or who coded that silly piece of code. If there is broken code, and the project has reviews, multiple people were in the pipeline for that result, and they were trying to get it right. Take shared ownership of the problem, and look for the solution and for how to avoid such issues in the future.

Praise the good work

Reviews carry some low energy feel by their very nature. No matter how positive you are about them, and how much the whole team understands and agrees it is for the best, you are in fact looking for places to put your finger in someone else’s work. For that reason, it is very helpful to take every chance you can of praising logic, design, code organization, or whatever else that you honestly felt was well done. It won’t ever balance it out, but it will at least remind the author that the contributions are welcome.

Suggestions are appreciated

Perhaps a longer variable name would be helpful, or that constant could have a more descriptive name? In many circumstances, the change is indeed subjective, and the gain is pretty marginal. In those cases, if you really can’t resist the urge to say something, a good approach is a suggestion that may be exercised or not at the author’s discretion. Ideally, suggest several options that would feel better to you, so that your point is better understood and agreement is easier. That said, read on.

Avoid trivialities

When reviewing that very simple point, think to yourself: all things considered, does it actually matter? Is the cost of the author’s time, and the potential debate, really worth it? You surely have your opinion about whether to spell “min <= count” or “count >= min“, but so does everybody else. When it’s purely a matter of preference, the author is entitled to have one after all.

Small branches win

Code reviews are useful for a number of secondary reasons, but the primary goal of the code review is to analyze a proposed change, to fix it for inclusion, or to reject it. It’s often tempting to recommend further changes to be bundled onto the same review, but it’s important to keep some focus. Are these additional changes tightly related to the original idea, or would they rather be more appropriate on a future branch?

Also keep an eye on large review submissions. It’s quite rare to see changes of a thousand lines or more that are really an indivisible unit. More often, it ends up like that organically, as a result of the workflow followed by the author. These branches may be very frustrating, both for the author and for reviewers. For the reviewer, it’s hard to keep the necessary level of attention and enthusiasm for the problem over expanded periods of time. For the author, it will be equally problematic to run over a large review. In some extreme cases, it may be worth going back and breaking down the change into more change sets.

Overall, fast iterations on small branches are much more rewarding to work with.

Work with inline comments

This is about tooling, but doing anything else should be considered unethical really. If you don’t have a system that allows the change diff to be seen within the rest of the content, and comments to be made inlined right where you see the issue, implement one right now. Moving to such a system was the most dramatic change in productivity I had as a reviewer in the past several years, and makes the whole experience a lot more bearable for everyone.

Enjoy!

Make sure you’re enjoying what you do, and appreciate what your code reviews are achieving. There’s little point in playing the role of an intelligent computer over extended periods of time if you are unhappy about it. Get yourself your preferred slow-drinking beverage (chimarrão?), perhaps some snacks, a comfortable chair, and relax.

por niemeyer em 06 de February de 2013 às 04:26

February 04, 2013

Gustavo Niemeyer

The ephemeral life of software development

Lately I’ve been considering the amount of waste we produce during software development, and how to increase the amount of recycled content. I’m not talking about actual trash, though, but rather about software development artifacts.

Over the years, we’ve learned about and put in practice several means for improving the quality and success rate of projects we create or contribute to. We have practices such as sprints to get people together with high communication bandwidth; we have code reviews for sharing knowledge and improving project quality; we’ve got technical leadership roles to mentor developers and guide the progress of projects; we’ve created kanban boards and burndown charts to help people visualize what they’re going through; and so on.

While all of that seems to have helped tremendously, there’s a sad fact about where we stand: the artifacts of most of these processes are local to their context, and very sensitive to time. That burndown chart is meaningless after it’s burned, and a kanban has no relevant history. Our technical leads indeed guide their teams, but their wisdom stays with the few people that had the chance to interact with them, and subjectively so. That brilliant code review from our best developers has a very limited audience, and rarely carries any meaning just days after it has been accomplished.

That last one is specially interesting. The process of reviewing code is an intense task, very expensive, and that takes a significant portion of the life of an active developer, and even then very little is carried forward as the outcome of that process. We have no effective means or even culture of sharing the generated wisdom to other teams. In fact, we rarely share these details even within the team itself. Why was that line changed like this? Why an interface like that is a bad idea? Who will instruct the new guy next week, and where did we record a bit of the wisdom of the brilliant guy that has left the company recently?

Unfortunately there’s probably no easy solution for this problem. At this point, I mainly recognize that most of the efforts I’ve lead to improve software development for the past several years had a very limited scope. The software itself became immediately better as a result of my efforts, its design became more sensible, and hopefully I contributed a bit to the growth of people around me, but at a company or even community-wide scope, all of these code reviews, sprints, and IRC conversations are buried for very rare revives.

I want to start doing something about this, though. There must be a way to shape these conversations in a more reusable format; in a way that knowledge and agreement can be more proactively preserved and scattered. Perhaps it’s more about how than it is about what. Perhaps we just need to write more posts like this, and cover more topics related to daily development findings. Not sure. I’ll be thinking…

por niemeyer em 04 de February de 2013 às 18:29

January 28, 2013

MetaPython

Dyamic Constants. Of the automatic kind

A quickie one -- sometimes we need named constants -
just like "True" and "False" are in Python  - and we'd like they to behave
like named constants - not just a  variable pointing to an int.

So, if the constant you want has an integer value, something that behaves like
Python's True and False is easily achievable with:


class Constant(int):
def __new__(cls, name, value=0):
return int.__new__(cls, value)
def __init__(self, name, value):
self.name = name
def __repr__(self):
return self.name
__str__ = __repr__

And there you are:
>>> RED = Constant("RED", 0)
>>> RED
RED
>>> RED + 1
1
>>> print RED
RED
Then ...we stumble on the DRY principle. The constant is nice, but the call for its creation requires its name as a string, and we have to associate the resulting object with a variable with the same name. It is a problem faced by "collections.namedtuple", and ORM's all around the Galaxy.

 We could make the code in the Constant class to inject the constant name in the caller frame, yes. But that is ugly, as it kills the "explicit is better than implicit" principle, and would break static code analysis tools everywhere - one can't have code that fiddles with the calling frames and don't feel too hackish for production code anyway:
from inspect import currentframe

class Constant(int):
def __new__(cls, name, value=0):
return int.__new__(cls, value)
def __init__(self, name, value):
self.name = name
currentframe().f_back.f_locals[name] = self
def __repr__(self):
return self.name
__str__ = __repr__

And now one can do:
>>> Constant("GREEN", 1)
GREEN
>>> GREEN
GREEN
>>> print (GREEN, GREEN + 0)
GREEN 1
No more WET stuff. But unsactisfactory, nonetheless... Then you think on the ridle: what is that can inject clean names in the current namespace? Assignment statements, also some statements like "for", "with", "except" and so on....but also the "import" statement! T

here it is -- if we can get our constants to be authomaticaly created when they are imported into the current module -- there is a drawback, the import semantics does not allow one to assign values to the names being imported.

A pity - but arbitrary constants would still work when only the name as a value is important. With you, the all new, all magic....DYNAMIC AUTO CONSTANTS


import sys

class Constant(int):
def __new__(cls, name, value=0):
return int.__new__(cls, value)
def __init__(self, name, value):
self.name = name
def __repr__(self):
return self.name
__str__ = __repr__


class _ConstantFactory(object):
counter = 0
Constant = globals()["Constant"]
def __init__(self):
self.counter = 0
self._all_constants = {}
def __getattr__(self, name):
cls = self.__class__
if name in self._all_constants:
return self._all_constants[name]
const = cls.Constant(name, self.counter)
self.counter += 1
self._all_constants[name] = const
return const

sys.modules[__name__] = _ConstantFactory()
So, this code as a not-so-well-behaved module, replaces itself in sys.modules with an instance of the _ConstantFactory class .... an almost ordinary class - but which will produce a new Constant object each time an attribute is retrueved from it - and..guess what "from <module> import name1, name2" does?

>>> from ConstantFactory import RED, GREEN, BLUE
>>> RED
RED
>>> GREEN + BLUE
5
>>> print RED, GREEN, BLUE
RED GREEN BLUE

There you are: no writing names twice, no names magic appearing in the module name-space, no declarations needed.

por João Sebastião de Oliveira Bueno (noreply@blogger.com) em 28 de January de 2013 às 15:30

January 26, 2013

Artificial Intelligence in Motion

How recommend deals on-line for coupon systems ? My Ranking model approach for this task!

Hi all,

In this post, I will share with you some of my scientific contributions at the startup Favoritoz, a previous business that I was involved as Co-Founder and Scientist Chief. The main contribution was an algorithm to rank on-line deals in coupon systems. This algorithm was implemented and worked for ten months when the startup was running on-line.   I believe that all this implementation could serve as baseline for anyone who is looking after some work related to this field and also a main contribution to the recommender system community.

Favoritoz's Coupon System

Favoritoz was on-line coupon system where retailers could publish offers with special discounts or their products to segmented customers interested at their products or by a specific brand. One of the critical features was the personalization, where people could say wha they would like to receive daily at their deals wall. For instance, If l liked sushis, videogames and junk-food , the system could detect those interests and using our algorithm it would rank higher offers and deals related by those topics.

My goal was to develop this baseline for ranking deals based on their interests, but not only using the user profile, also we could use particular aspects from the on-line deals such as: the initial date of the deal, the popularity of the deal or the number of coupons left for that deal. All those aspects could be measured in order to compute a overall score that would be used to rank those recommendable items.

Ranking Model


Recommender systems aim to present desirable items for a person to choose from. This task is accomplished by sorting some itens in ther order of utility or interest for the person. Generaly those items are organized in some form of list, such as, in our scenario, the various deals organized as wallboard on Favoritoz. But the question is how to order those deals in a way that users could interest at or even convert into transactions ?  That's my work! I came with a simple ranking algorithm that could use various type of information available in order to come with a useful ranking system that could recommend the best deals for each of our customers at Favoritoz.

By looking to specific features in our domain (coupons market) we could use them to build a ranking function that could give some personalized recommendations. For instance, we look for "hot" deals, which is represented by most bought deals (popularity) . But it can lead to deals that are common to everyone and it's the opposite of personalization. So let's use another information like the publishing date and expiration date of the deal which could give us the newest deals and the deals that are almost close to end. Furthermore, let's look into the number of coupons available, in this case, a deal that are almost with no coupons left, could atract more users to purchase the last ones.  Another important feature is the user taste. In Favoritoz people could follow retailers (their favorites) and categories (sports, cuisine, automobile, etc.)  We use also this information in the ranking equation. In the end,  in order to produce rankings that balance all of these aspects we came wih a prediction model using all those features.

I liked the NetFlix approach on his recommendation problem at their company, where they came up with a simple scoring approach by choosing the ranking function to be a linear combination of several features. We also came with this approach but using different features exclusive at our domain.

It's like this equation:

frank(u,d) =    w1 * SD  + w2 * ED + w3*P + w4*CA + w5*UP + w6*DV + b
where,
SD = Publishing Date of the deal d,
ED = Expiration Date of the deal d,
P =    Deal Popularity
CA =  Coupons Available of the deal d,
UP =   User Profile (user tastes)
DV =   Diversity (based on stores)

It's simple and of course there are many improvements that could be made. But it was our baseline and at our tests in production was very satisfactory. In 4 months running we achieved an increase of almot 300% in click-through-rates per user thant without any ranking methods. Of course several external factors could influence this result, but showed us promising results at our first attempt.   I implemented all the code with Python and a fork of my current framework Crab, a python framework for building recommender systems and variations.

All the algorithm explained can be accessed at this link.

Conclusion

As I presented, this ranking algorithm was my first attempt to solve this problem identified at our on-line website. Since the startup didn't go on (no more coupons), I couldn't reformulate the algorithm in terms of  optimization and more brute A/B testes. With more data availability we could achieve even better results. It was a rapid experimentation and I believe this work could be useful for someone that is working in this research field. I also invite anyone to qualify my recommendation approach to improve it or pointing out some flaws. (-- under approval --  This article is indexed at arxiv.org.)

Feel free to analyze it and if you want to reference this article or extend this work, let me know. Favoritoz was a great research lab for me!

That's all,

Regards,

Marcel Caraciolo

por Marcel Caraciolo (noreply@blogger.com) em 26 de January de 2013 às 15:58

January 25, 2013

Gustavo Niemeyer

Baby feeding statistics with R

Our son Otávio was born recently. Right in the first few days, we decided to keep tight control on the feeding times for a while, as it is an intense routine pretty unlike anything else, and obviously critical for the health of the baby. I imagined that it wouldn’t be hard to find an Android app that would do that in a reasonable way, and indeed there are quite a few. We went with Baby Care, as it has a polished interface and more features than we’ll ever use. The app also includes some basic statistics, but not enough for our needs. Luckily, though, it is able to export the data as a CSV file, and post-processing that file with the R language is easy, and allows extracting some fun facts about what the routine of a healthy baby can look like in the first month, as shown below.

Otávio

The first thing to do is to import the raw data from the CSV file. It is a one-liner in R:

> info = read.csv("baby-care.csv", header=TRUE)

Then, this file actually comes with other events that won’t be processed now, so we’ll slice it and grab only the rows and columns of interest:

> feeding <- info[info$Event.type == "Breast",
        c("Event.subType", "Start.Time", "End.Time", "Duration")]

This is how it looks like:

> feeding[100:103,]
    Event.subType       Start.Time         End.Time Duration
129          Left 2013/01/04 13:45 2013/01/04 14:01    00:16
132          Left 2013/01/04 16:21 2013/01/04 16:30    00:09
134         Right 2013/01/04 17:46 2013/01/04 17:54    00:08

Now things get more interesting. Let’s extract that duration column into a more useful vector, and do some basic analysis:

> duration <- as.difftime(as.vector(feeding$Duration), "%H:%M")

> length(duration)
[1] 365

> total = sum(duration)
> units(total) = "hours"
> total
Time difference of 63.71667 hours

> mean(duration)
Time difference of 10.47397 mins
> sd(duration)
[1] 5.937172

A total of 63 hours surprised me, but the mean time of around 10 minutes per feeding is within the recommendation, and the standard deviation looks reasonable. It may be more conveniently pictured as a histogram:

> hist(as.numeric(duration), breaks="FD",
    col="blue", main="", xlab="Minutes")

Duration histogram

Another point we were interested on is if both sides are properly balanced:

> sides <- c("  Right", "  Left")
> tapply(duration, feeding$Event.subType, mean)[sides]
   Right     Left 
10.72283 10.22099

Looks good.

All of the analysis so far goes over the whole period, but how has the daily intake changed over time? We’ll need an additional vector to compute this and visualize in a chart:

> day <- format(strptime(feeding$Start.Time, "%Y/%m/%d %H:%M"),
                "%Y/%m/%d")
> perday <- tapply(duration, day, sum)
> mean(perday)
[1] 136.5357
> sd(perday)
[1] 53.72735
> sd(perday[8:length(perday)])
[1] 17.49735

> plot(perday, type="h", col="blue", xlab="Day", ylab="Minutes")

Daily duration

The mean looks good, with about two hours every day. The standard deviation looks high on a first look, but it’s actually not that bad if we take off the first few days. Looking at the graph shows why: the slope on the left-hand side, which is expected as there’s less milk and the baby has more trouble right after birth.

The chart shows a red flag, though: one day seems well below the mean. This is something to be careful about, as babies can get into a loop where they sleep too much and miss being hungry, the lack of feeding causes hypoglycemia, which causes more sleep, and it doesn’t end up well. A rule of thumb is to wake the baby up every two hours in the first few days, and at most every four hours once he stabilizes for the following weeks.

So, this was another point of interest: what are the intervals between feedings?

> start = strptime(feeding$Start.Time, "%Y/%m/%d %H:%M")
> end = strptime(feeding$End.Time, "%Y/%m/%d %H:%M")
> interval <- start[-1]-end[-length(end)]

> hist(as.numeric(interval), breaks="FD", col="blue",
       main="", xlab="Minutes")

Interval histogram

Seems great, with most feedings well under two hours. There's a worrying outlier, though, of more than 6 hours. Unsurprisingly, it happened over night:

> feeding$End.Time[interval > 300]
[1] 2013/01/07 00:52

It wasn't a significant issue, but we don't want that happening often while his body isn't yet ready to hold enough energy for a full night of sleep. That's the kind of reason we've been monitoring him, and is important because our bodies are eager to get full nights of sleep, which opens the door for unintended slack. As a reward for that kind of control, we've got the chance to enjoy not only his health, but also an admirable mood.

Love, Dad.

por niemeyer em 25 de January de 2013 às 11:46

January 21, 2013

Elcio Luiz Ferreira

Pequena dica de Python: módulo webbrowser

O módulo webbrowser permite abrir uma URL no navegador do usuário. Só isso, simples assim. Por exemplo:

import webbrowser
webbrowser.open("http://visie.com.br")

E o site da Visie será aberto no navegador do usuário. Muito útil se você está fazendo um programa para desktop ou mesmo um script para o terminal. No caso de scripts para terminal, se o usuário estiver rodando o script sob uma interface gráfica o site será aberto no navegador padrão dele, já se estiver rodando via ssh ou num outro terminal sem interface gráfica, será usado um navegador de CLI (como o Lynx) se estiver disponível.

por elcio em 21 de January de 2013 às 16:20

Bruno Cezar Rocha

Gravando logs de aplicativos web2py

Como utilizar o módulo logging do Python em seus apps web2py.

Este video é parte da aula 4 do cursodepython.com.br

21 de January de 2013 às 05:29

January 14, 2013

Elcio Luiz Ferreira

Conversão de MDB para MySQL

Script para converter bancos de dados MDB para scripts MySQL no Linux:

https://github.com/elcio/mdb2mysql

Um oferecimento VisieAviso Brasil ;-)

por elcio em 14 de January de 2013 às 17:14

Python e Web - Hersonls

Projeto em Django: Portal Itz - Portal de informações

A quase um mês tive uma nova Experiência com um projeto pessoal chamado Portal Itz. O portal conta com conceito principal de colaboratividade, onde os usuários podem publicar conteúdos, alimentando o site de várias maneiras, como por exemplo blogs, eventos, cinema e fotos. Um projeto feito totalmente em Django.

14 de January de 2013 às 05:13

Django Static Files: Servindo arquivos estáticos a partir do Django 1.3

Com a saída do Django 1.3, os desenvolvedores ganharam uma nova forma para manipulação de arquivos estáticos em seus projetos, possibilitando-os a separação e a coleta dos arquivos estáticos a partir de suas respectivas aplicações. Veja esta nova forma de manipular seus arquivos estáticos.

14 de January de 2013 às 05:13

January 13, 2013

Ricbit

O Jogo do Pi

No último post eu falava de variações em jogos, aí lembrei de uma variação divertida em um jogo bem conhecido. Quem assistia Topa Tudo Por Dinheiro certamente deve se lembrar do Jogo do Pim. O objetivo é enumerar os naturais pelo maior tempo possível, trocando os múltiplos de quatro pela palavra "pim":

1,2,3,pim,  5,6,7,pim, 9,10,11,pim...

Parece simples, mas na prática muita gente se confundia e errava antes mesmo de chegar ao quarenta!


Uma variação mais difícil desse jogo foi inventada pelo Juca uns anos atrás: o Jogo do Pi. Dessa vez você ainda precisa enumerar os naturais, mas precisa falar "π" toda vez que passar um múltiplo inteiro de pi. Os primeiros múltiplos inteiros são aproximadamente 3.14, 6.28 e 9.42, então a sequência começa assim:

1,2,3,π,  4,5,6,π, 7,8,9,π...

Parece o mesmo jogo né? Você conta três números, fala π, conta mais três, fala π, e assim por diante. Mas se você seguir essa estratégia, vai perder! Olha o que acontece se você continuar:

..., 16,17,18,π, 19,20,21,π, 22,23,24,25,π,...

A estratégia de contar de três em três falha! Entre 7π e 8π tem quatro naturais ao invés de só três.

Bem, será que não dá pra melhorar a estratégia? Podemos contar quantos números tem entre os múltiplos de pi. Com sorte, o padrão é 33333334 e depois repete. Nesse caso, o padrão do Jogo do Pi é oito vezes maior que o padrão do Jogo do Pim. Infelizmente, se você fizer as contas, esse padrão também é quebrado após 112π.

Será que devemos procurar um padrão de padrões então? Nessa altura não já compensa fazer as contas na mão, melhor deixar o python achar o período pra gente:

Script em python para tentar achar um período

Más notícias: o script acha padrões maiores e maiores, sem parar. Não tem como concluir se existe ou não um padrão só analisando a saída do programinha.

O jeito de resolver essa dúvida, então, é usando matemática! Se você tem medo de teoria dos números, pule o quadro azul:


Antes de mais nada, vamos colocar nosso problema na notação correta. Nós queremos descobrir se a quantidade de números entre múltiplos inteiros consecutivos de pi formam uma sequência periódica. Vamos primeiro escrever a sequência explicitamente:


Isso gera a sequência que queremos. Agora vamos supor que essa sequência tem um período p. Das duas uma: ou a gente acha o valor de p, ou batemos em uma contradição pelo caminho.

Se nós somarmos todos os primeiros n termos dessa sequência, temos uma soma telescópica e um resultado curto:


Isso vale para todo n, inclusive no caso onde n é um múltiplo inteiro do período p:


Mas, nesse caso, podemos fazer a somatória de outro jeito. Ao invés de somar direto de 0 a kp, podemos somar k vezes o período p. Aí, como a sequência é periódica, um dos termos some:


O termo mais interno da somatória não varia mais com i, então essa somatória está somando k vezes a mesma coisa:


A conclusão é que, quando p é o período da sequência, podemos jogar um k inteiro de dentro para fora do piso. Podemos agora abrir a definição de piso para kpπ:



Dividindo todo mundo por kp, temos:



Agora, para todo real ε > 0, podemos escolher um k grande o suficiente tal que ε seja maior que 1/kp. Logo:



Pelo teorema do sanduíche, concluímos que:



Note que o numerador dessa função é um piso, logo é um inteiro. Sabemos também que p é um inteiro, logo a fração é um racional. Mas pi é irracional, portanto chegamos a uma contradição, e a sequência não tem período.

Ou seja, concluímos matematicamente que o Jogo do Pi não tem período. Outra maneira de dizer a mesma coisa é que o período do Jogo do Pi é infinito, e portanto o Jogo do Pi é infinitamente mais díficil que o Jogo do Pim!

Agradecimentos ao povo do Math Stack Exchange pela ajuda na demonstração

por noreply@blogger.com (Ricardo Bittencourt) em 13 de January de 2013 às 19:45

January 12, 2013

Bruno Cezar Rocha

KISS: Use the built in sum() instead of reduce to aggregate over a list comprehension

This post is the beginning of a KISS tag, a place where I will put all the "over complications" I find on codes that I work on, or even to comment on my own mistakes.

WTF?

Today I was working on a Django reports app and I saw this code:

result = reduce(lambda x, y: x + y, \
        [i.thing.price for i in \
            ModelObject.objects.filter(created_at__gte=date)])

At the first look, specially because of the use of reduce I thought it was a complicated issue to solve.

2 seconds after I realized.

Why using reduce for sum when Python already has the built in sum function?

result = sum([i.thing.price for i in ModelObject.objects.filter(created_at__gte=date)])

Well Python gives us powerful builtins so just use this!

The other problem here is the memory usage of the above solution, it will first get the objects list from filter() and after that it will iterate one by one, doing a field lookup to take the price and return a new list with values to sum.

It can kill your server!

On this case things can be done in a better way! we are talking about Django! and even I am being a Django ORM hater I know that it has some cool things like this one:

Django ORM aggregations

from django.db.models import Count
queryset = ModelObject.objects.filter(created_at__gte=date)
aggregation = queryset.aggregate(price=Sum('thing__price'))
result = aggregation.get('price', 0)

On the above code, the aggregation Sum will translate in to a SQL command and the sum will be performed on the database side! much better

I really do not like the Django ORM syntax, also I hate the way I bind the objects, maybe because I am used to use the wonderful DAL I prefer to refer to data as data, I mean, data as Rows not data as objects. But in cases I am working with Django, I think the best is to use its powerful tools!

Keep It Simple Stupid!

12 de January de 2013 às 01:31

January 11, 2013

Elcio Luiz Ferreira