Depois de um grande tempo em standby, eu retomei a minha busca pelo bot concurseiro. Resolvi tentar criar um bot bem simples (@RodrigoLiraBot no Telegram) só para testar a API do telegram.

bot

Para isso eu dei uma olhada no site do próprio Telegram . Nele eu encontrei um módulo para  Python chamada twx.botapi . Sua utilização é bem simples e por isso resolvi usá-la.

A instalação é usando o pip

$ sudo pip install twx.botapi

No próprio do github tem um exemplo que guiou o meu desenvolvimento.

from twx.botapi import TelegramBot, ReplyKeyboardMarkup

"""
Setup the bot
"""

bot = TelegramBot('')
bot.update_bot_info().wait()
print(bot.username)

"""
Send a message to a user
"""
user_id = int()

result = bot.send_message(user_id, 'test message body').wait()
print(result)

"""
Get updates sent to the bot
"""
updates = bot.get_updates().wait()
for update in updates:
    print(update)

"""
Use a custom keyboard
"""
keyboard = [
    ['7', '8', '9'],
    ['4', '5', '6'],
    ['1', '2', '3'],
         ['0']
]
reply_markup = ReplyKeyboardMarkup.create(keyboard)

bot.send_message(user_id, 'please enter a number', reply_markup=reply_markup).wait()

O API TOKEN é um token que é gerado polo BotFather na criação do Bot. Lembrando que isso é uma informação secreta do seu bot. O legal desse exemplo é que ele também mostra como o teclado do bot pode ser customizado para atender a um determinado bot.

Abaixo segue um exemplo de update que é retornado pela função get_updates(). Um update é uma interação com o bot. Ele contém a mensagem e o usuário que realizou a interação.

Update(update_id=194163476, message=Message(message_id=288, sender=User(id=31616677, first_name=u'Rodrigo Lira', last_name=None, username=u'rodrigoclira'), date=1458837621, chat=Chat(id=31616677, type=u'private', title=None, username=u'rodrigoclira', first_name=u'Rodrigo Lira', last_name=None), forward_from=None, forward_date=None, reply_to_message=None, text=u'teste', audio=None, document=None, photo=None, sticker=None, video=None, voice=None, caption=None, contact=None, location=None, new_chat_participant=None, left_chat_participant=None, new_chat_title=None, new_chat_photo=None, delete_chat_photo=None, group_chat_created=None, supergroup_chat_created=None, channel_chat_created=None, migrate_to_chat_id=None, migrate_from_chat_id=None), inline_query=None, chosen_inline_result=None)

No meu caso, eu modifiquei um pouco esse código para criar um bot que fica respondendo sempre a mesma mensagem independente do que foi escrito para ele. A cada 30 segundos, ele responde a quem falou com ele com uma mensagem determinada por mim.

Para evitar mensagens repetidas, eu coloquei uma funcionalidade que evita o envio de mensagem para o mesmo update. A cada resposta do bot é guardada os identificadores das mensagem que foram respondidas usando a biblioteca pickle de Python. Se por acaso o programa for encerrado, o arquivo será lido na sua inicialização. Essa foi a alternativa mais rápida que encontrei mas creio que haja formas melhores de contornar isso.

No momento esse script está sendo executando num servidor que tenho na Dreamhost, mas é possível executar ele em qualquer máquina que tenha acesso a internet. O código do final do @RodrigoLiraBot é o seguinte:


from twx.botapi import TelegramBot, ReplyKeyboardMarkup
from time import sleep
import pickle
from os import path

CURR_PATH = path.dirname(path.realpath(__file__))
DUMP_FILE = path.join(CURR_PATH, "data.pkl")


"""
Configurando o bot
"""

BOTAPI='API_AQUI'
bot = TelegramBot(BOTAPI)
bot.update_bot_info().wait()

print(bot.username)

if path.exists(DUMP_FILE): # Se existe, carregar a lista de mensagens respondidas
    pkl_file = open(DUMP_FILE)
    answered_messages = pickle.load(pkl_file)
else:
    answered_messages = []

bot_message = "Oi, eu sou um bot do http://blog.rodrigolira.net/. Em breve terei mais funcionalidades!"

