por Vinicius Assef (noreply@blogger.com) em 21 de May de 2013 às 01:28
Planeta PythonBrasil por Vinicius Assef (noreply@blogger.com) em 21 de May de 2013 às 01:28
Mais simples impossível:
$('#form1').validate({
ignore: [],
rules: {
corpo : {
required: function()
{
CKEDITOR.instances.corpo.updateElement();
}
}
}
})
por Vinicius Assef (noreply@blogger.com) em 15 de May de 2013 às 20:48
por Vinicius Assef (noreply@blogger.com) em 15 de May de 2013 às 20:47
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.
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.
A ideia até então é um bate-papo via Hangout ou Skype, despretensioso, preferencialmente regado à alguma cerveja.
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:
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!
Esse post tem como objetivo ser um guia com alguns links para quem que aprender a linguagem go.
An introduction to programming in go
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
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.
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.
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 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.
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.
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.
No ú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.
Em breve teremos mais uma edição do Encontro do PUG-SE! Para ficar por dentro, assine a nossa lista de discussão.
por Vinicius Assef (noreply@blogger.com) em 01 de May de 2013 às 17:50
por Vinicius Assef (noreply@blogger.com) em 30 de April de 2013 às 18:08
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:
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.
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ê!
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.
"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.
São atributos que são definidos diretamente a classe.
São atributos definidos a instância, geralmente através do "self", que representa a instância de uma classe.
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
por Marcel Caraciolo (noreply@blogger.com) em 15 de April de 2013 às 18:20
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.
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
por Francisco Souza (noreply@blogger.com) em 11 de April de 2013 às 22:47
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 Marcel Caraciolo (noreply@blogger.com) em 07 de April de 2013 às 06:43
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.
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:
pt-br, tudo minúsculo separado por hífen.PROJECT_DIR, veja nesta palestra.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.
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.
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.
Use vagrant mesmo em um site ridiculamente pequeno, e compartilhe seus tropeços para que outros possam rir de você, com você.
[]‘s, HB!
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!
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.
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')
cosine_distances(X, X)
| name | repeat | timing | loops | units |
|---|---|---|---|---|
| scipy.spatial 0.8.0 | 3 | 18.36 | 10 | ms |
- Intel Core i5 950 processor
- Mac Os 10.6
- Python 2.6.5 64-bit
- NumPy 1.6.1
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')
cosine_distances(X, X)
| name | repeat | timing | loops | units |
|---|---|---|---|---|
| scipy.spatial 0.8.0 | 3 | 19.19 | 10 | ms |
import numpy
X = numpy.random.uniform(1,5,(1000,))
from sklearn.metrics.pairwise import cosine_similarity as cosine_distances
cosine_distances(X, X)
| name | repeat | timing | loops | units |
|---|---|---|---|---|
| sklearn 0.13.1 | 3 | 0.1812 | 1000 | ms |
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)
cosine_distances(X, X)
| name | repeat | timing | loops | units |
|---|---|---|---|---|
| nltk.cluster | 3 | 0.01024 | 1e+04 | ms |
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)))
cosine_distances(X, X)
| name | repeat | timing | loops | units |
|---|---|---|---|---|
| numpy | 3 | 0.009339 | 1e+05 | ms |
| name | repeat | timing | loops | units | timeBaselines |
|---|---|---|---|---|---|
| scipy.spatial 0.8.0 | 3 | 19.19 | 10 | ms | 2055 |
| sklearn 0.13.1 | 3 | 0.1812 | 1000 | ms | 19.41 |
| nltk.cluster | 3 | 0.01024 | 1e+04 | ms | 1.097 |
| numpy | 3 | 0.009339 | 1e+05 | ms | 1 |
por Marcel Caraciolo (noreply@blogger.com) em 22 de March de 2013 às 09:52
Todo 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:
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.
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.
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:
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.
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:
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
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.
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
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 Vinicius Assef (noreply@blogger.com) em 15 de March de 2013 às 14:04
Quem 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:
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
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.
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.
por Vinicius Assef (noreply@blogger.com) em 10 de March de 2013 às 11:05
Já 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.
-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.
-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).
Com essas duas opções e um pouco de criatividade, é possível fazer coisas como:
Usando os módulos sys e pprint:
$ python -c 'import sys, pprint; pprint.pprint(sys.path)'
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
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']
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!
por Vinicius Assef (noreply@blogger.com) em 04 de March de 2013 às 19:38
The 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
>>> 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)
![]() |
| SnapGuide Graph Schema |
#-*- 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())
>>> 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)]
>>> script = g.scripts.get('avg_likes')
>>>likes = g.gremlin.command(script, params=None)
>>>likes111.089116326I like the tutorials Amanda preferred, what other tutorials does Amanda like that I haven't seen ?
I like food tutorials, what other food tutorials are there ?
![]() |
| Great dish by the way! |
This traversal doesn't provide us useful information, but we could put in action now the collaborative filtering with a extended query:>>> 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
>>>> 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']
>>> 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}>>> 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.>>> 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)]
>>>> 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)]
>>>> 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)]
>>>> 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)]
>>>> 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}
por Marcel Caraciolo (noreply@blogger.com) em 01 de March de 2013 às 22:08
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.
No ú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:
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.
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.
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.
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
{% 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
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:
Público presente no encontro do pug-pe
Parabenizar a Gileno e Fernando Rocha pela organização deste encontro!
Atenciosamente,
Equipe PUG-PE
Uma 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.
A small and fun experiment is out:
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 Vinicius Assef (noreply@blogger.com) em 18 de February de 2013 às 16:35
por Vinicius Assef (noreply@blogger.com) em 18 de February de 2013 às 14:18
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | # 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)
|
por Marcel Caraciolo (noreply@blogger.com) em 10 de February de 2013 às 22:18
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.
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…
class Constant(int):And there you are:
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__
>>> 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.from inspect import currentframeAnd now one can do:
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__
>>> 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! Timport sysSo, 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?
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()
>>> 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
![]() |
| Favoritoz's Coupon System |
frank(u,d) = w1 * SD + w2 * ED + w3*P + w4*CA + w5*UP + w6*DV + bwhere,
por Marcel Caraciolo (noreply@blogger.com) em 26 de January de 2013 às 15:58
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.

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")
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")
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")
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.
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.
Como utilizar o módulo logging do Python em seus apps web2py.
Este video é parte da aula 4 do cursodepython.com.br
Script para converter bancos de dados MDB para scripts MySQL no Linux:
https://github.com/elcio/mdb2mysql
Um oferecimento Visie e Aviso Brasil
por noreply@blogger.com (Ricardo Bittencourt) em 13 de January de 2013 às 19:45
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.
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.
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:
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!