<repo_name>Xanewok/WWWWybory<file_sep>/wybory/__init__.py
# http://prezydent2000.pkw.gov.pl/gminy/index.html
# Należy przygotować generator stron HTML, który weźmie wyniki
# (pliki w excelu lub skonwertowane csv) wyborów i przygotuje zestaw stron:

# Wyniki wyborów w całym kraju plus mapka z województwami, na których można klikać
# Wyniki wyborów w każdym z województw plus odnośniki do okręgów
# Wyniki wyborów w każdym okręgu plus odnośniki do gmin
# Wyniki wyborów w każdej gminie w podziale na obwody

# Wymagania dodatkowe

# Powinien być generowany poprawny HTML
# Powinien być generowany porawny CSS
# Strona powinna być responsywna

from jinja2 import Environment, PackageLoader, select_autoescape
from wybory import data  # Read and parse resources/*.xls data
env = Environment(
    loader=PackageLoader('wybory', 'templates'),
    autoescape=select_autoescape(['html', 'xml']),
    trim_blocks=True,
    lstrip_blocks=True,
)<file_sep>/wybory/data.py
import glob
from functools import reduce

import xlrd
from xlrd.timemachine import xrange


class Obwod:
    objects = []

    def __init__(self):
        self.wojewodztwo = ""
        self.wojewodztwo_criteria_id = 0
        self.nr_okregu = 0
        self.kod_gminy = 0
        self.gmina = ""
        self.powiat = ""
        self.nr_obwodu = 0
        self.typ_obwodu = ""
        self.adres = ""
        self.wyniki = [] # size of 12, starting from index 12 (0-indexed)

    def __str__(self):
        return "Wojewodztwo: " + str(self.wojewodztwo_criteria_id) + ", gmina: " + self.gmina

# https://developers.google.com/adwords/api/docs/appendix/geotargeting
# Target Type: Region
# Country Code: PL
# Parent ID: 2616
# Criteria ID, Name
# 20847, Lower Silesian Voivodeship
# 20848, Kuyavian-Pomeranian
# 20849, Lubusz Voivodeship
# 20850, Lodz Voivodeship
# 20851, Lublin Voivodeship
# 20852, Lesser Poland Voivodeship
# 20853, Masovian Voivodeship
# 20854, Opole Voivodeship
# 20855, Podlaskie Voivodeship
# 20856, Podkarpackie Voivodeship
# 20857, Pomeranian Voivodeship
# 20858, Swietokrzyskie
# 20859, Silesian Voivodeship
# 20860, Warmian-Masurian Voivodeship
# 20861, Greater Poland Voivodeship
# 20862, West Pomeranian Voivodeship
def okreg_to_geotarget_criteria_id(num):
    if 1 <= num <= 4:    # województwo DOLNOŚLĄSKIE: 1 Wrocław, 2 <NAME>, 3 Legnica, 4 Wałbrzych
        return 20847
    if 5 <= num <= 7:    # województwo KUJAWSKO-POMORSKIE: 5 Bydgoszcz, 6 Toruń, 7 Włocławek
        return 20848
    if 13 <= num <= 14:  # województwo LUBUSKIE: 13 <NAME>, 14 <NAME>
        return 20849
    if 15 <= num <= 19:  # województwo ŁÓDZKIE: 15 Łodź, 16 Łodź, 17 <NAME>, 18 Sieradz, 19 Skierniewice
        return 20850
    if 8 <= num <= 12:   # województwo LUBELSKIE: 8 Lublin, 9 B<NAME>, 10 Chełm, 11 Puławy, 12 Zamość
        return 20851
    if 20 <= num <= 27:  # województwo MAŁOPOLSKIE: 20 Kraków, 21 Kraków, 22 Kraków, 23 Chrzanów, 24 Myślenice: 25 Nowy Sącz, 26 Nowy Targ, 27 Tarnów
        return 20852
    if 28 <= num <= 36:  # województwo MAZOWIECKIE: 28 Warszawa, 29 Warszawa, 30 Ciechanów, 31 Legionów, 32 Ostrołęka, 33 Piaseczno, 34 Płock, 35 Radom, 36 Siedlce
        return 20853
    if 37 <= num <= 38:  # województwo OPOLSKIE: 37 Opole: 38 Opole
        return 20854
    if 43 <= num <= 45:  # województwo PODLASKIE: 43 Białystok, 44 Łomża, 45 Suwałki
        return 20855
    if 39 <= num <= 42:  # województwo PODKARPACKIE: 39 Rzeszów, 40 Krosno, 41 Przemyśl, 42 Tarnobrzeg
        return 20856
    if 46 <= num <= 48:  # województwo POMORSKIE: 46 Gdańsk, 47 Gdańsk, 48 Słupsk
        return 20857
    if 55 <= num <= 56:  # województwo ŚWIĘTOKRZYSKIE: 55 Kielce: 56 Kielce
        return 20858
    if 49 <= num <= 54:  # województwo ŚLĄSKIE: 49 Katowice: 50 Bielsko-Biała, 51 Bytom, 52 Częstochowa, 53 Gliwice: 54 Sosnowiec
        return 20859
    if 57 <= num <= 59:  # województwo WARMIŃSKO-MAZURSKIE: 57 Olsztyn, 58 Elbląg, 59 Ełk
        return 20860
    if 60 <= num <= 64:  # województwo WIELKOPOLSKIE: 60 Poznań, 61 Kalisz, 62 Konin, 63 Leszno, 64 Piła
        return 20861
    if 65 <= num <= 68:  # województwo ZACHODNIOPOMORSKIE: 65 Szczecin, 66 Koszalin, 67 <NAME>, 68 Szczecinek
        return 20862


