Django decorators

I am developing a page with Django and I had one interesting requirement: limit the number of users. The idea is to let a fixed number of users use the site and show a message telling the others to wait. I will like to share how I did it.

We need to check in every view used by a user. Instead of repeating the same code, the easiest way is to add a decorator for each function. Is really similar to AoP.

decorators.py:

from django.conf import settings
from django.shortcuts import redirect

MAX_NUMBERS_OF_USERS = getattr(settings, 'MAX_NUMBERS_OF_USERS', 100)

def check_user(view_function):
    def _wrapped_view_func(request, *args, **kwargs):
        auth_user = request.user
        
        if auth_user.id <= MAX_NUMBERS_OF_USERS:
            return view_function(request, *args, **kwargs)
        return redirect('coming_soon')
    return _wrapped_view_func

views.py:

from app.decorators import check_user
from django.contrib.auth.decorators import login_required
from django.shortcuts import render

@login_required
@check_user
def restricted_view(request):
    #Do stuff

def coming_soon(request):
    return render(request, 'coming_soon.html', {})

And that’s it ! Easy, clean and simple ! You can do more complex stuffs like logging.

Advertisements

Python expressiveness

Here i will post my solution of the first two problems in the qualifying round in the Google Code Jam. Both are easy problems.

The first one is:

https://code.google.com/codejam/contest/2974486/dashboard#s=p0

#!/usr/bin/python

def read_board(row_number):
    for i in xrange(4):
        if i + 1 == row_number:
            row = map(int, raw_input().split(' '))
        else:
            raw_input()
    return row 

ncases = int(raw_input())

for ncase in xrange(ncases):
    first_row_number = int(raw_input())
    first_row = read_board(first_row_number)

    second_row_number = int(raw_input())
    second_row = read_board(second_row_number)
    match_count = 0
    number = 0
    for i in first_row:
        for j in second_row:
            if i == j:
                number = i
                match_count += 1
                break

    answer = 'Case #' + str(ncase + 1) + ': '
    if match_count == 0:
        print answer + 'Volunteer cheated!'
    elif match_count == 1:
        print answer + str(number)
    else:
        print answer + 'Bad magician!'

And the other one was https://code.google.com/codejam/contest/2974486/dashboard#s=p1:

#!/usr/bin/python

ncases = int(raw_input())

for ncase in xrange(ncases):
    data = map(float, raw_input().split(' '))
    C, F, X = tuple(data)

    if X <= C:
        print 'Case #' + str(ncase + 1) + ': ' + str(X/2.0)
    else:
        house_times = [C/2.0]
        cookies_per_second = [2.0]
        min_time = X/2.0

        for i in xrange(int(X)/int(C)):
            new_cookies_per_second = cookies_per_second[i] + F
            new_time = house_times[i] + X/new_cookies_per_second
            house_times.append(house_times[i] + C/new_cookies_per_second)
            cookies_per_second.append(new_cookies_per_second)

            min_time = min(min_time, new_time)

        print 'Case #' + str(ncase + 1) + ': ' + str(min_time)

Python 🙂

Useful script i made some months ago

I am from Venezuela and some months ago we had presidential elections.

The opposition, which is in someway my tendency (I am tired of this goverment), called a fraud. So in order to check that my self i made a crawler for the web page (www.cne.gob.ve/resultado_presidencial_2013/r/1/reg_000000.html) with the results in order to gather and analyze them.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import requests
import re
import threading