while (True):
    print ("Getting updates".center(50, '-'))
    
    updates = bot.get_updates().wait()
    for pos, update in enumerate(updates):

        print(str(pos) +" "+  str(update) + "n")

        update_id = update.update_id
        if (update_id not in answered_messages): # Se a mensagem não foi respondida, responda o usuário
            sender_id = update.message.sender.id
            result = bot.send_message(sender_id, bot_message).wait()

            print(result)

            if (result):
                answered_messages.append(update_id)

    output = open(DUMP_FILE, 'wb') 
    pickle.dump(answered_messages, output) # persiste a lista de mensagens respondidas
    sleep(30)

Se você quiser usar com o seu bot simplesmente coloque o APITOKEN recebido na criação dele.
O resultado é algo assim:

bottelegram

| Criando um bot do Telegram (parte 1)
| Criando um bot do Telegram (parte 2)

Resolvi colocar um exemplo para demonstrar o funcionamento
do decorador @classmethod. Como se pode ver na execução,
nesse código, após chamar o método unpack, é criado um novo
objeto do tipo MinhaClasse.


#!/usr/bin/python
# -*- coding: utf-8 -*-

class MinhaClasse:
    def __init__(self, raw, prev):
        print ("Criando a classe MinhaClasse")
        self.raw = raw
        self.prev = prev

    #Método estático unpack
    @classmethod
    def unpack(cls, raw, prev=None):
        print ("Tipo='%s' com o raw='%s' e prev='%s'" % (cls.__name__, raw, prev))
        return cls(raw=raw, prev=prev)

if __name__ == '__main__':
    MinhaClasse.unpack("raw content", "prev content") #Não precisa de instância, o método é chamado como o nome da classe
    #Não precisa informar o valor de cls porque implicitamente ele sabe que deve ser passado o tipo da classe, ou seja "MinhaClasse"

Rodrigo Lira,

Um amigo me mandou um email perguntando uma dúvida sobre um decorator de Python…

@classmethod
def unpack (cls, raw, prev=None):
  return cls(raw=raw, prev=prev)

Pode destrinchar isto para mim? classmethod é uma função built-in do Python. Significa que dentro do método eu substituo cls por classmetho?

Oi,

Segundo o que vi em algumas referências, o @classmethod
é igual ao @staticmethod, ambos são para definir um método estático dentro de uma classe[1][2]. Um método estático não é nada mais que uma função definida dentro de uma classe. Não precisa criar uma instância de uma classe para chamar ele.

Por exemplo, supondo essa classe:

class A:
    def __init__(self):
        pass

    def foo(self):
        pass

    @staticmethod
    def boo():
        pass

O método foo não é estático então deveria ser chamado a partir de uma instância:

obj = A()
# Chamando um método não estático a partir de uma instância
obj.foo()

#Chamando um método estático a partir de uma instância
obj.boo()

Já o método boo é estático então não precisa ser chamado de uma instância, mas pode ser, apesar que não seja uma boa prática.

obj = A()
# Chamando um método estático a partir de uma classe
A.boo()

# Chamando um método não estático a partir de uma classe
A.foo()
Traceback (most recent call last):
File "input", line 1, in
TypeError: unbound method foo() must be called with A instance as first argument
(got nothing instead)

Como pode ver, conseguimos chamar um método estático a partir da classe, mas não um não estático.

Voltando a @classmethod e @staticmethod… O decorador @staticmethod permite criar métodos estáticos e esses métodos não podem ser sobrescritos pelas subclasses. Ele é imutável.

Já os métodos com o decorador @classmethod permite criar métodos estáticos que podem ser sobrescritos pelas subclasses. Isto é porque o primeiro parâmetro das funções que tem o @classmethod tem que ser sempre cls (classe)[3].

Aparentemente esse método que você enviou é uma factory[4]. Métodos que são usados para criar instância de outras classes.

O exemplo que você me enviou:

   @classmethod
   def unpack (cls, raw, prev=None):
       return cls(raw=raw, prev=prev)

Segundo o que eu disse, cls é um tipo de classe e o método retorna uma instância dessa classe no qual é passado os outros dois parâmetros para o construtor dela.

