<commit_before>import os

import PIL

from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw

# this is where the name lists and the icon id file is stored
ICON_DATABASE_FOLDER = "../icon-database"

# this is the subfolder inwhich the debug theme is saved
FINAL_THEME_FOLDER = "../final-themes"

# only these contexts are supported right now
supported_contexts = ["actions",
                      "applications",
                      "categories",
                      "devices",
                      "emblems",
                      "emotes",
                      "mimetypes",
                      "places",
                      "status"]

# this is used to print the context on the icon in a nice way
context_nice_names = {}
context_nice_names["actions"]      = "Actions"
context_nice_names["applications"] = "Applications"
context_nice_names["categories"]   = "Categories"
context_nice_names["devices"]      = "Devices"
context_nice_names["emblems"]      = "Emblems"
context_nice_names["emotes"]       = "Emotes"
context_nice_names["mimetypes"]    = "MimeTypes"
context_nice_names["places"]       = "Places"
context_nice_names["status"]       = "Status"

# this is the name of the subfolder for each supported category
context_folders = {}
context_folders["actions"]      = "actions"
context_folders["applications"] = "apps"
context_folders["categories"]   = "categories"
context_folders["devices"]      = "devices"
context_folders["emblems"]      = "emblems"
context_folders["emotes"]       = "emotes"
context_folders["mimetypes"]    = "mimetypes"
context_folders["places"]       = "places"
context_folders["status"]       = "status"

# for some icon contexts we define some nice abbreviation
context_abbrs = {}
context_abbrs["actions"]      = "AC"
context_abbrs["applications"] = "AP"
context_abbrs["categories"]   = "CA"
context_abbrs["devices"]      = "DE"
context_abbrs["emblems"]      = "EM"
context_abbrs["emotes"]       = "EO"
context_abbrs["mimetypes"]    = "MI"
context_abbrs["places"]       = "PL"
context_abbrs["status"]       = "ST"

# creates a string similar to "16x16/apps"
# this is used several times in the theme file
def generate_subfolder_name(size, name):
    return os.path.join("%dx%d" % (size, size), name) # this is done in this specific way because otherwise KDE will not find some theme icons

# this writes the theme file for all supported contexts and the user defined sizes
def write_theme_ini(output, sizes):
    """this creates an inifile with all paths"""

    # this is the header of the theme file
    ini_header = """[Icon Theme]
                 Name=Debug icons
                 Comment=A theme which can be used for debugging or creating new icon themes
                 """

    #####################
    # write the Directories string to the theme file which contains a comma separated list of all icon subdirectories

    contexts = supported_contexts[:]
    contexts.sort()

    folders_temp = []

    for c in contexts:

        for size in sizes:

            subfolder = generate_subfolder_name(size, context_folders[c])

            folders_temp.append(subfolder)

    folders_as_string = ",".join(folders_temp)

    ini_dir_string = """
                     Directories=%s
                     """ % folders_as_string

    ini_dir_sections = ""
    #####################
    # for each icon subdirectory create an entry to the ini file
    for c in contexts:

        for size in sizes:

            subfolder = generate_subfolder_name(size, context_folders[c])

            ini_dir_sections += """
                                [%s]
                                Size=%d
                                Context=%s
                                Type=Threshold
                                """ % (subfolder, size, context_nice_names[c])

    # these 4 lines remove all trailing whitespace which resulted from the indention above...
    # this is just done that the source file looks nicer...
    file_content = ini_header + ini_dir_string + ini_dir_sections
    file_content = file_content.splitlines()
    file_content = [l.strip() for l in file_content]
    file_content = "\n".join(file_content)

    #####################
    # write the ini text to the theme file

    complete_path = os.path.join(FINAL_THEME_FOLDER, output)
    if not os.path.exists(complete_path):
        os.makedirs(complete_path)

    with open(os.path.join(complete_path, "index.theme"), "w") as f:

        f.write(file_content)

def create_icon(size, iid, context=None, filename=None, bg_color=(255, 255, 255), font_color=(0, 0, 0)):

    if size < 16:
        raise ValueError("'size' must be >= 16!")

    # for some icon contexts we define some nice abbreviation
    context_abbrs = {}
    context_abbrs["actions"]      = "AC"
    context_abbrs["applications"] = "AP"
    context_abbrs["categories"]   = "CA"
    context_abbrs["devices"]      = "DV"
    context_abbrs["emblems"]      = "EB"
    context_abbrs["emotes"]       = "EO"
    context_abbrs["mimetypes"]    = "MI"
    context_abbrs["places"]       = "PL"
    context_abbrs["status"]       = "ST"

    # this is used to print the context on the icon in a nice way
    context_nice_formats = {}
    context_nice_formats["actions"]      = "Actions"
    context_nice_formats["applications"] = "Applications"
    context_nice_formats["categories"]   = "Categories"
    context_nice_formats["devices"]      = "Devices"
    context_nice_formats["emblems"]      = "Emblems"
    context_nice_formats["emotes"]       = "Emotes"
    context_nice_formats["mimetypes"]    = "MimeTypes"
    context_nice_formats["places"]       = "Places"
    context_nice_formats["status"]       = "Status"

    # check if a context is given
    if context is None:
        context      = "Undefined"
        context_abbr = "??"
    # check if the context is "supported" but the above dict...
    else:
        # if it is a supported, then read the abbreviation and make the
        # context name in nice upper/lower case regardless how the input string looks like
        if context_abbrs.has_key(context.lower()):
            context_abbr = context_abbrs[context.lower()]
            context = context_nice_formats[context.lower()]
        # if no supported contest is found then take the first two letters and amke them
        # uppercase
        else:
            context_abbr = context[0:2].upper()

    # turn the icon id into a 6 letter string. this makes it easier later on
    iid = "%-6.6s" % iid

    # create new image and a draw object
    img  = Image.new("RGBA", (size, size), bg_color)
    draw = ImageDraw.Draw(img)

    # this disables antialiasing
    draw.fontmode = "1"

    if (size >= 16) and (size < 22):
        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((1, 1), iid[0:3], font_color)
        draw.text((1, 8), iid[3:], font_color)

    elif (size >= 22) and (size < 24):
        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((4,  0), iid[0:3], font_color)
        draw.text((4,  7), iid[3:], font_color)

        draw.text((1, 22-7), str(size), font_color)
        draw.text((12, 22-7), context_abbr, font_color)

    elif (size >= 24) and (size < 32): # oben links
        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((5,  1), iid[0:3], font_color)
        draw.text((5,  8), iid[3:], font_color)

        draw.text((1, size-7), str(size), font_color)
        draw.text((14, size-7), context_abbr, font_color)

    elif (size >= 32) and (size < 64):
        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((1, 0), iid, font_color)
        draw.text((1, 8), context, font_color)
        draw.text((1, 16), filename, font_color)

        draw.text((1, size-7), str(size), font_color)

        draw.line([size-1, 0, size-1, size-1], bg_color)

    elif size >= 64:

        # this is a larger font which makes it more readable

        # draw.setfont(ImageFont.truetype("fonts/LiberationMono-Regular.ttf", 11))

        # draw.text((1, 0),  iid, font_color)
        # draw.text((1, 11), context, font_color)
        # draw.text((1, 22), filename, font_color)

        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((1, 0), iid, font_color)
        draw.text((1, 8), context, font_color)
        draw.text((1, 16), filename, font_color)

        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((1, size-7), str(size), font_color)

        draw.line([size-1, 0, size-1, size-1], bg_color)

    return img

# this loads the abbreviation file and returns a dict with all valid entries
def load_abbrs():

    abbrs = {}

    temp_unique = []

    with open(os.path.join(ICON_DATABASE_FOLDER, "icon.ids"), "r") as f:

        temp = f.read().splitlines()

        for line in temp:

            # remove comments
            line = line.split("#")[0]

            # split at the "=". if not "=" is present then just read the next line
            t = line.split("=")

            if len(t) != 2:
                continue

            # this part is a bit stupid: alle the line contain an entry like context/iconname
            # while the context should be lower case, the case of the icon name should be preserved

            Context_slash_name    = t[0].strip()
            icon_id               = t[1].strip()

            t = Context_slash_name.split("/")

            if len(t) != 2:
                continue

            Context, name = t

            context_slash_name = Context.lower() + "/" + name # convert context to lowercase but leave icon name

            if icon_id in temp_unique:
                print "warning, the icon id", icon_id, "appears at least to times in icon_ids.txt"

            temp_unique.append(icon_id)

            abbrs[context_slash_name] = icon_id

    return abbrs

def create_theme(base_themes, output, sizes):

    ##############
    # sets some default values
    bg_colors = {}
    bg_colors["actions"]      = (255,   0,   0) # red
    bg_colors["applications"] = (255,   0, 255) # pink
    bg_colors["categories"]   = (  0,   0, 255) # blau
    bg_colors["devices"]      = (  0, 255, 255) # hellblau
    bg_colors["emblems"]      = (255, 255, 255) # white
    bg_colors["emotes"]       = (133, 133, 133) # grau
    bg_colors["mimetypes"]    = (  0, 255,   0) # green
    bg_colors["places"]       = (255, 255,   0) # yellow
    bg_colors["status"]       = (255, 128,   0) # orange

    font_colors = {}
    font_colors["actions"]      = (255, 255, 255) # red
    font_colors["applications"] = (255, 255, 255) # pink
    font_colors["categories"]   = (255, 255, 255) # blau
    font_colors["devices"]      = (  0,   0,   0) # hellblau
    font_colors["emblems"]      = (  0,   0,   0) # white
    font_colors["emotes"]       = (  0,   0,   0) # grau
    font_colors["mimetypes"]    = (  0,   0,   0) # green
    font_colors["places"]       = (  0,   0,   0) # yellow
    font_colors["status"]       = (  0,   0,   0) # orange

    ##############
    # here we load the abbreveation file
    icon_abbrs = load_abbrs()

    write_theme_ini(output, sizes)

    ###
    # load icons
    temp_icons = []

    icons = {}

    # load all icon names from all files and populate a dict which contains a list of
    # all icon names for all supported contexts
    for theme in base_themes:

        with open(os.path.join(ICON_DATABASE_FOLDER, theme + ".txt"), "r") as f:
            lines = f.read().splitlines()

        for line in lines:
            t = line.split("/")

            if len(t) != 2:
                continue

            context = t[0].strip().lower()

            if not context in supported_contexts:
                continue

            n = t[1].strip()

            if len(n) == 0:
                continue

            if not icons.has_key(context):
                icons[context] = []

            if not n in icons[context]: # prevent double entries
                icons[context].append(n)

    icon_list = []

    for c in icons.iterkeys():
        icons[c].sort()

    # now run through all the icons and create
    for current_context in icons.iterkeys():

        print current_context

        # enumerate is used here because thenthe idx can be used as an icon ID
        for idx, name in enumerate(icons[current_context]):

            temp = current_context.lower() + "/" + name.lower()

            # remember: the icon id will be limited to 6 chars inside the icon creation routine
            if icon_abbrs.has_key(temp):
                icon_id = icon_abbrs[temp]
            else:
                icon_id = context_abbrs[current_context] + "%04d" % idx

            for size in sizes:

                icon = create_icon(size, icon_id, context=current_context, filename=name, bg_color=bg_colors[current_context], font_color=font_colors[current_context])

                # save icon
                sub_dir = generate_subfolder_name(size, context_folders[current_context])

                full_path = os.path.join(FINAL_THEME_FOLDER, output, sub_dir)

                if not os.path.exists(full_path):
                    os.makedirs(full_path)

                icon.save(os.path.join(full_path, name + ".png"))

            # this is used for the look up file for icon ids and filenames
            icon_list.append("%-6s = %s/%s" % (icon_id, current_context, name))

    # create the list of all icon ids and the coresponding file names
    icon_list.sort()
    icon_list = "\n".join(icon_list)

    with open(os.path.join(FINAL_THEME_FOLDER, output, "lookup_icons.txt"), "w") as f:
        f.write(icon_list)