paths_re = re.compile('<s*li\s+class="region-nav-item"><a\s+id="region_ref"\s+href="(.*)"\s*>(.*)<\s*/a\s*>\s*<\s*/li\s*>', re.IGNORECASE)
values_re = re.compile('<tr\s+class="tbsubtotalrow"\s*>\s*<td\s+class="lightRowContent"\s+align="center"\s*>\s*<img\s+src=".+"\s+alt=""\s+width="50"\s+/>\s*
\s*<td\s+class="lightRowContent">\s*<table\s+width="100%">\s*<\s*tr\s*>\s*<\s*td\s+align="left"\s*>\s*<\s*a\s+href="javascript:showCandidateInfo\(\d\);"\s*>(.*)<\s*/a\s*>\s*<\s*/td\s*>\s*<\s*/tr\s*>(\s*<\s*tr\s*>\s*<\s*td\s*>\s*<\s*font\s+color="\#990000"\s*>\s*Adjudicado\s*<\s*/font\s*>\s*<\s*/td\s*>\s*<\s*/tr\s*>\s*|\s*)<\s*/table\s*>\s*<\s*/td\s*>\s*<\s*td\s+class="lightRowContent"\s+align="right"\s*>\s*<\s*span\s*>(.*)<\s*/span\s*>\s*<\s*/td>\s*<\s*td\s+class="lightRowContent"\s+align="right"\s*>\s*<\s*span\s*>(.*)<\s*/span\s*>\s*<\s*/td>\s*', re.IGNORECASE)
filter_re = re.compile('%|\.|\s')
main_url = 'http://www.cne.gob.ve/resultado_presidencial_2013/r/1/'
depth_map = ['All', 'State', 'Municipality', 'County', 'Center', 'Table']
separator = '\t'
outfiles = []
outfilename = 'electionsdata'
qttythread = 6
rthreads = []
generalfile = open(outfilename, 'w')
firstorder = dict()

def crawl_page(url, region, depth, file_to_write):
    page = requests.get(url)
    paths = paths_re.findall(page.text)
    values = values_re.findall(page.text)

    if region == separator:
        names = map(lambda v: v[0], values)
        counter = 0
        for name in names:
	        firstorder[name] = counter
	        counter += 1
		firstorder = map(lambda v: v[0], values)
        print_headers(file_to_write, names)

    print_info(file_to_write, region, values, depth)

    if region == separator:
        chunked_lists = chunk_list(paths, (len(paths) + (qttythread - len(paths) % qttythread)) / qttythread)
        threadn = 0
        for chunked_list in chunked_lists:
            t = threading.Thread(target=recursive_calls, args=(chunked_list, region, depth, outfiles[threadn], ))
            t.start()
            rthreads.append(t)
            threadn += 1
    else:
        recursive_calls(paths, region, depth, file_to_write)

def recursive_calls(paths, region, depth, file_to_write):
    savedregion = region
    for path in paths:
        pathsurl = path[0]
        pathsfor = path[1]
        region =  savedregion + separator + pathsfor
        print region
        crawl_page(main_url + pathsurl, region, depth + 1, file_to_write)

def chunk_list(l, chunksize):
    result = []
    for i in xrange(0, len(l), chunksize):
        result.append(l[i:i+chunksize])
    return result

def print_headers(file_to_write, names):
    result = 'Type'
    for region_type in depth_map:
        result += separator + region_type
    for name in names:
        result += separator + name + ' value\t' + name + ' %'
    file_to_write.write(result + '\n')

def print_info(file_to_write, region, values, depth):
	order_values(values)
    result = depth_map[depth] + region
    for i in xrange(len(depth_map) - depth - 1):
        result += separator
    for value in values:
        result += separator + clean_number_srt(value[2]) + separator + clean_number_srt(value[3])
    file_to_write.write(result + '\n')

def order_values(values):
    position = 0
    while position < len(values):
        needed_position = firstorder[values[position][0]]
	    if position == needed_position:
            position += 1
	    else:
            swap(values, position, needed_position)

def swap(l, i, j):
	aux = l[i]
	l[i] = l[j]
	l[j] = aux

def clean_number_srt(number_str):
    return filter_re.sub('', number_str).replace(',', '.')

if __name__ == "__main__":
    for i in xrange(qttythread):
        outfile = open(outfilename + str(i), 'w')
        outfiles.append(outfile)

    crawl_page(main_url + 'reg_000000.html', separator, 0, generalfile)

    for rthread in rthreads:
        rthread.join()

    for outfile in outfiles:
        outfile.close()
    generalfile.close()

In the end, i didn’t run it. I think this final version is pretty complete and can be used for another variety of things, thus I am sharing the code :). It use a number of threads and check the pages in a recursive way writing to different files. The regular expressions are pretty ugly, but i didn’t want to use a HTML parser or something like that.