def okreg_to_province_name(num):
    if 1  <= num <= 4: return  "Dolnośląskie"
    if 5  <= num <= 7: return  "Kujawsko-pomorskie"
    if 13 <= num <= 14: return "Lubuskie"
    if 15 <= num <= 19: return "Łódzkie"
    if 8  <= num <= 12: return "Lubelskie"
    if 20 <= num <= 27: return "Małopolskie"
    if 28 <= num <= 36: return "Mazowieckie"
    if 37 <= num <= 38: return "Opolskie"
    if 43 <= num <= 45: return "Podlaskie"
    if 39 <= num <= 42: return "Podkarpackie"
    if 46 <= num <= 48: return "Pomorskie"
    if 55 <= num <= 56: return "Świętokrzyskie"
    if 49 <= num <= 54: return "Śląskie"
    if 57 <= num <= 59: return "Warmińsko-mazurskie"
    if 60 <= num <= 64: return "Wielkopolskie"
    if 65 <= num <= 68: return "Zachodniopomorskie"
    return "Nieznane"


def polish_province_ids():
    return list(range(20847, 20863))


def candidate_count():
    return 12


def candidate_name(id):
    if id == 0:
        return "<NAME>"
    if id == 1:
        return "<NAME>"
    if id == 2:
        return "<NAME>"
    if id == 3:
        return "<NAME>"
    if id == 4:
        return "<NAME>"
    if id == 5:
        return "<NAME>"
    if id == 6:
        return "<NAME>"
    if id == 7:
        return "<NAME>"
    if id == 8:
        return "<NAME>"
    if id == 9:
        return "<NAME>"
    if id == 10:
        return "<NAME>"
    if id == 11:
        return "<NAME>"

    return "Candidate name out of bounds"


def empty_result_set():
    results = [];
    for i in range(0, candidate_count()):
        results.append(0)
    return results


def sum_results(results, sum):
    for i in range(0, candidate_count()):
        results[i] += sum[i]
    return results


def calculate_result_set(obwod_obj_list):
    results = reduce(sum_results, map(lambda x: x.wyniki, obwod_obj_list), empty_result_set())
    total_count = int(sum(results))
    if total_count == 0: total_count = 1 # Used only for percentage, if sum is 0, then vote/sum still will be 0
    return map(lambda x: (candidate_name(x), int(results[x]), int(results[x])/total_count), range(0, candidate_count()))


def read_data():
    obw_files = glob.glob('resources/obw*.xls')
    for obw_file in obw_files:
        workbook = xlrd.open_workbook(obw_file)
        worksheet = workbook.sheet_by_index(0)  # Assume only single sheet

        for rownum in xrange(worksheet.nrows):
            if rownum == 0:  # Header
                continue

            obwod = Obwod()
            values = worksheet.row_values(rownum)
            obwod.wojewodztwo = okreg_to_province_name(values[0])
            obwod.wojewodztwo_criteria_id = okreg_to_geotarget_criteria_id(values[0])  # num
            obwod.nr_okregu = int(values[0])  # num
            obwod.kod_gminy = int(values[1])  # num
            obwod.gmina = values[2]
            obwod.powiat = values[3]
            obwod.nr_obwodu = values[4]  # num
            obwod.typ_obwodu = values[5]
            obwod.adres = values[6]
            for i in range(0, candidate_count()): # 12 candidates
                obwod.wyniki.append(values[12 + i])  # num, values are values[12...23]

            Obwod.objects.append(obwod)

read_data()
<file_sep>/wybory/build.py
# generate the page at some point
import os
import errno
import shutil
from collections import OrderedDict

from wybory import env, data
from  more_itertools import unique_everseen

# Wyniki wyborów w całym kraju plus mapka z województwami, na których można klikać
# Wyniki wyborów w każdym z województw plus odnośniki do okręgów
# Wyniki wyborów w każdym okręgu plus odnośniki do gmin
# Wyniki wyborów w każdej gminie w podziale na obwody

