v                       
                                                          
                                                          
                                                          
                                                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                   Animating with ASCII                   
                                                          
               (Or, An Analysis Of The Code               
                Behind My PyCon 2017 Talk)                
                                                          
                                                          
                         Keynote                          
                  North Bay Python 2017                   
                     @brandon_rhodes                      
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                     PyCon 2017 talk                      
                   used ASCII animation                   
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                     PyCon 2017 talk                      
                   used ASCII animation                   
                                                          
                          (demo)                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                     PyCon 2017 talk                      
                   used ASCII animation                   
                                                          
                   “How did you do it?”                   
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                     PyCon 2017 talk                      
                   used ASCII animation                   
                                                          
                   “How did you do it?”                   
                         “Badly”                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                 Guardrails for My Talks                  
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                    1. Per-slide timer                    
                                                          
      number_of_seconds_left / number_of_slides_left      
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
              2. Constrain the design space               
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
              2. Constrain the design space               
                                                          
                  Normal presentations:                   
          RestructuredText →  HTML + Custom CSS           
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
              2. Constrain the design space               
                                                          
                  Normal presentations:                   
          RestructuredText →  HTML + Custom CSS           
                                                          
                   ASCII presentations:                   
                    • Python script                       
                    • Terminal window                     
                    • Ubuntu Mono                         
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                     3. Brief slides                      
                                                          
                          Lessig                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                  Short slides are less                   
                 distracting for audience                 
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                       Short slides                       
                    keep you on track                     
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                  Short slides decrease                   
                 the load on your memory                  
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
           Rule: if I discover during practice            
            that a slide has two ideas inside,            
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
           Rule: if I discover during practice            
            that a slide has two ideas inside,            
                I split it into two slides                
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                       4. Big font                        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                       4. Big font                        
                                                          
            This is the biggest terminal font             
           that still fits the code on slide 86           
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                 Guardrails for My Talks                  
                                                          
              1. Per-slide timer                          
              2. Constrain the design space               
              3. Brief slides                             
              4. Big font                                 
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                        PyCon 2017                        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                        PyCon 2017                        
                                                          
           Wrote my own ASCII animation library           
         because I couldn’t understand the others         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                        Challenges                        
                                                          
                     1. Technical                         
                     2. Architectural                     
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                 The Technical Challenges                 
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
              f / space = Forward one slide               
              b = Backward one slide                      
              r = Repeat slide                            
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
              keystroke = sys.stdin.read(1)               
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
              keystroke = sys.stdin.read(1)               
                                                          
                  — the animation froze                   
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
          if select([sys.stdin], (), (), 0)[0]:           
              keystroke = sys.stdin.read(1)               
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
            But my program still didn’t see my            
             keystrokes until I pressed Enter             
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                     You might think                      
                                                          
                (your process) ↔  terminal                
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                    You would be wrong                    
                                                          
          (your process) ↔  termios ↔  terminal           
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                         termios                          
                                                          
            controlled not by write(), but an             
           out-of-band system call tcsetattr()            
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                   “man termios”, or —                    
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
$ stty -a                                                 
speed 38400 baud; rows 17; columns 56; line = 0;          
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D;    
eol = ; eol2 = ; swtch = ;           
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;             
werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0; 
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal  
-crtscts                                                  
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr     
-igncr icrnl -ixon -ixoff -iuclc -ixany -imaxbel iutf8    
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel    
nl0 cr0 tab0 bs0 vt0 ff0                                  
isig icanon iexten echo echoe echok -echonl -noflsh       
-xcase -tostop -echoprt echoctl echoke -flusho -extproc   
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
     Why have a driver between you and the terminal?      
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
      $ man termios                                       
                                                         
             ONLCR  (XSI) Map NL to CR-NL on output.      
                                                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
             CR: Moves cursor to left margin              
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
             CR: Moves cursor to left margin              
                                                          
                                                          
  def update_progress_bar(percent):                       
      out = sys.stdout                                    
      out.write('\rFile {:.1f}% done'.format(percent))    
      out.flush()                                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
              LF: Moves cursor straight down              
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                     For simplicity,                      
                 UNIX files put only a LF                 
                 at the end of each line                  
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
$ ps                                                      
  PID TTY          TIME CMD                               
 3712 pts/0    00:00:04 zsh                               
 4412 pts/0    00:00:00 ps                                
 8375 pts/0    00:23:22 emacs                             
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
$ ps                                                      
  PID TTY          TIME CMD                               
 3712 pts/0    00:00:04 zsh                               
 4412 pts/0    00:00:00 ps                                
 8375 pts/0    00:23:22 emacs                             
                                                          
