Django-Dynamic-Fixture 1.4.0 possui bugfixes e novas funcionalidades:
- Relatório com o número de queries executadas em cada método de teste: manage.py test --with-queries
- Conta quantas queries são executas ao inserir e atualizar um objeto (pode variar de acordo com listeners, sobrescrita do método save, etc): manage.py count_queries_on_save
http://code.google.com/p/django-dynamic-fixture/
Mostrando postagens com marcador Python. Mostrar todas as postagens
Mostrando postagens com marcador Python. Mostrar todas as postagens
sábado, 29 de outubro de 2011
quarta-feira, 12 de outubro de 2011
Apresentação sobre testes na Python Brasil 2011
Padrões de Testes Automatizados com Django
http://www.slideshare.net/paulocheque/padroes-de-testes-automatizados-com-django
http://www.slideshare.net/paulocheque/padroes-de-testes-automatizados-com-django
domingo, 9 de outubro de 2011
Feature Flip para Continuous Deployment? Django Intruder
As ferramentas mais populares para ativar e desativar funcionalidades no Django são intrusivas, ou seja, é necessário acrescentar código adicional para permitir que uma funcionalidade seja ativada ou desativada. Essa abordagem é interessante, mas complexa para resolver um problema simples, além do que não é uma solução 100% dinâmica.
Django Intruder é uma solução simples e transparente para a aplicação. Sem qualquer código adicional é possível desativar qualquer request ao sistema.
http://code.google.com/p/django-intruder/
http://pypi.python.org/pypi/django-intruder
Django Intruder é uma solução simples e transparente para a aplicação. Sem qualquer código adicional é possível desativar qualquer request ao sistema.
http://code.google.com/p/django-intruder/
http://pypi.python.org/pypi/django-intruder
terça-feira, 15 de março de 2011
Boas práticas com Django
[Editado em 2011/03/27]: melhor explicado e detalhado o primeiro tópico.
- Usar filter e exclude somente dentro de managers ou models: Com django é tão fácil fazer query que acabamos inserindo filters e excludes em tudo quanto é local, tais como views e forms, o que é uma ideia terrível. Prejudica a testabilidade do código, mistura responsabilidades dos objetos etc.
- Dar nomes às urls e usar reverse e a tag url: Usar urls hard-coded além de prejudicar a manutenção, ainda dificulta i18n. Além disso, a aplicação pode deixar de ser um "pluggable", ou seja, dificilmente poderá ser reaproveitada em outros projetos.
- Utilizar select_related sempre que possível/necessário para otimização (http://docs.djangoproject.com/en/1.2/ref/models/querysets/#select-related)
- Usar distinct em buscas que envolvem várias tabelas. Mais comumente quando são usados campos many to many para buscas. Isso é pra evitar que uma busca traga registros repetidos. Chatices de SQL que são propagadas nos resultados das buscas. (http://docs.djangoproject.com/en/1.2/ref/models/querysets/#distinct)
- Criar Custom Fields caso um field siga um padrão (http://docs.djangoproject.com/en/1.2/howto/custom-model-fields)
- Sempre dar redirect depois de salvar um formulário (básico de qualquer framework Web).
- Não utilizar o arquivo tests.py. Criar uma pasta tests e adicionar arquivos de teste para arquivo da aplicação.
- Há várias maneiras de organizar o settings. Uma básica e boa é criar (pelo menos) um arquivo de settings para desenvolvimento e um para produção.
domingo, 13 de março de 2011
Django Dynamic Fixture 1.2.1
Lançada nova versão da ferramenta (1.2.1). A documentação foi atualizada, incluindo comparação com outras ferramentas.
Antes dessa versão, a ferramenta atrapalhava a criação de objetos que tinham campos auto calculados, como é o caso dos objetos que usam a ferramenta Dango-MPTT (http://code.google.com/p/django-mptt).
Django Dynamic Fixture 1.2.1: http://code.google.com/p/django-dynamic-fixture
quarta-feira, 9 de março de 2011
Discussão sobre Django, Internet e frameworks Web
Já mexi com muitos frameworks Web, de diferentes linguagens: JSP/Servlets, Struts, JSF, GWT, Echo2 (todos anteriores para Java), Django (Python), Grails (Groovy), Rails (Ruby) etc. Desses todos, destaco dois como sendo os mais inteligentes: Django e GWT.
Django porque é muito simples, legível e poderoso.
GWT porque foi criado pensando completamente em comandos assíncronos. Talvez apenas o Echo2 poderia se comparar a ele.
Ainda não existe um framework perfeito (ou quase), até mesmo porque a internet ainda é muito bagunçada. Prova disso são as próprias "linguagens" de HTML, Javascript e CSS que são completamente rebuscadas. Não é a toa que hoje existem diversas ferramentas para geração de CSS e ferramentas de Javascript, tais como JQuery, que não apenas criam funções bacanas para serem usadas, mas que também fazem uma série de correções e adaptações para navegadores e pro próprio HTML/Javascript para que o desenvolvimento Web se torne menos amaldiçoado.
Isso dá até um bom argumento para a Microsoft e o IE não adotarem certos padrões e convenções. Uma empresa do tamanho da Microsoft não deve acatar a padrões mal definidos. Claro que não estou defendendo a Microsoft, até porque isso só piora ainda mais a situação. Entretanto, é compreensível.
Mas enfim, onde quero chegar é que Django não é perfeito e, acredito, tem certas coisas que devem ser evitadas. Segue uma lista:
Django porque é muito simples, legível e poderoso.
GWT porque foi criado pensando completamente em comandos assíncronos. Talvez apenas o Echo2 poderia se comparar a ele.
Ainda não existe um framework perfeito (ou quase), até mesmo porque a internet ainda é muito bagunçada. Prova disso são as próprias "linguagens" de HTML, Javascript e CSS que são completamente rebuscadas. Não é a toa que hoje existem diversas ferramentas para geração de CSS e ferramentas de Javascript, tais como JQuery, que não apenas criam funções bacanas para serem usadas, mas que também fazem uma série de correções e adaptações para navegadores e pro próprio HTML/Javascript para que o desenvolvimento Web se torne menos amaldiçoado.
Isso dá até um bom argumento para a Microsoft e o IE não adotarem certos padrões e convenções. Uma empresa do tamanho da Microsoft não deve acatar a padrões mal definidos. Claro que não estou defendendo a Microsoft, até porque isso só piora ainda mais a situação. Entretanto, é compreensível.
Mas enfim, onde quero chegar é que Django não é perfeito e, acredito, tem certas coisas que devem ser evitadas. Segue uma lista:
- Framework de permissões: Acho útil apenas para interface de Admin. Para uso interno, não faz sentido. Devemos simplificar as coisas, não complicar. Logo, devemos trabalhar com grupos de usuários (vide django snippets). Perdemos em flexibilidade mas ganhamos em simplicidade e clareza.
- Formsets, Inline Formsets etc: Foram criados pensando na interface de Admin. Apesar de quebrarem um galhão as vezes, são muito rebuscados e limitados.
- Templates para comandos assíncronos: Templates no Django são muito legais, principalmente seu sistema de herança que é muito simples. Contudo, meu modo de ver é que templates é uma arquitetura pensando em páginas e comandos síncronos. Quando vamos trabalhar com chamadas assíncronas, eles perdem importância. Django não foi arquiteturado como o GWT, logo, não é trivial criar componentes de interface de usuário.
- get_absolute_url: O quê tem a ver url com a base de dados? Isso é uma tentativa de DRY, mas, ao meu ver, equivocada. Primeiro porque deixa confuso aonde a url será definida (temos o urls.py pra isso). Depois porque mistura de responsabilidade da camada de dados/negócios com a de exibição.
- Fixtures (estáticas) nos testes: Fixtures estáticas, não importa se é xml, yaml, json etc, são horríveis para manutenção. O máximo é ter um initial_data com usuários, grupos, permissões e algum outro dado básico e olhe lá.
À medida que for tendo novos pensamentos vou adicionando aqui.
Mockito-Python
A biblioteca mais legal de mocks para Java é a Mockito (http://mockito.org), que na verdade é uma biblioteca de spies e stubs, não apenas de mocks. Segunda mais simples e objetiva a EasyMock e, por último, JMock.
Para python não conhecia nenhuma biblioteca de objetos dublês bacana (simples e clara), até que vi que em 2010 surgiu a Mockito-Python:
http://code.google.com/p/mockito-python/downloads/list
Um link bacana de comparação entre outras ferramentas:
http://code.google.com/p/pymox/wiki/MoxComparison
Para python não conhecia nenhuma biblioteca de objetos dublês bacana (simples e clara), até que vi que em 2010 surgiu a Mockito-Python:
http://code.google.com/p/mockito-python/downloads/list
Um link bacana de comparação entre outras ferramentas:
http://code.google.com/p/pymox/wiki/MoxComparison
domingo, 27 de fevereiro de 2011
Django Dynamic Fixture
Utilizar dados estáticos para testes é um antipadrão. Mesmo assim, o Django fornece facilidades para usar fixtures estáticas (yaml, json...) nos testes. Não use! A manutenção dos testes se torna péssima.
A melhor solução é criar os objetos dinâmicamente para cada caso de teste. Para facilitar, pode-se criar fixtures que criam instância de objetos já com dados populados. Melhor ainda, deixe que uma ferramenta faça isso por você, como é o caso da Django Dynamic Fixture: http://code.google.com/p/django-dynamic-fixture/
Instalação: pip install django-dynamic-fixture
Documentação: A documentação está toda na página inicial.
A melhor solução é criar os objetos dinâmicamente para cada caso de teste. Para facilitar, pode-se criar fixtures que criam instância de objetos já com dados populados. Melhor ainda, deixe que uma ferramenta faça isso por você, como é o caso da Django Dynamic Fixture: http://code.google.com/p/django-dynamic-fixture/
Instalação: pip install django-dynamic-fixture
Documentação: A documentação está toda na página inicial.
quinta-feira, 9 de setembro de 2010
Refactory my code
Um site muito bacana para buscar código fonte, soluções etc para várias linguagens:
http://refactormycode.com/codes/recent/python
Alias, muitas das minhas buscas no google por soluções, bugs etc acabam caindo no site StackOverflow. Também é um ótimo site: http://stackoverflow.com
http://refactormycode.com/codes/recent/python
Alias, muitas das minhas buscas no google por soluções, bugs etc acabam caindo no site StackOverflow. Também é um ótimo site: http://stackoverflow.com
terça-feira, 7 de setembro de 2010
Combinação de Listas em Python
Combinação de Listas: Imagina que você tem diversas listas e você quer montar todas as combinações de um número específico de elementos de cada lista.
Implementação:
Testes de Unidade:
Implementação:
class CombinationOfListsGenerator(object):
def __init__(self, lists, amount_per_list):
if(amount_per_list == None or lists == None):
raise Exception('Invalid argument: None.')
elif len(lists) < 1:
raise Exception('Invalid argument: Empty list.')
elif not isinstance(amount_per_list, int):
if len(lists) > len(amount_per_list):
raise Exception('Invalid argument: It is missing information in amount_per_list, too few amounts.')
else:
for l, a in zip(lists, amount_per_list):
if len(l) < a:
raise Exception('Invalid argument: Amount per list is bigger than size of the list.')
self.lists = lists
self._current = []
self.generators = []
if isinstance(amount_per_list, int):
for l in self.lists:
generator = CombinationGenerator(len(l), amount_per_list)
self.generators.append(generator)
else:
for l, a in zip(self.lists, amount_per_list):
generator = CombinationGenerator(len(l), a)
self.generators.append(generator)
self._total = 1
for generator in self.generators:
self._total *= generator.total()
self.reset()
def total(self):
return self._total
def reset(self):
self._current = []
for generator in self.generators[:-1]:
generator.reset()
generator.next()
# last one is loaded in 'next' method
self.generators[-1].reset()
def current(self):
return self._current
def has_next(self):
return not (not self.generators[0].has_next() and not self.generators[-1].has_next())
def _combination_of_list(self, list, indexes):
combination = []
for index in indexes:
combination.append(list[index])
return combination
def _update_generators(self):
# Atualiza anteriores
i = len(self.generators) - 1
while i >= 0 and not self.generators[i].has_next():
self.generators[i].reset()
self.generators[i].next()
i -= 1
if i < 0:
# Tratando fim:
i = 0
self.generators[i].next()
def _update_current(self):
self._current = []
for i in range(0, len(self.generators)):
indexes = self.generators[i].current()
self._current.extend(self._combination_of_list(self.lists[i], indexes))
def next(self):
self._update_generators()
self._update_current()
return self._current
Testes de Unidade:
class CombinationOfListsTests(unittest.TestCase):
def test_input_accepts_int_or_list(self):
CombinationOfListsGenerator([[1], [2], [3]], 1)
CombinationOfListsGenerator([[1], [2], [3]], [1,1,1])
def test_invalid_input(self):
self.assertRaises(Exception, CombinationOfListsGenerator, None, 1)
self.assertRaises(Exception, CombinationOfListsGenerator, [1], None)
self.assertRaises(Exception, CombinationOfListsGenerator, [], 1)
self.assertRaises(Exception, CombinationOfListsGenerator, [[1],[2]], 2)
self.assertRaises(Exception, CombinationOfListsGenerator, [[1]], 0)
# len([1]) < len([[1],[2]])
self.assertRaises(Exception, CombinationOfListsGenerator, [[1],[2]], [1])
self.assertRaises(Exception, CombinationOfListsGenerator, [[1,2],[2],[3]], [2,1])
# 2 > len([2])
self.assertRaises(Exception, CombinationOfListsGenerator, [[1],[2]], [1, 2])
self.assertRaises(Exception, CombinationOfListsGenerator, [[1],[2,3]], [1, 3])
def test_1_element_of_each_list_of_size_1(self):
generator = CombinationOfListsGenerator([[1], [2]], 1)
self.assertEquals(1, generator.total())
self.assertEquals([1, 2], generator.next())
def test_1_element_of_each_list_of_size_2(self):
generator = CombinationOfListsGenerator([[1, 2], [3, 4]], 1)
self.assertEquals(4, generator.total())
self.assertEquals([1, 3], generator.next())
self.assertEquals([1, 4], generator.next())
self.assertEquals([2, 3], generator.next())
self.assertEquals([2, 4], generator.next())
def test_2_elements_of_each_list_of_size_2(self):
generator = CombinationOfListsGenerator([[1, 2], [3, 4]], 2)
self.assertEquals(1, generator.total())
self.assertEquals([1, 2, 3, 4], generator.next())
def test_2_elements_of_each_list_of_size_3(self):
generator = CombinationOfListsGenerator([[1, 2, 3], [4, 5, 6]], 2)
self.assertEquals(9, generator.total())
self.assertEquals([1, 2, 4, 5], generator.next())
self.assertEquals([1, 2, 4, 6], generator.next())
self.assertEquals([1, 2, 5, 6], generator.next())
self.assertEquals([1, 3, 4, 5], generator.next())
self.assertEquals([1, 3, 4, 6], generator.next())
self.assertEquals([1, 3, 5, 6], generator.next())
self.assertEquals([2, 3, 4, 5], generator.next())
self.assertEquals([2, 3, 4, 6], generator.next())
self.assertEquals([2, 3, 5, 6], generator.next())
def test_1_element_of_each_list_of_size_2(self):
generator = CombinationOfListsGenerator([[1, 2], [3, 4], [5, 6]], 1)
self.assertEquals(8, generator.total())
self.assertEquals([1, 3, 5], generator.next())
self.assertEquals([1, 3, 6], generator.next())
self.assertEquals([1, 4, 5], generator.next())
self.assertEquals([1, 4, 6], generator.next())
self.assertEquals([2, 3, 5], generator.next())
self.assertEquals([2, 3, 6], generator.next())
self.assertEquals([2, 4, 5], generator.next())
self.assertEquals([2, 4, 6], generator.next())
def test_custom_elements_of_each_list_of_size_2(self):
generator = CombinationOfListsGenerator([[1, 2], [3, 4], [5, 6]], [1, 2, 1])
self.assertEquals(4, generator.total())
self.assertEquals([1, 3, 4, 5], generator.next())
self.assertEquals([1, 3, 4, 6], generator.next())
self.assertEquals([2, 3, 4, 5], generator.next())
self.assertEquals([2, 3, 4, 6], generator.next())
def test_has_next(self):
generator = CombinationOfListsGenerator([[1, 2], [3, 4]], 1)
self.assertEquals(4, generator.total())
self.assertTrue(generator.has_next())
self.assertEquals([1, 3], generator.next())
self.assertTrue(generator.has_next())
self.assertEquals([1, 4], generator.next())
self.assertTrue(generator.has_next())
self.assertEquals([2, 3], generator.next())
self.assertTrue(generator.has_next())
self.assertEquals([2, 4], generator.next())
self.assertFalse(generator.has_next())
generator.next()
self.assertTrue(generator.has_next())
def test_reset(self):
generator = CombinationOfListsGenerator([[1, 2], [3, 4]], 1)
self.assertEquals(4, generator.total())
self.assertEquals([1, 3], generator.next())
generator.reset()
self.assertEquals([1, 3], generator.next())
def test_current(self):
generator = CombinationOfListsGenerator([[1, 2], [3, 4]], 1)
self.assertEquals(4, generator.total())
self.assertEquals([], generator.current())
self.assertEquals([1, 3], generator.next())
self.assertEquals([1, 3], generator.current())
self.assertEquals([1, 4], generator.next())
self.assertEquals([1, 4], generator.current())
segunda-feira, 6 de setembro de 2010
Python Decorator para imprimir o desempenho de um método
Decorators do Python são bem legais, né? É uma solução elegante, simples e 100% OO. Olha um decorator que fiz para imprimir o desempenho de um método (sugestões são sempre bemvindas):
Exemplo de uso:
Implementação:
Exemplo de uso:
@print_performance
def minha_funcao():
pass
Implementação:
try:
from functools import wraps
except ImportError:
# Python 2.3, 2.4 fallback.
from django.utils.functional import wraps
import time
def print_performance(function):
def wrapped_function(*args, **kwargs):
print('START %s(%s)' % (function.__name__, args,))
start_time = time.clock()
exception = None
try:
result = function(*args, **kwargs)
except Exception, e:
exception = e
end_time = time.clock()
if exception:
print('END-ERROR %s(%s): %ss' % (function.__name__, args, str(end_time - start_time)))
raise exception
print('END %s(%s): %ss' % (function.__name__, args, str(end_time - start_time)))
return result
return wraps(function)(wrapped_function)
Combinação(n, r) em Python
Gerar todas combinações possíveis de uma coleção de ítens é muito útil para jogos, por exemplo, para criar uma inteligência artificial para o computador. Python oferece funções prontas pra isso, como pode ser visto em http://docs.python.org/library/itertools.html. De qualquer modo, em alguma situação pode ser útil que as combinações sejam geradas iterativamente, uma de cada vez, como é sugerido pelo algoritmo de Rosen. Segue uma implementação que fiz desse algoritmo:
Testes de Unidade:
import math
class CombinationGenerator(object):
def __init__(self, n, r):
if n < 1: raise Exception('Invalid argument: n (%d) must be greater than 1.' % (n,))
elif r < 1: raise Exception('Invalid argument: r (%d) must be greater than 1.' % (r,))
elif r > n: raise Exception('Invalid argument: r (%d) must be lower or equal than n (%d)' % (r, n))
self.n = n
self.r = r
# total = n! / r! * (n - r)!
self._total = math.factorial(n) / (math.factorial(r) * math.factorial(n-r))
self._current = []
def first_combination(self):
return list(range(self.r))
def last_combination(self):
return list(range(self.n - self.r, self.n))
def __get_index_of_last_valid_element_to_increment(self):
for index in reversed(range(self.r)):
possibleValue = self._current[index] + 1
possibleValueIsValid = (possibleValue <= (self.n - (self.r - index)))
if possibleValueIsValid:
return index
return None
def total(self):
return self._total
def reset(self):
self._current = []
def current(self):
return self._current
def has_next(self):
return self._current != self.last_combination()
# Algorithm from Rosen
def next(self):
'''
Return a list of indexes
'''
if len(self._current) == 0:
self._current = self.first_combination()
else:
theIndex = self.__get_index_of_last_valid_element_to_increment()
if theIndex == None:
self._current = self.first_combination()
else:
self._current[theIndex] += 1
ref = self._current[theIndex]
for index in range(theIndex + 1, self.r):
ref += 1
self._current[index] = ref
return self._current
Testes de Unidade:
import unittest
class CombinationGeneratorTests(unittest.TestCase):
def test_1Choose1(self):
generator = utilities.CombinationGenerator(1, 1)
self.assertEquals(1, generator.total())
self.assertEquals([0], generator.next())
self.assertEquals([0], generator.first_combination())
self.assertEquals([0], generator.last_combination())
def test_NChooseN(self):
generator = utilities.CombinationGenerator(3, 3)
self.assertEquals(1, generator.total())
self.assertEquals([0, 1, 2], generator.next())
self.assertEquals([0, 1, 2], generator.first_combination())
self.assertEquals([0, 1, 2], generator.last_combination())
def test_2Choose1(self):
generator = utilities.CombinationGenerator(2, 1)
self.assertEquals(2, generator.total())
self.assertEquals([0], generator.next())
self.assertEquals([1], generator.next())
self.assertEquals([0], generator.first_combination())
self.assertEquals([1], generator.last_combination())
def test_3Choose1(self):
generator = utilities.CombinationGenerator(3, 1)
self.assertEquals(3, generator.total())
self.assertEquals([0], generator.next())
self.assertEquals([1], generator.next())
self.assertEquals([2], generator.next())
def test_3Choose2(self):
generator = utilities.CombinationGenerator(3, 2)
self.assertEquals(3, generator.total())
self.assertEquals([0, 1], generator.next())
self.assertEquals([0, 2], generator.next())
self.assertEquals([1, 2], generator.next())
def test_4Choose3(self):
generator = utilities.CombinationGenerator(4, 3)
self.assertEquals(4, generator.total())
self.assertEquals([0, 1, 2], generator.next())
self.assertEquals([0, 1, 3], generator.next())
self.assertEquals([0, 2, 3], generator.next())
self.assertEquals([1, 2, 3], generator.next())
def test_4Choose2(self):
generator = utilities.CombinationGenerator(4, 2)
self.assertEquals(6, generator.total())
self.assertEquals([0, 1], generator.next())
self.assertEquals([0, 2], generator.next())
self.assertEquals([0, 3], generator.next())
self.assertEquals([1, 2], generator.next())
self.assertEquals([1, 3], generator.next())
self.assertEquals([2, 3], generator.next())
def test_5Choose3(self):
generator = utilities.CombinationGenerator(5, 3)
self.assertEquals(10, generator.total())
self.assertEquals([0, 1, 2], generator.next())
self.assertEquals([0, 1, 3], generator.next())
self.assertEquals([0, 1, 4], generator.next())
self.assertEquals([0, 2, 3], generator.next())
self.assertEquals([0, 2, 4], generator.next())
self.assertEquals([0, 3, 4], generator.next())
self.assertEquals([1, 2, 3], generator.next())
self.assertEquals([1, 2, 4], generator.next())
self.assertEquals([1, 3, 4], generator.next())
self.assertEquals([2, 3, 4], generator.next())
self.assertEquals([0, 1, 2], generator.first_combination())
self.assertEquals([2, 3, 4], generator.last_combination())
def test_Sanity15Choose4(self):
generator = utilities.CombinationGenerator(15, 4)
for x in range(30):
combination = generator.next()
self.assertEquals(4, len(combination))
for y in combination:
self.assertTrue(y >= 0 and y < 15)
def test_Sanity50Choose7(self):
generator = utilities.CombinationGenerator(50, 7)
for x in range(100):
combination = generator.next()
self.assertEquals(7, len(combination))
for y in combination:
self.assertTrue(y >= 0 and y < 50)
def test_invalid_input(self):
self.assertRaises(Exception, utilities.CombinationGenerator, 0, 0)
self.assertRaises(Exception, utilities.CombinationGenerator, -2, -1)
self.assertRaises(Exception, utilities.CombinationGenerator, 1, 2)
self.assertRaises(Exception, utilities.CombinationGenerator, 2, 0)
def test_performance(self):
n = 16 # Java Rosen algorithm 22 in 1 second
for r in range(1, n+1):
generator = utilities.CombinationGenerator(n, r)
while generator.has_next(): indexes = generator.next()
def test_AfterLastCombinationRestart(self):
generator = utilities.CombinationGenerator(3, 2)
self.assertEquals([0, 1], generator.next())
self.assertEquals([0, 2], generator.next())
self.assertEquals([1, 2], generator.next())
self.assertEquals([0, 1], generator.next())
def test_has_next(self):
generator = utilities.CombinationGenerator(3, 2)
self.assertTrue(generator.has_next())
generator.next()
self.assertTrue(generator.has_next())
generator.next()
self.assertTrue(generator.has_next())
generator.next()
self.assertFalse(generator.has_next())
generator.next()
self.assertTrue(generator.has_next())
def test_reset(self):
generator = utilities.CombinationGenerator(3, 2)
self.assertEquals([0, 1], generator.next())
generator.reset()
self.assertEquals([0, 1], generator.next())
def test_current(self):
generator = utilities.CombinationGenerator(3, 2)
self.assertEquals([0, 1], generator.next())
self.assertEquals([0, 1], generator.current())
self.assertEquals([0, 2], generator.next())
self.assertEquals([0, 2], generator.current())
domingo, 29 de agosto de 2010
Django Pluggables
Alguns Django pluggables para funcionalidades rotineiras em Websites.
DjangoOpenID (http://code.google.com/p/djangoopenid): Para facilitar a integração do OpenID para autenticação em aplicações com Django. É uma solução bem simples, não indicado se você precisa de uma solução mais elaborada.
Django-WorldDB (http://code.google.com/p/django-worlddb): Para facilitar a criação de caixas de seleção “país/região/cidade”.
Django-ip2geo (http://code.google.com/p/django-ip2geo): Para descobrir o local de um usuário através de seu IP. Usa a base de dados livre do Maxmind.
Fontes:
http://www.maxmind.com/app/geolitecity
http://www.maxmind.com/app/python
http://www.maxmind.com/app/api
http://www.maxmind.com/app/installation?city=1
http://code.google.com/p/pygeoip/
http://www.ip2phrase.com/
DjangoOpenID (http://code.google.com/p/djangoopenid): Para facilitar a integração do OpenID para autenticação em aplicações com Django. É uma solução bem simples, não indicado se você precisa de uma solução mais elaborada.
Django-WorldDB (http://code.google.com/p/django-worlddb): Para facilitar a criação de caixas de seleção “país/região/cidade”.
Django-ip2geo (http://code.google.com/p/django-ip2geo): Para descobrir o local de um usuário através de seu IP. Usa a base de dados livre do Maxmind.
Fontes:
http://www.maxmind.com/app/geolitecity
http://www.maxmind.com/app/python
http://www.maxmind.com/app/api
http://www.maxmind.com/app/installation?city=1
http://code.google.com/p/pygeoip/
http://www.ip2phrase.com/
Sua versão Django na Locaweb
Os servidores Linux da Locaweb, assim como os do Google App Engine, fornecem uma versão padrão do Django (0.96, 1.0 ..). Assim, basta configurar sua aplicação Django e pronto (http://wiki.locaweb.com.br/pt-br/Como_instalar_uma_aplicação_Django%3F). O detalhe é que o desenvolvimento do Django é muito ativo, vire e mexe tem versão nova e com MUITAS funcionalidades bacanas. Portanto, compensa sempre utilizar as versões mais novas do framework.
O problema é que nenhuma empresa (tem alguma?) consegue manter uma equipe para gerenciar milhares de versões de milhares de aplicativos de um servidor. É o que ocorre com a Locaweb e também com o Google (no caso do Google App Engine).
A melhor maneira para resolver isso é a solução proposta pelo Google App Engine, que também é aplicável nos servidores da Locaweb. Basta copiar o diretório da versão do Django que desejar na raiz do seu projeto, como se fosse um pluggable (Django = simplicidade + flexibilidade), e configurar o classpath apropriadamente. Resumindo a parte da configuração, basta utilizar o index.wsgi a seguir:
Importante: Faça backup do index.wsgi original antes de qualquer mudança.
O problema é que nenhuma empresa (tem alguma?) consegue manter uma equipe para gerenciar milhares de versões de milhares de aplicativos de um servidor. É o que ocorre com a Locaweb e também com o Google (no caso do Google App Engine).
A melhor maneira para resolver isso é a solução proposta pelo Google App Engine, que também é aplicável nos servidores da Locaweb. Basta copiar o diretório da versão do Django que desejar na raiz do seu projeto, como se fosse um pluggable (Django = simplicidade + flexibilidade), e configurar o classpath apropriadamente. Resumindo a parte da configuração, basta utilizar o index.wsgi a seguir:
Importante: Faça backup do index.wsgi original antes de qualquer mudança.
import os, sys, site
# Using Django of your project directory:
# Remove the standard version of Django.
for k in [k for k in sys.modules if k.startswith('django')]:
del sys.modules[k]
# Force sys.path to have our own directory first, in case we want to import from it.
sys.path.insert(0, '/home/SEUUSUARIO/wsgi_apps/SEUPROJETO')
sys.path.append('/home/ginlab/wsgi_apps/SEUPROJETO')
os.environ['DJANGO_SETTINGS_MODULE']='settings'
# se usa outras bibliotecas
site.addsitedir('/home/SEUUSUARIO/.python/lib')
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Fontes:
http://code.google.com/appengine/articles/django.html
Sistema de autenticação/autorização das redes sociais
Para muitos sistemas, compensa mais utilizar um sistema de autenticação/autorização dos WebServices de redes sociais famosas (semelhante ao sistema de OpenID) do que implementar um módulo do zero. O primeiro passo é a criação de "contas de aplicação" (análogo a contas de usuário) nas redes sociais. Segue as URLs para cadastrar uma aplicação nas redes sociais mais famosas:
Facebook: http://www.facebook.com/developers/createapp.php
Twitter: http://twitter.com/apps
Orkut/Gmail/Google: https://www.google.com/accounts/ManageDomains
LinkedIn: http://developer.linkedin.com/docs/DOC-1008
Ainda, existem plugins que facilitam a integração dessas funcionalidades ao seu framework MVC-Web. Por exemplo, para Python-Django:
Social-Auth:
http://uswaretech.com/blog/2009/08/django-socialauth-login-via-twitter-facebook-openid-yahoo-google/
http://github.com/uswaretech/Django-Socialauth
PyFacebook:
http://code.google.com/p/pyfacebook/
Facebook: http://www.facebook.com/developers/createapp.php
Twitter: http://twitter.com/apps
Orkut/Gmail/Google: https://www.google.com/accounts/ManageDomains
LinkedIn: http://developer.linkedin.com/docs/DOC-1008
Ainda, existem plugins que facilitam a integração dessas funcionalidades ao seu framework MVC-Web. Por exemplo, para Python-Django:
Social-Auth:
http://uswaretech.com/blog/2009/08/django-socialauth-login-via-twitter-facebook-openid-yahoo-google/
http://github.com/uswaretech/Django-Socialauth
PyFacebook:
http://code.google.com/p/pyfacebook/
sábado, 28 de agosto de 2010
Comparações entre linguagens
Quando vamos discutir sobre linguagens de programação, alguns comportamentos são típicos: Uns tentam puxar a sardinha pro que lhe convém, outros fogem da raia e dizem que não existe uma linguagem perfeita e fim de papo.
Hoje estamos mais evoluidos e novos paradigmas estão surgindo. A interminável guerra entre tipagem estática ou dinâmica está a ponto de receber um pouco mais de emoção com o surgimento do JRuby e Jython que misturam os dois paradigmas. Também está ficando mais interessante as discussões sobre conceitos de programação, como orientação a objetos, programação funcional, orientação a aspectos e reflexão que podem ser utilizados juntos e de forma amigável, principalmente com linguagens com bom suporte como Smalltalk, Python, Ruby e Scala, entre outras.
Minha opinião é que pode existir sim uma linguagem perfeita, que atenda a todas a necessidades, mas ainda deve demorar para chegarmos as conclusões pertinentes para isso. Para pensarmos sobre isso, temos que pensar o que esperamos de uma linguagem, destaco algumas características interessantes:
- Performance
- Produtividade
- Sintaxe bonita
- Boas IDEs
- API completa, extensível e fácil de usar
- Frameworks produtivos e completos
- Suporte a orientação a objetos
- Suporte a orientação a aspectos
- Suporte a programação funcional
- Suporte a reflexão
- Tipagem estática ou dinâmica ou as duas
- Bom suporte a programação concorrente ou paralela
- Interpretada ou compilada
- Multi-plataforma
- Código aberto
- ente infinitos outros
Se formos pensar só em performance, escolheriamos C++ ou Lua, pensando em sintaxe bonita escolheriamos Python, considerando frameworks produtivos escolheriamos Ruby (por causa do Rails), bom suporte a programação concorrente ou paralesla optaríamos por Scala, boa IDE escolheríamos Java (com Eclipse + JUnitMax) e por ai vai.
Destas características, algumas são incostestáveis, por exemplo, todos querem melhor performance. Em relação às APIs e frameworks também. Quem não prefere fazer print("alguma coisa") ao invés de System.out.println("alguma coisa")?? Lembro que quando comecei a aprender Java eu achava lindo fazer "new BufferedReader(new FileReader(new InputStreamReader(new InternalAlgumaCoisaReader(new BytecodeReader(..." porque sabia que a orientação a objetos por trás desta API estava muito bonita, mas depois de um tempo isto me torrou a paciência.
Já em relação aos conceitos de programação, todos são compatíveis e podem trabalhar juntos em perfeita harmonia, vide exemplos como Java + AspectJ, Hibernate + Reflection, Ruby OO + Ruby funcional, etc..
O que acho que é o mais crítico e difícil de chegar a uma conclusão é em relação a tipagem. Escrever código com tipagem dinâmica é muito mais gostoso, por outro lado trabalhar com o auxílio do compilador também é, não é uma delícia dar control+espaço e a IDE completa o resto pra gente? E agora? Alguns usam como argumentos a facilidade de refatoração, por exemplo Java possui um suporte a refatoração esplêndido, mas SmallTalk e Python também! Então fica complicado chegar a alguma conclusão a partir deste argumento.
Bom, enfim, o objetivo deste post não era concluir nada, é só para aguçar a discussão e talvez estimular posts como "Scala vs Java", "Scala vs Python", "Scala vs Ruby", "Scala vs Haskell", "Scala vs Groovy", que acho uma excelente maneira da gente entender melhor os pontos fortes e fracos das linguagens.
Hoje estamos mais evoluidos e novos paradigmas estão surgindo. A interminável guerra entre tipagem estática ou dinâmica está a ponto de receber um pouco mais de emoção com o surgimento do JRuby e Jython que misturam os dois paradigmas. Também está ficando mais interessante as discussões sobre conceitos de programação, como orientação a objetos, programação funcional, orientação a aspectos e reflexão que podem ser utilizados juntos e de forma amigável, principalmente com linguagens com bom suporte como Smalltalk, Python, Ruby e Scala, entre outras.
Minha opinião é que pode existir sim uma linguagem perfeita, que atenda a todas a necessidades, mas ainda deve demorar para chegarmos as conclusões pertinentes para isso. Para pensarmos sobre isso, temos que pensar o que esperamos de uma linguagem, destaco algumas características interessantes:
- Performance
- Produtividade
- Sintaxe bonita
- Boas IDEs
- API completa, extensível e fácil de usar
- Frameworks produtivos e completos
- Suporte a orientação a objetos
- Suporte a orientação a aspectos
- Suporte a programação funcional
- Suporte a reflexão
- Tipagem estática ou dinâmica ou as duas
- Bom suporte a programação concorrente ou paralela
- Interpretada ou compilada
- Multi-plataforma
- Código aberto
- ente infinitos outros
Se formos pensar só em performance, escolheriamos C++ ou Lua, pensando em sintaxe bonita escolheriamos Python, considerando frameworks produtivos escolheriamos Ruby (por causa do Rails), bom suporte a programação concorrente ou paralesla optaríamos por Scala, boa IDE escolheríamos Java (com Eclipse + JUnitMax) e por ai vai.
Destas características, algumas são incostestáveis, por exemplo, todos querem melhor performance. Em relação às APIs e frameworks também. Quem não prefere fazer print("alguma coisa") ao invés de System.out.println("alguma coisa")?? Lembro que quando comecei a aprender Java eu achava lindo fazer "new BufferedReader(new FileReader(new InputStreamReader(new InternalAlgumaCoisaReader(new BytecodeReader(..." porque sabia que a orientação a objetos por trás desta API estava muito bonita, mas depois de um tempo isto me torrou a paciência.
Já em relação aos conceitos de programação, todos são compatíveis e podem trabalhar juntos em perfeita harmonia, vide exemplos como Java + AspectJ, Hibernate + Reflection, Ruby OO + Ruby funcional, etc..
O que acho que é o mais crítico e difícil de chegar a uma conclusão é em relação a tipagem. Escrever código com tipagem dinâmica é muito mais gostoso, por outro lado trabalhar com o auxílio do compilador também é, não é uma delícia dar control+espaço e a IDE completa o resto pra gente? E agora? Alguns usam como argumentos a facilidade de refatoração, por exemplo Java possui um suporte a refatoração esplêndido, mas SmallTalk e Python também! Então fica complicado chegar a alguma conclusão a partir deste argumento.
Bom, enfim, o objetivo deste post não era concluir nada, é só para aguçar a discussão e talvez estimular posts como "Scala vs Java", "Scala vs Python", "Scala vs Ruby", "Scala vs Haskell", "Scala vs Groovy", que acho uma excelente maneira da gente entender melhor os pontos fortes e fracos das linguagens.
Plugins pro Eclipse
Python:
Java:
ajdt (AspectJ): http://download.eclipse.org/tools/ajdt/34/update
maven: http://m2eclipse.sonatype.org/update
Scala:
scala: http://www.scala-lang.org/scala-eclipse-plugin-nigthly
Groovy:
groovy/grails: http://dist.codehaus.org/groovy/distributions/update/
Métricas:
eclemma: http://update.eclemma.org
coverclipse: http://coverlipse.sf.net/update
metrics: http://www.stateofflow.com/UpdateSite
Testes:
testng: http://beust.com/eclipse
jsunit: download http://sourceforge.net/projects/jsunit/files/
Controle de Versão:
subclipse: http://subclipse.tigris.org/update_1.0.x
ajdt (AspectJ): http://download.eclipse.org/tools/ajdt/34/update
maven: http://m2eclipse.sonatype.org/update
Scala:
scala: http://www.scala-lang.org/scala-eclipse-plugin-nigthly
Groovy:
groovy/grails: http://dist.codehaus.org/groovy/distributions/update/
Métricas:
eclemma: http://update.eclemma.org
coverclipse: http://coverlipse.sf.net/update
metrics: http://www.stateofflow.com/UpdateSite
Testes:
testng: http://beust.com/eclipse
jsunit: download http://sourceforge.net/projects/jsunit/files/
Controle de Versão:
subclipse: http://subclipse.tigris.org/update_1.0.x
Bibliotecas Python
Básicas:
sudo apt-get install python-setuptools
Testes:
sudo easy_install mock
Redes sociais, autenticação:
sudo easy_install python-openid
sudo easy_install python-yadis
sudo easy_install oauth
Biblioteca de manipulação de imagens:
Antes de instalar PIL, instalar dependências, senão dá problema:
sudo apt-get install libfreetype6-dev libjpeg-dev libfreetype6 zlib1g-dev liblcms1-dev
sudo easy_install PIL
sudo apt-get install python-imaging
Fontes:
Bug PIL: http://www.answermysearches.com/fixing-pil-ioerror-decoder-jpeg-not-available/320/
sudo apt-get install python-setuptools
Testes:
sudo easy_install mock
Redes sociais, autenticação:
sudo easy_install python-openid
sudo easy_install python-yadis
sudo easy_install oauth
Biblioteca de manipulação de imagens:
Antes de instalar PIL, instalar dependências, senão dá problema:
sudo apt-get install libfreetype6-dev libjpeg-dev libfreetype6 zlib1g-dev liblcms1-dev
sudo easy_install PIL
sudo apt-get install python-imaging
Fontes:
Bug PIL: http://www.answermysearches.com/fixing-pil-ioerror-decoder-jpeg-not-available/320/
Assinar:
Postagens (Atom)