Abraço.

[1] http://jfine-python-classes.readthedocs.org/en/latest/decorators.html
[2] http://stackoverflow.com/questions/12179271/python-classmethod-and-staticmethod-for-beginner
[3] http://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python
[4] https://pt.wikipedia.org/wiki/Factory_Method

Como eu disse recentemente,  caminhos relativos costumam dar dor de cabeça quando se está trabalhando com CronJobs. Já fui surpreendido algumas vezes com erros devido a isso. Por isso, eu sempre uso a estratégia de pegar o caminho do script que estou executando e concatenar ao caminho relativo que desejo usar.  Anteriormente, eu mostrei como fazer isso em Shell Script e agora estou postando o que faço nos meus scritps em Python.

from os import path

CURR_PATH = path.dirname(path.realpath(__file__))

print CURR_PATH

Rodrigo Lira,

Flask is pretty awesome! It’s so simple. I’ve worked with Django and was nice, but flask seems really funny. Nowadays, i’m developing an app just for fun using Flask. Actually, It will be a new feature to http://calc.coeus.com.br . Well, bellow there is a tutorial about Flesk.

http://flask.pocoo.org/

RL

Many fellas ask me: “why should I learn Python?” so I solved to list a lot of reasons.

Python is the most excited language I’ve ever worked. I use Python since 2008, actually I started to study python since my first year on the graduation. It was funny because I was studying C and Python shows up so easy. I remember which I had many problems with semicolon. Six years passed and now, Python is stronger. So, let me show you some reasons for u use Python:

  • Python is easy and it is clear. You don’t need to waste time with monkey jobs. You just need to develop what you want.
  • Many companies use Python like NASA, GLOBO (Brazil) , M$, APPLE, DISNEY, DROPBOX, GOOGLE… believe Python is everywhere.
    • “Python has been an important part of Google since the beginning, and remains so as the system grows and evolves. Today dozens of Google engineers use Python, and we’re looking for more people with skills in this language.” said Peter Norvig, director of search quality at Google, Inc.  See more.
  • Object-Oriented Programming or Functional Programming or Imperative programming. You don’t need to choose it. You can use all it with Python. Lambda, map, filter, zip… I love it.
  • The Python interpreter allow you test code snippets very quickly. Actually, if you are using Python on Linux, you should install bpython.
  • There is no company behind Python (like Java has) but there is a huge community. Actually, community is the most cool thing when is talking about opensource.
  • Python is now the the most popupar introductory  teaching language at top US universities because it is powerfull and easy to learn it.
  • Also, Python won twice the “Programming language of the year” created by the TIOBE and according the IEEE, Python is the 4th language most popular.
  • There are a lot of content on the web to study. See my page.

So, listen to me. You should learn it, man! I will increase that list but for while it is enough.

RL

 

No meu trabalho de Reconhecimento de padrões, eu precisei utilizar uma base que me fornecia imagens como vetor de bits. Por exemplo, o f  era representado pelo seguinte vetor:

