Coverage for src/turtlesc/__init__.py: 100%

338 statements  

« prev     ^ index     » next       coverage.py v7.7.0, created at 2025-03-18 22:46 -0400

1import turtle, time, re 

2 

3ALL_SHORTCUTS = 'f b l r h c g tele x y st u pd pu ps pc fc bc sh cir undo bf ef sleep n s e w nw ne sw se u t cs css spd' + \ 

4 'forward backward left right home clear goto setx sety stamp update pendown penup pensize pencolor fillcolor bgcolor setheading' + \ 

5 'circle undo begin_fill end_fill north south east west northwest northeast southwest southeast reset bye done exitonclick update' + \ 

6 'tracer hide show dot clearstamp clearstamps degrees radians speed' 

7 

8CARDINAL_TO_DEGREES = {'n': '90', 's': '270', 'e': '0', 'w': '180', 'nw': '135', 'ne': '45', 'sw': '225', 'se': '315'} 

9 

10_MAP_FULL_TO_SHORT_NAMES = {'forward': 'f', 'backward': 'b', 'right': 'r', 'left': 'l', 'home': 'h', 'clear': 'c', 

11 'goto': 'g', 'teleport': 'tele', 'setx': 'x', 'sety': 'y', 'stamp': 'st', 'update': 'u', 'pendown': 'pd', 'penup': 'pu', 

12 'pensize': 'ps', 'pencolor': 'pc', 'fillcolor': 'fc', 'bgcolor': 'bc', 'setheading': 'sh', 'circle': 'cir', 

13 'begin_fill': 'bf', 'end_fill': 'ef', 'north': 'n', 'south': 's', 'east': 'e', 'west': 'w', 

14 'northwest': 'nw', 'northeast': 'ne', 'southwest': 'sw', 'southeast': 'se', 'update': 'u', 'tracer': 't', 

15 'clearstamp': 'cs', 'clearstamps': 'css', 'speed': 'spd'} 

16 

17class TurtleShortcutException(Exception): 

18 pass 

19 

20def sc(*args, turtle_obj=None, _return_turtle_code=False): # type: () -> int 

21 """TODO 

22 """ 

23 

24 """Supported commands: 

25 

26 f N - forward(N) 

27 b N - backward(N) 

28 l N - left(N) 

29 r N - right(N) 

30 h - home() 

31 c - clear() 

32 g X Y - goto(X, Y) 

33 tele X Y - teleport(X, Y) 

34 x X - setx(X) 

35 y Y - sety(Y) 

36 st - stamp() 

37 pd - pendown() 

38 pu - penup() 

39 ps N - pensize(N) 

40 pc RGB - pencolor(RGB) (RGB value can either be a single string like `red` or three dec/hex numbers `1.0 0.0 0.5` or `FF FF 00` 

41 fc RGB - fillcolor(RGB) 

42 bc RGB - bgcolor(RGB) 

43 sh N - setheading(N) 

44 cir N - circle(N) 

45 undo - undo() 

46 bf - begin_fill() 

47 ef - end_fill() 

48 reset - reset() 

49 

50 sleep N - time.sleep(N) 

51 

52 n N - setheading(90);forward(N) 

53 s N - setheading(270);forward(N) 

54 w N - setheading(180);forward(N) 

55 e N - setheading(0);forward(N) 

56 nw N - setheading(135);forward(N) 

57 ne N - setheading(45);forward(N) 

58 sw N - setheading(225);forward(N) 

59 se N - setheading(315);forward(N) 

60 north N - setheading(90);forward(N) 

61 south N - setheading(270);forward(N) 

62 west N - setheading(180);forward(N) 

63 east N - setheading(0);forward(N) 

64 northwest N - setheading(135);forward(N) 

65 northeast N - setheading(45);forward(N) 

66 southwest N - setheading(225);forward(N) 

67 southeast N - setheading(315);forward(N) 

68 

69 done - done() 

70 bye - bye() 

71 exitonclick - exitonclick() 

72 

73 t N1 N2 - tracer(N1, N2) 

74 u - update() 

75 

76 hide - hide() 

77 show - show() 

78 

79 dot N - dot(N) 

80 cs N - clearstamp(N) 

81 css N - clearstamps(N) 

82 degrees - degrees() 

83 radians - radians() 

84  

85 spd N - speed(N) but N can also be 'fastest', 'fast', 'normal', 'slow', 'slowest' 

86 !!shape N - shape(N) where N can be “arrow”, “turtle”, “circle”, “square”, “triangle”, “classic” 

87 !!resizemode N - resizemode(N) where N can be “auto”, “user”, or "noresize" 

88 !!bgpic N - bgpic(N) where the N filename cannot have a comma in it. 

89 

90 !!shapesize N1 N2 N3 - shapesize(N1, N2, N3) 

91 !!settiltangle N - settiltangle(N) 

92 !!tilt N - tilt(N) 

93 !!tiltangle N - tiltangle(N) 

94  

95 

96 

97 

98 Note:  

99 

100 

101 Furthermore, you can also use the full names: forward N translates to forward(N). 

102 Note: None of these functions can take string args that have spaces in them, since spaces are the arg delimiter here. 

103 Note: You also can't use variables here, only static values. But you can use f-strings. 

104 

105 Return value is the number of commands executed. 

106 Whitespace is insignificant. ' f 100 ' is the same as 'f 100' 

107 """ 