##############
##############
# here starts the real program

sizes = [16, 22, 24, 32, 48, 64, 96, 128]
# sizes = [96]

# themes = ["standard_icons", "oxygen", "hicolor", "Moka"]
# themes = ["standard_icons", "oxygen"]
# themes = ["standard_icons"]
# themes = ["Faba", "hicolor_local", "Moka", "oxygen", "standard_icons"]
# themes = ["standard-icons-0.8.90"]

create_theme(base_themes=["standard-icons-0.8.90"], output="debug-icons-standard-0.8.90", sizes=sizes)<commit_msg>added oxygen theme to create program<commit_after>import os

import PIL

from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw

# this is where the name lists and the icon id file is stored
ICON_DATABASE_FOLDER = "../icon-database"

# this is the subfolder inwhich the debug theme is saved
FINAL_THEME_FOLDER = "../final-themes"

# only these contexts are supported right now
supported_contexts = ["actions",
                      "applications",
                      "categories",
                      "devices",
                      "emblems",
                      "emotes",
                      "mimetypes",
                      "places",
                      "status"]

# this is used to print the context on the icon in a nice way
context_nice_names = {}
context_nice_names["actions"]      = "Actions"
context_nice_names["applications"] = "Applications"
context_nice_names["categories"]   = "Categories"
context_nice_names["devices"]      = "Devices"
context_nice_names["emblems"]      = "Emblems"
context_nice_names["emotes"]       = "Emotes"
context_nice_names["mimetypes"]    = "MimeTypes"
context_nice_names["places"]       = "Places"
context_nice_names["status"]       = "Status"

# this is the name of the subfolder for each supported category
context_folders = {}
context_folders["actions"]      = "actions"
context_folders["applications"] = "apps"
context_folders["categories"]   = "categories"
context_folders["devices"]      = "devices"
context_folders["emblems"]      = "emblems"
context_folders["emotes"]       = "emotes"
context_folders["mimetypes"]    = "mimetypes"
context_folders["places"]       = "places"
context_folders["status"]       = "status"

# for some icon contexts we define some nice abbreviation
context_abbrs = {}
context_abbrs["actions"]      = "AC"
context_abbrs["applications"] = "AP"
context_abbrs["categories"]   = "CA"
context_abbrs["devices"]      = "DE"
context_abbrs["emblems"]      = "EM"
context_abbrs["emotes"]       = "EO"
context_abbrs["mimetypes"]    = "MI"
context_abbrs["places"]       = "PL"
context_abbrs["status"]       = "ST"

# creates a string similar to "16x16/apps"
# this is used several times in the theme file
def generate_subfolder_name(size, name):
    return os.path.join("%dx%d" % (size, size), name) # this is done in this specific way because otherwise KDE will not find some theme icons

# this writes the theme file for all supported contexts and the user defined sizes
def write_theme_ini(output, sizes):
    """this creates an inifile with all paths"""

    # this is the header of the theme file
    ini_header = """[Icon Theme]
                 Name=Debug icons
                 Comment=A theme which can be used for debugging or creating new icon themes
                 """

    #####################
    # write the Directories string to the theme file which contains a comma separated list of all icon subdirectories

    contexts = supported_contexts[:]
    contexts.sort()

    folders_temp = []

    for c in contexts:

        for size in sizes:

            subfolder = generate_subfolder_name(size, context_folders[c])

            folders_temp.append(subfolder)

    folders_as_string = ",".join(folders_temp)

    ini_dir_string = """
                     Directories=%s
                     """ % folders_as_string

    ini_dir_sections = ""
    #####################
    # for each icon subdirectory create an entry to the ini file
    for c in contexts:

        for size in sizes:

            subfolder = generate_subfolder_name(size, context_folders[c])

            ini_dir_sections += """
                                [%s]
                                Size=%d
                                Context=%s
                                Type=Threshold
                                """ % (subfolder, size, context_nice_names[c])

    # these 4 lines remove all trailing whitespace which resulted from the indention above...
    # this is just done that the source file looks nicer...
    file_content = ini_header + ini_dir_string + ini_dir_sections
    file_content = file_content.splitlines()
    file_content = [l.strip() for l in file_content]
    file_content = "\n".join(file_content)

    #####################
    # write the ini text to the theme file

    complete_path = os.path.join(FINAL_THEME_FOLDER, output)
    if not os.path.exists(complete_path):
        os.makedirs(complete_path)

    with open(os.path.join(complete_path, "index.theme"), "w") as f:

        f.write(file_content)

def create_icon(size, iid, context=None, filename=None, bg_color=(255, 255, 255), font_color=(0, 0, 0)):

    if size < 16:
        raise ValueError("'size' must be >= 16!")

    # for some icon contexts we define some nice abbreviation
    context_abbrs = {}
    context_abbrs["actions"]      = "AC"
    context_abbrs["applications"] = "AP"
    context_abbrs["categories"]   = "CA"
    context_abbrs["devices"]      = "DV"
    context_abbrs["emblems"]      = "EB"
    context_abbrs["emotes"]       = "EO"
    context_abbrs["mimetypes"]    = "MI"
    context_abbrs["places"]       = "PL"
    context_abbrs["status"]       = "ST"

    # this is used to print the context on the icon in a nice way
    context_nice_formats = {}
    context_nice_formats["actions"]      = "Actions"
    context_nice_formats["applications"] = "Applications"
    context_nice_formats["categories"]   = "Categories"
    context_nice_formats["devices"]      = "Devices"
    context_nice_formats["emblems"]      = "Emblems"
    context_nice_formats["emotes"]       = "Emotes"
    context_nice_formats["mimetypes"]    = "MimeTypes"
    context_nice_formats["places"]       = "Places"
    context_nice_formats["status"]       = "Status"

    # check if a context is given
    if context is None:
        context      = "Undefined"
        context_abbr = "??"
    # check if the context is "supported" but the above dict...
    else:
        # if it is a supported, then read the abbreviation and make the
        # context name in nice upper/lower case regardless how the input string looks like
        if context_abbrs.has_key(context.lower()):
            context_abbr = context_abbrs[context.lower()]
            context = context_nice_formats[context.lower()]
        # if no supported contest is found then take the first two letters and amke them
        # uppercase
        else:
            context_abbr = context[0:2].upper()

    # turn the icon id into a 6 letter string. this makes it easier later on
    iid = "%-6.6s" % iid

    # create new image and a draw object
    img  = Image.new("RGBA", (size, size), bg_color)
    draw = ImageDraw.Draw(img)

    # this disables antialiasing
    draw.fontmode = "1"

    if (size >= 16) and (size < 22):
        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((1, 1), iid[0:3], font_color)
        draw.text((1, 8), iid[3:], font_color)

    elif (size >= 22) and (size < 24):
        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((4,  0), iid[0:3], font_color)
        draw.text((4,  7), iid[3:], font_color)

        draw.text((1, 22-7), str(size), font_color)
        draw.text((12, 22-7), context_abbr, font_color)

    elif (size >= 24) and (size < 32): # oben links
        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((5,  1), iid[0:3], font_color)
        draw.text((5,  8), iid[3:], font_color)

        draw.text((1, size-7), str(size), font_color)
        draw.text((14, size-7), context_abbr, font_color)

    elif (size >= 32) and (size < 64):
        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((1, 0), iid, font_color)
        draw.text((1, 8), context, font_color)
        draw.text((1, 16), filename, font_color)

        draw.text((1, size-7), str(size), font_color)

        draw.line([size-1, 0, size-1, size-1], bg_color)

    elif size >= 64:

        # this is a larger font which makes it more readable

        # draw.setfont(ImageFont.truetype("fonts/LiberationMono-Regular.ttf", 11))

        # draw.text((1, 0),  iid, font_color)
        # draw.text((1, 11), context, font_color)
        # draw.text((1, 22), filename, font_color)

        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((1, 0), iid, font_color)
        draw.text((1, 8), context, font_color)
        draw.text((1, 16), filename, font_color)

        draw.setfont(ImageFont.truetype("fonts/04B_03.ttf", 8))

        draw.text((1, size-7), str(size), font_color)

        draw.line([size-1, 0, size-1, size-1], bg_color)

    return img

# this loads the abbreviation file and returns a dict with all valid entries
def load_abbrs():

    abbrs = {}

    temp_unique = []

    with open(os.path.join(ICON_DATABASE_FOLDER, "icon.ids"), "r") as f:

        temp = f.read().splitlines()

        for line in temp:

            # remove comments
            line = line.split("#")[0]

            # split at the "=". if not "=" is present then just read the next line
            t = line.split("=")

            if len(t) != 2:
                continue

            # this part is a bit stupid: alle the line contain an entry like context/iconname
            # while the context should be lower case, the case of the icon name should be preserved

            Context_slash_name    = t[0].strip()
            icon_id               = t[1].strip()

            t = Context_slash_name.split("/")

            if len(t) != 2:
                continue

            Context, name = t

            context_slash_name = Context.lower() + "/" + name # convert context to lowercase but leave icon name

            if icon_id in temp_unique:
                print "warning, the icon id", icon_id, "appears at least to times in icon_ids.txt"

            temp_unique.append(icon_id)

            abbrs[context_slash_name] = icon_id

    return abbrs