Always learning !

As i wrote before, i did participate on Google Code Jam Qualification Round. I just did 3 problems and got 50 points.I’ll talk about one of the problems: Lawnmower.

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

from sys import stdin

if __name__ == "__main__":
 ncases = int(stdin.readline())

 for ncase in xrange(ncases):
     n, m = map(int, stdin.readline().split(' '))

     lawn = [[] for j in xrange(n)]

     for row in xrange(n):
         lawn[row] = map(int, stdin.readline().split(' '))

         allle = True

         for row in xrange(n):
             for column in xrange(m):

                 hle = True
                 vle = True
             for frow in xrange(n):
                 if lawn[frow][column] > lawn[row][column]:
                     vle = False
             for fcolumn in xrange(m):
                 if lawn[row][fcolumn] > lawn[row][column]:
                     hle = False

             allle = hle or vle

             if not allle:
                 break
         if not allle:
             break

     result = 'YES' if allle else 'NO'
     print 'Case #' + str(ncase + 1) + ': ' + result

I got stuck for sometime, but in the end i found and coded quite elegant solution in python. We have a matrix and every element e[i,j] on it had to satisfy the following constraints:

  1. All elements e[i,k], with k != j must be e[i,k] <= e [i, j]
  2. All elements e[k,j], with k !=i must be e[k,j] <= e [i, j]

If both constraints are satisfied, then the answer is yes, else we can’t cut the lawn.

The interesting part is the next round i’ll like to talk about. I didn’t participate on Round A, but i did try round B. As i told before, i never practice for this, and after trying quite a bit the first problem i got frustrated and decided to stop. In like 30 minutes, there were already a lot of people with 2 or more problems completed.

I want to talk about the first problem: Osmos. The problem was easy to understand, my mistake was getting so stuck in thinking “efficiently” and trying to find the best solution. In the end i made a bad assumption and never passed the runs. I stopped and reminded to view the solution later.

I viewed the solution found my error and learned a lot from the code i saw.

I’ll show my fixed code:

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

from sys import stdin

def dp(arminmote, motes):
    if len(motes) == 1:
        return 1 if arminmote <= motes[0] else 0 
    elif arminmote > motes[0]:
        steps = dp(arminmote + motes[0], motes[1:])
    else:
         steps = 1 + min(dp(2*arminmote - 1, motes), dp(arminmote, motes[1:]))
    return steps

if __name__ == "__main__":
    ncases = int(stdin.readline())

    for ncase in xrange(ncases):
        case = stdin.readline()
        arminmote, leftmotes = map(int, case.split(' '))

        case = stdin.readline()
        motes = map(int, case.split(' '))
        motes.sort()

        if arminmote > 1:
            steps = dp(arminmote, motes)
        else:
            steps = len(motes)

        print 'Case #' + str(ncase + 1) + ': ' + str(steps)

The Round B winner code:

# dolphinigle
# GCJ 2013 1B
# 4 May 2013

ntest = int(raw_input())
for itc in range(ntest):
  print 'Case #%d:' % (itc+1),
  my_mote, n = map(int, raw_input().split())
  motes = sorted(map(int, raw_input().split()))
  if my_mote == 1:
    print n
    continue
  best_answer = n
  my_answer = 0
  for index, i in enumerate(motes):
    if i < my_mote:
      my_mote += i
      continue
    # maybe stop here?
    best_answer = min([best_answer, my_answer + n - index])
    while my_mote <= i:
      my_mote += my_mote - 1
      my_answer += 1
    my_mote += i
  best_answer = min([best_answer, my_answer])
  print best_answer

Quite the difference? Yes. First i didn’t see any polynomial way of solving, i just though that it was needed in some cases to choose between 2 possibilities and didn’t use any memorization or dynamic programming technique. I did fail quite hard, but it is important to learn from mistakes.

