Completed
Push — master ( 48908b...b5f14c )
by Jace
02:17 queued 42s
created

Application.frame_text()   A

Complexity

Conditions 1

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 15
rs 9.4285
1
#!env/bin/python
2
3
import logging
4
5
import tkinter as tk
6
from tkinter import ttk
7
from PIL import Image, ImageTk
0 ignored issues
show
Configuration introduced by
The import PIL could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
8
try:
9
    import speech_recognition  # pylint: disable=import-error
10
except ImportError:
11
    speech_recognition = None
12
13
from memegen import __project__, __version__
14
from memegen.settings import ProdConfig
15
from memegen.app import create_app
16
from memegen.domain import Text
17
18
log = logging.getLogger(__name__)
19
20
21
class Application:
22
23
    def __init__(self, app):
24
        self.app = app
25
        self.label = None
26
        self.text = None
27
        self._image = None
28
        self._update_event = None
29
        self._clear_event = None
30
31
        # Configure speech recognition
32
        if speech_recognition:
33
            self._recogizer = speech_recognition.Recognizer()
34
            self._recogizer.energy_threshold = 1500
35
            self._recogizer.dynamic_energy_adjustment_ratio = 3
36
            self._microphone = speech_recognition.Microphone()
37
            with self._microphone as source:
38
                log.info("Adjusting for ambient noise...")
39
                self._recogizer.adjust_for_ambient_noise(source, duration=3)
40
            log.info("Listening for audio...")
41
            self._recogizer.listen_in_background(self._microphone, self.listen)
42
43
        # Configure root window
44
        self.root = tk.Tk()
45
        self.root.title("{} (v{})".format(__project__, __version__))
46
        self.root.minsize(500, 500)
47
48
        # Initialize the GUI
49
        self.label = None
50
        frame = self.init(self.root)
51
        frame.pack(fill=tk.BOTH, expand=1)
52
53
        # Start the event loop
54
        self.restart()
55
        self.root.mainloop()
56
57
    def init(self, root):
58
        padded = {'padding': 5}
59
        sticky = {'sticky': tk.NSEW}
60
61
        # Configure grid
62
        frame = ttk.Frame(root, **padded)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
63
        frame.rowconfigure(0, weight=1)
64
        frame.rowconfigure(1, weight=0)
65
        frame.columnconfigure(0, weight=1)
66
67
        def frame_image(root):
68
            frame = ttk.Frame(root, **padded)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
69
70
            # Configure grid
71
            frame.rowconfigure(0, weight=1)
72
            frame.columnconfigure(0, weight=1)
73
74
            # Place widgets
75
            self.label = ttk.Label(frame)
76
            self.label.grid(row=0, column=0)
77
78
            return frame
79
80
        def frame_text(root):
81
            frame = ttk.Frame(root, **padded)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
82
83
            # Configure grid
84
            frame.rowconfigure(0, weight=1)
85
            frame.rowconfigure(1, weight=1)
86
            frame.columnconfigure(0, weight=1)
87
88
            # Place widgets
89
            self.text = ttk.Entry(frame)
90
            self.text.bind("<Key>", self.restart)
91
            self.text.grid(row=0, column=0, **sticky)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
92
            self.text.focus_set()
93
94
            return frame
95
96
        def separator(root):
97
            return ttk.Separator(root)
98
99
        # Place widgets
100
        frame_image(frame).grid(row=0, **sticky)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
101
        separator(frame).grid(row=1, padx=10, pady=5, **sticky)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
102
        frame_text(frame).grid(row=2, **sticky)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
103
104
        return frame
105
106
    def listen(self, recognizer, audio):
107
        log.info("Recognizing speech...")
108
        try:
109
            value = recognizer.recognize_google(audio)
110
        except speech_recognition.UnknownValueError:
111
            log.warning("No speech detected")
112
        else:
113
            log.info("Detected speech: %s", value)
114
            self.update(value)
115
        log.info("Listening for audio...")
116
117
    def update(self, value=None):
118
        text = Text(value or self.text.get())
119
120
        ratio = 0
121
        match = None
122
123
        for template in self.app.template_service.all():
124
            _ratio, path = template.match(str(text).lower())
125
            if _ratio > ratio:
126
                ratio = _ratio
127
                log.info("Matched at %s: %s - %s", ratio, template, path)
128
                match = template, Text(path)
129
130
        if match:
131
            domain = self.app.image_service.create(*match)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
132
            image = Image.open(domain.path)
133
            old_size = image.size
134
            max_size = self.root.winfo_width(), self.root.winfo_height()
135
            ratio = min(max_size[0] / old_size[0], max_size[1] / old_size[1])
136
            new_size = [int(s * ratio * 0.9) for s in old_size]
137
            image = image.resize(new_size, Image.ANTIALIAS)
138
            self._image = ImageTk.PhotoImage(image)
139
            self.label.configure(image=self._image)
140
141
            self.clear()
142
143
        self.restart(update=True, clear=False)
144
145
    def clear(self, *_):
146
        self.text.delete(0, tk.END)
147
        self.restart()
148
149
    def restart(self, *_, update=True, clear=True):
150
        if update:
151
            if self._update_event:
152
                self.root.after_cancel(self._update_event)
153
            self._update_event = self.root.after(1000, self.update)
154
        if clear:
155
            if self._clear_event:
156
                self.root.after_cancel(self._clear_event)
157
            self._clear_event = self.root.after(5000, self.clear)
158
159
160
if __name__ == '__main__':
161
    Application(create_app(ProdConfig))
162