108 

109 """ 

110 

111  

112 """ 

113 # Join multiple arg strings into one, separated by commas: 

114 shortcuts = ','.join(args) 

115 

116 # Newlines become commas as well: 

117 shortcuts = shortcuts.replace('\n', ',') 

118 

119 if shortcuts == '' or len(shortcuts.split(',')) == 0: 

120 return 0 

121 

122 count_of_shortcuts_run = 0 

123 

124 # Go through and check that all shortcuts are syntactically correct: 

125 for shortcut in shortcuts.split(','): 

126 count_of_shortcuts_run += _run_shortcut(shortcut, turtle_obj=turtle_obj, dry_run=True) 

127 

128 # Go through and actually run all the shortcuts: 

129 count_of_shortcuts_run = 0 

130 turtle_code = tuple() 

131 for shortcut in shortcuts.split(','): 

132 if _return_turtle_code: 

133 turtle_code += _run_shortcut(shortcut, turtle_obj=turtle_obj, _return_turtle_code=True) 

134 else: 

135 count_of_shortcuts_run += _run_shortcut(shortcut, turtle_obj=turtle_obj) 

136 

137 if _return_turtle_code: 

138 return turtle_code 

139 else: 

140 return count_of_shortcuts_run 

141 

142 

143def _run_shortcut(shortcut, turtle_obj=None, dry_run=False, _return_turtle_code=False): 

144 if turtle_obj is None: 

145 turtle_obj = turtle # Use the main turtle given by the module. 

146 

147 # Clean up shortcut name from " FOrWARD " to "f", for example. 

148 shortcut_parts = shortcut.strip().split() 

149 if len(shortcut_parts) == 0: 

150 return 0 

151 _sc = shortcut_parts[0].lower() 

152 _sc = _MAP_FULL_TO_SHORT_NAMES.get(_sc, _sc) 

153 

154 # Check that the shortcut's syntax is valid: 

155 

156 if _sc not in ALL_SHORTCUTS: 

157 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: `' + shortcut_parts[0] + '` is not a turtle shortcut.') 

158 

159 raise_exception = False 

160 count_of_shortcuts_run = 0 

161 

162 

163 

164 # SHORTCUTS THAT TAKE A SINGLE NUMERIC ARGUMENT: 