I saw why the first place on round B is this guys. In just 7 minutes he came with this brilliant solution. With one cycle and using two variables: one to count the motes needed to eat and the other the best solution so far, starting with removing all the motes. I was amazed and learned a lot seeing this code. I had never use raw_input and enumerate. They are so useful.

Learning and sharing is so important, specially all regarding computers. One of the reason i made this post is that. Hope it is useful to someone.

Some programming problems

I am not a big fan of programming competions, but i do love good challenges and interesting problems. Google Code Jam (https://code.google.com/codejam/) is comming soon and i decide to participate in a normal way. I am not that hardcore programmer 24/7.

For practice I did two problems: File Fix-it and All Your Base. As i was so lazy, i used Python. I want to comment my reasoning for solving each of the problems.

  • File Fix-It: The problem consisted on on telling the minimum number of mkdirs (it creates folders one by one) to create the given directories. In each case was given the already done directories and the ones we needed to create. Creating directories can be viewed as building a tree. I simulated that using a dictonary.
#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import stdin

def add_directory(directory_hash, path, done):
    directory = ''
    created_directories = 0
    for node in path.split('/')[1:]:
        directory += '/' + node
        if not directory_hash.has_key(directory):
            directory_hash[directory] = True
            created_directories += 1
    return 0 if done else created_directories

if __name__ == "__main__":
    ncases = int(stdin.readline())

    for ncase in xrange(ncases):
        case = stdin.readline()
        done_nodes, left_nodes = map(int, case.split(' '))

        directory_hash = dict()

        for done_node in xrange(done_nodes):
            add_directory(directory_hash, stdin.readline().replace('\n',''), True)

        created_directories = 0

        for left_node in xrange(left_nodes):
            created_directories += add_directory(directory_hash, stdin.readline().replace('\n',''), False)

        print 'Case #' + str(ncase + 1) + ': ' +  str(created_directories)
  • All Your Base: A little more complicated problem. The input was an alphanumeric string and the output a mapping each symbol of it to de minimum number, in any base, expresed as a decimal. The minimum base was 2 and the first symbol can’t be 0. The solution was quite simple, map the first symbol to 1, after that, map from left to right each diferent symbol to 0, then 2, then 3 and so on. Finally change the number to base 10.
#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import stdin

if __name__ == "__main__":
    ncases = int(stdin.readline())

    for ncase in xrange(ncases):
        case = stdin.readline()

        mapped_number = 0
        symbol_number = dict()
        symbol_number[case[0]] = 1

        for symbol in case[1:-1]:
            if not symbol_number.has_key(symbol):
                symbol_number[symbol] = mapped_number
                mapped_number = 2 if mapped_number ==  0 else mapped_number + 1

        if mapped_number == 0:
            symbol_number[case[0]] = 1
            case.replace(case[0], '1')
            mapped_number = 2

        to_pow = len(case) - 3
        result_decimal = 1 * pow(mapped_number, to_pow + 1)

        for symbol in case[1:-1]:
            result_decimal += (pow(mapped_number, to_pow) * symbol_number[symbol])
            to_pow -= 1

        print 'Case #' + str(ncase + 1) + ': ' +  str(result_decimal)

Both handled the large inputs and are quite efficient. The teaching here is that before doing any code is important to reason how to solve the problem.
Lets see how i perform in the Code Jam :3.

Big Data, mi opinión y varias cosas cool en Python

Big Data

Ayer revisando mi twitter, me encuentro con lo siguiente:

http://techcrunch.com/2012/10/27/big-data-right-now-five-trendy-open-source-technologies/

Varias de esas tecnología las he escuchado y usado: he usado un poco hadoop mediante pig y otros en el trabajo usan Kafka. Es increíble hacia donde esta yendo el mundo de la computación e información. Ciertamente las metaheurísticas que vi y use para hacer data clustering en mi tesis están en el rumbo correcto. Ya la programación normal no se de abasto. Pensar en paralelización y formas para manejar cantidades gigantes de datos es el futuro. Es la era de la información y hay que saber como explotar y sacar todo lo posible de los datos. Ya veremos como siguen las cosas, mientras a conocer un poco de estas cosas.

Python

En lo que estaba haciendo me vi en la necesidad de hacer request a MySQL, a páginas web, mandar correos, hacer gráficas, entre otras cosas. Todo lo hice mediante Python y ciertos bash para ayudarme.

Request a páginas web

Use lo siguiente: http://docs.python-requests.org/en/latest/. La libreria urllib2 es muy buena y es posible que no halla tenido que usar esta, pero en verdad fue lo que me salió más rápido y conseguí de primero.

Hacer una petición POST es así de tonto:

import requests
    result = request.post(url, params = parametros[, cookies = ....])

Si queremos que sea una petición GET, siemplemente se cambie la palabra. Por ejemplo si queremos atentificarnos en una página y luego sacar información el script sería algo así:

import request

auth_cookies = None
def login():
    request_result = requests.post(url, params = {'username' : usuario, 'password' : clave})
    request_result.raise_for_status()
    global auth_cookies
    auth_cookies = request_result.cookies

def get_information():
    request_result = requests.get(url', params = ..., cookies = auth_cookies)
    request_result.raise_for_status()
    #En request.text esta el resultado, lo parseamos o buscamos lo que necesitamos de acá

if __name__ == "__main__":
    login()
    get_info()
    ....

Así de fácil.

Mandar email

Lo saque de internet y le comenté ciertas cosas que no me agarranon bien:

import os
import smtplib
import mimetypes
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.MIMEAudio import MIMEAudio
from email.MIMEImage import MIMEImage
from email.Encoders import encode_base64
from sys import argv

def sendMail(subject, text, *attachmentFilePaths):
    gmailUser = ''
    gmailPassword = ''
    recipient = ''
    msg = MIMEMultipart()
    msg['From'] = gmailUser
    msg['To'] = recipient
    msg['Subject'] = subject
    msg.attach(MIMEText(text))
    for attachmentFilePath in attachmentFilePaths:
        msg.attach(getAttachment(attachmentFilePath))
        mailServer = smtplib.SMTP('smtp.gmail.com', 587)
        mailServer.ehlo()
        mailServer.starttls()
        mailServer.ehlo()
        mailServer.login(gmailUser, gmailPassword)
        mailServer.sendmail(gmailUser, recipient, msg.as_string())
        mailServer.close()
       print('Email enviado a %s' % recipient)

def getAttachment(attachmentFilePath):
    contentType, encoding = mimetypes.guess_type(attachmentFilePath)
    if contentType is None or encoding is not None:
    contentType = 'application/octet-stream'
    mainType, subType = contentType.split('/', 1)
    file = open(attachmentFilePath, 'rb')
    '''
    if mainType == 'text':
        attachment = MIMEText(file.read())
    elif mainType == 'message':
        attachment = email.message_from_file(file)
    elif mainType == 'image':
        attachment = MIMEImage(file.read(),_subType=subType)
    elif mainType == 'audio':
        attachment = MIMEAudio(file.read(),_subType=subType)
    else:
    '''
    attachment = MIMEBase(mainType, subType)
    attachment.set_payload(file.read())
    encode_base64(attachment)
    file.close()
    attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachmentFilePath))
    return attachment
 

