Introduction to Asyncio stack

Introduction to Asyncio stack

Brief introduction to Asyncio stack for Python web developers. Describing aiohttp.web, aiopg, and rororo - libraries for building web applications on top of Python 3.

D809571c81f596ccc197f90142c966ab?s=128

Igor Davydenko

May 30, 2015
Tweet

Transcript

  1. 3.

    asyncio Asynchronous I/O, event loop, coroutines, and tasks https://docs.python.org/3/library/asyncio.html i

    m p o r t a s y n c i o @ a s y n c i o . c o r o u t i n e d e f h e l l o ( ) : r e t u r n " H e l l o , w o r l d ! " l o o p = a s y n c i o . g e t _ e v e n t _ l o o p ( ) l o o p . r u n _ u n t i l _ c o m p l e t e ( h e l l o ( ) ) l o o p . c l o s e ( ) Included in Python 3.4 and later Available in Python 3.3 with $ p i p i n s t a l l a s y n c i o Backported to Python 2.7 as trollius (I don't recommend to use it anyway)
  2. 4.

    aiohttp HTTP client/server for asyncio Latest version: 0 . 1

    6 . 2 http://aiohttp.readthedocs.org/ i m p o r t a s y n c i o i m p o r t a i o h t t p @ a s y n c i o . c o r o u t i n e d e f f e t c h _ p a g e ( u r l ) : r e s p o n s e = y i e l d f r o m a i o h t t p . r e q u e s t ( ' G E T ' , u r l ) a s s e r t r e s p o n s e . s t a t u s = = 2 0 0 r e t u r n ( y i e l d f r o m r e s p o n s e . r e a d ( ) ) l o o p = a s y n c i o . g e t _ e v e n t _ l o o p ( ) c o n t e n t = l o o p . r u n _ u n t i l _ c o m p l e t e ( f e t c h _ p a g e ( ' h t t p : / / l v i v p y . o r g . u a / ' ) ) p r i n t ( c o n t e n t ) l o o p . c l o s e ( )
  3. 5.

    aiohttp.web Web framework for asyncio http://aiohttp.readthedocs.org/en/v0.16.2/web.html i m p o

    r t a s y n c i o f r o m a i o h t t p i m p o r t w e b @ a s y n c i o . c o r o u t i n e d e f h e l l o ( r e q u e s t ) : r e t u r n w e b . R e s p o n s e ( b o d y = ' H e l l o , w o r l d ! ' , c o n t e n t _ t y p e = ' t e x t / p l a i n ' ) a p p = w e b . A p p l i c a t i o n ( ) a p p . r o u t e r . a d d _ r o u t e ( ' G E T ' , ' / ' , h e l l o ) $ g u n i c o r n - k a i o h t t p . w o r k e r . G u n i c o r n W e b W o r k e r - w 9 - t 6 0 a p p : a p p
  4. 6.

    aiopg Accessing PostgreSQL database from the asyncio Latest version: 0

    . 7 . 0 http://aiopg.readthedocs.org/ i m p o r t a s y n c i o f r o m a i o p g i m p o r t c r e a t e _ p o o l @ a s y n c i o . c o r o u t i n e d e f h e l l o ( d s n ) : p o o l = y i e l d f r o m c r e a t e _ p o o l ( d s n ) w i t h ( y i e l d f r o m p o o l . c u r s o r ( ) ) a s c u r s o r : y i e l d f r o m c u r s o r . e x e c u t e ( ' S E L E C T 1 ' ) s e l e c t e d = y i e l d f r o m c u r s o r . f e t c h o n e ( ) a s s e r t s e l e c t e d = = ( 1 , ) l o o p = a s y n c i o . g e t _ e v e n t _ l o o p ( ) l o o p . r u n _ u n t i l _ c o m p l e t e ( h e l l o ( ' d b n a m e = a i o p g u s e r = . . . p a s s w o r d = . . . h o s t = . . . ' ) ) l o o p . c l o s e ( )
  5. 7.

    aioredis / asyncio_redis Accessing Redis datasotre from the asyncio a

    i o r e d i s from a i o - l i b s Latest version: 0 . 1 . 5 http://aioredis.readthedocs.org/ a s y n c i o _ r e d i s from third-party developers Latest version: 0 . 1 3 . 4 http://asyncio-redis.readthedocs.org/ Supports PUB/SUB
  6. 8.

    And many others Python Asyncio Resources MySQL: aiomysql Mongo: asyncio_mongo

    CouchDB: aiocouchdb ElasticSearch: aioes Memcached: aiomcache AMQP: aioamqp ØMQ: aiozmq
  7. 9.

    And many others All Asyncio projects @ PyPI S3: aio-s3

    SSH: asyncssh Autobahn, WebSocket & WAMP RxPY, Reactive Extensions for Python Pulsar, Concurrent framework for Python
  8. 12.

    Architecture All starts from view functions (handlers) View functions should

    be a coroutine, and return w e b . R e s p o n s e i m p o r t a s y n c i o f r o m a i o h t t p i m p o r t w e b @ a s y n c i o . c o r o u t i n e d e f i n d e x ( r e q u e s t ) : r e t u r n w e b . R e s p o n s e ( b o d y = ' H e l l o , w o r l d ! ' , c o n t e n t _ t y p e = ' t e x t / p l a i n ' ) It's good idea to put all view functions to v i e w s . p y module
  9. 13.

    Architecture Next you need to create an w e b

    . A p p l i c a t i o n And register handler for a request f r o m a i o h t t p i m p o r t w e b f r o m . i m p o r t v i e w s a p p = w e b . A p p l i c a t i o n ( ) a p p . r o u t e r . a d d _ r o u t e ( ' G E T ' , ' / ' , v i e w s . i n d e x ) Obvious to put application code to a p p . p y module
  10. 14.

    Architecture Now you ready to serve your application I recommend

    to use Gunicorn $ g u n i c o r n - b 0 . 0 . 0 . 0 : 8 0 0 0 - k a i o h t t p . w o r k e r . G u n i c o r n W e b W o r k e r - w 9 - t 6 0 p r o j e c t . a p p : a p p Add - - r e l o a d flag to automatically reload Gunicorn server on code change
  11. 15.

    Handling GET/POST data In views.py, @ a s y n

    c i o . c o r o u t i n e d e f s e a r c h ( r e q u e s t ) : " " " S e a r c h b y q u e r y f r o m G E T p a r a m s . " " " q u e r y = r e q u e s t . G E T [ ' q u e r y ' ] l o c a l e = r e q u e s t . G E T . g e t ( ' l o c a l e ' , ' u k _ U A ' ) . . . r e t u r n w e b . R e s p o n s e ( . . . )
  12. 16.

    Handling GET/POST data In views.py, @ a s y n

    c i o . c o r o u t i n e d e f s u b m i t ( r e q u e s t ) : " " " S u b m i t f o r m P O S T d a t a . " " " d a t a = y i e l d f r o m r e q u e s t . p o s t ( ) # N o w P O S T d a t a a v a i l a b l e a s ` ` r e q u e s t . P O S T ` ` . . . r e t u r n w e b . R e s p o n s e ( . . . )
  13. 17.

    Handling GET/POST data In app.py, a p p . r

    o u t e r . a d d _ r o u t e ( ' G E T ' , ' / s e a r c h ' , v i e w s . s e a r c h ) a p p . r o u t e r . a d d _ r o u t e ( ' P O S T ' , ' / s u b m i t ' , v i e w s . s u b m i t )
  14. 18.

    Handling variable routes In views.py, @ a s y n

    c i o . c o r o u t i n e d e f p r o j e c t ( r e q u e s t ) : p r o j e c t _ i d = r e q u e s t . m a t c h _ i n f o [ ' p r o j e c t _ i d ' ] . . . r e t u r n w e b . R e s p o n s e ( . . . )
  15. 19.

    Handling variable routes In app.py, a p p . r

    o u t e r . a d d _ r o u t e ( ' G E T ' , ' / p r o j e c t s / { p r o j e c t _ i d } ' , v i e w s . p r o j e c t ) Or even, a p p . r o u t e r . a d d _ r o u t e ( ' G E T ' , ' / p r o j e c t s / { p r o j e c t _ i d : \ d + } ' , v i e w s . p r o j e c t )
  16. 20.

    Named routes, reverse constructing, and redirect In app.py, a p

    p . r o u t e r . a d d _ r o u t e ( ' G E T ' , ' / p r o j e c t s ' , v i e w s . p r o j e c t s , n a m e = ' p r o j e c t s ' ) a p p . r o u t e r . a d d _ r o u t e ( ' P O S T ' , ' / p r o j e c t s ' , v i e w s . a d d _ p r o j e c t )
  17. 21.

    Named routes, reverse constructing, and redirect In views.py, @ a

    s y n c i o . c o r o u t i n e d e f a d d _ p r o j e c t ( r e q u e s t ) : d a t a = y i e l d f r o m r e q u e s t . p o s t ( ) . . . u r l = r e q u e s t . a p p . r o u t e r [ ' p r o j e c t s ' ] . u r l ( ) r e t u r n w e b . H T T P F o u n d ( u r l ) @ a s y n c i o . c o r o u t i n e d e f p r o j e c t s ( r e q u e s t ) : . . .
  18. 22.

    You don't need to f r o m a p

    p i m p o r t a p p Or f r o m f l a s k i m p o r t c u r r e n t _ a p p either Request contains a p p instance for all your needs In app.py, f r o m . i m p o r t s e t t i n g s . . . a p p [ ' s e t t i n g s ' ] = s e t t i n g s
  19. 23.

    You don't need to f r o m a p

    p i m p o r t a p p In views.py, @ a s y n c i o . c o r o u t i n e d e f s e a r c h ( r e q u e s t ) : s e t t i n g s = r e q u e s t . a p p [ ' s e t t i n g s ' ] q u e r y = r e q u e s t . G E T [ ' q u e r y ' ] l o c a l e = r e q u e s t . G E T . g e t ( ' l o c a l e ' , s e t t i n g s . D E F A U L T _ L O C A L E ) . . . r e t u r n w e b . R e s p o n s e ( . . . )
  20. 24.

    Middlewares w e b . A p p l i

    c a t i o n accepts optional middlewares factories sequence Middleware Factory should be a coroutine and returns a coroutine In app.py, @ a s y n c i o . c o r o u t i n e d e f t r i v i a l _ m i d d l e w a r e ( a p p , h a n d l e r ) : @ a s y n c i o . c o r o u t i n e d e f m i d d l e w a r e ( r e q u e s t ) : r e t u r n ( y i e l d f r o m h a n d l e r ( r e q u e s t ) ) r e t u r n m i d d l e w a r e . . . a p p = w e b . A p p l i c a t i o n ( m i d d l e w a r e s = [ t r i v i a l _ m i d d l e w a r e ] )
  21. 25.

    Middlewares Ready to use Middlewares User Sessions, a i o

    h t t p _ s e s s i o n Debug Toolbar, a i o h t t p _ d e b u g t o o l b a r In app.py, i m p o r t a i o h t t p _ d e b u g t o o l b a r f r o m a i o h t t p _ d e b u g t o o l b a r i m p o r t t o o l b a r _ m i d d l e w a r e _ f a c t o r y f r o m a i o h t t p _ s e s s i o n i m p o r t s e s s i o n _ m i d d l e w a r e f r o m a i o h t t p _ s e s s i o n . c o o k i e _ s t o r a g e i m p o r t E n c r y p t e d C o o k i e S t o r a g e a p p = w e b . A p p l i c a t i o n ( m i d d l e w a r e s = [ t o o l b a r _ m i d d l e w a r e _ f a c t o r y , s e s s i o n _ m i d d l e w a r e ( E n c r y p t e d C o o k i e S t o r a g e ( b ' 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 ' ) ) ] ) a i o h t t p _ d e b u g t o o l b a r . s e t u p ( a p p )
  22. 26.

    Middlewares Handling Exceptions In app.py, @ a s y n

    c i o . c o r o u t i n e d e f e r r o r h a n d l e r _ m i d d l e w a r e ( a p p , h a n d l e r ) : @ a s y n c i o . c o r o u t i n e d e f m i d d l e w a r e ( r e q u e s t ) : t r y : r e t u r n ( y i e l d f r o m h a n d l e r ( r e q u e s t ) ) e x c e p t w e b . H T T P E r r o r a s e r r : # A s i t s p e c i a l c a s e w e c o u l d p a s s ` ` e r r ` ` a s s e c o n d a r g u m e n t t o # e r r o r h a n d l e r r e t u r n ( y i e l d f r o m v i e w s . e r r o r ( r e q u e s t , e r r ) ) r e t u r n m i d d l e w a r e
  23. 27.

    User Sessions aiohttp_session Latest version: 0 . 1 . 1

    Supports storing session data in encrypted cookie or redis Enabled by passing s e s s i o n _ m i d d l e w a r e to middleware factories sequence In views.py, f r o m a i o h t t p _ s e s s i o n i m p o r t g e t _ s e s s i o n @ a s y n c i o . c o r o u t i n e d e f l o g i n ( r e q u e s t ) : . . . s e s s i o n = y i e l d f r o m g e t _ s e s s i o n ( r e q u e s t ) s e s s i o n [ ' u s e r _ i d ' ] = u s e r _ i d r e t u r n w e b . R e s p o n s e ( . . . )
  24. 28.

    Rendering Templates Jinja2 & Mako supported via aiohttp_jinja2 & aiohttp_mako

    Jinja2 Support In app.py, i m p o r t a i o h t t p _ j i n j a 2 i m p o r t j i n j a 2 . . . a i o h t t p _ j i n j a 2 . s e t u p ( a p p , l o a d e r = j i n j a 2 . F i l e S y s t e m L o a d e r ( ' / p a t h / t o / t e m p l a t e s ' ) )
  25. 29.

    Rendering Templates Jinja2 Support In views.py, i m p o

    r t a i o h t t p _ j i n j a 2 @ a i o h t t p _ j i n j a 2 . t e m p l a t e ( ' i n d e x . h t m l ' ) d e f i n d e x ( r e q u e s t ) : r e t u r n { ' i s _ i n d e x ' : T r u e }
  26. 30.

    Rendering Templates Jinja2 Support In views.py, f r o m

    a i o h t t p _ j i n j a 2 i m p o r t r e n d e r _ t e m p l a t e @ a s y n c i o . c o r o u t i n e d e f i n d e x ( r e q u e s t ) : r e t u r n r e n d e r _ t e m p l a t e ( ' i n d e x . h t m l ' , r e q u e s t , { ' i s _ i n d e x ' : T r u e } )
  27. 31.

    Rendering JSON In utils.py, i m p o r t

    u j s o n f r o m a i o h t t p i m p o r t w e b d e f j s o n _ r e s p o n s e ( d a t a , * * k w a r g s ) : # S o m e t i m e s u s e r n e e d s t o o v e r r i d e d e f a u l t c o n t e n t t y p e f o r J S O N k w a r g s . s e t d e f a u l t ( ' c o n t e n t _ t y p e ' , ' a p p l i c a t i o n / j s o n ' ) r e t u r n w e b . R e s p o n s e ( u j s o n . d u m p s ( d a t a ) , * * k w a r g s ) Note: I recommend to use ujson for work with JSON data in Python, cause of speed.
  28. 32.

    Rendering JSON In views.py, f r o m . u

    t i l s i m p o r t j s o n _ r e s p o n s e @ a s y n c i o . c o r o u t i n e d e f a p i _ b r o w s e r ( r e q u e s t ) : r e t u r n j s o n _ r e s p o n s e ( { ' p r o j e c t s _ u r l ' : r e q u e s t . a p p . r o u t e r [ ' p r o j e c t s ' ] . u r l ( ) , } )
  29. 33.

    Serving Static Files Important: It's highly recommend to use nginx,

    Apache, or other web server for serving static files in production. In app.py, a p p . r o u t e r . a d d _ s t a t i c ( ' / s t a t i c ' , ' / p a t h / t o / s t a t i c ' , n a m e = ' s t a t i c ' )
  30. 34.

    Serving Static Files In views.py, @ a i o h

    t t p _ j i n j a 2 . t e m p l a t e ( ' i n d e x . h t m l ' ) d e f i n d e x ( r e q u e s t ) : r e t u r n { ' a p p ' : r e q u e s t . a p p , ' i s _ i n d e x ' : T r u e }
  31. 35.

    Serving Static Files In index.html, < s c r i

    p t s r c = " { { a p p . r o u t e r . s t a t i c . u r l ( f i l e n a m e = " d i s t / j s / p r o j e c t . j s " ) } } " t y p e = " t e x t / j a v a s c r i p t " > < / s c r i p t >
  32. 36.

    And More WebSockets Expect Header Custom Conditions for Routes Lookup

    Class Based Handlers And I say it again, WebSockets
  33. 37.
  34. 38.

    Basics Supports SQLAlchemy core (functional SQL layer) So you able

    to describe tables with SQLAlchemy and then execute queries Maybe you will miss ORM, but man, ORM is overrated :) Also implements asyncio DBAPI like interface for PostgreSQL
  35. 39.

    Basics i m p o r t s q l

    a l c h e m y a s s a m e t a d a t a = s a . M e t a D a t a ( ) u s e r s _ t a b l e = s a . T a b l e ( ' u s e r s ' , m e t a d a t a , s a . C o l u m n ( ' i d ' , s a . I n t e g e r , p r i m a r y _ k e y = T r u e ) , s a . C o l u m n ( ' e m a i l ' , s a . U n i c o d e ( 2 5 5 ) , u n i q u e = T r u e ) , s a . C o l u m n ( ' d i s p l a y _ n a m e ' , s a . U n i c o d e ( 6 4 ) , n u l l a b l e = T r u e ) , )
  36. 40.

    Basics i m p o r t a s y

    n c i o f r o m a i o p g . s a i m p o r t c r e a t e _ e n g i n e @ a s y n c i o . c o r o u t i n e d e f g e t _ u s e r ( d s n , u s e r _ i d ) : e n g i n e = y i e l d f r o m c r e a t e _ e n g i n e ( d s n ) w i t h ( y i e l d f r o m e n g i n e ) a s c o n n : q u e r y = u s e r s _ t a b l e . s e l e c t ( u s e r s _ t a b l e . c . i d = = u s e r _ i d ) r e t u r n ( y i e l d f r o m ( y i e l d f r o m c o n n . e x e c u t e ( q u e r y ) ) . f i r s t ( ) ) l o o p = a s y n c i o . g e t _ e v e n t _ l o o p ( ) u s e r = l o o p . r u n _ u n t i l _ c o m p l e t e ( g e t _ u s e r ( ' p o s t g r e s : / / . . . ' , 1 ) ) p r i n t ( u s e r ) l o o p . c l o s e ( )
  37. 41.

    Integration with aiohttp.web Common practice is describing tables and place

    functions to manipulate data in one place, e.g., s t o r a g e . p y module Put _ t a b l e suffix to every described table, e.g., u s e r s _ t a b l e , not just u s e r s Connect to database in middleware factory Store database connection in main app instance to avoid overflow
  38. 42.

    Integration with aiohttp.web In app.py, @ a s y n

    c i o . c o r o u t i n e d e f d b _ m i d d l e w a r e ( a p p , h a n d l e r ) : @ a s y n c i o . c o r o u t i n e d e f m i d d l e w a r e ( r e q u e s t ) : d b = a p p . g e t ( ' d b ' ) i f n o t d b : a p p [ ' d b ' ] = d b = y i e l d f r o m c r e a t e _ e n g i n e ( a p p [ ' d s n ' ] ) r e q u e s t . a p p [ ' d b ' ] = d b r e t u r n ( y i e l d f r o m h a n d l e r ( r e q u e s t ) ) r e t u r n m i d d l e w a r e a p p = w e b . A p p l i c a t i o n ( m i d d l e w a r e s = [ d b _ m i d d l e w a r e ] ) a p p [ ' d s n ' ] = ' p o s t g r e s : / / u s e r : p a s s w o r d @ 1 2 7 . 0 . 0 . 1 : 5 4 3 2 / d a t a b a s e ' a p p . r o u t e r . a d d _ r o u t e ( ' G E T ' , ' / u s e r s / { u s e r _ i d : \ d + } ' , v i e w s . u s e r _ p r o f i l e )
  39. 43.

    Integration with aiohttp.web In views.py, f r o m .

    s t o r a g e i m p o r t u s e r s _ t a b l e @ a i o h t t p _ j i n j a 2 . t e m p l a t e ( ' u s e r _ p r o f i l e . h t m l ' ) d e f u s e r _ p r o f i l e ( r e q u e s t ) : u s e r _ i d = r e q u e s t . m a t c h _ i n f o [ ' u s e r _ i d ' ] w i t h ( y i e l d f r o m r e q u e s t . a p p [ ' d b ' ] ) a s c o n n : q u e r y = u s e r s _ t a b l e . s e l e c t ( u s e r s _ t a b l e . c . i d = = u s e r _ i d ) u s e r = y i e l d f r o m ( y i e l d f r o m c o n n . e x e c u t e ( q u e r y ) ) . f i r s t ( ) i f n o t u s e r : r a i s e w e b . H T T P N o t F o u n d ( ) r e t u r n { ' u s e r ' : u s e r }
  40. 48.

    Add Route Context Manager f r o m c o

    n t e x t l i b i m p o r t c o n t e x t m a n a g e r @ c o n t e x t m a n a g e r d e f a d d _ r o u t e _ c o n t e x t ( a p p , v i e w s , u r l _ p r e f i x = N o n e , n a m e _ p r e f i x = N o n e ) : d e f a d d _ r o u t e ( m e t h o d , u r l , n a m e ) : v i e w = g e t a t t r ( v i e w s , n a m e ) u r l = ( ' / ' . j o i n ( ( u r l _ p r e f i x . r s t r i p ( ' / ' ) , u r l . l s t r i p ( ' / ' ) ) ) i f u r l _ p r e f i x e l s e u r l ) n a m e = ' . ' . j o i n ( ( n a m e _ p r e f i x , n a m e ) ) i f n a m e _ p r e f i x e l s e n a m e r e t u r n a p p . r o u t e r . a d d _ r o u t e ( m e t h o d , u r l , v i e w , n a m e = n a m e ) r e t u r n a d d _ r o u t e
  41. 49.

    Add Route Context Manager In app.py, f r o m

    . a p i i m p o r t v i e w s a s a p i _ v i e w s w i t h a d d _ r o u t e _ c o n t e x t ( a p p , a p i _ v i e w s , ' / a p i ' , ' a p i ' ) a s a d d _ r o u t e : a d d _ r o u t e ( ' G E T ' , ' / ' , ' i n d e x ' ) a d d _ r o u t e ( ' G E T ' , ' / p r o j e c t s ' , ' p r o j e c t s ' ) a d d _ r o u t e ( ' P O S T ' , ' / p r o j e c t s ' , ' a d d _ p r o j e c t ' ) a d d _ r o u t e ( ' G E T ' , ' / p r o j e c t / { p r o j e c t _ i d : \ d + } ' , ' p r o j e c t ' ) a d d _ r o u t e ( ' P U T ' , ' / p r o j e c t / { p r o j e c t _ i d : \ d + } ' , ' e d i t _ p r o j e c t ' ) a d d _ r o u t e ( ' D E L E T E ' , ' / p r o j e c t / { p r o j e c t _ i d : \ d + } ' , ' d e l e t e _ p r o j e c t ' )
  42. 50.

    Add Route Context Manager In api/views.py, i m p o

    r t a s y n c i o f r o m . . u t i l s i m p o r t j s o n _ r e s p o n s e @ a s y n c i o . c o r o u t i n e d e f i n d e x ( r e q u e s t ) : r o u t e r = r e q u e s t . a p p . r o u t e r p r o j e c t _ u r l = r o u t e r [ ' a p i . p r o e j c t ' ] . u r l ( p a r t s = { ' p r o j e c t _ i d ' : 4 2 } ) p r o j e c t _ u r l = p r o j e c t _ u r l . r e p l a c e ( ' 4 2 ' , ' { p r o j e c t _ i d } ' ) r e t u r n j s o n _ r e s p o n s e ( { ' u r l s ' : { ' a d d _ p r o j e c t ' : r o u t e r [ ' a p i . a d d _ p r o j e c t ' ] . u r l ( ) , ' p r o j e c t ' : p r o j e c t _ u r l , ' p r o j e c t s ' : r o u t e r [ ' a p i . p r o j e c t s ' ] . u r l ( ) , } } )
  43. 51.

    Immutable Settings Python 3.3+ has M a p p i

    n g T y p e P r o x y Settings shouldn't be changed across the app Welcome, rororo.settings In app.py, f r o m r o r o r o . s e t t i n g s i m p o r t i m m u t a b l e _ s e t t i n g s f r o m . i m p o r t s e t t i n g s d e f c r e a t e _ a p p ( * * o p t i o n s ) : s e t t i n g s _ d i c t = i m m u t a b l e _ s e t t i n g s ( s e t t i n g s , * * o p t i o n s ) a p p = w e b . A p p l i c a t i o n ( ) a p p [ ' s e t t i n g s ' ] = s e t t i n g s _ d i c t . . . r e t u r n a p p
  44. 52.

    Other Settings & Logging Helpers rororo.settings i n j e

    c t _ s e t t i n g s s e t u p _ l o c a l e s e t u p _ l o g g i n g s e t u p _ t i m e z o m e t o _ b o o l rororo.logger d e f a u l t _ l o g g i n g _ d i c t u p d a t e _ s e n t r y _ l o g g i n g
  45. 53.

    Supports DEBUG Mode from Settings c l a s s

    A p p l i c a t i o n ( w e b . A p p l i c a t i o n ) : d e f _ _ i n i t _ _ ( s e l f , * * k w a r g s ) : s e l f [ ' s e t t i n g s ' ] = k w a r g s . p o p ( ' s e t t i n g s ' ) s u p e r ( ) . _ _ i n i t _ _ ( * * k w a r g s ) d e f m a k e _ h a n d l e r ( s e l f , * * k w a r g s ) : k w a r g s [ ' d e b u g ' ] = s e l f [ ' s e t t i n g s ' ] [ ' D E B U G ' ] k w a r g s [ ' l o o p ' ] = s e l f . l o o p r e t u r n s e l f . _ h a n d l e r _ f a c t o r y ( s e l f , s e l f . r o u t e r , * * k w a r g s )
  46. 54.

    Schemas You need to validate request & response data Use

    JSON Schema for validation Describe Schemas with jsl Welcome, rororo.schemas In api/views.py, f r o m r o r o r o . s c h e m a s i m p o r t S c h e m a f r o m . i m p o r t s c h e m a s @ a s y n c i o . c o r o u t i n e d e f a d d _ p r o j e c t ( r e q u e s t ) : s c h e m a = S c h e m a ( s c h e m a s . a d d _ p r o j e c t , r e s p o n s e _ f a c t o r y = j s o n _ r e s p o n s e ) d a t a = s c h e m a . v a l i d a t e _ r e q u e s t ( ( y i e l d f r o m r e q u e s t . p o s t ( ) ) ) . . . r e t u r n s c h e m a . m a k e _ r e s p o n s e ( p r o j e c t _ d i c t )
  47. 55.

    Schemas Describing Schemas In api/schemas/add_project.py, f r o m j

    s l i m p o r t D o c u m e n t , I n t e g e r F i e l d , S t r i n g F i e l d c l a s s P r o j e c t ( D o c u m e n t ) : n a m e = S t r i n g F i e l d ( m i n _ l e n g t h = 1 , m a x _ l e n g t h = 3 2 , r e q u i r e d = T r u e ) s l u g = S t r i n g F i e l d ( m i n _ l e n g t h = 1 , m a x _ l e n g t h = 3 2 , r e q u i r e d = T r u e ) d e s c r i p t i o n = S t r i n g F i e l d ( m a x _ l e n g t h = 2 5 5 ) c l a s s R e s p o n s e ( P r o j e c t ) : i d = I n t e g e r F i e l d ( m i n i m u m = 0 , r e q u i r e d = T r u e ) r e q u e s t = P r o j e c t . g e t _ s c h e m a ( ) r e s p o n s e = R e s p o n s e . g e t _ s c h e m a ( ) Or use plain Python dicts instead
  48. 56.

    Schemas Describing Schemas In api/schemas/__init__.py, f r o m .

    i m p o r t a d d _ p r o j e c t # n o q a
  49. 58.
  50. 59.
  51. 60.
  52. 61.

    Um, Really? I don't believe in this Django and aiohttp.web

    are frameworks for different tasks You would miss everything you know
  53. 63.
  54. 64.

    My Success Story I migrated Python backend from Flask to

    aiohttp.web 1 working day Quick Notes: Global state -> read all from request Extensions -> ? Blueprints -> list of routes or custom router Flask before/after request -> aiohttp.web middleware Error handlers -> middleware { { u r l _ f o r ( . . . ) } } -> { { a p p . r o u t e r [ . . . ] . u r l ( . . . ) } }
  55. 65.

    Other Thoughts I was a huge Flask fanboy http://igordavydenko.com/talks/ua-pycon-2012.pdf aiohttp.web

    solves my problem with large Flask applications I don't need to use lazy views concept to keep my large apps Pythonic aiohttp.web solves my problem with global state and contexts Everything read from the request. It's just works I'm really tired of Armin's complaints about Python 3
  56. 66.
  57. 67.
  58. 68.

    Asyncio Stack is ready for usage The Future is Here!

    Use Python 3.4 for all good things a i o h t t p . w e b , easy to start and easy to use a i o p g . s a allows you to forget about ORM r o r o r o contains useful helpers for aiohttp.web apps If you miss something, port it to Asyncio stack by yourself Don't forget to payback to Open Source Software