0000000000000000000001111110000
0000000000000000000001111111100
0000000000000000000001111111110
0000000000000000000001111111111
0000000000000000000111111111110
0000000000000000000111111111110
0000000000000000000111111111111
0000000000000000000011111111111
0000000000000000000111111111111
0000000000000000001111111111110
0000000000000000000111111111111
0000000000000000000111111111111
0000000000000000000111111111111
0000000000000000001111111111111
0000000000000000001111111111111
0000000000000000011111111111110
0000000000000000011111111111110
0000000000000000011111111111100
0000000000000000011111111111100
0000000000000000001111111111100
0000000000000000011111111111000
0000000000000000011111111111000
0000000000000000011111111111000
0000000000000000111111111111000
0000000000000000111111111110000
0000000000000111111111111100000
0000000000011111111111111000000
0000000000011111111111111000000
0000000000111111111111111000000
0000000011111111111111111000000
0000001111111111111111110000000
0000011111111111111111110000000
0000111111111111111111110000000
0011111111111111111111110000000
1111111111111111111111110000000
1111111111111111111111111000000
1111111111111111111111111000111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111110000000111111111111111111
1111100000000111111111111111111
1100000000000011111111111111111
0000000000000001111111111111111
0000000000000001111111111111110
0000000000000000111111111111000
0000000000000001111111100000000
0000000000000000111111110000000
0000000000000000111111110000000
0000000000000000111111110000000
0000000000000000111111111000000
0000000000000000111111111000000
0000000000000000111111111000000
0000000000000000111111111100000
0000000000000000111111111110000
0000000000000000111111111110000
0000000000000000111111111111000
0000000000000001111111111110000
0000000000000000111111111111000
0000000000000000111111111111000
0000000000000000111111111111100
0000000000000000011111111111100
0000000000000000111111111111000
0000000000000000011111111111100
0000000000000000011111111111100
0000000000000000001111111111100
0000000000000000001111111111100
0000000000000000001111111111100
0000000000000000001111111111100
0000000000000000001111111111100
0000000000000000000111111111100
0000000000000000000011111111100
0000000000000000000011111111100
0000000000000000000001111111100
0000000000000000000000111111100
0000000000000000000000001111100

Infelizmente, eu estava utilizando uma framework que necessitava receber a imagem e não o vetor de bits que é extraído dela. Logo, eu tinha que dá um passo pra trás pra puder dá dois pra frente.

Fazendo uma pesquisa na internet, encontrei uma função do scipy que fazia exatamente o que eu queria.  scipy.misc.imsave cria uma imagem a partir de um array da classe numpy.

A partir disso, eu criei o seguinte código:

#!/bin/bash

import scipy
import numpy

def create_bynary_image(binary_content, output_name):
    letter = open(bynary_content)
    bits_image = []

    for line in letter:
        bits_image.append(map(lambda x: int(x), list(line.replace('n',''))))

    np_array = numpy.array(bits_image)
    letter.close()
    scipy.misc.imsave(output_name, np_array)

if __name__ == '__main__':
    create_bynary_image('letter.txt', 'f.png')
   

Abaixo o conteúdo de letter.txt que é usado no exemplo.

0000000000000000000001111110000
0000000000000000000001111111100
0000000000000000000001111111110
0000000000000000000001111111111
0000000000000000000111111111110
0000000000000000000111111111110
0000000000000000000111111111111
0000000000000000000011111111111
0000000000000000000111111111111
0000000000000000001111111111110
0000000000000000000111111111111
0000000000000000000111111111111
0000000000000000000111111111111
0000000000000000001111111111111
0000000000000000001111111111111
0000000000000000011111111111110
0000000000000000011111111111110
0000000000000000011111111111100
0000000000000000011111111111100
0000000000000000001111111111100
0000000000000000011111111111000
0000000000000000011111111111000
0000000000000000011111111111000
0000000000000000111111111111000
0000000000000000111111111110000
0000000000000111111111111100000
0000000000011111111111111000000
0000000000011111111111111000000
0000000000111111111111111000000
0000000011111111111111111000000
0000001111111111111111110000000
0000011111111111111111110000000
0000111111111111111111110000000
0011111111111111111111110000000
1111111111111111111111110000000
1111111111111111111111111000000
1111111111111111111111111000111
1111111111111111111111111111111
1111111111111111111111111111111
1111111111111111111111111111111
1111110000000111111111111111111
1111100000000111111111111111111
1100000000000011111111111111111
0000000000000001111111111111111
0000000000000001111111111111110
0000000000000000111111111111000
0000000000000001111111100000000
0000000000000000111111110000000
0000000000000000111111110000000
0000000000000000111111110000000
0000000000000000111111111000000
0000000000000000111111111000000
0000000000000000111111111000000
0000000000000000111111111100000
0000000000000000111111111110000
0000000000000000111111111110000
0000000000000000111111111111000
0000000000000001111111111110000
0000000000000000111111111111000
0000000000000000111111111111000
0000000000000000111111111111100
0000000000000000011111111111100
0000000000000000111111111111000
0000000000000000011111111111100
0000000000000000011111111111100
0000000000000000001111111111100
0000000000000000001111111111100
0000000000000000001111111111100
0000000000000000001111111111100
0000000000000000001111111111100
0000000000000000000111111111100
0000000000000000000011111111100
0000000000000000000011111111100
0000000000000000000001111111100
0000000000000000000000111111100
0000000000000000000000001111100
e o resultado foi

