Coverage for help_about.py: 24%

111 statements  

« prev     ^ index     » next       coverage.py v7.2.5, created at 2023-05-11 13:22 -0700

1"""About Dialog for IDLE 

2 

3""" 

4import os 

5import sys 

6import webbrowser 

7from platform import python_version, architecture 

8 

9from tkinter import Toplevel, Frame, Label, Button, PhotoImage 

10from tkinter import SUNKEN, TOP, BOTTOM, LEFT, X, BOTH, W, EW, NSEW, E 

11 

12from idlelib import textview 

13 

14version = python_version() 

15 

16 

17def build_bits(): 

18 "Return bits for platform." 

19 if sys.platform == 'darwin': 

20 return '64' if sys.maxsize > 2**32 else '32' 

21 else: 

22 return architecture()[0][:2] 

23 

24 

25class AboutDialog(Toplevel): 

26 """Modal about dialog for idle 

27 

28 """ 

29 def __init__(self, parent, title=None, *, _htest=False, _utest=False): 

30 """Create popup, do not return until tk widget destroyed. 

31 

32 parent - parent of this dialog 

33 title - string which is title of popup dialog 

34 _htest - bool, change box location when running htest 

35 _utest - bool, don't wait_window when running unittest 

36 """ 

37 Toplevel.__init__(self, parent) 

38 self.configure(borderwidth=5) 

39 # place dialog below parent if running htest 

40 self.geometry("+%d+%d" % ( 

41 parent.winfo_rootx()+30, 

42 parent.winfo_rooty()+(30 if not _htest else 100))) 

43 self.bg = "#bbbbbb" 

44 self.fg = "#000000" 

45 self.create_widgets() 

46 self.resizable(height=False, width=False) 

47 self.title(title or 

48 f'About IDLE {version} ({build_bits()} bit)') 

49 self.transient(parent) 

50 self.grab_set() 

51 self.protocol("WM_DELETE_WINDOW", self.ok) 

52 self.parent = parent 

53 self.button_ok.focus_set() 

54 self.bind('<Return>', self.ok) # dismiss dialog 

55 self.bind('<Escape>', self.ok) # dismiss dialog 

56 self._current_textview = None 

57 self._utest = _utest 

58 

59 if not _utest: 

60 self.deiconify() 

61 self.wait_window() 

62 

63 def create_widgets(self): 

64 frame = Frame(self, borderwidth=2, relief=SUNKEN) 

65 frame_buttons = Frame(self) 

66 frame_buttons.pack(side=BOTTOM, fill=X) 

67 frame.pack(side=TOP, expand=True, fill=BOTH) 

68 self.button_ok = Button(frame_buttons, text='Close', 

69 command=self.ok) 

70 self.button_ok.pack(padx=5, pady=5) 

71 

72 frame_background = Frame(frame, bg=self.bg) 

73 frame_background.pack(expand=True, fill=BOTH) 

74 

75 header = Label(frame_background, text='IDLE', fg=self.fg, 

76 bg=self.bg, font=('courier', 24, 'bold')) 

77 header.grid(row=0, column=0, sticky=E, padx=10, pady=10) 

78 

79 tk_patchlevel = self.info_patchlevel() 

80 ext = '.png' if tk_patchlevel >= (8, 6) else '.gif' 

81 icon = os.path.join(os.path.abspath(os.path.dirname(__file__)), 

82 'Icons', f'idle_48{ext}') 

83 self.icon_image = PhotoImage(master=self._root(), file=icon) 

84 logo = Label(frame_background, image=self.icon_image, bg=self.bg) 

85 logo.grid(row=0, column=0, sticky=W, rowspan=2, padx=10, pady=10) 

86 

87 byline_text = "Python's Integrated Development\nand Learning Environment" + 5*'\n' 

88 byline = Label(frame_background, text=byline_text, justify=LEFT, 

89 fg=self.fg, bg=self.bg) 

90 byline.grid(row=2, column=0, sticky=W, columnspan=3, padx=10, pady=5) 

91 email = Label(frame_background, text='email: idle-dev@python.org', 

92 justify=LEFT, fg=self.fg, bg=self.bg) 

93 email.grid(row=6, column=0, columnspan=2, sticky=W, padx=10, pady=0) 

94 docs_url = ("https://docs.python.org/%d.%d/library/idle.html" % 

95 sys.version_info[:2]) 

96 docs = Label(frame_background, text=docs_url, 

97 justify=LEFT, fg=self.fg, bg=self.bg) 

98 docs.grid(row=7, column=0, columnspan=2, sticky=W, padx=10, pady=0) 

99 docs.bind("<Button-1>", lambda event: webbrowser.open(docs['text'])) 

100 

101 Frame(frame_background, borderwidth=1, relief=SUNKEN, 

102 height=2, bg=self.bg).grid(row=8, column=0, sticky=EW, 

103 columnspan=3, padx=5, pady=5) 

104 

105 pyver = Label(frame_background, 

106 text='Python version: ' + version, 

107 fg=self.fg, bg=self.bg) 

