File: utils.py

package info (click to toggle)
python-art 6.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,076 kB
  • sloc: python: 73,473; makefile: 7; sh: 4
file content (145 lines) | stat: -rw-r--r-- 4,625 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# -*- coding: utf-8 -*-
"""Art utility module."""
import random

from .params import FONT_MAP
from .params import DECORATION_NAMES, FONT_NAMES, NON_ASCII_FONTS
from .params import RANDOM_FILTERED_FONTS
from .params import XLARGE_WIZARD_FONT, LARGE_WIZARD_FONT, MEDIUM_WIZARD_FONT, SMALL_WIZARD_FONT
from .params import FONT_SMALL_THRESHOLD, FONT_MEDIUM_THRESHOLD, FONT_LARGE_THRESHOLD, TEXT_XLARGE_THRESHOLD
from .params import TEXT_LARGE_THRESHOLD, TEXT_MEDIUM_THRESHOLD


def distance_calc(s1, s2):
    """
    Calculate Levenshtein distance between two words.

    :param s1: first word
    :type s1 : str
    :param s2: second word
    :type s2 : str
    :return: distance between two word

    References :
    1- https://stackoverflow.com/questions/2460177/edit-distance-in-python
    2- https://en.wikipedia.org/wiki/Levenshtein_distance
    """
    if len(s1) > len(s2):
        s1, s2 = s2, s1

    distances = range(len(s1) + 1)
    for i2, c2 in enumerate(s2):
        distances_ = [i2 + 1]
        for i1, c1 in enumerate(s1):
            if c1 == c2:
                distances_.append(distances[i1])
            else:
                distances_.append(
                    1 + min((distances[i1], distances[i1 + 1], distances_[-1])))
        distances = distances_
    return distances[-1]


def wizard_font(text):
    """
    Check input text length for wizard mode.

    :param text: input text
    :type text:str
    :return: font as str
    """
    text_length = len(text)
    if text_length <= TEXT_XLARGE_THRESHOLD:
        font = random.choice(XLARGE_WIZARD_FONT)
    elif text_length <= TEXT_LARGE_THRESHOLD:
        font = random.choice(LARGE_WIZARD_FONT)
    elif text_length <= TEXT_MEDIUM_THRESHOLD:
        font = random.choice(MEDIUM_WIZARD_FONT)
    else:
        font = random.choice(SMALL_WIZARD_FONT)
    return font


def indirect_font(font, text):
    """
    Check input font for indirect modes.

    :param font: input font
    :type font : str
    :param text: input text
    :type text:str
    :return: font as str
    """
    fonts = FONT_NAMES
    if font in ["rnd-small", "random-small", "rand-small"]:
        font = random.choice(RND_SIZE_DICT["small_list"])
        return font
    if font in ["rnd-medium", "random-medium", "rand-medium"]:
        font = random.choice(RND_SIZE_DICT["medium_list"])
        return font
    if font in ["rnd-large", "random-large", "rand-large"]:
        font = random.choice(RND_SIZE_DICT["large_list"])
        return font
    if font in ["rnd-xlarge", "random-xlarge", "rand-xlarge"]:
        font = random.choice(RND_SIZE_DICT["xlarge_list"])
        return font
    if font in ["random", "rand", "rnd"]:
        filtered_fonts = list(set(fonts) - set(RANDOM_FILTERED_FONTS))
        font = random.choice(filtered_fonts)
        return font
    if font in ["wizard", "wiz", "magic"]:
        font = wizard_font(text)
        return font
    if font in ["rnd-na", "random-na", "rand-na"]:
        font = random.choice(NON_ASCII_FONTS)
        return font
    if font not in fonts:
        font = min(fonts, key=lambda x: distance_calc(font, x))
    return font


def indirect_decoration(decoration):
    """
    Check input decoration for indirect modes.

    :param decoration: input decoration
    :type decoration : str
    :return: decoration as str
    """
    decorations = DECORATION_NAMES
    if decoration in ["random", "rand", "rnd"]:
        decoration = random.choice(decorations)
        return decoration
    if decoration not in decorations:
        decoration = min(decorations, key=lambda x: distance_calc(decoration, x))
    return decoration


def font_size_splitter(font_map):
    """
    Split fonts to 4 category (small,medium,large,xlarge) by maximum length of letter in each font.

    :param font_map: input fontmap
    :type font_map : dict
    :return: splitted fonts as dict
    """
    small_font, medium_font, large_font, xlarge_font = [], [], [], []
    fonts = set(font_map) - set(RANDOM_FILTERED_FONTS)
    for font in sorted(fonts):
        length = max(len(x) for x in font_map[font][0].values())
        if length <= FONT_SMALL_THRESHOLD:
            small_font.append(font)
        elif length <= FONT_MEDIUM_THRESHOLD:
            medium_font.append(font)
        elif length <= FONT_LARGE_THRESHOLD:
            large_font.append(font)
        else:
            xlarge_font.append(font)
    return {
        "small_list": small_font,
        "medium_list": medium_font,
        "large_list": large_font,
        "xlarge_list": xlarge_font}


RND_SIZE_DICT = font_size_splitter(FONT_MAP)  # pragma: no cover