Mandarlo es simplemente completar las variables y usar las funciones como uno desee.

XSRF Django

En la web uno se debe cuidar de tres cosas (y muchas otras, pero de las principales y más comunes para mí) son: inyecciones SQL, XSS y XSRF.

La primera como dice el nombre es simplemente a través de llamadas HTTP ingresar código de SQL (esto puede aplicar a otro tipo de bases de datos No-SQL). La forma más común es a la hora de un formulario por el cual se pasan datos bien sea por POST o GET, colocar valores estílo ‘; comando sql;  por medio del cual se pueden robar valores, dañar la base datos, etc.

Luego tenemos los XSS, siglas de cross-site scripting, lo cual es ingresar código en la página que se ataca. Ejemplo un párametro que se pasa por GET y que se imprime en la página. Con poner en ese parámetro algo estilo < iframe src = “http://paginamaliciosa” > </ iframe >  se logra que otras personas vean lo que uno desee y se puede robar información u otras cosas.

Finalmente tenemos el XSRF, siglas de cross-site request forergy. Éste ataque es más complejo, pero puede hacer mucho daño. Consiste en hacer que un usuario autentificado en una página haga cosas que él no autorizo. Un ejemplo sería el siguiente:

  • Un usuario anda autentificado en X página, la cual hace el cambio de contraseña por POST.
  • Una persona maliciosa simplemente debe recrear ese request de POST y hacer que el usuario lo haga sin darse cuenta.