def create_theme(base_themes, output, sizes):

    ##############
    # sets some default values
    bg_colors = {}
    bg_colors["actions"]      = (255,   0,   0) # red
    bg_colors["applications"] = (255,   0, 255) # pink
    bg_colors["categories"]   = (  0,   0, 255) # blau
    bg_colors["devices"]      = (  0, 255, 255) # hellblau
    bg_colors["emblems"]      = (255, 255, 255) # white
    bg_colors["emotes"]       = (133, 133, 133) # grau
    bg_colors["mimetypes"]    = (  0, 255,   0) # green
    bg_colors["places"]       = (255, 255,   0) # yellow
    bg_colors["status"]       = (255, 128,   0) # orange

    font_colors = {}
    font_colors["actions"]      = (255, 255, 255) # red
    font_colors["applications"] = (255, 255, 255) # pink
    font_colors["categories"]   = (255, 255, 255) # blau
    font_colors["devices"]      = (  0,   0,   0) # hellblau
    font_colors["emblems"]      = (  0,   0,   0) # white
    font_colors["emotes"]       = (  0,   0,   0) # grau
    font_colors["mimetypes"]    = (  0,   0,   0) # green
    font_colors["places"]       = (  0,   0,   0) # yellow
    font_colors["status"]       = (  0,   0,   0) # orange

    ##############
    # here we load the abbreveation file
    icon_abbrs = load_abbrs()

    write_theme_ini(output, sizes)

    ###
    # load icons
    temp_icons = []

    icons = {}

    # load all icon names from all files and populate a dict which contains a list of
    # all icon names for all supported contexts
    for theme in base_themes:

        with open(os.path.join(ICON_DATABASE_FOLDER, theme + ".txt"), "r") as f:
            lines = f.read().splitlines()

        for line in lines:
            t = line.split("/")

            if len(t) != 2:
                continue

            context = t[0].strip().lower()

            if not context in supported_contexts:
                continue

            n = t[1].strip()

            if len(n) == 0:
                continue

            if not icons.has_key(context):
                icons[context] = []

            if not n in icons[context]: # prevent double entries
                icons[context].append(n)

    icon_list = []

    for c in icons.iterkeys():
        icons[c].sort()

    # now run through all the icons and create
    for current_context in icons.iterkeys():

        print current_context

        # enumerate is used here because thenthe idx can be used as an icon ID
        for idx, name in enumerate(icons[current_context]):

            temp = current_context.lower() + "/" + name.lower()

            # remember: the icon id will be limited to 6 chars inside the icon creation routine
            if icon_abbrs.has_key(temp):
                icon_id = icon_abbrs[temp]
            else:
                icon_id = context_abbrs[current_context] + "%04d" % idx

            for size in sizes:

                icon = create_icon(size, icon_id, context=current_context, filename=name, bg_color=bg_colors[current_context], font_color=font_colors[current_context])

                # save icon
                sub_dir = generate_subfolder_name(size, context_folders[current_context])

                full_path = os.path.join(FINAL_THEME_FOLDER, output, sub_dir)

                if not os.path.exists(full_path):
                    os.makedirs(full_path)

                icon.save(os.path.join(full_path, name + ".png"))

            # this is used for the look up file for icon ids and filenames
            icon_list.append("%-6s = %s/%s" % (icon_id, current_context, name))

    # create the list of all icon ids and the coresponding file names
    icon_list.sort()
    icon_list = "\n".join(icon_list)

    with open(os.path.join(FINAL_THEME_FOLDER, output, "lookup_icons.txt"), "w") as f:
        f.write(icon_list)

##############
##############
# here starts the real program

sizes = [16, 22, 24, 32, 48, 64, 96, 128]

create_theme(base_themes=["standard-icons-0.8.90"], output="debug-icons-standard-0.8.90", sizes=sizes)
create_theme(base_themes=["Oxygen-4"], output="debug-icons-oxygen-4", sizes=sizes)<|endoftext|>


<commit_before>import shutil
import urllib
import os
from fabric.api import env, run, put, cd, get, local
from cloudinitd.statics import *

def _iftar(filename):
    """Return base filename if filename ends with .tar.gz (and does not simply equal that suffix)
    Otherwise return None
    """
    if not filename:
        return None
    idx = filename.rfind('.tar.gz')
    if idx > 0:
        return filename[:idx]
    else:
        return None

def _tartask(directory, basename, tarball, run_pgm=run):
    """Expand the tarball, ensure it contains a directory with the basename.
    Ensure run.sh exists inside.
    Return path to the run.sh file.
    """
    with cd(directory):
        run_pgm("tar -xvzf %s" % tarball)
    tardir = os.path.join(directory, basename)
    try:
        run_pgm("test -d %s" % tardir)
    except:
        raise Exception("The tarball does not expand to a directory of the same name: %s" % tardir)
    destpgm = os.path.join(tardir, "run.sh")
    try:
        run_pgm("test -f %s" % destpgm)
    except:
        raise Exception("The tarball does contain a 'run.sh' file: %s" % tarball)

    # In case they forgot:
    run_pgm("chmod +x %s" % destpgm)

    return destpgm

def _make_ssh(pgm, args="", local_exe=None):

    if local_exe:
        cmd = "%s %s" % (pgm, args)
        return cmd

    ssh_opts = "-A -n -T -o BatchMode=yes -o StrictHostKeyChecking=no -o PasswordAuthentication=no"
    try:
        if 'CLOUDINITD_SSH_OPTS' in os.environ:
            ssh_opts = os.environ['CLOUDINITD_SSH_OPTS']
    except:
        pass

    sshexec = "ssh"
    try:
        if os.environ['CLOUDINITD_SSH']:
            sshexec = os.environ['CLOUDINITD_SSH']
    except:
        pass

    args = urllib.unquote(args)
    user = ""
    if env.user:
        user = env.user + '@'
    port = ""
    if env.port:
        port = "-p " + env.port
    key = ""
    if env.key_filename and env.key_filename[0]:
        key = "-i " + env.key_filename[0]

    cmd = "%s %s %s %s %s%s '%s %s'" % (sshexec, port, ssh_opts, key, user, env.host, pgm, args)

    return cmd

def readypgm(pgm=None, args=None, stagedir=None, local_exe=None):
    local_exe = str(local_exe).lower() == 'true'
    pgm_to_use = run
    put_pgm = put
    if local_exe:
        pgm_to_use = local
        put_pgm = shutil.copy

    args = urllib.unquote(args)
    env.warn_only = True
    pgm_to_use('mkdir -p %s' % stagedir)
    relpgm = os.path.basename(pgm)
    destpgm = "%s/%s" % (stagedir, relpgm)

    if local_exe:
        put_pgm(pgm, destpgm)
        os.chmod(destpgm, 0755)
        os.chdir(stagedir)
    else:
        put_pgm(pgm, destpgm, mode=0755)

    tarname = _iftar(relpgm)
    if tarname:
         destpgm = _tartask(stagedir, tarname, destpgm)
    env.warn_only = False
    destpgm = destpgm + " " + args
    with cd(stagedir):
        pgm_to_use(destpgm)

def cleanup_dirs(stagedir=None, local_exe=None):
    cmd = _make_ssh("rm -rf %s" %(stagedir), local_exe=local_exe)
    local(cmd)

def bootpgm(pgm=None, args=None, conf=None, env_conf=None, output=None, stagedir=None, remotedir=None, local_exe=None):
    local_exe = str(local_exe).lower() == 'true'
    pgm_to_use = run
    put_pgm = put
    if local_exe:
        pgm_to_use = local
        put_pgm = shutil.copy

    args = urllib.unquote(args)
    pgm_to_use('mkdir %s;chmod 777 %s' % (remotedir, remotedir))
    pgm_to_use('mkdir -p %s' % stagedir)
    relpgm = os.path.basename(pgm)
    destpgm = "%s/%s" % (stagedir, relpgm)
    if local_exe:
        put_pgm(pgm, destpgm)
        os.chmod(destpgm, 0755)
    else:
        put_pgm(pgm, destpgm, mode=0755)
    tarname = _iftar(relpgm)
    if tarname:
        destpgm = _tartask(stagedir, tarname, destpgm, run_pgm=pgm_to_use)
    if conf and conf != "None":
        destconf = "%s/bootconf.json" % stagedir
        put_pgm(conf, destconf)
    if env_conf and env_conf != "None":
        destenv = "%s/bootenv.sh" % stagedir
        put_pgm(env_conf, destenv)
    destpgm = destpgm + " " + args

    local_cmd = _make_ssh("cd %s;%s" %(stagedir, destpgm), local_exe=local_exe)
    if local_cmd:
        local(local_cmd)

    with cd(stagedir):
        #run(destpgm)
        try:
            fetch_conf(output=output, stagedir=stagedir, local_exe=local_exe)
        except:
            pass

def fetch_conf(output=None, stagedir=None, local_exe=None):
    remote_output = "%s/bootout.json" % (stagedir)

    if local_exe:
        shutil.copy(remote_output, output)
    else:
        get(remote_output, output)
<commit_msg>make sure the local directory is set before untarring the file<commit_after>import shutil
import urllib
import os
from fabric.api import env, run, put, cd, get, local
from cloudinitd.statics import *

def _iftar(filename):
    """Return base filename if filename ends with .tar.gz (and does not simply equal that suffix)
    Otherwise return None
    """
    if not filename:
        return None
    idx = filename.rfind('.tar.gz')
    if idx > 0:
        return filename[:idx]
    else:
        return None

def _tartask(directory, basename, tarball, run_pgm=run):
    """Expand the tarball, ensure it contains a directory with the basename.
    Ensure run.sh exists inside.
    Return path to the run.sh file.
    """
    with cd(directory):
        run_pgm("tar -xvzf %s" % tarball)
    tardir = os.path.join(directory, basename)
    try:
        run_pgm("test -d %s" % tardir)
    except:
        raise Exception("The tarball does not expand to a directory of the same name: %s" % tardir)
    destpgm = os.path.join(tardir, "run.sh")
    try:
        run_pgm("test -f %s" % destpgm)
    except:
        raise Exception("The tarball does contain a 'run.sh' file: %s" % tarball)

    # In case they forgot:
    run_pgm("chmod +x %s" % destpgm)

    return destpgm

def _make_ssh(pgm, args="", local_exe=None):

    if local_exe:
        cmd = "%s %s" % (pgm, args)
        return cmd

    ssh_opts = "-A -n -T -o BatchMode=yes -o StrictHostKeyChecking=no -o PasswordAuthentication=no"
    try:
        if 'CLOUDINITD_SSH_OPTS' in os.environ:
            ssh_opts = os.environ['CLOUDINITD_SSH_OPTS']
    except:
        pass

    sshexec = "ssh"
    try:
        if os.environ['CLOUDINITD_SSH']:
            sshexec = os.environ['CLOUDINITD_SSH']
    except:
        pass

    args = urllib.unquote(args)
    user = ""
    if env.user:
        user = env.user + '@'
    port = ""
    if env.port:
        port = "-p " + env.port
    key = ""
    if env.key_filename and env.key_filename[0]:
        key = "-i " + env.key_filename[0]

    cmd = "%s %s %s %s %s%s '%s %s'" % (sshexec, port, ssh_opts, key, user, env.host, pgm, args)

    return cmd