165 if _sc in ('f', 'b', 'r', 'l', 'x', 'y', 'ps', 'sh', 'cir', 'sleep', 'n', 's', 'e', 'w', 'nw', 'ne', 'sw', 'se', 'dot', 'cs', 'spd'): 

166 if len(shortcut_parts) < 2: 

167 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: Missing the required numeric argument.') 

168 if len(shortcut_parts) > 2: 

169 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: Too many arguments.') 

170 

171 # Convert the string arguments for the `speed` shortcut to their numeric equivalents. 

172 if _sc == 'spd': 

173 shortcut_parts[1] = {'fastest': 0, 'fast': 10, 'normal': 6, 'slow': 3, 'slowest': 1}.get(shortcut_parts[1].lower(), shortcut_parts[1].lower()) 

174 

175 try: 

176 float(shortcut_parts[1]) 

177 except ValueError: 

178 raise_exception = True # We don't raise here so we can hide the original ValueError and make the stack trace a bit neater. 

179 if raise_exception: 

180 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: `' + shortcut_parts[1] + '` is not a number.') 

181 

182 # `dot` shortcut doesn't allow negative values: 

183 if _sc == 'dot' and float(shortcut_parts[1]) < 0: 

184 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: `dot` argument cannot be a negative number.') 

185 

186 if not dry_run: 

187 # Run the shortcut that has exactly one numeric argument: 

188 if _sc == 'f': 

189 if _return_turtle_code: 

190 return ('forward(' + shortcut_parts[1] + ')',) 

191 turtle_obj.forward(float(shortcut_parts[1])) 

192 elif _sc == 'b': 

193 if _return_turtle_code: 

194 return ('backward(' + shortcut_parts[1] + ')',) 

195 turtle_obj.backward(float(shortcut_parts[1])) 

196 elif _sc == 'r': 

197 if _return_turtle_code: 

198 return ('right(' + shortcut_parts[1] + ')',) 

199 turtle_obj.right(float(shortcut_parts[1])) 

200 elif _sc == 'l': 

201 if _return_turtle_code: 

202 return ('left(' + shortcut_parts[1] + ')',) 

203 turtle_obj.left(float(shortcut_parts[1])) 

204 elif _sc == 'x': 

205 if _return_turtle_code: 

206 return ('setx(' + shortcut_parts[1] + ')',) 

207 turtle_obj.setx(float(shortcut_parts[1])) 

208 elif _sc == 'y': 

209 if _return_turtle_code: 

210 return ('sety(' + shortcut_parts[1] + ')',) 

211 turtle_obj.sety(float(shortcut_parts[1])) 

212 elif _sc == 'ps': 

213 if _return_turtle_code: 

214 return ('pensize(' + shortcut_parts[1] + ')',) 

215 turtle_obj.pensize(float(shortcut_parts[1])) 

216 elif _sc == 'sh': 

217 if _return_turtle_code: 

218 return ('setheading(' + shortcut_parts[1] + ')',) 

219 turtle_obj.setheading(float(shortcut_parts[1])) 

220 elif _sc == 'cir': 

221 if _return_turtle_code: 

222 return ('circle(' + shortcut_parts[1] + ')',) 

223 turtle_obj.circle(float(shortcut_parts[1])) 

224 elif _sc == 'sleep': 

225 if _return_turtle_code: 

226 return ('sleep(' + shortcut_parts[1] + ')', ) 

227 time.sleep(float(shortcut_parts[1])) 

228 elif _sc in ('n', 's', 'e', 'w', 'nw', 'ne', 'sw', 'se'): 

229 originally_in_radians_mode = in_radians_mode() 

230 

231 if _return_turtle_code: 

232 if originally_in_radians_mode: 

233 return ('degrees()', 'setheading(' + CARDINAL_TO_DEGREES[_sc] + ')', 'forward(' + shortcut_parts[1] + ')', 'radians()') 

234 else: 