Yo ya en un post pasado publique un link (http://google-gruyere.appspot.com/) que encontré muy bueno que habla de seguridad de páginas web y que explican de estos ataques y como defenderse.

Hable de todo ésto ya que me topé con lo siguiente:

https://docs.djangoproject.com/en/dev/ref/contrib/csrf/

Cada día me sorprendo más con lo excelente que es este framework, al igual que Python.

De un modo bastante simple previsto por Django se es posible defenderse de éste último tipo de ataque que comente. No soy un experto de en programación web, nunca me ha gustado, pero me pregunto si muchos de los otros frameworks tienen está capacidad.

Fuera del tema, ya empezó el curso de seguridad ofrecido por la universidad de Standford, espero poder dedicarle, ya vi por encima el material que colocaron y se ve full interesante, espero tener el tiempo y las ganas de leerlo, ya veremos!

Python

Hoy decidí escribir sobre Python

Para empezar este lenguaje lo llevo 3 semanas usando en el trabajo y para mi tesis lo use para generar la tablas de Latex de los resultados. Hasta los momentos me ha parecido excelente. Considero que es justamente para una de las cosas que fue creado: scripting. Tiene un sintaxis muy simple y que a su vez lo hace ser bastante entendible, además de tener un montón de librerías con muchas cosas hechas. Ahora cosas resaltantes que decir:

  • Es interpretado y su máquina virtual está escrita en C, en líneas generales es un lenguaje relativamente rápido. Además hay diversas herramientas para mejorar el código bien sea optimizando o compilando a otro lenguaje de bajo nivel el código.
  • Tiene muchas cosas ya hechas
  • No hay chequeo estático de tipos, lo cual es una ventaja y desventaja. Te permite hacer cosas interesantes con el lenguaje, pero hace el código más difícil de mantener
  • Obliga a identar el código, cosa que me parece genial
  • Se pueden escribir cosas bastante complejas con pocas líneas
  • El manejo de memoria es automático
  • Es orientado a objetos
  • Tiene diversas cosas de los lenguajes funcionales para las listas (map, fold)

Ahora comento de mi experiencias:

  1. La primera vez que la use fue para crear un script que leyera una base de datos de sqlite y generara diversos archivos .tex con tablas de Latex. Esto hacerlo en algo estilo C, Java, C++ era muchas líneas de código. En Python me tomó unas 200 líneas. Ya tengo el módulo para conectarme a sqlite, el manejo de strings es muy fácil, del mismo modo lo que uno puede hacer con los arreglos. Simplemente cree ciertos arreglos y una función que se le pasaban diversos valores y extraía lo que quería de la base de datos. A medida que hacía eso simplemente iba concatenando los datos en strings con el formato de la tabla latex y los escribía a un archivo. Super simple.
  2. En el trabajo uso Django y acá uno ve muchas cosas del potencial del lenguaje. Recomiendo mucho este framework para hacer páginas, es muy potente. Al estar tocando el código he podido notar muchas cosas interesantes del lenguaje: se pueden hacer funciones con número de parámetros variable (estilo printf de C), crear listas por comprensión (este nombre lo tome así de como lo nombran en un artículo que ando leyendo que  coloque al final).

En fin échenle un ojo, este lenguaje es muy usado por google (solo conozco su uso en páginas web por parte de ellos),  y recomiendo este artículo que estoy leyendo de como optimizar el código de python, que pienso que a su vez enseña parte de como funciona el lenguaje.

http://wiki.python.org/moin/PythonSpeed/PerformanceTips