def readypgm(pgm=None, args=None, stagedir=None, local_exe=None):
    local_exe = str(local_exe).lower() == 'true'
    pgm_to_use = run
    put_pgm = put
    if local_exe:
        os.chdir(stagedir)
        pgm_to_use = local
        put_pgm = shutil.copy

    args = urllib.unquote(args)
    env.warn_only = True
    pgm_to_use('mkdir -p %s' % stagedir)
    relpgm = os.path.basename(pgm)
    destpgm = "%s/%s" % (stagedir, relpgm)

    if local_exe:
        put_pgm(pgm, destpgm)
        os.chmod(destpgm, 0755)
    else:
        put_pgm(pgm, destpgm, mode=0755)

    tarname = _iftar(relpgm)
    if tarname:
         destpgm = _tartask(stagedir, tarname, destpgm)
    env.warn_only = False
    destpgm = destpgm + " " + args
    with cd(stagedir):
        pgm_to_use(destpgm)

def cleanup_dirs(stagedir=None, local_exe=None):
    cmd = _make_ssh("rm -rf %s" %(stagedir), local_exe=local_exe)
    local(cmd)

def bootpgm(pgm=None, args=None, conf=None, env_conf=None, output=None, stagedir=None, remotedir=None, local_exe=None):
    local_exe = str(local_exe).lower() == 'true'
    pgm_to_use = run
    put_pgm = put
    if local_exe:
        pgm_to_use = local
        put_pgm = shutil.copy
        os.chdir(stagedir)

    args = urllib.unquote(args)
    pgm_to_use('mkdir %s;chmod 777 %s' % (remotedir, remotedir))
    pgm_to_use('mkdir -p %s' % stagedir)
    relpgm = os.path.basename(pgm)
    destpgm = "%s/%s" % (stagedir, relpgm)
    if local_exe:
        put_pgm(pgm, destpgm)
        os.chmod(destpgm, 0755)
    else:
        put_pgm(pgm, destpgm, mode=0755)
    tarname = _iftar(relpgm)
    if tarname:
        destpgm = _tartask(stagedir, tarname, destpgm, run_pgm=pgm_to_use)
    if conf and conf != "None":
        destconf = "%s/bootconf.json" % stagedir
        put_pgm(conf, destconf)
    if env_conf and env_conf != "None":
        destenv = "%s/bootenv.sh" % stagedir
        put_pgm(env_conf, destenv)
    destpgm = destpgm + " " + args

    local_cmd = _make_ssh("cd %s;%s" %(stagedir, destpgm), local_exe=local_exe)
    if local_cmd:
        local(local_cmd)

    with cd(stagedir):
        #run(destpgm)
        try:
            fetch_conf(output=output, stagedir=stagedir, local_exe=local_exe)
        except:
            pass

def fetch_conf(output=None, stagedir=None, local_exe=None):
    remote_output = "%s/bootout.json" % (stagedir)

    if local_exe:
        shutil.copy(remote_output, output)
    else:
        get(remote_output, output)
<|endoftext|>


<commit_before>#!/bin/python

from __future__ import print_function
import argparse
import sys
import time

parser = argparse.ArgumentParser(description="Filters phased genotypes with genotype probability lower than the threshold provided. It also replaces triallelic genotypes with ./. ")

#example usage
#python filter_vcf_GP.py -i chr1.1.out.vcf -o test.out -t 0.90

#add options to argparser
parser.add_argument('-i', action="store", dest="vcf_input", type=str)
parser.add_argument('-o', action="store", dest="vcf_output", type=str)
parser.add_argument('-t', action="store", dest="genotype_probability_threshold", type=float)

#test parameters
try:
    options=parser.parse_args()
except:
    parser.print_help()
    sys.exit(0)

vcf_input=options.vcf_input
vcf_output=options.vcf_output
threshold=options.genotype_probability_threshold
outfile=open(vcf_output,'w')

def genotype_prob_parser(snp, threshold):
	"""
	Filters genotypes with genotype probability lower than the threshold provided.
	"""
	changed_snps=0
	snps2=0
	empty_individual_snp="./."
	new_snp=[]
	for individual_snp in snp:
		#is it a phased genotype?
		if "|" not in individual_snp:
			new_snp.append(individual_snp)
		#if it is a phased genotype
		#if homoz reference
		elif (individual_snp.split(":")[0].startswith("0|0")):
			if (float(individual_snp.split(":")[2].split(",")[0]))>= threshold:
				new_snp.append(individual_snp)
			else:
				new_snp.append(empty_individual_snp)
				changed_snps += 1
		#if heterozygous
		elif (individual_snp.split(":")[0].startswith("0|1")):
			if (float(individual_snp.split(":")[2].split(",")[1]))>= threshold:
				new_snp.append(individual_snp)
			else:
				new_snp.append(empty_individual_snp)
				changed_snps += 1
		#if heterozygous
		elif (individual_snp.split(":")[0].startswith("1|0")):
			if (float(individual_snp.split(":")[2].split(",")[1]))>= threshold:
				new_snp.append(individual_snp)
			else:
				new_snp.append(empty_individual_snp)
				changed_snps += 1
		#if homoz alternative allele
		elif (individual_snp.split(":")[0].startswith("1|1")):
			if (float(individual_snp.split(":")[2].split(",")[2]))>= threshold:
				new_snp.append(individual_snp)
			else:
				new_snp.append(empty_individual_snp)
				changed_snps += 1
		#exclude triallelic snps2
		else:
			new_snp.append(empty_individual_snp)
	return(new_snp)

start = time.time()

#iterate through each line
counter=0
initial_vcf=[]
header=[]
with open(vcf_input,'r') as f:
	for line in f:
		#get header lines
		if line.startswith('#'):
			headline=line.strip('\n').split("\t")
			header.append(headline)
			outfile.write('\t'.join(headline) + '\n')
		else:
			counter += 1
			#process snp lines with the genotype_prob_parser function
			snp=line.strip('\n').split("\t")
			outfile.write('\t'.join(genotype_prob_parser(snp,threshold)) + '\n')
			sys.stdout.write("SNPs processed: %d   \r" % (counter) )
			sys.stdout.flush()

outfile.close()

end = time.time()
elapsed = end - start

print("\n" + str(round(elapsed,2)) + " sec.")
<commit_msg>added usage<commit_after>#!/bin/python
#
# Rui Martiniano 12/2015
#
# usage:
# filter_vcf_GP.py [-h] [-i VCF_INPUT] [-o VCF_OUTPUT] [-t GENOTYPE_PROBABILITY_THRESHOLD]
# #example usage
# python filter_vcf_GP.py -i chr1.1.out.vcf -o test.out -t 0.90

from __future__ import print_function
import argparse
import sys
import time

parser = argparse.ArgumentParser(description="Filters phased genotypes with genotype probability lower than the threshold provided. It also replaces triallelic genotypes with ./. ")

#add options to argparser
parser.add_argument('-i', action="store", dest="vcf_input", type=str)
parser.add_argument('-o', action="store", dest="vcf_output", type=str)
parser.add_argument('-t', action="store", dest="genotype_probability_threshold", type=float)

#test parameters
try:
    options=parser.parse_args()
except:
    parser.print_help()
    sys.exit(0)

vcf_input=options.vcf_input
vcf_output=options.vcf_output
threshold=options.genotype_probability_threshold
outfile=open(vcf_output,'w')

def genotype_prob_parser(snp, threshold):
	"""
	Filters genotypes with genotype probability lower than the threshold provided.
	"""
	changed_snps=0
	snps2=0
	empty_individual_snp="./."
	new_snp=[]
	for individual_snp in snp:
		#is it a phased genotype?
		if "|" not in individual_snp:
			new_snp.append(individual_snp)
		#if it is a phased genotype
		#if homoz reference
		elif (individual_snp.split(":")[0].startswith("0|0")):
			if (float(individual_snp.split(":")[2].split(",")[0]))>= threshold:
				new_snp.append(individual_snp)
			else:
				new_snp.append(empty_individual_snp)
				changed_snps += 1
		#if heterozygous
		elif (individual_snp.split(":")[0].startswith("0|1")):
			if (float(individual_snp.split(":")[2].split(",")[1]))>= threshold:
				new_snp.append(individual_snp)
			else:
				new_snp.append(empty_individual_snp)
				changed_snps += 1
		#if heterozygous
		elif (individual_snp.split(":")[0].startswith("1|0")):
			if (float(individual_snp.split(":")[2].split(",")[1]))>= threshold:
				new_snp.append(individual_snp)
			else:
				new_snp.append(empty_individual_snp)
				changed_snps += 1
		#if homoz alternative allele
		elif (individual_snp.split(":")[0].startswith("1|1")):
			if (float(individual_snp.split(":")[2].split(",")[2]))>= threshold:
				new_snp.append(individual_snp)
			else:
				new_snp.append(empty_individual_snp)
				changed_snps += 1
		#exclude triallelic snps2
		else:
			new_snp.append(empty_individual_snp)
	return(new_snp)

start = time.time()

#iterate through each line
counter=0
initial_vcf=[]
header=[]
with open(vcf_input,'r') as f:
	for line in f:
		#get header lines
		if line.startswith('#'):
			headline=line.strip('\n').split("\t")
			header.append(headline)
			outfile.write('\t'.join(headline) + '\n')
		else:
			counter += 1
			#process snp lines with the genotype_prob_parser function
			snp=line.strip('\n').split("\t")
			outfile.write('\t'.join(genotype_prob_parser(snp,threshold)) + '\n')
			sys.stdout.write("SNPs processed: %d   \r" % (counter) )
			sys.stdout.flush()

outfile.close()

end = time.time()
elapsed = end - start

print("\n" + str(round(elapsed,2)) + " sec.")
<|endoftext|>


<commit_before>""" Pandas extension for chemical analysis """
from __future__ import absolute_import
from collections import deque
from six import BytesIO
import pandas as pd

import oddt

pd.set_option("display.max_colwidth", 999999)
image_backend = 'png'  # png or svg