235 return ('setheading(' + CARDINAL_TO_DEGREES[_sc] + ')', 'forward(' + shortcut_parts[1] + ')') 

236 turtle.degrees() 

237 if _sc == 'n': 

238 turtle.setheading(90) 

239 elif _sc == 's': 

240 turtle.setheading(270) 

241 elif _sc == 'e': 

242 turtle.setheading(0) 

243 elif _sc == 'w': 

244 turtle.setheading(180) 

245 elif _sc == 'nw': 

246 turtle.setheading(135) 

247 elif _sc == 'ne': 

248 turtle.setheading(45) 

249 elif _sc == 'sw': 

250 turtle.setheading(225) 

251 elif _sc == 'se': 

252 turtle.setheading(315) 

253 else: # pragma: no cover 

254 assert False, 'Unhandled shortcut: ' + _sc 

255 turtle_obj.forward(float(shortcut_parts[1])) 

256 if originally_in_radians_mode: 

257 turtle.radians() 

258 elif _sc == 'dot': 

259 if _return_turtle_code: 

260 return ('dot(' + shortcut_parts[1] + ')',) 

261 turtle_obj.dot(float(shortcut_parts[1])) 

262 elif _sc == 'cs': 

263 if _return_turtle_code: 

264 return ('clearstamp(' + shortcut_parts[1] + ')',) 

265 turtle_obj.clearstamp(float(shortcut_parts[1])) 

266 elif _sc == 'spd': 

267 if _return_turtle_code: 

268 return ('speed(' + str(shortcut_parts[1]) + ')',) 

269 turtle_obj.speed(float(shortcut_parts[1])) 

270 else: # pragma: no cover 

271 assert False, 'Unhandled shortcut: ' + _sc 

272 count_of_shortcuts_run += 1 

273 

274 

275 

276 

277 

278 # SHORTCUTS THAT TAKE A SINGLE INTEGER ARGUMENT OR NONE ARGUMENT: 

279 elif _sc in ('css',): 

280 if len(shortcut_parts) > 2: 

281 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: Too many arguments.') 

282 

283 # Technically, the css shortcut can take a float argument, but it gets passed to int() silently. Not ideal, but not a big deal either. 

284 

285 if len(shortcut_parts) == 2: 

286 try: 

287 int(shortcut_parts[1]) 

288 except ValueError: 

289 raise_exception = True # We don't raise here so we can hide the original ValueError and make the stack trace a bit neater. 

290 if raise_exception: 

291 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: `' + shortcut_parts[1] + '` is not a number.') 

292 

293 if not dry_run: 

294 # Run the shortcut: 

295 if _sc == 'css': 

296 if len(shortcut_parts) == 1: 

297 if _return_turtle_code: 

298 return ('clearstamps()',) 

299 turtle_obj.clearstamps() 

300 elif len(shortcut_parts) == 2: 

301 if _return_turtle_code: 

302 return ('clearstamps(' + shortcut_parts[1] + ')',) 

303 turtle_obj.clearstamps(int(shortcut_parts[1])) 

304 else: # pragma: no cover 

305 assert False, 'Unhandled shortcut: ' + _sc 

306 else: # pragma: no cover 

307 assert False, 'Unhandled shortcut: ' + _sc 

308 count_of_shortcuts_run += 1 

309 

310 

311 

312 

313 

314 

315 # SHORTCUTS THAT TAKE EXACTLY TWO NUMERIC ARGUMENTS: 

316 elif _sc in ('g', 't', 'tele'): 

317 if len(shortcut_parts) < 3: 

318 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: Missing two required numeric argument.') 

319 elif len(shortcut_parts) > 3: 

320 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: Too many arguments.') 

321 

322 try: 

323 float(shortcut_parts[1]) 

324 except ValueError: 

325 raise_exception = True # We don't raise here so we can hide the original ValueError and make the stack trace a bit neater. 

326 if raise_exception: 