def create_navigation(obwod, path_len):
    path = [("Kraj", "kraj.html")]
    if path_len == 1: return path
    path.append( (obwod.wojewodztwo, "woj{0}.html".format(obwod.wojewodztwo_criteria_id)) )
    if path_len == 2: return path
    path.append( ("Okręg {0}".format(obwod.nr_okregu), "okr{0}.html".format(obwod.nr_okregu)) )
    if path_len == 3: return path
    path.append((obwod.gmina, "gm{0}.html".format(obwod.kod_gminy)))

    return path


def build_kraj():
    html_name = "kraj.html"

    for woj_id in data.polish_province_ids():
        build_wojewodztwo(woj_id)

    result_set = list(data.calculate_result_set(data.Obwod.objects))

    template = env.get_template('kraj.html')
    out = template.render(result_set=result_set)
    with open("build/" + html_name, "w+") as f:
        f.write(out)
        f.close()


def build_wojewodztwo(wojewodztwo_id):
    html_name = "woj{0}.html".format(wojewodztwo_id)
    if os.path.isfile("build/" + html_name): # Don't rerender if not needed
        return html_name

    wojewodztwo_list = filter(lambda x: x.wojewodztwo_criteria_id == wojewodztwo_id, data.Obwod.objects)
    children = sorted(list(unique_everseen(wojewodztwo_list, lambda x: x.nr_okregu)), key=lambda x: x.nr_okregu)
    children_links = OrderedDict(map(lambda x: ("Okręg {0}".format(x.nr_okregu), build_okreg(x.nr_okregu)), children))

    wojewodztwo_list = filter(lambda x: x.wojewodztwo_criteria_id == wojewodztwo_id, data.Obwod.objects)
    result_set = list(data.calculate_result_set(wojewodztwo_list))

    next_obwod = next(obj for obj in data.Obwod.objects if obj.wojewodztwo_criteria_id == wojewodztwo_id)
    nav_list = create_navigation(next_obwod, 2)

    template = env.get_template('wojewodztwo.html')
    out = template.render(my_dict=children_links, result_set=result_set, nav=nav_list)
    with open("build/" + html_name, "w+") as f:
        f.write(out)
        f.close()

    return html_name


def build_okreg(nr_okregu):
    html_name = "okr{0}.html".format(nr_okregu)
    if os.path.isfile("build/" + html_name): # Don't rerender if not needed
        return html_name

    okreg_list = filter(lambda x: x.nr_okregu == nr_okregu, data.Obwod.objects)
    children = sorted(list(unique_everseen(okreg_list, lambda x: x.kod_gminy)), key=lambda x: x.gmina)
    children_links = OrderedDict(map(lambda x: (x.gmina, build_gmina(x.kod_gminy)), children))

    okreg_list = filter(lambda x: x.nr_okregu == nr_okregu, data.Obwod.objects)
    result_set = list(data.calculate_result_set(okreg_list))

    next_obwod = next(obj for obj in data.Obwod.objects if obj.nr_okregu == nr_okregu)
    nav_list = create_navigation(next_obwod, 3)

    template = env.get_template('okreg.html')
    out = template.render(my_dict=children_links, result_set=result_set, nav=nav_list)
    with open("build/" + html_name, "w+") as f:
        f.write(out)
        f.close()

    return html_name


def build_gmina(kod_gminy):
    html_name = "gm{0}.html".format(kod_gminy)
    if os.path.isfile("build/" + html_name): # Don't rerender if not needed
        return html_name

    gmina_list = filter(lambda x: x.kod_gminy == kod_gminy, data.Obwod.objects)
    results = OrderedDict(map(lambda x: (x, list(data.calculate_result_set([x]))), gmina_list))

    next_obwod = next(obj for obj in data.Obwod.objects if obj.kod_gminy == kod_gminy)
    nav_list = create_navigation(next_obwod, 4)

    template = env.get_template('gmina.html')
    out = template.render(my_list=gmina_list, result_set=results, nav=nav_list)
    with open("build/" + html_name, "w+") as f:
        f.write(out)
        f.close()

    return html_name


def make_sure_path_exists(path):
    try:
        os.makedirs(path)
    except OSError as exception:
        if exception.errno != errno.EEXIST:
            raise


if __name__ == "__main__":
    shutil.rmtree("build/", ignore_errors=True)
    make_sure_path_exists("build/")
    make_sure_path_exists("build/static/")
    shutil.copyfile("static/style.css", "build/static/style.css")
    shutil.copyfile("static/logo.png", "build/static/logo.png")
    build_kraj()

<file_sep>/wybory/resources/download_data.sh
#!/bin/bash
for i in {1..68}; do wget `echo "http://prezydent2000.pkw.gov.pl/gminy/obwody/obw"$i".xls"`; done