def _mol_reader(fmt='sdf',
                filepath_or_buffer=None,
                usecols=None,
                molecule_column='mol',
                molecule_name_column='mol_name',
                smiles_column=None,
                skip_bad_mols=False,
                chunksize=None,
                **kwargs):
    """Universal reading function for private use.

    .. versionadded:: 0.3

    Parameters
    ----------
        fmt : string
            The format of molecular file

        filepath_or_buffer : string or None
            File path

        usecols : list or None, optional (default=None)
            A list of columns to read from file. If None then all available
            fields are read.

        molecule_column : string or None, optional (default='mol')
            Name of molecule column. If None the molecules will be skipped and
            the reading will be speed up significantly.

        molecule_name_column : string or None, optional (default='mol_name')
            Column name which will contain molecules' title/name. Column is
            skipped when set to None.

        smiles_column  : string or None, optional (default=None)
            Column name containg molecules' SMILES, by default it is disabled.

        skip_bad_mols : bool, optional (default=False)
            Switch to skip empty (bad) molecules. Useful for RDKit, which Returns
            None if molecule can not sanitize.

        chunksize : int or None, optional (default=None)
            Size of chunk to return. If set to None whole set is returned.

    Returns
    -------
        chunk :
            A `ChemDataFrame` containg `chunksize` molecules.

    """
    # capture options for reader
    reader_kwargs = {}
    if 'opt' in kwargs:
        reader_kwargs['opt'] = kwargs.pop('opt')
    if 'sanitize' in kwargs:
        reader_kwargs['sanitize'] = kwargs.pop('sanitize')

    # when you dont read molecules you can skip parsing them
    if molecule_column is None:
        if oddt.toolkit.backend == 'ob' and fmt == 'sdf':
            if 'opt' in reader_kwargs:
                reader_kwargs['opt']['P'] = None
            else:
                reader_kwargs['opt'] = {'P': None}
        elif oddt.toolkit.backend == 'rdk':
            reader_kwargs['sanitize'] = False

    chunk = []
    for n, mol in enumerate(oddt.toolkit.readfile(fmt, filepath_or_buffer, **reader_kwargs)):
        if skip_bad_mols and mol is None:
            continue  # add warning with number of skipped molecules
        if usecols is None:
            mol_data = mol.data.to_dict()
        else:
            mol_data = dict((k, mol.data[k]) for k in usecols)

        if molecule_column:
            mol_data[molecule_column] = mol
        if molecule_name_column:
            mol_data[molecule_name_column] = mol.title
        if smiles_column:
            mol_data[smiles_column] = mol.write('smi').split()[0]
        chunk.append(mol_data)
        if chunksize and (n + 1) % chunksize == 0:
            yield ChemDataFrame(chunk, **kwargs)
            chunk = []
    if chunk or chunksize is None:
        yield ChemDataFrame(chunk, **kwargs)

def _mol_writer(dataframe,
                fmt='sdf',
                filepath_or_buffer=None,
                update_properties=True,
                molecule_column='mol',
                columns=None):
    out = oddt.toolkit.Outputfile(fmt, filepath_or_buffer, overwrite=True)
    for ix, row in dataframe.iterrows():
        mol = row[molecule_column].clone
        if update_properties:
            new_data = row.to_dict()
            del new_data[molecule_column]
            mol.data.update(new_data)
        if columns:
            for k in mol.data.keys():
                if k not in columns:
                    del mol.data[k]
        out.write(mol)
    out.close()

def read_sdf(filepath_or_buffer=None,
             usecols=None,
             molecule_column='mol',
             molecule_name_column='mol_name',
             smiles_column=None,
             skip_bad_mols=False,
             chunksize=None,
             **kwargs):
    """Read SDF/MDL multi molecular file to ChemDataFrame

    .. versionadded:: 0.3

    Parameters
    ----------
        filepath_or_buffer : string or None
            File path

        usecols : list or None, optional (default=None)
            A list of columns to read from file. If None then all available
            fields are read.

        molecule_column : string or None, optional (default='mol')
            Name of molecule column. If None the molecules will be skipped and
            the reading will be speed up significantly.

        molecule_name_column : string or None, optional (default='mol_name')
            Column name which will contain molecules' title/name. Column is
            skipped when set to None.

        smiles_column  : string or None, optional (default=None)
            Column name containg molecules' SMILES, by default it is disabled.

        skip_bad_mols : bool, optional (default=False)
            Switch to skip empty (bad) molecules. Useful for RDKit, which Returns
            None if molecule can not sanitize.

        chunksize : int or None, optional (default=None)
            Size of chunk to return. If set to None whole set is returned.

    Returns
    -------
        result :
            A `ChemDataFrame` containg all molecules if `chunksize` is None
            or genrerator of `ChemDataFrame` with `chunksize` molecules.

    """
    result = _mol_reader(fmt='sdf',
                         filepath_or_buffer=filepath_or_buffer,
                         usecols=usecols,
                         molecule_column=molecule_column,
                         molecule_name_column=molecule_name_column,
                         smiles_column=smiles_column,
                         skip_bad_mols=skip_bad_mols,
                         chunksize=chunksize,
                         **kwargs)
    if chunksize:
        return result
    else:
        return deque(result, maxlen=1).pop()

def read_mol2(filepath_or_buffer=None,
              usecols=None,
              molecule_column='mol',
              molecule_name_column='mol_name',
              smiles_column=None,
              skip_bad_mols=False,
              chunksize=None,
              **kwargs):
    """Read Mol2 multi molecular file to ChemDataFrame. UCSF Dock 6 comments
    style is supported, i.e. `#### var_name: value` before molecular block.

    .. versionadded:: 0.3

    Parameters
    ----------
        filepath_or_buffer : string or None
            File path

        usecols : list or None, optional (default=None)
            A list of columns to read from file. If None then all available
            fields are read.

        molecule_column : string or None, optional (default='mol')
            Name of molecule column. If None the molecules will be skipped and
            the reading will be speed up significantly.

        molecule_name_column : string or None, optional (default='mol_name')
            Column name which will contain molecules' title/name. Column is
            skipped when set to None.

        smiles_column  : string or None, optional (default=None)
            Column name containg molecules' SMILES, by default it is disabled.

        skip_bad_mols : bool, optional (default=False)
            Switch to skip empty (bad) molecules. Useful for RDKit, which Returns
            None if molecule can not sanitize.

        chunksize : int or None, optional (default=None)
            Size of chunk to return. If set to None whole set is returned.

    Returns
    -------
        result :
            A `ChemDataFrame` containg all molecules if `chunksize` is None
            or genrerator of `ChemDataFrame` with `chunksize` molecules.

    """
    result = _mol_reader(fmt='mol2',
                         filepath_or_buffer=filepath_or_buffer,
                         usecols=usecols,
                         molecule_column=molecule_column,
                         molecule_name_column=molecule_name_column,
                         smiles_column=smiles_column,
                         skip_bad_mols=skip_bad_mols,
                         chunksize=chunksize,
                         **kwargs)
    if chunksize:
        return result
    else:
        return deque(result, maxlen=1).pop()

class ChemSeries(pd.Series):
    """Pandas Series modified to adapt `oddt.toolkit.Molecule` objects and apply
    molecular methods easily.
    """

    @property
    def _constructor(self):
        """ Force new class to be usead as constructor """
        return ChemSeries

    @property
    def _constructor_expanddim(self):
        """ Force new class to be usead as constructor when expandig dims """
        return ChemDataFrame

class ChemDataFrame(pd.DataFrame):
    """Chemical DataFrame object, which contains molecules column of
    `oddt.toolkit.Molecule` objects. Rich display of moleucles (2D) is available
    in iPython Notebook. Additional `to_sdf` and `to_mol2` methods make writing
    to molecular formats easy.

    Note:
    Thanks to: http://blog.snapdragon.cc/2015/05/05/subclass-pandas-dataframe-to-save-custom-attributes/
    """

    def to_sdf(self,
               filepath_or_buffer=None,
               update_properties=True,
               molecule_column='mol',
               columns=None):
        _mol_writer(self,
                    fmt='sdf',
                    filepath_or_buffer=filepath_or_buffer,
                    update_properties=update_properties,
                    molecule_column=molecule_column,
                    columns=columns)

    def to_mol2(self,
                filepath_or_buffer=None,
                update_properties=True,
                molecule_column='mol',
                columns=None):
        _mol_writer(self,
                    fmt='mol2',
                    filepath_or_buffer=filepath_or_buffer,
                    update_properties=update_properties,
                    molecule_column=molecule_column,
                    columns=columns)

    def to_html(self, *args, **kwargs):
        kwargs['escape'] = False
        return super(ChemDataFrame, self).to_html(*args, **kwargs)

    def to_excel(self, *args, **kwargs):
        columns = kwargs['columns'] if 'columns' in kwargs else self.columns.tolist()
        molecule_column = 'mol'  # TODO: Get appropriate molecule_column
        molecule_column_idx = columns.index(molecule_column)
        size = kwargs.pop('size') if 'size' in kwargs else (200, 200)
        excel_writer = pd.ExcelWriter(args[0], engine='xlsxwriter')

        super(ChemDataFrame, self).to_excel(excel_writer, *args[1:], **kwargs)

        sheet = excel_writer.sheets['Sheet1']  # TODO: Get appropriate sheet name
        sheet.set_column(molecule_column_idx + 1, molecule_column_idx + 1, width=size[1] / 6.)
        for i, mol in enumerate(self[molecule_column]):
            img = BytesIO()
            png = mol.clone.write('png', size=size)
            if type(png) is str:
                png = png.encode('utf-8', errors='surrogateescape')
            img.write(png)
            sheet.write_string(i + 1, molecule_column_idx + 1, "")
            sheet.insert_image(i + 1,
                               molecule_column_idx + 1,
                               'dummy',
                               {'image_data': img,
                                'positioning': 2,
                                'x_offset': 1,
                                'y_offset': 1})
            sheet.set_row(i + 1, height=size[0])  # TODO: get actual size
        excel_writer.save()

    @property
    def _constructor(self):
        """ Force new class to be usead as constructor """
        return ChemDataFrame

    @property
    def _constructor_sliced(self):
        """ Force new class to be usead as constructor when slicing """
        return ChemSeries

    @property
    def _constructor_expanddim(self):
        """ Force new class to be usead as constructor when expandig dims """
        return ChemPanel
# Copy some docscrings from upstream classes
for method in ['to_html', 'to_excel']:
    try:
        getattr(ChemDataFrame, method).__doc__ = getattr(pd.DataFrame, method).__doc__
    except AttributeError:  # Python 2 compatible
        getattr(ChemDataFrame, method).__func__.__doc__ = getattr(pd.DataFrame, method).__func__.__doc__

class ChemPanel(pd.Panel):
    """Modified `pandas.Panel` to adopt higher dimension data than
    `ChemDataFrame`. Main purpose is to store molecular fingerprints in one
    column and keep 2D numpy array underneath.

    """

    @property
    def _constructor(self):
        """ Force new class to be usead as constructor """
        return ChemPanel

    @property
    def _constructor_sliced(self):
        """ Force new class to be usead as constructor when slicing """
        return ChemDataFrame
<commit_msg>Add writing to buffers and keep molecule column in hidden var<commit_after>""" Pandas extension for chemical analysis """
from __future__ import absolute_import
from collections import deque
from six import BytesIO, StringIO
import pandas as pd

import oddt

pd.set_option("display.max_colwidth", 999999)
image_backend = 'png'  # png or svg