327 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: `' + shortcut_parts[1] + '` is not a number.') 

328 try: 

329 float(shortcut_parts[2]) 

330 except ValueError: 

331 raise_exception = True # We don't raise here so we can hide the original ValueError and make the stack trace a bit neater. 

332 if raise_exception: 

333 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: `' + shortcut_parts[2] + '` is not a number.') 

334 

335 if not dry_run: 

336 # Run the shortcut that has exactly two numeric arguments: 

337 x = float(shortcut_parts[1]) 

338 y = float(shortcut_parts[2]) 

339 

340 # Run the shortcut: 

341 if _sc == 'g': 

342 if _return_turtle_code: 

343 return ('goto(' + shortcut_parts[1] + ', ' + shortcut_parts[2] + ')',) 

344 turtle_obj.goto(x, y) 

345 elif _sc == 't': 

346 if _return_turtle_code: 

347 return ('tracer(' + shortcut_parts[1] + ', ' + shortcut_parts[2] + ')',) 

348 turtle.tracer(x, y) # Note: tracer() is not a Turtle method, there's only the global tracer() function. 

349 elif _sc == 'tele': 

350 if _return_turtle_code: 

351 return ('teleport(' + shortcut_parts[1] + ', ' + shortcut_parts[2] + ')',) 

352 turtle_obj.teleport(x, y) 

353 else: # pragma: no cover 

354 assert False, 'Unhandled shortcut: ' + _sc 

355 count_of_shortcuts_run += 1 

356 

357 

358 

359 

360 

361 # SHORTCUTS THAT TAKE EXACTLY ZERO ARGUMENTS: 

362 elif _sc in ('h', 'c', 'st', 'pd', 'pu', 'undo', 'bf', 'ef', 'reset', 'bye', 'done', 'exitonclick', 'u', 'show', 'hide'): 

363 if len(shortcut_parts) > 1: 

364 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: This shortcut does not have arguments.') 

365 

366 if not dry_run: 

367 # Run the shortcut that has exactly zero arguments: 

368 if _sc == 'h': 

369 if _return_turtle_code: 

370 return ('home()',) 

371 turtle_obj.home() 

372 elif _sc == 'c': 

373 if _return_turtle_code: 

374 return ('clear()',) 

375 turtle_obj.clear() 

376 elif _sc == 'st': 

377 if _return_turtle_code: 

378 return ('stamp()',) 

379 turtle_obj.stamp() 

380 elif _sc == 'pd': 

381 if _return_turtle_code: 

382 return ('pendown()',) 

383 turtle_obj.pendown() 

384 elif _sc == 'pu': 

385 if _return_turtle_code: 

386 return ('penup()',) 

387 turtle_obj.penup() 

388 elif _sc == 'undo': 

389 if _return_turtle_code: 

390 return ('undo()',) 

391 turtle_obj.undo() 

392 elif _sc == 'bf': 

393 if _return_turtle_code: 

394 return ('begin_fill()',) 

395 turtle_obj.begin_fill() 

396 elif _sc == 'ef': 

397 if _return_turtle_code: 

398 return ('end_fill()',) 

399 turtle_obj.end_fill() 

400 elif _sc == 'reset': 

401 if _return_turtle_code: 

402 return ('reset()',) 

403 turtle_obj.reset() 

404 elif _sc == 'bye': # pragma: no cover 

405 if _return_turtle_code: 

406 return ('bye()',) 

407 turtle_obj.bye() 

408 elif _sc == 'done': # pragma: no cover 

409 if _return_turtle_code: 

410 return ('done()',) 

411 turtle_obj.done() 

412 elif _sc == 'exitonclick': # pragma: no cover 

413 if _return_turtle_code: 

414 return ('exitonclick()',) 

415 turtle_obj.exitonclick() 

416 elif _sc == 'u': 

417 if _return_turtle_code: 

418 return ('update()',) 

419 turtle_obj.update() 