teste

RL

 

Estava desenvolvendo um script e precisava de alguma estrutura que permitisse-me fazer manipulações da seguinte forma:

dicionario[dia][hora][chave1] = x
dicionario[dia][hora][chave2] = y

Ou seja, basicamente criar dicionários aninhados. Eu poderia manipular de forma mais espartana um dicionário e criar uma estrutura aninhada, porém eu queria fazer isso de uma forma mais direta. Queria que essa criação fosse invisível a mim. Dessa forma, eu encontrei o defaultdict. O defaultdict é uma classe do módulo collections em python que faz exatamente o que queria. Infelizmente pra meu azar, essa classe só foi inserida na versão 2.5 da linguagem e a versão que eu tinha disponível no servidor era apenas a 2.4 – old but gold.

Depois de uma pesquisada na internet, encontrei uma implementação da classe defaultdict no qual venho usando desde então nos meus scripts. Abaixo segue a implementação e um exemplo de uso.

CODE

http://pastebin.com/8LDaqW4G
#!/usr/bin/python

class defaultdict(dict):
    def __init__(self, default_factory=None, *a, **kw):
        if (default_factory is not None and
            not hasattr(default_factory, '__call__')):
            raise TypeError('first argument must be callable')
        dict.__init__(self, *a, **kw)
        self.default_factory = default_factory
    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)
    def __missing__(self, key):
        if self.default_factory is None:
            raise KeyError(key)
        self[key] = value = self.default_factory()
        return value
    def __reduce__(self):
        if self.default_factory is None:
            args = tuple()
        else:
            args = self.default_factory,
        return type(self), args, None, None, self.items()
    def copy(self):
        return self.__copy__()
    def __copy__(self):
        return type(self)(self.default_factory, self)
    def __deepcopy__(self, memo):
        import copy
        return type(self)(self.default_factory,
                          copy.deepcopy(self.items()))
    def __repr__(self):
        return 'defaultdict(%s, %s)' % (self.default_factory,
                                        dict.__repr__(self))

def recursively_default_dict():
    return defaultdict(recursively_default_dict)

if __name__ == '__main__':
    dic = recursively_default_dict()
    dic['a']['b']['c'] = 3
    dic['a']['b']['d'] = 4

    print "dic['a']['b']['d']", dic['a']['b']['c']
    print "dic['a']['b']['d']", dic['a']['b']['d']

After a long time… I’m back!

Now, I going to show you how use python to add borders to an image.


import Image
import ImageOps

if __name__ == '__main__':
    image_name="terminator.jpg"
    new_image_name="terminator_with_border.jpg"
    image_file = Image.open(image_name)
    new_image_file = ImageOps.expand(image_file, border=10, fill='red')
    new_image_file.save(new_image_name)

Input image

Input image

Output image

Output image

That’s all folks!

Essa semana estava lendo a Linux Magazine e vi uma matéria sobre um programa bem interessante, acho que o título da matéria era “Script Gráfico”.  Essa matéria refere-se a um programa chamado Project Sikuli que ainda está versão beta. Pelo pouco que li é um projeto de pesquisa do MIT Computer Science and Artificial Intelligence Laboratory (CSAIL)

Bem, acho que o título da matéria da LM fala tudo, usando o Sikuli é possível automatizar tarefas utilizando screenshots. Algo que chamou a atenção também é que o Sikuli usa Jython 🙂
No site do projeto há um vídeo de demostração – usando o MacOS –

mas o uso dele é bastante simples, se você precisa que seu script clique em algum local, basta escrever click e especificar com screenshot o local.  Aconselho dá uma olhada na documentação do projeto.

Bem, acho que é isso é tudo bem intuitivo. Get Started !

PS.: Eu precisei instalar a biblioteca libcvaux2.1, mas talvez você tenha que instalar o java 6 caso não tenha instalado.

Rodrigo Lira