def _mol_reader(fmt='sdf',
                filepath_or_buffer=None,
                usecols=None,
                molecule_column='mol',
                molecule_name_column='mol_name',
                smiles_column=None,
                skip_bad_mols=False,
                chunksize=None,
                **kwargs):
    """Universal reading function for private use.

    .. versionadded:: 0.3

    Parameters
    ----------
        fmt : string
            The format of molecular file

        filepath_or_buffer : string or None
            File path

        usecols : list or None, optional (default=None)
            A list of columns to read from file. If None then all available
            fields are read.

        molecule_column : string or None, optional (default='mol')
            Name of molecule column. If None the molecules will be skipped and
            the reading will be speed up significantly.

        molecule_name_column : string or None, optional (default='mol_name')
            Column name which will contain molecules' title/name. Column is
            skipped when set to None.

        smiles_column  : string or None, optional (default=None)
            Column name containg molecules' SMILES, by default it is disabled.

        skip_bad_mols : bool, optional (default=False)
            Switch to skip empty (bad) molecules. Useful for RDKit, which Returns
            None if molecule can not sanitize.

        chunksize : int or None, optional (default=None)
            Size of chunk to return. If set to None whole set is returned.

    Returns
    -------
        chunk :
            A `ChemDataFrame` containg `chunksize` molecules.

    """
    # capture options for reader
    reader_kwargs = {}
    if 'opt' in kwargs:
        reader_kwargs['opt'] = kwargs.pop('opt')
    if 'sanitize' in kwargs:
        reader_kwargs['sanitize'] = kwargs.pop('sanitize')

    # when you dont read molecules you can skip parsing them
    if molecule_column is None:
        if oddt.toolkit.backend == 'ob' and fmt == 'sdf':
            if 'opt' in reader_kwargs:
                reader_kwargs['opt']['P'] = None
            else:
                reader_kwargs['opt'] = {'P': None}
        elif oddt.toolkit.backend == 'rdk':
            reader_kwargs['sanitize'] = False

    chunk = []
    for n, mol in enumerate(oddt.toolkit.readfile(fmt, filepath_or_buffer, **reader_kwargs)):
        if skip_bad_mols and mol is None:
            continue  # add warning with number of skipped molecules
        if usecols is None:
            mol_data = mol.data.to_dict()
        else:
            mol_data = dict((k, mol.data[k]) for k in usecols)

        if molecule_column:
            mol_data[molecule_column] = mol
        if molecule_name_column:
            mol_data[molecule_name_column] = mol.title
        if smiles_column:
            mol_data[smiles_column] = mol.write('smi').split()[0]
        chunk.append(mol_data)
        if chunksize and (n + 1) % chunksize == 0:
            chunk_frm = ChemDataFrame(chunk, **kwargs)
            chunk_frm._molecule_column = molecule_column
            yield chunk_frm
            chunk = []
    if chunk or chunksize is None:
        chunk_frm = ChemDataFrame(chunk, **kwargs)
        chunk_frm._molecule_column = molecule_column
        yield chunk_frm

def _mol_writer(data,
                fmt='sdf',
                filepath_or_buffer=None,
                update_properties=True,
                molecule_column=None,
                columns=None):
    molecule_column = molecule_column or data._molecule_column
    if filepath_or_buffer is None:
        out = StringIO()
    elif hasattr(filepath_or_buffer, 'write'):
        out = filepath_or_buffer
    else:
        out = oddt.toolkit.Outputfile(fmt, filepath_or_buffer, overwrite=True)
    if isinstance(data, pd.DataFrame):
        for ix, row in data.iterrows():
            mol = row[molecule_column].clone
            if update_properties:
                new_data = row.to_dict()
                del new_data[molecule_column]
                mol.data.update(new_data)
            if columns:
                for k in mol.data.keys():
                    if k not in columns:
                        del mol.data[k]
            if filepath_or_buffer is None or hasattr(filepath_or_buffer, 'write'):
                out.write(mol.write(fmt))
            else:
                out.write(mol)
    elif isinstance(data, pd.Series):
        for mol in data:
            if filepath_or_buffer is None or hasattr(filepath_or_buffer, 'write'):
                out.write(mol.write(fmt))
            else:
                out.write(mol)
    if filepath_or_buffer is None:
        return out.getvalue()
    elif not hasattr(filepath_or_buffer, 'write'):  # dont close foreign buffer
        out.close()

def read_sdf(filepath_or_buffer=None,
             usecols=None,
             molecule_column='mol',
             molecule_name_column='mol_name',
             smiles_column=None,
             skip_bad_mols=False,
             chunksize=None,
             **kwargs):
    """Read SDF/MDL multi molecular file to ChemDataFrame

    .. versionadded:: 0.3

    Parameters
    ----------
        filepath_or_buffer : string or None
            File path

        usecols : list or None, optional (default=None)
            A list of columns to read from file. If None then all available
            fields are read.

        molecule_column : string or None, optional (default='mol')
            Name of molecule column. If None the molecules will be skipped and
            the reading will be speed up significantly.

        molecule_name_column : string or None, optional (default='mol_name')
            Column name which will contain molecules' title/name. Column is
            skipped when set to None.

        smiles_column  : string or None, optional (default=None)
            Column name containg molecules' SMILES, by default it is disabled.

        skip_bad_mols : bool, optional (default=False)
            Switch to skip empty (bad) molecules. Useful for RDKit, which Returns
            None if molecule can not sanitize.

        chunksize : int or None, optional (default=None)
            Size of chunk to return. If set to None whole set is returned.

    Returns
    -------
        result :
            A `ChemDataFrame` containg all molecules if `chunksize` is None
            or genrerator of `ChemDataFrame` with `chunksize` molecules.

    """
    result = _mol_reader(fmt='sdf',
                         filepath_or_buffer=filepath_or_buffer,
                         usecols=usecols,
                         molecule_column=molecule_column,
                         molecule_name_column=molecule_name_column,
                         smiles_column=smiles_column,
                         skip_bad_mols=skip_bad_mols,
                         chunksize=chunksize,
                         **kwargs)
    if chunksize:
        return result
    else:
        return deque(result, maxlen=1).pop()

def read_mol2(filepath_or_buffer=None,
              usecols=None,
              molecule_column='mol',
              molecule_name_column='mol_name',
              smiles_column=None,
              skip_bad_mols=False,
              chunksize=None,
              **kwargs):
    """Read Mol2 multi molecular file to ChemDataFrame. UCSF Dock 6 comments
    style is supported, i.e. `#### var_name: value` before molecular block.

    .. versionadded:: 0.3

    Parameters
    ----------
        filepath_or_buffer : string or None
            File path

        usecols : list or None, optional (default=None)
            A list of columns to read from file. If None then all available
            fields are read.

        molecule_column : string or None, optional (default='mol')
            Name of molecule column. If None the molecules will be skipped and
            the reading will be speed up significantly.

        molecule_name_column : string or None, optional (default='mol_name')
            Column name which will contain molecules' title/name. Column is
            skipped when set to None.

        smiles_column  : string or None, optional (default=None)
            Column name containg molecules' SMILES, by default it is disabled.

        skip_bad_mols : bool, optional (default=False)
            Switch to skip empty (bad) molecules. Useful for RDKit, which Returns
            None if molecule can not sanitize.

        chunksize : int or None, optional (default=None)
            Size of chunk to return. If set to None whole set is returned.

    Returns
    -------
        result :
            A `ChemDataFrame` containg all molecules if `chunksize` is None
            or genrerator of `ChemDataFrame` with `chunksize` molecules.

    """
    result = _mol_reader(fmt='mol2',
                         filepath_or_buffer=filepath_or_buffer,
                         usecols=usecols,
                         molecule_column=molecule_column,
                         molecule_name_column=molecule_name_column,
                         smiles_column=smiles_column,
                         skip_bad_mols=skip_bad_mols,
                         chunksize=chunksize,
                         **kwargs)
    if chunksize:
        return result
    else:
        return deque(result, maxlen=1).pop()

class ChemSeries(pd.Series):
    """Pandas Series modified to adapt `oddt.toolkit.Molecule` objects and apply
    molecular methods easily.
    """
    def to_smiles(self, filepath_or_buffer=None):
        return _mol_writer(self, fmt='smi', filepath_or_buffer=filepath_or_buffer)

    def to_sdf(self, filepath_or_buffer=None):
        return _mol_writer(self, fmt='sdf', filepath_or_buffer=filepath_or_buffer)

    def to_mol2(self, filepath_or_buffer=None):
        return _mol_writer(self, fmt='mol2', filepath_or_buffer=filepath_or_buffer)

    @property
    def _constructor(self):
        """ Force new class to be usead as constructor """
        return ChemSeries

    @property
    def _constructor_expanddim(self):
        """ Force new class to be usead as constructor when expandig dims """
        return ChemDataFrame

class ChemDataFrame(pd.DataFrame):
    """Chemical DataFrame object, which contains molecules column of
    `oddt.toolkit.Molecule` objects. Rich display of moleucles (2D) is available
    in iPython Notebook. Additional `to_sdf` and `to_mol2` methods make writing
    to molecular formats easy.

    Note:
    Thanks to: http://blog.snapdragon.cc/2015/05/05/subclass-pandas-dataframe-to-save-custom-attributes/
    """
    _molecule_column = None

    def to_sdf(self,
               filepath_or_buffer=None,
               update_properties=True,
               molecule_column=None,
               columns=None):
        molecule_column = molecule_column or self._molecule_column
        return _mol_writer(self,
                           filepath_or_buffer=filepath_or_buffer,
                           update_properties=update_properties,
                           fmt='sdf',
                           molecule_column=molecule_column,
                           columns=columns)

    def to_mol2(self,
                filepath_or_buffer=None,
                update_properties=True,
                molecule_column='mol',
                columns=None):
        molecule_column = molecule_column or self._molecule_column
        return _mol_writer(self,
                           fmt='mol2',
                           filepath_or_buffer=filepath_or_buffer,
                           update_properties=update_properties,
                           molecule_column=molecule_column,
                           columns=columns)

    def to_html(self, *args, **kwargs):
        kwargs['escape'] = False
        return super(ChemDataFrame, self).to_html(*args, **kwargs)

    def to_excel(self, *args, **kwargs):
        columns = kwargs['columns'] if 'columns' in kwargs else self.columns.tolist()
        if 'molecule_column' in kwargs:
            molecule_column = kwargs['molecule_column']
        else:
            molecule_column = self._molecule_column
        molecule_column_idx = columns.index(molecule_column)
        size = kwargs.pop('size') if 'size' in kwargs else (200, 200)
        excel_writer = pd.ExcelWriter(args[0], engine='xlsxwriter')

        super(ChemDataFrame, self).to_excel(excel_writer, *args[1:], **kwargs)

        sheet = excel_writer.sheets['Sheet1']  # TODO: Get appropriate sheet name
        sheet.set_column(molecule_column_idx + 1, molecule_column_idx + 1, width=size[1] / 6.)
        for i, mol in enumerate(self[molecule_column]):
            img = BytesIO()
            png = mol.clone.write('png', size=size)
            if type(png) is str:
                png = png.encode('utf-8', errors='surrogateescape')
            img.write(png)
            sheet.write_string(i + 1, molecule_column_idx + 1, "")
            sheet.insert_image(i + 1,
                               molecule_column_idx + 1,
                               'dummy',
                               {'image_data': img,
                                'positioning': 2,
                                'x_offset': 1,
                                'y_offset': 1})
            sheet.set_row(i + 1, height=size[0])
        excel_writer.save()

    @property
    def _constructor(self):
        """ Force new class to be usead as constructor """
        return ChemDataFrame

    @property
    def _constructor_sliced(self):
        """ Force new class to be usead as constructor when slicing """
        return ChemSeries

    @property
    def _constructor_expanddim(self):
        """ Force new class to be usead as constructor when expandig dims """
        return ChemPanel