420 elif _sc == 'show': 

421 if _return_turtle_code: 

422 return ('showturtle()',) 

423 turtle_obj.showturtle() 

424 elif _sc == 'hide': 

425 if _return_turtle_code: 

426 return ('hideturtle()',) 

427 turtle_obj.hideturtle() 

428 else: # pragma: no cover 

429 assert False, 'Unhandled shortcut: ' + _sc 

430 count_of_shortcuts_run += 1 

431 

432 

433 

434 # SHORTCUTS THAT TAKE AN RGB OR COLOR ARGUMENT: 

435 elif _sc in ('pc', 'fc', 'bc'): 

436 if len(shortcut_parts) < 2: 

437 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: Missing required RGB argument.') 

438 elif len(shortcut_parts) not in (2, 4): 

439 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: Invalid RGB argument. It must either be a color name like `red` or three numbers like `1.0 0.5 0.0` or `255 0 255` or `FF 00 FF`.') 

440 

441 color_arg_is_color_name = False 

442 

443 if len(shortcut_parts) == 4: 

444 # We expect the color arg to either be something like (255, 0, 0) or (1.0, 0.0, 0.0): 

445 raise_exception = False 

446 

447 try: 

448 float(shortcut_parts[1]) 

449 except ValueError: 

450 raise_exception = True # We don't raise here so we can hide the original ValueError and make the stack trace a bit neater. 

451 if raise_exception: 

452 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: `' + shortcut_parts[1] + '` is not a number.') 

453 

454 try: 

455 float(shortcut_parts[2]) 

456 except ValueError: 

457 raise_exception = True # We don't raise here so we can hide the original ValueError and make the stack trace a bit neater. 

458 if raise_exception: 

459 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: `' + shortcut_parts[2] + '` is not a number.') 

460 

461 try: 

462 float(shortcut_parts[3]) 

463 except ValueError: 

464 raise_exception = True # We don't raise here so we can hide the original ValueError and make the stack trace a bit neater. 

465 if raise_exception: 

466 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: `' + shortcut_parts[3] + '` is not a number.') 

467 

468 color_arg = (float(shortcut_parts[1]), float(shortcut_parts[2]), float(shortcut_parts[3])) 

469 elif len(shortcut_parts) == 2: 

470 # We expect the color arg to be a string like 'blue' or 'ff0000' or '#FF0000: 

471 raise_exception = False 

472 

473 # If the argument is an RGB value, convert to numbers: 

474 shortcut_parts[1] = shortcut_parts[1].strip('#') 

475 

476 # Lowercase possible color names: 

477 shortcut_parts[1] = shortcut_parts[1].lower() 

478 

479 if re.match(r'^[0-9a-f]{6}$', shortcut_parts[1]): 

480 # Convert hex color to decimal color: 

481 if turtle_obj.colormode() == 255: 

482 color_arg = (int(shortcut_parts[1][0:2], 16), int(shortcut_parts[1][2:4], 16), int(shortcut_parts[1][4:6], 16)) 

483 elif turtle_obj.colormode() == 1.0: 

484 color_arg = (int(shortcut_parts[1][0:2], 16) / 255.0, int(shortcut_parts[1][2:4], 16) / 255.0, int(shortcut_parts[1][4:6], 16) / 255.0) 

485 else: # pragma: no cover 

486 assert False, 'Unknown return value from turtle.colormode(): ' + str(turtle_obj.colormode()) 

487 else: 

488 # shortcut_parts[1] must be a color name like 'blue' 

489 color_arg = shortcut_parts[1] 

490 color_arg_is_color_name = True 

491 

492 # Test the color name by actually calling pencolor(): 

493 original_pen_color = turtle_obj.pencolor() 

494 try: 

495 turtle_obj.pencolor(color_arg) 

496 except turtle.TurtleGraphicsError: 