$ stty -onlcr                                             
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
$ ps                                                      
  PID TTY          TIME CMD                               
 3712 pts/0    00:00:04 zsh                               
 4412 pts/0    00:00:00 ps                                
 8375 pts/0    00:23:22 emacs                             
                                                          
$ stty -onlcr                                             
                                                          
$ ps                                                      
  PID TTY          TIME CMD                               
                            3712 pts/0    00:00:04 zsh    
                                                       442
2 pts/0    00:00:00 ps                                    
                      8375 pts/0    00:23:22 emacs        
                                                  $       
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
           $ man termios                                  
                                                         
                  ECHO   Echo input characters.           
                                                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                 termios also includes a                  
                  built-in TEXT EDITOR —                  
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                 termios also includes a                  
                  built-in TEXT EDITOR —                  
                                                          
               that’s turned on by default!               
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
  $ man termios                                           
                                                         
         ICANON Enable canonical mode (described below).  
                                                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
  $ man termios                                           
  ⋮                                                       
         ICANON Enable canonical mode (described below).  
  ⋮                                                       
                                                          
                          (demo)                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                         $ reset                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                         $ reset                          
                                                          
                         man page:                        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                         $ reset                          
                                                          
                         man page:                        
                                                          
  “This is useful after a program dies leaving a          
   terminal in an abnormal state.  Note, you may have to  
   type reset (the line-feed character is         
   normally control-J) to get the terminal to work, as    
   carriage-return may no longer work in the abnormal     
   state.”                                                
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                    >>> import termios                    
                    >>> termios.ICANON                    
                    2                                     
                    >>> termios.ECHO                      
                    8                                     
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                 >>> bin(termios.ICANON)                  
                 '0b10'                                   
                 >>> bin(termios.ECHO)                    
                 '0b1000'                                 
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                    Turning flags on:                     
                                                          
          >>> oflags = termios.tcgetattr(fd)[3]           
                                                          
          >>> bin(oflags)                                 
          '0b1000101000110011                             
                                                          
          >>> oflags = oflags | termios.ECHO              
                                                          
          >>> bin(oflags)                                 
          '0b1000101000111011'                            
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                    Turning flags off:                    
                                                          
           >>> bin(~termios.ECHO + 2**32)                 
           '0b11111111111111111111111111110111'           
                                                          
           >>> oflags = oflags & ~termios.ECHO            
                                                          
           >>> bin(oflags)                                
           '0b1000101000110011'                           
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
               So, what about the terminal?               
                                                          
          (your process) ↔  termios ↔  terminal           
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
           ANSI escape codes: “in-band” signal            
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                        train.txt                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
          ESC = '\033'                                    
          HIDE_CURSOR = ESC + '[?25l'                     
          SHOW_CURSOR = ESC + '[?12l' + ESC + '[?25h'     
          GOTO_ORIGIN = ESC + '[H'                        
          FG = ESC + '[38;2;{0[0]};{0[1]};{0[2]}m'        
          BG = ESC + '[48;2;{0[0]};{0[1]};{0[2]}m'        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
             try:                                         
                 set_echo_and_icanon(0)                   
                 write(HIDE_CURSOR)                       
                 ...                                      
             finally:                                     
                 set_echo_and_icanon(1)                   
                 write(SHOW_CURSOR)                       
                 write(BG.format(rgb(black)))             
                 write(FG.format(rgb(white)))             
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                           2.7                            
                           3.5                            
                           3.6                            
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                          exec()                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                          exec()                          
                                                          
            Replaces a process with a new one             
        without leaving a dangling parent process         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
               zsh$ ps                                    
                 PID TTY          TIME CMD                
                7807 pts/16   00:00:00 zsh                
                7975 pts/16   00:00:00 ps                 
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
               zsh$ ps                                    
                 PID TTY          TIME CMD                
                7807 pts/16   00:00:00 zsh                
                7975 pts/16   00:00:00 ps                 
                                                          
               zsh$ exec /bin/bash                        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
               zsh$ ps                                    
                 PID TTY          TIME CMD                
                7807 pts/16   00:00:00 zsh                
                7975 pts/16   00:00:00 ps                 
                                                          
               zsh$ exec /bin/bash                        
                                                          
               bash$ ps                                   
                 PID TTY          TIME CMD                
                7807 pts/16   00:00:00 bash               
                7993 pts/16   00:00:00 ps                 
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
      python = ...  # path to correct binary              
      os.execvp(python, [python], next_slide_number)      
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
      python = ...  # path to correct binary              
      os.execvp(python, [python], next_slide_number)      
                                                          
     • Each slide can have a different Python version     
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
      python = ...  # path to correct binary              
      os.execvp(python, [python], next_slide_number)      
                                                          
     • Each slide can have a different Python version     
     • No need for auto-reload!                           
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                   Dictionary stability                   
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
   def main():                                            
       if os.environ['PYTHONHASHSEED'] != '0':            
           print("You forgot to set PYTHONHASHSEED=0")    
           sys.exit(2)                                    
       ...                                                
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
       def main():                                        
           if os.environ['PYTHONHASHSEED'] != '0':        
               cmd = [sys.executable] + sys.argv          
               env = dict(os.environ)                     
               env['PYTHONHASHSEED'] = '0'                
               os.execvpe(sys.executable, cmd, env)       
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                        Challenges                        
                                                          
                     1. Technical                         
                     2. Architectural                     
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
              How can I store the screen to               
            allow random-access modification?             
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
              How can I store the screen to               
            allow random-access modification?             
                                                          
        canvas = [                                        
            [' ', ' ', ' ', ...],    # characters         
            [(1,1,1), (1,1,1), ...], # foreground         
            [(0,0,0), (0,0,0), ...], # background         
        ]                                                 
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
        def scrawl(canvas, x, y, text, fg, bg):           
            i = y * WIDTH + x                             
            j = i + len(string)                           
            chars, foreground, background = canvas        
            chars[i:j] = text                             
            fgcolors[i:j] = [fg] * len(string)            
            bgcolors[i:j] = [bg] * len(string)            
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
       yield GOTO_ORIGIN                                  
                                                          
       old_fg, old_bg = None, None                        
                                                          
       for character, fg, bg in zip(*canvas)[:-1]:        
           if fg != ofg:                                  
               yield FG.format(fg)                        
               ofg = fg                                   
           if bg != obg:                                  
               yield BG.format(bg)                        
               obg = bg                                   
           yield character                                
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                     How did I write                      
                animations using scrawl()?                
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
             Animations unfold through time               
                                                          
           ├─effect 1─┤                                   
                      ├────effect 2────┤                  
                                 ├─effect 3─┤             
                                                          
           ├──────────┼──────────┼──────────┤             
           0s         1s         2s         3s            
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
             Animations unfold through time               
                                                          
           ├─effect 1─┤                                   
                      ├────effect 2────┤                  
                                 ├─effect 3─┤             
                                                          
           ├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤             
           0s         1s         2s         3s            
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
          script = [                                      
              [function1],             # frame 1          
              [function1],             # frame 2          
              [function2],             # frame 3          
              [function2, function3],  # frame 4          
              [function2, function3],  # frame 5          
              [function3],             # frame 6          
              ...                                         
          ]                                               
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                    Sample animation:                     
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                        Beautiful                         
                        is better                         
                        than ugly                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
     def slide_5(script):                                 
         fade_in(script, 0.0, 1.0, 5, 5, 'Beautiful')     
         fade_in(script, 1.0, 1.0, 5, 6, 'is better')     
         fade_in(script, 2.0, 1.0, 5, 7, 'than ugly')     
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
          script = [                                      
              [function1],             # frame 1          
              [function1],             # frame 2          
              [function2],             # frame 3          
              [function2, function3],  # frame 4          
              ...                                         
                                                          
                 fade_in() needs a callable               
                 to insert into the script                
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                         Option 1:                        
                       Bound method                       
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
class FadeIn(object):                                     
    def __init__(self, script, start, duration, x, y, s): 
        self.duration = duration                          
        self.x = x                                        
        self.y = y                                        
        self.string = s                                   
        end = start + duration                            
        for i in range(int(start * HZ), int(end * HZ)):   
            script[i].append(self.draw)                   
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
class FadeIn(object):                                     
    def __init__(self, script, start, duration, x, y, s): 
        self.duration = duration                          
        self.x = x                                        
        self.y = y                                        
        self.string = s                                   
        end = start + duration                            
        for i in range(int(start * HZ), int(end * HZ)):   
            script[i].append(self.draw)                   
                                                          
    def draw(self, t, canvas):  # `t`: time since `start` 
        r = t / self.duration if t < self.duration else 1 
        fg = gray(r)                                      
        scrawl(canvas, self.x, self.y, self.string, fg)   
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                        Option 2:                         
                        A closure                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
   def fade_in(script, start, duration, x, y, string):    
                                                          
       def draw(t, canvas):                               
           r = t / duration if t < duration else 1.0      
           scrawl(canvas, x, y, string, gray(r))          
                                                          
       end = start + duration                             
       for i in range(int(start * HZ), int(end * HZ)):    
           script[i].append(draw)                         
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
           Problem: what if the text I need to            
          fade is itself produced by a function?          
                                                          
                def draw_dictionary(...):                 
                                                          
                                                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
  def fade_in(script, start, duration, x, y, animation):  
                                                          
      def draw(t, canvas):                                
          r = t / duration if t < duration else 1.0       
          ?                                               
          ... animation(t, canvas) ...                    
          ?                                               
                                                          
      end = start + duration                              
      for i in range(int(start * HZ), int(end * HZ)):     
          script[i].append(draw)                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                  Monkey patch scrawl()?                  
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                            No                            
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                            No                            
                                                          
          Monkey patching is software bankruptcy          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
          Problem: animations aren’t composable           
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                   Crucial observation:                   
                                                          
            `canvas` is never actually touched            
               by an effect like fade_in()!               
                                                          
                                                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                  Solution: Noun →  Verb                  
                  ───────────────────────                 
                                                          
         def draw(t, canvas):                             
             scrawl(canvas, 4, 5, 'Hello', blue)          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                  Solution: Noun →  Verb                  
                  ───────────────────────                 
                                                          
         def draw(t, canvas):                             
             scrawl(canvas, 4, 5, 'Hello', blue)          
                                                          
                                                         
                                                          
         def draw(t, scrawl):                             
             scrawl(4, 5, 'Hello', blue)                  
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                    Win: Composability                    
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
    def fade_in(script, start, duration, animation):      
                                                          
        def draw(t, scrawl):                              
                                                          
            def my_scrawl(x, y, text, fg, bg):            
                faded_fg = blend(bg, fg, r)               
                scrawl(x, y, text, faded_fg, bg)          
                                                          
            r = t / duration if t < duration else 1.0     
            animation(t, my_scrawl)                       
                                                          
        for i in range(int(start * HZ), len(script)):     
            script[i].append(self.draw)                   
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                        PyCon 2017                        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                        PyCon 2017                        
                                                          
                SO MANY WRAPPER FUNCTIONS                 
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                          Review                          
                                                          
                                                          
fade_in(script,...)                                       
                                                         
└draw(t,scrawl,…)  d_dict(t,scrawl,…)  d_item(t,scrawl,…) 
 │                 │                                      
 └my_scrawl(...)   └my_scrawl(...)                        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                       Let’s trace—                       
                                                          
                                                          
fade_in(script,...)                                       
                                                          
 draw(t,scrawl,…)  d_dict(t,scrawl,…)  d_item(t,scrawl,…) 
                                                          
  my_scrawl(...)    my_scrawl(...)                        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
          1. fade_in() call as slide is built             
                                                          
                                                         
fade_in(script,...)                                       
                                                         
 draw(t,scrawl,…)  d_dict(t,scrawl,…)  d_item(t,scrawl,…) 
                                                          
  my_scrawl(...)    my_scrawl(...)                        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
               2. draw() to paint a canvas                
                                                          
                                                          
fade_in(script,...)                                       
                                                         
 draw(t,scrawl,…)→ d_dict(t,scrawl,…)→ d_item(t,scrawl,…) 
                                                         
← my_scrawl(...)  ← my_scrawl(...)     ↲                  
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                    1. It worked                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                    1. It worked                          
                    2. I wasn’t happy                     
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                   Think about the data                   
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                   t=105                t=105             
                                                         
 draw(t,scrawl,…)→ d_dict(t,scrawl,…)→ d_item(t,scrawl,…) 
                                                         
← my_scrawl(...)  ← my_scrawl(...)     ↲                  
                                                          
6,7,'[item]',gray  5,6,'[item]',black  0,1,'item',black   
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
          Can we create a “good parts” version?           
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                   “No-Scrawl” Solution                   
                                                          
                Restructure to explicitly                 
                defer drawing until later                 
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                        New design                        
                                                          
        `frame`: list [(x, y, text, fg, bg), ...]         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                        New design                        
                                                          
        `frame`: list [(x, y, text, fg, bg), ...]         
        `animation`: generator that returns frames        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                        Beautiful                         
                        is better                         
                        than ugly                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
      def center_text(y, text, fg=black, bg=white):       
          """Center `text` at height `y`."""              
          x = (WIDTH - len(text)) // 2                    
          frame = [(x, y, text, fg, bg)]                  
          while True:                                     
              yield frame                                 
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
   def fade_in(duration, animation):                      
       """Fade another animation into visibility."""      
                                                          
       levels = [i / duration for i in range(duration)]   
                                                          
       for level, frame in zip(levels, animation):        
           yield [                                        
               (x, y, text, blend(bg, fg, level), bg)     
               for (x, y, text, fg, bg) in frame          
           ]                                              
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
     def concat(*args):                                   
         """Run several animations simultaneously."""     
         for frames in zip(*args):                        
             yield [tup for frame in frames               
                        for item in frame]                
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
 def zen():                                               
     line1 = center_text(5, 'Beautiful')                  
     line2 = center_text(6, 'is better')                  
     line3 = center_text(7, 'than ugly')                  
                                                          
     yield from fade_in(line1, HZ)                        
     yield from concat(line1, fade_in(line2, HZ))         
     yield from concat(line1, line2, fade_in(line3, HZ))  
     yield next(line1) + next(line2) + next(line3)        
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                                                          
                                                          
                        Beautiful                         
                        is better                         
                        than ugly                         
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                        Challenges                        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                        Challenges                        
                                                          
                   1. Technical: A                        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                        Challenges                        
                                                          
                   1. Technical: A                        
                   2. Architectural: C-                   
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                                                          
                        Challenges                        
                                                          
                   1. Technical: A                        
                   2. Architectural: C-                   
                                                          
            My code wound up more complicated             
         than the problem it was trying to solve          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                        Conclusion                        
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                        Conclusion                        
                                                          
                  You can give the talk                   
                 “The Clean Architecture”                 
                 at PyCon Ireland in 2014                 
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
                                                          
----------------------------------------------------------
                                                          
                                                          
                        Conclusion                        
                                                          
                  You can give the talk                   
                 “The Clean Architecture”                 
                 at PyCon Ireland in 2014                 
                                                          
                   — and still struggle                   
                   to produce code that                   
                     is shaped enough                     
                      like its data