# Copy some docscrings from upstream classes
for method in ['to_html', 'to_excel']:
    try:
        getattr(ChemDataFrame, method).__doc__ = getattr(pd.DataFrame, method).__doc__
    except AttributeError:  # Python 2 compatible
        getattr(ChemDataFrame, method).__func__.__doc__ = getattr(pd.DataFrame, method).__func__.__doc__

class ChemPanel(pd.Panel):
    """Modified `pandas.Panel` to adopt higher dimension data than
    `ChemDataFrame`. Main purpose is to store molecular fingerprints in one
    column and keep 2D numpy array underneath.

    """

    @property
    def _constructor(self):
        """ Force new class to be usead as constructor """
        return ChemPanel

    @property
    def _constructor_sliced(self):
        """ Force new class to be usead as constructor when slicing """
        return ChemDataFrame
<|endoftext|>


<commit_before>'''
Killmail posting cog for antinub-gregbot project.

Monitors zKillboard's redisQ api and posts killmails relevant to your corp in
the given channel.
'''
import asyncio
from datetime import datetime
import logging

import aiohttp
from discord.embeds import Embed

from config import KILLMAILS, OWNER_ID

class Killmails:
    '''A cog which monitors zKillboard's redisQ api and posts links to
    killmails which match the provided rule'''
    def __init__(self, bot, config):
        self.logger = logging.getLogger(__name__)
        self.bot = bot
        self.conf = config

        self.session = aiohttp.ClientSession()
        self.channel = self.bot.get_channel(self.conf['channel_id'])

        self.zkb_listener = self.bot.loop.create_task(self.retrieve_kills())
        self.zkb_listener.add_done_callback(self.handle_exception)

    def __unload(self):
        self.zkb_listener.cancel()

    def get_health(self):
        'Returns a string describing the status of this cog'
        if not self.zkb_listener.done():
            return '\n  \u2714 Listening'
        else:
            return '\n  \u2716 Not listening'

    async def retrieve_kills(self):
        '''Loops to try to retrieve killmail packages'''
        try:
            while True:
                package = await self.wait_for_package()
                if package:
                    if self.is_relevant(package):
                        k_id = package['killID']
                        self.logger.info('Relaying killmail, ID: %s', k_id)
                        crest_package = await self.fetch_crest_info(package)
                        embed = self.killmail_embed(crest_package)
                        await self.bot.send_message(self.channel, embed=embed)
                    else:
                        self.logger.debug('Ignoring killmail')
                else:
                    self.logger.debug('Got empty package')
        except asyncio.CancelledError:
            pass
        finally:
            await self.session.close()

    def handle_exception(self, fut):
        'Make sure any exception from the future is consumed'
        exc = fut.exception()
        if exc:
            self.logger.exception(exc)
            self.bot.loop.create_task(
                self.bot.send_message(OWNER_ID, '`{}`'.format(exc)))

    async def wait_for_package(self):
        'Returns a dictionary containing the contents of the redisQ package'
        async with self.session.get(self.conf['redisQ_url']) as resp:
            if resp.status == 200:
                zkb_data = await resp.json()
                return zkb_data['package']
            elif resp.status == 502:
                self.logger.info('redisQ is taking too long to respond')
            else:
                self.logger.error('redisQ: %s error occurred', resp.status)

    def is_relevant(self, package):
        'Returns True if a killmail should be relayed to discord'
        value = package['zkb']['totalValue'] / 1000000.0
        if value >= self.conf['others_value'] and self.conf['others_value']:
            return True

        victim_corp_id = package['killmail']['victim']['corporation']['id']
        if str(victim_corp_id) in self.conf['corp_ids']:
            if value >= self.conf['corp_ids'][victim_corp_id]:
                return True

        for attacker in package['killmail']['attackers']:
            if 'corporation' in attacker:
                attacker_corp_id = attacker['corporation']['id']
                if str(attacker_corp_id) in self.conf['corp_ids']:
                    if value >= self.conf['corp_ids'][attacker_corp_id]:
                        return True

        return False

    async def fetch_crest_info(self, package):
        'Fills in potentially missing information from CREST api'
        zkb = package['zkb']  # The zkb specific part of the package
        async with self.session.get(zkb['href']) as resp:
            if resp.status == 200:
                crest_data = await resp.json()
                crest_data['zkb'] = zkb
                return crest_data
            elif resp.status == 502:
                self.logger.info('CREST is taking too long to respond')
            else:
                self.logger.error('CREST: %s error occurred', resp.status)

    def killmail_embed(self, package):
        'Generates the embed which the killmail will be posted in'
        victim = package['victim']
        if 'character' in victim:
            victim_str = '{} ({})'.format(
                victim['character']['name'],
                victim['corporation']['name'])
        else:
            victim_str = victim['corporation']['name']
        ship = victim['shipType']

        embed = Embed()
        embed.title = '{} | {} | {}'.format(
            package['solarSystem']['name'],
            ship['name'],
            victim['corporation']['name'])
        embed.description = ('{} lost their {} in {}\n'
                             'Total Value: {:,} ISK\n'
                             '\u200b').format(
                                 victim_str,
                                 ship['name'],
                                 package['solarSystem']['name'],
                                 package['zkb']['totalValue'])
        embed.url = 'https://zkillboard.com/kill/{}/'.format(package['killID'])
        embed.timestamp = datetime.strptime(package['killTime'],
                                            '%Y.%m.%d %H:%M:%S')
        if victim['corporation']['id_str'] in self.conf['corp_ids']:
            embed.colour = 0x7a0000  # red
        else:
            embed.colour = 0x007a00  # green
        embed.set_thumbnail(url=('http://imageserver.eveonline.com/Type/'
                                 '{}_64.png').format(ship['id_str']))
        return embed

def setup(bot):
    'Adds the cog to the provided discord bot'
    bot.add_cog(Killmails(bot, KILLMAILS))
<commit_msg>Message needs to be sent to user object<commit_after>'''
Killmail posting cog for antinub-gregbot project.

Monitors zKillboard's redisQ api and posts killmails relevant to your corp in
the given channel.
'''
import asyncio
from datetime import datetime
import logging

import aiohttp
from discord.embeds import Embed

from config import KILLMAILS, OWNER_ID

class Killmails:
    '''A cog which monitors zKillboard's redisQ api and posts links to
    killmails which match the provided rule'''
    def __init__(self, bot, config):
        self.logger = logging.getLogger(__name__)
        self.bot = bot
        self.conf = config

        self.session = aiohttp.ClientSession()
        self.channel = self.bot.get_channel(self.conf['channel_id'])

        self.zkb_listener = self.bot.loop.create_task(self.retrieve_kills())
        self.zkb_listener.add_done_callback(self.handle_exception)

    def __unload(self):
        self.zkb_listener.cancel()

    def get_health(self):
        'Returns a string describing the status of this cog'
        if not self.zkb_listener.done():
            return '\n  \u2714 Listening'
        else:
            return '\n  \u2716 Not listening'

    async def retrieve_kills(self):
        '''Loops to try to retrieve killmail packages'''
        try:
            while True:
                package = await self.wait_for_package()
                if package:
                    if self.is_relevant(package):
                        k_id = package['killID']
                        self.logger.info('Relaying killmail, ID: %s', k_id)
                        crest_package = await self.fetch_crest_info(package)
                        embed = self.killmail_embed(crest_package)
                        await self.bot.send_message(self.channel, embed=embed)
                    else:
                        self.logger.debug('Ignoring killmail')
                else:
                    self.logger.debug('Got empty package')
        except asyncio.CancelledError:
            pass
        finally:
            await self.session.close()

    def handle_exception(self, fut):
        'Make sure any exception from the future is consumed'
        exc = fut.exception()
        if exc:
            self.logger.exception(exc)
            chan = self.bot.get_user_info(OWNER_ID)
            self.bot.loop.create_task(
                self.bot.send_message(chan, '`{}`'.format(exc)))

    async def wait_for_package(self):
        'Returns a dictionary containing the contents of the redisQ package'
        async with self.session.get(self.conf['redisQ_url']) as resp:
            if resp.status == 200:
                zkb_data = await resp.json()
                return zkb_data['package']
            elif resp.status == 502:
                self.logger.info('redisQ is taking too long to respond')
            else:
                self.logger.error('redisQ: %s error occurred', resp.status)

    def is_relevant(self, package):
        'Returns True if a killmail should be relayed to discord'
        value = package['zkb']['totalValue'] / 1000000.0
        if value >= self.conf['others_value'] and self.conf['others_value']:
            return True

        victim_corp_id = package['killmail']['victim']['corporation']['id']
        if str(victim_corp_id) in self.conf['corp_ids']:
            if value >= self.conf['corp_ids'][victim_corp_id]:
                return True

        for attacker in package['killmail']['attackers']:
            if 'corporation' in attacker:
                attacker_corp_id = attacker['corporation']['id']
                if str(attacker_corp_id) in self.conf['corp_ids']:
                    if value >= self.conf['corp_ids'][attacker_corp_id]:
                        return True

        return False

    async def fetch_crest_info(self, package):
        'Fills in potentially missing information from CREST api'
        zkb = package['zkb']  # The zkb specific part of the package
        async with self.session.get(zkb['href']) as resp:
            if resp.status == 200:
                crest_data = await resp.json()
                crest_data['zkb'] = zkb
                return crest_data
            elif resp.status == 502:
                self.logger.info('CREST is taking too long to respond')
            else:
                self.logger.error('CREST: %s error occurred', resp.status)

    def killmail_embed(self, package):
        'Generates the embed which the killmail will be posted in'
        victim = package['victim']
        if 'character' in victim:
            victim_str = '{} ({})'.format(
                victim['character']['name'],
                victim['corporation']['name'])
        else:
            victim_str = victim['corporation']['name']
        ship = victim['shipType']

        embed = Embed()
        embed.title = '{} | {} | {}'.format(
            package['solarSystem']['name'],
            ship['name'],
            victim['corporation']['name'])
        embed.description = ('{} lost their {} in {}\n'
                             'Total Value: {:,} ISK\n'
                             '\u200b').format(
                                 victim_str,
                                 ship['name'],
                                 package['solarSystem']['name'],
                                 package['zkb']['totalValue'])
        embed.url = 'https://zkillboard.com/kill/{}/'.format(package['killID'])
        embed.timestamp = datetime.strptime(package['killTime'],
                                            '%Y.%m.%d %H:%M:%S')
        if victim['corporation']['id_str'] in self.conf['corp_ids']:
            embed.colour = 0x7a0000  # red
        else:
            embed.colour = 0x007a00  # green
        embed.set_thumbnail(url=('http://imageserver.eveonline.com/Type/'
                                 '{}_64.png').format(ship['id_str']))
        return embed

