Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Flask Basics

Flask Basics

Python CodeLabs - Introduction to Flask
http://eueung.github.io/python/flask-basics

Eueung Mulyana

November 28, 2015
Tweet

More Decks by Eueung Mulyana

Other Decks in Programming

Transcript

  1. < u l > { % f o r r

    o w i n r o w s % } < l i > { { r o w } } < / l i > { % e n d f o r % } < / u l > templates/rows.jinja2.html f r o m f l a s k i m p o r t F l a s k , r e n d e r _ t e m p l a t e a p p = F l a s k ( " a p p " ) a p p . d e b u g = T r u e d e f t o p _ a r t i c l e s ( ) : r e t u r n [ { " t i t l e " : " G o o g l e " , " l i n k " : " h t t p : / / g o o g l e . c o m " , " d a t e " { " t i t l e " : " Y a h o o " , " l i n k " : " h t t p : / / y a h o o . c o m " , " d a t e " ] @ a p p . r o u t e ( ' / ' ) d e f i n d e x ( ) : a r t i c l e s = t o p _ a r t i c l e s ( ) r e t u r n r e n d e r _ t e m p l a t e ( " r o w s . j i n j a 2 . h t m l " , r o w s = a r t i c l e s ) P O R T = 4 0 0 1 a p p . r u n ( h o s t = " 0 . 0 . 0 . 0 " , p o r t = P O R T , u s e _ r e l o a d e r = F a l s e ) Example #1 3 / 20
  2. Example #2 Notes: If you enable debug support the server

    will reload itself on code changes, and it will also provide you with a helpful debugger if things go wrong The route() decorator Default Port 5000 f r o m f l a s k i m p o r t F l a s k a p p = F l a s k ( _ _ n a m e _ _ ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @ a p p . r o u t e ( ' / ' ) d e f i n d e x ( ) : r e t u r n ' I n d e x P a g e ' @ a p p . r o u t e ( ' / h e l l o ' ) d e f h e l l o ( ) : r e t u r n ' H e l l o W o r l d ' # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : # a p p . r u n ( ) a p p . r u n ( h o s t = ' 0 . 0 . 0 . 0 ' ) # a p p . d e b u g = T r u e # a p p . r u n ( d e b u g = T r u e ) hello.py 4 / 20
  3. Example #3 Notes: Variable rules Unique URLs / redirection behaviours:

    trailing / vs. none @ a p p . r o u t e ( ' / u s e r / < u s e r n a m e > ' ) d e f s h o w _ u s e r _ p r o f i l e ( u s e r n a m e ) : # s h o w t h e u s e r p r o f i l e f o r t h a t u s e r r e t u r n ' U s e r % s ' % u s e r n a m e @ a p p . r o u t e ( ' / p o s t / < i n t : p o s t _ i d > ' ) d e f s h o w _ p o s t ( p o s t _ i d ) : # s h o w t h e p o s t w i t h t h e g i v e n i d , t h e i d i s a n i n t e g e r r e t u r n ' P o s t % d ' % p o s t _ i d @ a p p . r o u t e ( ' / p r o j e c t s / ' ) d e f p r o j e c t s ( ) : r e t u r n ' T h e p r o j e c t p a g e ' @ a p p . r o u t e ( ' / a b o u t ' ) d e f a b o u t ( ) : r e t u r n ' T h e a b o u t p a g e ' R u n n i n g o n h t t p : / / 0 . 0 . 0 . 0 : 5 0 0 0 / ( P r e s s C T R L + C t o q u i t ) 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 7 : 2 2 : 0 1 ] " G E T / u s e r H T T P / 1 . 1 " 4 0 4 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 7 : 2 2 : 2 4 ] " G E T / u s e r / o t o n g H T T P / 1 . 1 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 7 : 2 6 : 1 1 ] " G E T / p o s t H T T P / 1 . 1 " 4 0 4 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 7 : 2 6 : 2 3 ] " G E T / p o s t / 2 H T T P / 1 . 1 " 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 7 : 2 6 : 5 9 ] " G E T / p o s t / o t o n g H T T P / 1 . 1 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 7 : 2 7 : 5 2 ] " G E T / p r o j e c t s H T T P / 1 . 1 " 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 7 : 2 7 : 5 2 ] " G E T / p r o j e c t s / H T T P / 1 . 1 " 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 7 : 2 8 : 3 0 ] " G E T / p r o j e c t s / H T T P / 1 . 1 " 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 7 : 2 9 : 0 1 ] " G E T / a b o u t H T T P / 1 . 1 " 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 7 : 2 9 : 0 5 ] " G E T / a b o u t / H T T P / 1 . 1 " 5 / 20
  4. Example #4 URL Building ... Static Files u r l

    _ f o r ( ' s t a t i c ' , f i l e n a m e = ' s t y l e . c s s ' ) # s t a t i c / s t y l e . c s s f r o m f l a s k i m p o r t F l a s k , u r l _ f o r a p p = F l a s k ( _ _ n a m e _ _ ) @ a p p . r o u t e ( ' / ' ) d e f i n d e x ( ) : p a s s @ a p p . r o u t e ( ' / l o g i n ' ) d e f l o g i n ( ) : p a s s @ a p p . r o u t e ( ' / u s e r / < u s e r n a m e > ' ) d e f p r o f i l e ( u s e r n a m e ) : p a s s w i t h a p p . t e s t _ r e q u e s t _ c o n t e x t ( ) : p r i n t u r l _ f o r ( ' i n d e x ' ) p r i n t u r l _ f o r ( ' l o g i n ' ) p r i n t u r l _ f o r ( ' l o g i n ' , n e x t = ' / ' ) p r i n t u r l _ f o r ( ' p r o f i l e ' , u s e r n a m e = ' J o h n D o e ' ) $ p y t h o n a p p . p y / / l o g i n / l o g i n ? n e x t = % 2 F / u s e r / J o h n % 2 0 D o e 6 / 20
  5. f r o m f l a s k i

    m p o r t F l a s k , r e q u e s t a p p = F l a s k ( _ _ n a m e _ _ ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - d e f d o _ t h e _ l o g i n ( ) : r e t u r n ' D o L o g i n ' d e f s h o w _ t h e _ l o g i n _ f o r m ( ) : r e t u r n ' S h o w F o r m ' # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @ a p p . r o u t e ( ' / l o g i n ' , m e t h o d s = [ ' G E T ' , ' P O S T ' ] ) d e f l o g i n ( ) : i f r e q u e s t . m e t h o d = = ' P O S T ' : r e t u r n d o _ t h e _ l o g i n ( ) e l s e : r e t u r n s h o w _ t h e _ l o g i n _ f o r m ( ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : a p p . r u n ( h o s t = ' 0 . 0 . 0 . 0 ' , d e b u g = T r u e ) * R u n n i n g o n h t t p : / / 0 . 0 . 0 . 0 : 5 0 0 0 / ( P r e s s C T R L + C t o q u i t ) * R e s t a r t i n g w i t h s t a t 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 8 : 4 7 : 0 2 ] " G E T / l o g i n H T T P / 1 . 1 " 1 2 7 . 0 . 0 . 1 - - [ 2 2 / N o v / 2 0 1 5 1 8 : 4 9 : 4 5 ] " P O S T / l o g i n H T T P / 1 . 1 " Example #5 HTTP Methods 7 / 20
  6. Example #6 1 2 7 . 0 . 0 .

    1 - - [ 2 3 / N o v / 2 0 1 5 0 2 : 4 7 : 0 0 ] " G E T / h e l l o H T T P / 1 . 1 " 1 2 7 . 0 . 0 . 1 - - [ 2 3 / N o v / 2 0 1 5 0 2 : 4 7 : 0 0 ] " G E T / h e l l o / H T T P / 1 . 1 " 1 2 7 . 0 . 0 . 1 - - [ 2 3 / N o v / 2 0 1 5 0 2 : 4 9 : 0 3 ] " G E T / h e l l o / O t o n g H T T P / 1 . 1 " f r o m f l a s k i m p o r t F l a s k , r e n d e r _ t e m p l a t e a p p = F l a s k ( _ _ n a m e _ _ ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @ a p p . r o u t e ( ' / h e l l o / ' ) @ a p p . r o u t e ( ' / h e l l o / < n a m e > ' ) d e f h e l l o ( n a m e = N o n e ) : r e t u r n r e n d e r _ t e m p l a t e ( ' h e l l o . h t m l ' , n a m e = n a m e ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : a p p . r u n ( h o s t = ' 0 . 0 . 0 . 0 ' , d e b u g = T r u e ) < ! d o c t y p e h t m l > < t i t l e > H e l l o f r o m F l a s k < / t i t l e > { % i f n a m e % } < h 1 > H e l l o { { n a m e } } ! < / h 1 > { % e l s e % } < h 1 > H e l l o W o r l d ! < / h 1 > { % e n d i f % } hello.html 8 / 20
  7. f r o m f l a s k i

    m p o r t F l a s k , M a r k u p # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - p r i n t M a r k u p ( ' < s t r o n g > H e l l o % s ! < / s t r o n g > ' ) % ' < b l i n k > h a c k e r < / b l i n k > ' p r i n t " - - - " p r i n t M a r k u p . e s c a p e ( ' < b l i n k > h a c k e r < / b l i n k > ' ) p r i n t " - - - " p r i n t M a r k u p ( ' < e m > M a r k e d u p < / e m > » H T M L ' ) . s t r i p t a g s ( ) Example #7 Markup 9 / 20
  8. Flaskr Files & Folders f l a s k r

    . p y i n i t d b _ f l a s k r . p y s c h e m a . s q l t e m p l a t e s / l a y o u t . h t m l t e m p l a t e s / l o g i n . h t m l t e m p l a t e s / s h o w _ e n t r i e s . h t m l s t a t i c / s t y l e . c s s schema.sql d r o p t a b l e i f e x i s t s e n t r i e s ; c r e a t e t a b l e e n t r i e s ( i d i n t e g e r p r i m a r y k e y a u t o i n c r e m e n t , t i t l e t e x t n o t n u l l , ' t e x t ' t e x t n o t n u l l ) ; initdb_flaskr.py s q l i t e 3 f l a s k r . d b < s c h e m a . s q l i m p o r t s q l i t e 3 f r o m f l a s k i m p o r t F l a s k f r o m c o n t e x t l i b i m p o r t c l o s i n g # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - D A T A B A S E = ' f l a s k r . d b ' # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - a p p = F l a s k ( _ _ n a m e _ _ ) a p p . c o n f i g . f r o m _ o b j e c t ( _ _ n a m e _ _ ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - d e f c o n n e c t _ d b ( ) : r e t u r n s q l i t e 3 . c o n n e c t ( a p p . c o n f i g [ ' D A T A B A S E ' ] ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - d e f i n i t _ d b ( ) : w i t h c l o s i n g ( c o n n e c t _ d b ( ) ) a s d b : w i t h a p p . o p e n _ r e s o u r c e ( ' s c h e m a . s q l ' , m o d e = ' r ' ) a s f : d b . c u r s o r ( ) . e x e c u t e s c r i p t ( f . r e a d ( ) ) d b . c o m m i t ( ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i n i t _ d b ( ) 12 / 20
  9. layout.html < ! d o c t y p e

    h t m l > < t i t l e > F l a s k r < / t i t l e > < l i n k r e l = " s t y l e s h e e t " t y p e = " t e x t / c s s " h r e f = " { { u r l _ f o r ( ' s t a t i c ' , f i l e n a m e = ' s t y l e . c s s ' ) } } " < d i v c l a s s = " p a g e " > < h 1 > F l a s k r < / h 1 > < d i v c l a s s = " m e t a n a v " > { % i f n o t s e s s i o n . l o g g e d _ i n % } < a h r e f = " { { u r l _ f o r ( ' l o g i n ' ) } } " > l o g i n < / a > { % e l s e % } < a h r e f = " { { u r l _ f o r ( ' l o g o u t ' ) } } " > l o g o u t < / a > { % e n d i f % } < / d i v > { % f o r m e s s a g e i n g e t _ f l a s h e d _ m e s s a g e s ( ) % } < d i v c l a s s = " f l a s h " > { { m e s s a g e } } < / d i v > { % e n d f o r % } { % b l o c k b o d y % } { % e n d b l o c k % } < / d i v > flaskr.py 13 / 20
  10. i m p o r t o s f r

    o m s q l i t e 3 i m p o r t d b a p i 2 a s s q l i t e 3 f r o m f l a s k i m p o r t F l a s k , r e q u e s t , s e s s i o n , g , r e d i r e c t , u r l _ f o r , a b o r t , r e n d e r _ t e m p l a t e , f l a s h # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - a p p = F l a s k ( _ _ n a m e _ _ ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # L o a d d e f a u l t c o n f i g a n d o v e r r i d e c o n f i g f r o m a n e n v i r o n m e n t v a r i a b l e a p p . c o n f i g . u p d a t e ( d i c t ( D A T A B A S E = o s . p a t h . j o i n ( a p p . r o o t _ p a t h , ' f l a s k r . d b ' ) , D E B U G = T r u e , S E C R E T _ K E Y = ' d e v e l o p m e n t k e y ' , U S E R N A M E = ' a d m i n ' , P A S S W O R D = ' d e f a u l t ' ) ) a p p . c o n f i g . f r o m _ e n v v a r ( ' F L A S K R _ S E T T I N G S ' , s i l e n t = T r u e ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - d e f c o n n e c t _ d b ( ) : r v = s q l i t e 3 . c o n n e c t ( a p p . c o n f i g [ ' D A T A B A S E ' ] ) r v . r o w _ f a c t o r y = s q l i t e 3 . R o w r e t u r n r v # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - d e f g e t _ d b ( ) : i f n o t h a s a t t r ( g , ' s q l i t e _ d b ' ) : g . s q l i t e _ d b = c o n n e c t _ d b ( ) r e t u r n g . s q l i t e _ d b # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @ a p p . t e a r d o w n _ a p p c o n t e x t d e f c l o s e _ d b ( e r r o r ) : i f h a s a t t r ( g , ' s q l i t e _ d b ' ) : g . s q l i t e _ d b . c l o s e ( ) flaskr.py 14 / 20
  11. flaskr.py @ a p p . r o u t

    e ( ' / ' ) d e f s h o w _ e n t r i e s ( ) : d b = g e t _ d b ( ) c u r = d b . e x e c u t e ( ' s e l e c t t i t l e , t e x t f r o m e n t r i e s o r d e r b y i d d e s c ' e n t r i e s = c u r . f e t c h a l l ( ) r e t u r n r e n d e r _ t e m p l a t e ( ' s h o w _ e n t r i e s . h t m l ' , e n t r i e s = e n t r i e s ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @ a p p . r o u t e ( ' / a d d ' , m e t h o d s = [ ' P O S T ' ] ) d e f a d d _ e n t r y ( ) : i f n o t s e s s i o n . g e t ( ' l o g g e d _ i n ' ) : a b o r t ( 4 0 1 ) d b = g e t _ d b ( ) d b . e x e c u t e ( ' i n s e r t i n t o e n t r i e s ( t i t l e , t e x t ) v a l u e s ( ? , ? ) ' [ r e q u e s t . f o r m [ ' t i t l e ' ] , r e q u e s t . f o r m [ ' t e x t ' ] ] ) d b . c o m m i t ( ) f l a s h ( ' N e w e n t r y w a s s u c c e s s f u l l y p o s t e d ' ) r e t u r n r e d i r e c t ( u r l _ f o r ( ' s h o w _ e n t r i e s ' ) ) show_entries.html { % e x t e n d s " l a y o u t . h t m l " % } { % b l o c k b o d y % } { % i f s e s s i o n . l o g g e d _ i n % } < f o r m a c t i o n = " { { u r l _ f o r ( ' a d d _ e n t r y ' ) } } " m e t h o d = " p o s t " < d l > < d t > T i t l e : < d d > < i n p u t t y p e = " t e x t " s i z e = " 3 0 " n a m e = " t i t l e " > < d t > T e x t : < d d > < t a g t e x t a r e a n a m e = " t e x t " r o w s = " 5 " c o l s = " 4 0 " > < / t a g t < d d > < i n p u t t y p e = " s u b m i t " v a l u e = " S h a r e " > < / d l > < / f o r m > { % e n d i f % } < u l c l a s s = " e n t r i e s " > { % f o r e n t r y i n e n t r i e s % } < l i > < h 2 > { { e n t r y . t i t l e } } < / h 2 > { { e n t r y . t e x t | s a f e } } { % e l s e % } < l i > < e m > U n b e l i e v a b l e . N o e n t r i e s h e r e s o f a r < / e m > { % e n d f o r % } < / u l > { % e n d b l o c k % } 15 / 20
  12. flaskr.py @ a p p . r o u t

    e ( ' / l o g i n ' , m e t h o d s = [ ' G E T ' , ' P O S T ' ] ) d e f l o g i n ( ) : e r r o r = N o n e i f r e q u e s t . m e t h o d = = ' P O S T ' : i f r e q u e s t . f o r m [ ' u s e r n a m e ' ] ! = a p p . c o n f i g [ ' U S E R N A M E ' e r r o r = ' I n v a l i d u s e r n a m e ' e l i f r e q u e s t . f o r m [ ' p a s s w o r d ' ] ! = a p p . c o n f i g [ ' P A S S W O R D ' e r r o r = ' I n v a l i d p a s s w o r d ' e l s e : s e s s i o n [ ' l o g g e d _ i n ' ] = T r u e f l a s h ( ' Y o u w e r e l o g g e d i n ' ) r e t u r n r e d i r e c t ( u r l _ f o r ( ' s h o w _ e n t r i e s ' ) ) r e t u r n r e n d e r _ t e m p l a t e ( ' l o g i n . h t m l ' , e r r o r = e r r o r ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @ a p p . r o u t e ( ' / l o g o u t ' ) d e f l o g o u t ( ) : s e s s i o n . p o p ( ' l o g g e d _ i n ' , N o n e ) f l a s h ( ' Y o u w e r e l o g g e d o u t ' ) r e t u r n r e d i r e c t ( u r l _ f o r ( ' s h o w _ e n t r i e s ' ) ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : a p p . r u n ( ) login.html { % e x t e n d s " l a y o u t . h t m l " % } { % b l o c k b o d y % } < h 2 > L o g i n < / h 2 > { % i f e r r o r % } < p c l a s s = " e r r o r " > < s t r o n g > E r r o r : < / s t r o n g > { { e r < f o r m a c t i o n = " { { u r l _ f o r ( ' l o g i n ' ) } } " m e t h o d = " p o s t " > < d l > < d t > U s e r n a m e : < d d > < i n p u t t y p e = " t e x t " n a m e = " u s e r n a m e " > < d t > P a s s w o r d : < d d > < i n p u t t y p e = " p a s s w o r d " n a m e = " p a s s w o r d " > < d d > < i n p u t t y p e = " s u b m i t " v a l u e = " L o g i n " > < / d l > < / f o r m > { % e n d b l o c k % } 16 / 20
  13. test_flaskr.py p y . t e s t t e

    s t _ f l a s k r . p y p y . t e s t will run all files in the current directory and its subdirectories of the form t e s t _ * . p y or * _ t e s t . p y i m p o r t p y t e s t i m p o r t o s i m p o r t f l a s k r i m p o r t t e m p f i l e # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @ p y t e s t . f i x t u r e d e f c l i e n t ( r e q u e s t ) : d b _ f d , f l a s k r . a p p . c o n f i g [ ' D A T A B A S E ' ] = t e m p f i l e . m k s t e m p ( ) f l a s k r . a p p . c o n f i g [ ' T E S T I N G ' ] = T r u e c l i e n t = f l a s k r . a p p . t e s t _ c l i e n t ( ) w i t h f l a s k r . a p p . a p p _ c o n t e x t ( ) : f l a s k r . i n i t _ d b ( ) d e f t e a r d o w n ( ) : o s . c l o s e ( d b _ f d ) o s . u n l i n k ( f l a s k r . a p p . c o n f i g [ ' D A T A B A S E ' ] ) r e q u e s t . a d d f i n a l i z e r ( t e a r d o w n ) r e t u r n c l i e n t # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - d e f l o g i n ( c l i e n t , u s e r n a m e , p a s s w o r d ) : r e t u r n c l i e n t . p o s t ( ' / l o g i n ' , d a t a = d i c t ( u s e r n a m e = u s e r n a m e , p a s s w o r d = p a s s w o r d ) , f o l l o w _ r e d i r e c t s = T r u e ) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - d e f l o g o u t ( c l i e n t ) : r e t u r n c l i e n t . g e t ( ' / l o g o u t ' , f o l l o w _ r e d i r e c t s = T r u e ) 17 / 20
  14. d e f t e s t _ e m

    p t y _ d b ( c l i e n t ) : " " " S t a r t w i t h a b l a n k d a t a b a s e . " " " r v = c l i e n t . g e t ( ' / ' ) a s s e r t b ' N o e n t r i e s h e r e s o f a r ' i n r v . d a t a # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - d e f t e s t _ l o g i n _ l o g o u t ( c l i e n t ) : " " " M a k e s u r e l o g i n a n d l o g o u t w o r k s " " " r v = l o g i n ( c l i e n t , f l a s k r . a p p . c o n f i g [ ' U S E R N A M E ' ] , f l a s k r . a p p . c o n f i g [ a s s e r t b ' Y o u w e r e l o g g e d i n ' i n r v . d a t a r v = l o g o u t ( c l i e n t ) a s s e r t b ' Y o u w e r e l o g g e d o u t ' i n r v . d a t a r v = l o g i n ( c l i e n t , f l a s k r . a p p . c o n f i g [ ' U S E R N A M E ' ] + ' x ' , f l a s k r . a p p . c o n f i g [ a s s e r t b ' I n v a l i d u s e r n a m e ' i n r v . d a t a r v = l o g i n ( c l i e n t , f l a s k r . a p p . c o n f i g [ ' U S E R N A M E ' ] , f l a s k r . a p p . c o n f i g [ a s s e r t b ' I n v a l i d p a s s w o r d ' i n r v . d a t a # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - d e f t e s t _ m e s s a g e s ( c l i e n t ) : " " " T e s t t h a t m e s s a g e s w o r k " " " l o g i n ( c l i e n t , f l a s k r . a p p . c o n f i g [ ' U S E R N A M E ' ] , f l a s k r . a p p . c o n f i g [ r v = c l i e n t . p o s t ( ' / a d d ' , d a t a = d i c t ( t i t l e = ' < H e l l o > ' , t e x t = ' < s t r o n g > H T M L < / s t r o n g > a l l o w e d h e r e ' ) , f o l l o w _ r e d i r e c t s = T r u e ) a s s e r t b ' N o e n t r i e s h e r e s o f a r ' n o t i n r v . d a t a a s s e r t b ' < H e l l o > ' i n r v . d a t a a s s e r t b ' < s t r o n g > H T M L < / s t r o n g > a l l o w e d h e r e ' i n r v . d a t a test_flaskr.py 18 / 20