108 pyver.grid(row=9, column=0, sticky=W, padx=10, pady=0) 

109 tkver = Label(frame_background, text=f'Tk version: {tk_patchlevel}', 

110 fg=self.fg, bg=self.bg) 

111 tkver.grid(row=9, column=1, sticky=W, padx=2, pady=0) 

112 py_buttons = Frame(frame_background, bg=self.bg) 

113 py_buttons.grid(row=10, column=0, columnspan=2, sticky=NSEW) 

114 self.py_license = Button(py_buttons, text='License', width=8, 

115 highlightbackground=self.bg, 

116 command=self.show_py_license) 

117 self.py_license.pack(side=LEFT, padx=10, pady=10) 

118 self.py_copyright = Button(py_buttons, text='Copyright', width=8, 

119 highlightbackground=self.bg, 

120 command=self.show_py_copyright) 

121 self.py_copyright.pack(side=LEFT, padx=10, pady=10) 

122 self.py_credits = Button(py_buttons, text='Credits', width=8, 

123 highlightbackground=self.bg, 

124 command=self.show_py_credits) 

125 self.py_credits.pack(side=LEFT, padx=10, pady=10) 

126 

127 Frame(frame_background, borderwidth=1, relief=SUNKEN, 

128 height=2, bg=self.bg).grid(row=11, column=0, sticky=EW, 

129 columnspan=3, padx=5, pady=5) 

130 

131 idlever = Label(frame_background, 

132 text='IDLE version: ' + version, 

133 fg=self.fg, bg=self.bg) 

134 idlever.grid(row=12, column=0, sticky=W, padx=10, pady=0) 

135 idle_buttons = Frame(frame_background, bg=self.bg) 

136 idle_buttons.grid(row=13, column=0, columnspan=3, sticky=NSEW) 

137 self.readme = Button(idle_buttons, text='README', width=8, 

138 highlightbackground=self.bg, 

139 command=self.show_readme) 

140 self.readme.pack(side=LEFT, padx=10, pady=10) 

141 self.idle_news = Button(idle_buttons, text='NEWS', width=8, 

142 highlightbackground=self.bg, 

143 command=self.show_idle_news) 

144 self.idle_news.pack(side=LEFT, padx=10, pady=10) 

145 self.idle_credits = Button(idle_buttons, text='Credits', width=8, 

146 highlightbackground=self.bg, 

147 command=self.show_idle_credits) 

148 self.idle_credits.pack(side=LEFT, padx=10, pady=10) 

149 

150 # License, copyright, and credits are of type _sitebuiltins._Printer 

151 def show_py_license(self): 

152 "Handle License button event." 

153 self.display_printer_text('About - License', license) 

154 

155 def show_py_copyright(self): 

156 "Handle Copyright button event." 

157 self.display_printer_text('About - Copyright', copyright) 

158 

159 def show_py_credits(self): 

160 "Handle Python Credits button event." 

161 self.display_printer_text('About - Python Credits', credits) 

162 

163 # Encode CREDITS.txt to utf-8 for proper version of Loewis. 

164 # Specify others as ascii until need utf-8, so catch errors. 

165 def show_idle_credits(self): 

166 "Handle Idle Credits button event." 

167 self.display_file_text('About - Credits', 'CREDITS.txt', 'utf-8') 1b

168 

169 def show_readme(self): 

170 "Handle Readme button event." 

171 self.display_file_text('About - Readme', 'README.txt', 'ascii') 1b

172 

173 def show_idle_news(self): 

174 "Handle News button event." 

175 self.display_file_text('About - NEWS', 'NEWS.txt', 'utf-8') 1b

176 

177 def display_printer_text(self, title, printer): 

178 """Create textview for built-in constants. 

179 

180 Built-in constants have type _sitebuiltins._Printer. The 

181 text is extracted from the built-in and then sent to a text 

182 viewer with self as the parent and title as the title of 

183 the popup. 

184 """ 

185 printer._Printer__setup() 

186 text = '\n'.join(printer._Printer__lines) 

187 self._current_textview = textview.view_text( 

188 self, title, text, _utest=self._utest) 

189 

190 def display_file_text(self, title, filename, encoding=None): 

191 """Create textview for filename. 

192 

193 The filename needs to be in the current directory. The path 

194 is sent to a text viewer with self as the parent, title as 

195 the title of the popup, and the file encoding. 

196 """ 

197 fn = os.path.join(os.path.abspath(os.path.dirname(__file__)), filename) 1b

198 self._current_textview = textview.view_file( 1b

199 self, title, fn, encoding, _utest=self._utest) 

200 

201 def ok(self, event=None): 

202 "Dismiss help_about dialog." 

203 self.grab_release() 

204 self.destroy() 

205 

206 

207if __name__ == '__main__': 207 ↛ 208line 207 didn't jump to line 208, because the condition on line 207 was never true

208 from unittest import main 

209 main('idlelib.idle_test.test_help_about', verbosity=2, exit=False) 

210 

211 from idlelib.idle_test.htest import run 

212 run(AboutDialog)