def setup(bot):
    'Adds the cog to the provided discord bot'
    bot.add_cog(Killmails(bot, KILLMAILS))
<|endoftext|>


<commit_before>from django.contrib import admin
from django.contrib import messages

from . import models

@admin.register(models.Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ("name", "code")

@admin.register(models.Indicator)
class IndicatorAdmin(admin.ModelAdmin):
    list_display = (
        "code",
        "name",
        "tier",
        "measurement",
        "reporting",
        "alignment",
        "frequency",
    )
    list_filter = ("tier", "reporting", "frequency")

@admin.register(models.IndicatorElements)
class ElementAdmin(admin.ModelAdmin):
    list_display = ("code", "name", "definition")

@admin.register(models.IndicatorQuarterResult)
class QuarterResultAdmin(admin.ModelAdmin):
    list_display = (
        "indicator",
        "financial_year",
        "geography",
        "target",
        "quarter_one",
        "quarter_two",
        "quarter_three",
        "quarter_four",
    )
    search_fields = ["geography__geo_code"]

@admin.register(models.FinancialYear)
class FinancialYearAdmin(admin.ModelAdmin):
    list_display = ("budget_year", "active")

    def save_model(self, request, obj, form, change):
        if change:
            if form.cleaned_data["active"] == False:
                super().save_model(request, obj, form, change)
            else:
                try:
                    active_model = models.FinancialYear.objects.get(active=True)
                except models.FinancialYear.DoesNotExist:
                    super().save_model(request, obj, form, change)
                else:
                    messages.error(request, "A Financial Year Is already active")

        else:
            super().save_model(request, obj, form, change)
<commit_msg>add new models to admin<commit_after>from django.contrib import admin
from django.contrib import messages
from django_q.tasks import async_task

from . import models
from .forms import FinancialYearForm, UpdateFileForm

@admin.register(models.Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ("name", "code")

@admin.register(models.Indicator)
class IndicatorAdmin(admin.ModelAdmin):
    list_display = (
        "code",
        "name",
        "tier",
        "measurement",
        "reporting",
        "alignment",
        "frequency",
        "goal",
    )
    list_filter = ("tier", "reporting", "frequency")

@admin.register(models.IndicatorElements)
class ElementAdmin(admin.ModelAdmin):
    list_display = ("code", "name", "definition")

@admin.register(models.IndicatorQuarterResult)
class QuarterResultAdmin(admin.ModelAdmin):
    list_display = (
        "indicator",
        "financial_year",
        "geography",
        "target",
        "quarter_one",
        "quarter_two",
        "quarter_three",
        "quarter_four",
    )
    search_fields = ["geography__geo_code"]

@admin.register(models.FinancialYear)
class FinancialYearAdmin(admin.ModelAdmin):
    list_display = ("budget_year", "active", "quarter")
    form = FinancialYearForm

    def save_model(self, request, obj, form, change):
        if change:
            if obj.active and form.cleaned_data["active"]:
                super().save_model(request, obj, form, change)
            elif not obj.active and form.cleaned_data["active"]:
                try:
                    active_model = models.FinancialYear.objects.get(active=True)
                except models.FinancialYear.DoesNotExist:
                    super().save_model(request, obj, form, change)
                else:
                    messages.error(request, "A Financial Year Is already active")

        else:
            super().save_model(request, obj, form, change)

@admin.register(models.UpdateFile)
class UpdateFileAdmin(admin.ModelAdmin):
    list_display = ("financial_year", "quarter", "geography", "document", "status")
    form = UpdateFileForm

    def save_model(self, request, obj, form, change):
        messages.add_message(
            request, messages.INFO, "File is currently being processed."
        )
        super().save_model(request, obj, form, change)
        task_id = async_task("metro.upload.process_file", obj.id)
<|endoftext|>


<commit_before>from __future__ import unicode_literals

from django.contrib.messages.views import SuccessMessageMixin
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import get_object_or_404, render
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, UpdateView, DeleteView

from django.views.generic.edit import ModelFormMixin

from hourly.models import Hourly

from .models import Pricing, Main
from source_utils.permission_mixins import FinanceCheckMixin, SuperUserCheckMixin
from source_utils.view_mixins import DeleteViewMixin
from .forms import PricingForm, HourlyBaseForm

class PricingMixin(FinanceCheckMixin):
    model = Pricing

class PricingListView(PricingMixin, ListView):

    def get_context_data(self, **kwargs):
        context = super(PricingListView, self).get_context_data(**kwargs)
        hourly = get_object_or_404(Hourly, pk=1)
        context['hourly'] = hourly.hourly_base
        return context

class PricingDetailView(PricingMixin, DetailView):
    template_name = "finance/pricing_detail.html"

class PricingEditMixin(PricingMixin, SuccessMessageMixin):
    template_name = 'form.html'
    form_class = PricingForm
    success_url = reverse_lazy('finance:pricing_list')

class PricingCreateView(PricingEditMixin, CreateView):
    success_message = "Pricing was successfully created"

class PricingUpdateView(PricingEditMixin, UpdateView):
    success_message = "Pricing was successfully updated"

class HourlyBaseUpdateView(SuccessMessageMixin, UpdateView):
    model = Hourly
    template_name = 'form.html'
    form_class = HourlyBaseForm
    success_url = reverse_lazy('finance:pricing_list')
    success_message = "Base hourly rate was successfully changed to %(amount)s"

    def get_context_data(self, **kwargs):
        context = super(HourlyBaseUpdateView, self).get_context_data(**kwargs)
        context['title'] = "Change Base Hourly Rate"
        return context

    def get_success_message(self, cleaned_data):
        return self.success_message % dict(
            cleaned_data,
            amount=self.object.hourly_base,
        )

class MainLedgerDetailView(FinanceCheckMixin, DetailView):
    model = Main
    template_name = "finance/master_ledger_detail.html"

    def get_context_data(self, **kwargs):
        context = super(MainLedgerDetailView, self).get_context_data(**kwargs)
        (
            total,
            taxes,
            profit,
            customers_balances,
            customers_count,
            customers_conflicts,
            customers_unresolved_conflicts,
            projected_before_tax
        ) = self.object.get_customer_balance_sheet()

        context['customers_total'] = total
        context['customers_taxes'] = taxes
        context['customers_profit'] = profit
        context['customers_balances'] = customers_balances
        context['customers_count'] = customers_count
        context['customers_conflicts'] = customers_conflicts
        context['customers_unresolved_conflicts'] = customers_unresolved_conflicts
        context['projected_before_tax'] = projected_before_tax
        (
            expenses,
            operation_balances,
            operation_count,
            operation_conflicts,
            operation_unresolved_conflicts
        ) = self.object.get_operation_balance_sheet()
        context['operation_expenses'] = expenses
        context['operation_balances'] = operation_balances
        context['operation_count'] = operation_count
        context['operation_conflicts'] = operation_conflicts
        context['operation_unresolved_conflicts'] = operation_unresolved_conflicts
        context['net_profit'] = profit - expenses
        return context
<commit_msg>Update views.py<commit_after>from __future__ import unicode_literals

from django.contrib.messages.views import SuccessMessageMixin
from django.core.urlresolvers import reverse_lazy
from django.shortcuts import get_object_or_404, render
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, UpdateView, DeleteView

from django.views.generic.edit import ModelFormMixin

from hourly.models import Hourly

from .models import Pricing, Main
from source_utils.permission_mixins import FinanceCheckMixin, SuperUserCheckMixin
from source_utils.view_mixins import DeleteViewMixin
from .forms import PricingForm, HourlyBaseForm

class PricingMixin(FinanceCheckMixin):
    model = Pricing

class PricingListView(PricingMixin, ListView):

    def get_context_data(self, **kwargs):
        context = super(PricingListView, self).get_context_data(**kwargs)
        hourly = get_object_or_404(Hourly, pk=1)
        context['hourly'] = hourly.hourly_base
        return context

class PricingDetailView(PricingMixin, DetailView):
    template_name = "finance/pricing_detail.html"

class PricingEditMixin(PricingMixin, SuccessMessageMixin):
    template_name = 'form.html'
    form_class = PricingForm
    success_url = reverse_lazy('finance:pricing_list')

class PricingCreateView(PricingEditMixin, CreateView):
    success_message = "Pricing was successfully created"

class PricingUpdateView(PricingEditMixin, UpdateView):
    success_message = "Pricing was successfully updated"

class HourlyBaseUpdateView(FinanceCheckMixin, SuccessMessageMixin, UpdateView):
    model = Hourly
    template_name = 'form.html'
    form_class = HourlyBaseForm
    success_url = reverse_lazy('finance:pricing_list')
    success_message = "Base hourly rate was successfully changed to %(amount)s"

    def get_context_data(self, **kwargs):
        context = super(HourlyBaseUpdateView, self).get_context_data(**kwargs)
        context['title'] = "Change Base Hourly Rate"
        return context

    def get_success_message(self, cleaned_data):
        return self.success_message % dict(
            cleaned_data,
            amount=self.object.hourly_base,
        )

class MainLedgerDetailView(FinanceCheckMixin, DetailView):
    model = Main
    template_name = "finance/master_ledger_detail.html"

    def get_context_data(self, **kwargs):
        context = super(MainLedgerDetailView, self).get_context_data(**kwargs)
        (
            total,
            taxes,
            profit,
            customers_balances,
            customers_count,
            customers_conflicts,
            customers_unresolved_conflicts,
            projected_before_tax
        ) = self.object.get_customer_balance_sheet()

        context['customers_total'] = total
        context['customers_taxes'] = taxes
        context['customers_profit'] = profit
        context['customers_balances'] = customers_balances
        context['customers_count'] = customers_count
        context['customers_conflicts'] = customers_conflicts
        context['customers_unresolved_conflicts'] = customers_unresolved_conflicts
        context['projected_before_tax'] = projected_before_tax
        (
            expenses,
            operation_balances,
            operation_count,
            operation_conflicts,
            operation_unresolved_conflicts
        ) = self.object.get_operation_balance_sheet()
        context['operation_expenses'] = expenses
        context['operation_balances'] = operation_balances
        context['operation_count'] = operation_count
        context['operation_conflicts'] = operation_conflicts
        context['operation_unresolved_conflicts'] = operation_unresolved_conflicts
        context['net_profit'] = profit - expenses
        return context
<|endoftext|>