497 raise_exception = True # We don't raise here so we can hide the original TurtleGraphicsError and make the stack trace a bit neater. 

498 if raise_exception: 

499 raise TurtleShortcutException('Syntax error in `' + shortcut + '`: `' + shortcut_parts[1] + '` is not a valid color.') 

500 turtle_obj.pencolor(original_pen_color) 

501 

502 if not dry_run: 

503 if isinstance(color_arg, tuple): 

504 temp_switch_to_mode_255 = len(color_arg) == 3 and turtle_obj.colormode() == 1.0 and (color_arg[0] > 1.0 or color_arg[1] > 1.0 or color_arg[2] > 1.0) 

505 temp_switch_to_mode_1 = len(color_arg) == 3 and turtle_obj.colormode() == 255 and (0.0 <= color_arg[0] <= 1.0 and 0.0 <= color_arg[1] <= 1.0 and 0.0 <= color_arg[2] <= 1.0) 

506 assert not (temp_switch_to_mode_255 and temp_switch_to_mode_1) 

507 else: 

508 temp_switch_to_mode_255 = False 

509 temp_switch_to_mode_1 = False 

510 

511 if temp_switch_to_mode_255: 

512 turtle_obj.colormode(255) 

513 color_arg = (int(color_arg[0]), int(color_arg[1]), int(color_arg[2])) 

514 elif temp_switch_to_mode_1: 

515 turtle_obj.colormode(1.0) 

516 

517 # Return the turtle code, if that was asked: 

518 if _return_turtle_code: 

519 if _sc == 'pc': 

520 func_name_prefix = 'pen' 

521 elif _sc == 'fc': 

522 func_name_prefix = 'fill' 

523 elif _sc == 'bc': 

524 func_name_prefix = 'bg' 

525 

526 if temp_switch_to_mode_255: 

527 turtle_obj.colormode(1.0) 

528 return ('colormode(255)', func_name_prefix + 'color(' + str(color_arg) + ')', 'colormode(1.0)') 

529 elif temp_switch_to_mode_1: 

530 turtle_obj.colormode(255) 

531 return ('colormode(1.0)', func_name_prefix + 'color(' + str(color_arg) + ')', 'colormode(255)') 

532 else: 

533 if color_arg_is_color_name: 

534 return (func_name_prefix + "color('" + str(color_arg) + "')",) 

535 else: 

536 return (func_name_prefix + 'color(' + str(color_arg) + ')',) 

537 

538 

539 # Run the shortcut that has an RGB color argument: 

540 if _sc == 'pc': 

541 turtle_obj.pencolor(color_arg) 

542 elif _sc == 'fc': 

543 turtle_obj.fillcolor(color_arg) 

544 elif _sc == 'bc': 

545 turtle_obj.bgcolor(color_arg) 

546 else: # pragma: no cover 

547 assert False, 'Unhandled shortcut: ' + _sc 

548 count_of_shortcuts_run += 1 

549 

550 if temp_switch_to_mode_255: 

551 turtle_obj.colormode(1.0) 

552 elif temp_switch_to_mode_1: 

553 turtle_obj.colormode(255) 

554 

555 return count_of_shortcuts_run 

556 

557 

558def in_radians_mode(): 

559 """Returns True if turtle is in radians mode, False if in degrees mode.""" 

560 original_heading = turtle.heading() 

561 turtle.left(1) 

562 turtle.radians() # Switch to radians mode. 

563 turtle.right(1) 

564 if turtle.heading() == original_heading: 

565 return True 

566 else: 

567 turtle.degrees() # Switch back to degrees mode. 

568 return False 

569 

570 

571def in_degrees_mode(): 

572 """Returns True if turtle is in degrees mode, False if in radians mode.""" 

573 return not in_radians_mode() 

574 

575 

576def get_turtle_code(*args): 

577 """Returns the Python code that would be executed by the sc() function.""" 

578 return sc(*args, _return_turtle_code=True)