<s> """<STR_LIT>""" <EOL> import json <EOL> import jsonschema <EOL> from functools import partial <EOL> from urllib . parse import urlencode <EOL> import rethinkdb as r <EOL> from sondra . document import valuehandlers <EOL> from sondra . expose import method_schema , method_help <EOL> from sondra . format . json import JSONFormatter <EOL> from . ref import Reference <EOL> class ValidationError ( Exception ) : <EOL> pass <EOL> class RequestProcessor ( object ) : <EOL> def process_api_request ( self , r ) : <EOL> return r <EOL> def __call__ ( self , * args , ** kwargs ) : <EOL> return self . process_api_request ( * args , ** kwargs ) <EOL> class APIRequest ( object ) : <EOL> formats = { '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' } <EOL> DEFAULT_FORMAT = '<STR_LIT>' <EOL> MAX_RESULTS = <NUM_LIT:100> <EOL> SAFE_OPS = { <EOL> '<STR_LIT>' , <EOL> '<STR_LIT:count>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' <EOL> } <EOL> GEOSPATIAL_OPS = { <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> } <EOL> def __str__ ( self ) : <EOL> return """<STR_LIT>""" . format ( <EOL> request_method = self . request_method , <EOL> url = self . reference , <EOL> headers = "<STR_LIT:\n>" . join ( [ '<STR_LIT>' . format ( * i ) for i in self . headers . items ( ) ] ) if self . headers else "<STR_LIT>" , <EOL> api_args = "<STR_LIT:\n>" . join ( [ '<STR_LIT>' . format ( * i ) for i in self . api_arguments . items ( ) ] ) if self . api_arguments else "<STR_LIT>" , <EOL> objects = "<STR_LIT:\n>" . join ( [ '<STR_LIT>' . format ( * i ) for i in enumerate ( self . objects ) ] ) if self . objects else "<STR_LIT>" <EOL> ) <EOL> def __init__ ( self , suite , headers , body , method , user , path , query_params , files ) : <EOL> self . suite = suite <EOL> self . headers = headers <EOL> self . body = body <EOL> self . request_method = method . upper ( ) <EOL> self . user = user <EOL> self . query_params = query_params or { } <EOL> self . files = files <EOL> self . objects = [ ] <EOL> self . api_arguments = { } <EOL> self . formatter_kwargs = { } <EOL> self . query = None <EOL> self . reference = Reference ( <EOL> self . suite , <EOL> "<STR_LIT>" . format ( <EOL> path , <EOL> urlencode ( query_params ) if not isinstance ( query_params , str ) else query_params <EOL> ) <EOL> ) <EOL> self . _parse_query ( ) <EOL> if self . reference . kind in { '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' } and self . reference . get_collection ( ) . private : <EOL> raise PermissionError ( "<STR_LIT>" ) <EOL> self . decision_tree = { <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : self . help , <EOL> '<STR_LIT:POST>' : self . help , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : self . help , <EOL> '<STR_LIT:POST>' : self . help , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : self . help , <EOL> '<STR_LIT:POST>' : self . help , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : self . help , <EOL> '<STR_LIT:POST>' : self . help , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : self . help , <EOL> '<STR_LIT:POST>' : self . help , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : self . help , <EOL> '<STR_LIT:POST>' : self . help , <EOL> } , <EOL> '<STR_LIT>' : { } , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT>' : { } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . json_response , self . method_call ) , <EOL> '<STR_LIT:POST>' : partial ( self . json_response , self . method_call ) , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . json_response , self . get_collection_items ) , <EOL> '<STR_LIT:POST>' : partial ( self . json_response , self . add_collection_items ) , <EOL> '<STR_LIT>' : partial ( self . json_response , self . replace_collection_items ) , <EOL> '<STR_LIT>' : partial ( self . json_response , self . update_collection_items ) , <EOL> '<STR_LIT>' : partial ( self . json_response , self . delete_collection_items ) , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . json_response , self . method_call ) , <EOL> '<STR_LIT:POST>' : partial ( self . json_response , self . method_call ) , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . json_response , self . get_document ) , <EOL> '<STR_LIT:POST>' : partial ( self . json_response , self . set_document ) , <EOL> '<STR_LIT>' : partial ( self . json_response , self . set_document ) , <EOL> '<STR_LIT>' : partial ( self . json_response , self . update_document ) , <EOL> '<STR_LIT>' : partial ( self . json_response , self . delete_document ) , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . json_response , self . method_call ) , <EOL> '<STR_LIT:POST>' : partial ( self . json_response , self . method_call ) , <EOL> } , <EOL> '<STR_LIT>' : { } <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT>' : { } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . geojson_response , self . get_collection_items ) , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . geojson_response , self . get_document ) , <EOL> } , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . json_response , self . schema ) , <EOL> '<STR_LIT:POST>' : partial ( self . json_response , self . schema ) , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . json_response , self . schema ) , <EOL> '<STR_LIT:POST>' : partial ( self . json_response , self . schema ) , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . json_response , self . schema ) , <EOL> '<STR_LIT:POST>' : partial ( self . json_response , self . schema ) , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . json_response , self . schema ) , <EOL> '<STR_LIT:POST>' : partial ( self . json_response , self . schema ) , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . json_response , self . schema ) , <EOL> '<STR_LIT:POST>' : partial ( self . json_response , self . schema ) , <EOL> } , <EOL> '<STR_LIT>' : { <EOL> '<STR_LIT:GET>' : partial ( self . json_response , self . schema ) , <EOL> '<STR_LIT:POST>' : partial ( self . json_response , self . schema ) , <EOL> } <EOL> } , <EOL> } <EOL> def __call__ ( self ) : <EOL> kind = self . reference . kind <EOL> method = self . request_method <EOL> format = self . reference . format <EOL> return self . decision_tree [ format ] [ kind ] . get ( method , self . exceptional_request ) ( ) <EOL> def _parse_query ( self ) : <EOL> target = self . reference . value <EOL> if self . reference . kind . endswith ( '<STR_LIT>' ) : <EOL> schema = method_schema ( * target ) [ '<STR_LIT>' ] [ '<STR_LIT>' ] <EOL> elif self . reference . kind in [ '<STR_LIT>' , '<STR_LIT>' ] : <EOL> schema = target . schema <EOL> else : <EOL> schema = target . collection . schema <EOL> self . formatter_kwargs = self . reference . kwargs <EOL> if self . query_params : <EOL> for k , v in self . query_params . items ( ) : <EOL> v = v [ <NUM_LIT:0> ] <EOL> if v . startswith ( '<STR_LIT:">' ) : <EOL> v = v [ <NUM_LIT:1> : - <NUM_LIT:1> ] <EOL> else : <EOL> try : <EOL> v = int ( v ) <EOL> except ValueError : <EOL> try : <EOL> v = float ( v ) <EOL> except ValueError : <EOL> pass <EOL> self . api_arguments [ k ] = v <EOL> if self . body : <EOL> if isinstance ( self . body , bytes ) : <EOL> body_args = json . loads ( self . body . decode ( '<STR_LIT:utf-8>' ) ) <EOL> elif isinstance ( self . body , str ) : <EOL> body_args = json . loads ( self . body ) <EOL> else : <EOL> body_args = self . body <EOL> if isinstance ( body_args , list ) : <EOL> self . objects . extend ( body_args ) <EOL> else : <EOL> if "<STR_LIT>" in body_args : <EOL> self . api_arguments . update ( body_args [ '<STR_LIT>' ] ) <EOL> self . request_method = body_args . get ( '<STR_LIT>' , self . request_method ) . upper ( ) <EOL> self . objects = body_args . get ( "<STR_LIT>" , [ ] ) <EOL> else : <EOL> self . objects = [ body_args ] <EOL> for object in self . objects : <EOL> jsonschema . validate ( object , schema ) <EOL> if self . files : <EOL> self . objects [ <NUM_LIT:0> ] . update ( self . files ) <EOL> self . durability = self . api_arguments . get ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> self . return_changes = self . api_arguments . get ( '<STR_LIT>' , '<STR_LIT:false>' ) . lower ( ) != '<STR_LIT:false>' <EOL> self . dereference = self . api_arguments . get ( '<STR_LIT>' , '<STR_LIT:false>' ) . lower ( ) != '<STR_LIT:false>' <EOL> self . delete_all = self . api_arguments . get ( '<STR_LIT>' , '<STR_LIT:false>' ) . lower ( ) != '<STR_LIT:false>' <EOL> self . conflict = self . api_arguments . get ( '<STR_LIT>' , { <EOL> '<STR_LIT:POST>' : "<STR_LIT:error>" , <EOL> '<STR_LIT>' : "<STR_LIT:replace>" , <EOL> '<STR_LIT>' : "<STR_LIT:replace>" <EOL> } . get ( self . request_method , '<STR_LIT:error>' ) ) <EOL> def help ( self ) : <EOL> """<STR_LIT>""" <EOL> if '<STR_LIT>' in self . reference . kind : <EOL> instance , method = self . reference . value <EOL> return '<STR_LIT>' , self . suite . docstring_processor ( method_help ( instance , method ) ) <EOL> else : <EOL> value = self . reference . value <EOL> return '<STR_LIT>' , self . suite . docstring_processor ( value . help ( ) ) <EOL> def json_response ( self , method ) : <EOL> return JSONFormatter ( ) ( self . reference , method ( ) , ** self . formatter_kwargs ) <EOL> def _feature ( self , doc ) : <EOL> properties = doc . obj <EOL> for key , value in doc . specials . items ( ) : <EOL> if isinstance ( value , valuehandlers . Geometry ) : <EOL> geometry = doc . obj [ key ] <EOL> break <EOL> else : <EOL> geometry = None <EOL> return { <EOL> "<STR_LIT:type>" : "<STR_LIT>" , <EOL> "<STR_LIT>" : geometry , <EOL> "<STR_LIT>" : properties <EOL> } <EOL> def geojson_response ( self , method ) : <EOL> result = method ( ) <EOL> if isinstance ( result , list ) : <EOL> ret = { <EOL> "<STR_LIT:type>" : "<STR_LIT>" , <EOL> "<STR_LIT>" : [ self . _feature ( x ) for x in result ] <EOL> } <EOL> else : <EOL> ret = self . _feature ( result ) <EOL> return '<STR_LIT:application/json>' , json . dumps ( ret , indent = <NUM_LIT:4> ) <EOL> def method_call ( self ) : <EOL> instance , method = self . reference . value <EOL> if len ( self . objects ) > <NUM_LIT:1> : <EOL> ret = [ method ( ** o ) for o in self . objects ] <EOL> elif len ( self . objects ) == <NUM_LIT:1> : <EOL> ret = method ( ** self . objects [ <NUM_LIT:0> ] ) <EOL> else : <EOL> ret = method ( ) <EOL> return ret <EOL> def _handle_simple_filters ( self , q ) : <EOL> if '<STR_LIT>' in self . api_arguments : <EOL> flt = json . loads ( <EOL> self . api_arguments [ '<STR_LIT>' ] ) if isinstance ( self . api_arguments [ '<STR_LIT>' ] , str ) else self . api_arguments [ '<STR_LIT>' ] <EOL> if isinstance ( flt , dict ) : <EOL> flt = [ flt ] <EOL> print ( flt ) <EOL> for f in flt : <EOL> default = f . get ( '<STR_LIT:default>' , False ) <EOL> op = f . get ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> if op == '<STR_LIT>' : <EOL> q = q . filter ( { f [ '<STR_LIT>' ] : f [ '<STR_LIT>' ] } , default = default ) <EOL> elif op == '<STR_LIT>' : <EOL> q = q . filter ( r . row [ f [ '<STR_LIT>' ] ] != f [ '<STR_LIT>' ] , default = default ) <EOL> elif op == '<STR_LIT:<>' : <EOL> q = q . filter ( r . row [ f [ '<STR_LIT>' ] ] < f [ '<STR_LIT>' ] , default = default ) <EOL> elif op == '<STR_LIT>' : <EOL> q = q . filter ( r . row [ f [ '<STR_LIT>' ] ] <= f [ '<STR_LIT>' ] , default = default ) <EOL> elif op == '<STR_LIT:>>' : <EOL> q = q . filter ( r . row [ f [ '<STR_LIT>' ] ] > f [ '<STR_LIT>' ] , default = default ) <EOL> elif op == '<STR_LIT>' : <EOL> q = q . filter ( r . row [ f [ '<STR_LIT>' ] ] >= f [ '<STR_LIT>' ] , default = default ) <EOL> elif op == '<STR_LIT>' : <EOL> field = f [ '<STR_LIT>' ] <EOL> pattern = f [ '<STR_LIT>' ] <EOL> q = q . filter ( lambda x : x [ field ] . match ( pattern ) , default = default ) <EOL> elif op == '<STR_LIT>' : <EOL> field = f [ '<STR_LIT>' ] <EOL> pattern = f [ '<STR_LIT>' ] <EOL> q = q . filter ( lambda x : x [ field ] . contains ( pattern ) ) <EOL> elif op == '<STR_LIT>' : <EOL> q = q . filter ( lambda x : x . has_fields ( f [ '<STR_LIT>' ] ) , default = default ) <EOL> else : <EOL> raise ValidationError ( "<STR_LIT>" ) <EOL> return q <EOL> def _handle_spatial_filters ( self , coll , q ) : <EOL> if '<STR_LIT>' in self . api_arguments : <EOL> print ( "<STR_LIT>" ) <EOL> geo = json . loads ( <EOL> self . api_arguments [ '<STR_LIT>' ] ) if isinstance ( self . api_arguments [ '<STR_LIT>' ] , str ) else self . api_arguments [ '<STR_LIT>' ] <EOL> geometries = [ k for k in coll . document_class . specials if coll . document_class . specials [ k ] . is_geometry ] <EOL> if not geometries : <EOL> raise ValidationError ( "<STR_LIT>" ) <EOL> if '<STR_LIT>' not in geo : <EOL> test_property = geometries [ <NUM_LIT:0> ] <EOL> elif geo [ '<STR_LIT>' ] not in geometries : <EOL> raise KeyError ( '<STR_LIT>' ) <EOL> else : <EOL> test_property = geo [ '<STR_LIT>' ] <EOL> op = geo [ '<STR_LIT>' ] <EOL> geom = r . geojson ( geo [ '<STR_LIT:test>' ] ) <EOL> if op not in self . GEOSPATIAL_OPS : <EOL> raise ValidationError ( "<STR_LIT>" ) <EOL> q = getattr ( q , op ) ( geom , index = test_property , * geo . get ( '<STR_LIT:args>' , [ ] ) , ** geo . get ( '<STR_LIT>' , { } ) ) <EOL> return q <EOL> def _handle_aggregations ( self , q ) : <EOL> if '<STR_LIT>' in self . api_arguments : <EOL> op = json . loads ( self . api_arguments [ '<STR_LIT>' ] ) <EOL> if op [ '<STR_LIT:name>' ] not in self . SAFE_OPS : <EOL> raise ValidationError ( "<STR_LIT>" ) <EOL> q = getattr ( q , op [ '<STR_LIT:name>' ] ) ( * op . get ( '<STR_LIT:args>' , [ ] ) , ** op . get ( '<STR_LIT>' , { } ) ) <EOL> return q <EOL> def _handle_limits ( self , q ) : <EOL> if '<STR_LIT:start>' and '<STR_LIT:end>' in self . api_arguments : <EOL> s = self . api_arguments [ '<STR_LIT:start>' ] <EOL> e = self . api_arguments [ '<STR_LIT:end>' ] <EOL> if e == <NUM_LIT:0> : <EOL> q = q . skip ( s ) <EOL> else : <EOL> q = q . slice ( s , e ) <EOL> else : <EOL> if '<STR_LIT:start>' in self . api_arguments : <EOL> s = self . api_arguments [ '<STR_LIT:start>' ] <EOL> q = q . skip ( s ) <EOL> if '<STR_LIT>' in self . api_arguments : <EOL> limit = self . api_arguments [ '<STR_LIT>' ] <EOL> q = q . limit ( limit ) <EOL> else : <EOL> q = q . limit ( self . MAX_RESULTS ) <EOL> return q <EOL> def get_collection_items ( self ) : <EOL> coll = self . reference . get_collection ( ) <EOL> if len ( self . objects ) : <EOL> if '<STR_LIT:index>' in self . api_arguments : <EOL> q = coll . table . get_all ( self . objects , index = self . api_arguments [ '<STR_LIT:index>' ] ) <EOL> else : <EOL> q = coll . table . get_all ( self . objects ) <EOL> else : <EOL> q = coll . table <EOL> q = self . _handle_simple_filters ( q ) <EOL> q = self . _handle_spatial_filters ( coll , q ) <EOL> q = self . _handle_aggregations ( q ) <EOL> q = self . _handle_limits ( q ) <EOL> return [ x for x in coll . q ( q ) ] <EOL> def add_collection_items ( self ) : <EOL> coll = self . reference . get_collection ( ) <EOL> changes = coll . create ( self . objects ) <EOL> keys = [ v . id for v in changes ] <EOL> return keys <EOL> def update_collection_items ( self ) : <EOL> coll = self . reference . get_collection ( ) <EOL> docs = [ ] <EOL> for k , updates in self . objects : <EOL> doc = coll [ k ] <EOL> for prop , value in updates . items ( ) : <EOL> doc [ prop ] = value <EOL> docs . append ( doc ) <EOL> ret = coll . save ( docs , conflict = self . conflict , durability = self . durability , return_changes = self . return_changes ) <EOL> return ret <EOL> def replace_collection_items ( self ) : <EOL> coll = self . reference . get_collection ( ) <EOL> docs = [ ] <EOL> for k , new_value in self . objects : <EOL> doc = coll [ k ] . doc ( new_value ) <EOL> doc . id = k <EOL> docs . append ( doc ) <EOL> ret = coll . save ( docs , conflict = self . conflict , durability = self . durability , return_changes = self . return_changes ) <EOL> return ret <EOL> def delete_collection_items ( self ) : <EOL> coll = self . reference . get_collection ( ) <EOL> if len ( self . objects ) : <EOL> if '<STR_LIT:index>' in self . api_arguments : <EOL> q = coll . table . get_all ( self . objects , index = self . api_arguments [ '<STR_LIT:index>' ] ) <EOL> else : <EOL> q = coll . table . get_all ( self . objects ) <EOL> elif self . delete_all : <EOL> q = coll . table <EOL> else : <EOL> raise PermissionError ( "<STR_LIT>" ) <EOL> q = self . _handle_simple_filters ( q ) <EOL> q = self . _handle_spatial_filters ( coll , q ) <EOL> return q . delete ( durability = self . durability , return_changes = self . return_changes ) . run ( coll . application . connection ) <EOL> def get_document ( self ) : <EOL> doc = self . reference . get_document ( ) <EOL> return doc <EOL> def set_document ( self ) : <EOL> doc = self . reference . get_document ( ) <EOL> id = doc . id <EOL> new_doc = doc . collection . doc ( self . objects [ <NUM_LIT:0> ] ) <EOL> new_doc . id = id <EOL> ret = new_doc . save ( conflict = self . conflict , durability = self . durability , return_changes = self . return_changes ) <EOL> return ret <EOL> def update_document ( self ) : <EOL> doc = self . reference . get_document ( ) <EOL> if doc . collection . primary_key in self . objects [ <NUM_LIT:0> ] : <EOL> del self . objects [ <NUM_LIT:0> ] [ doc . collection . primary_key ] <EOL> for k , v in self . objects [ <NUM_LIT:0> ] . items ( ) : <EOL> doc [ k ] = v <EOL> ret = doc . save ( conflict = '<STR_LIT:replace>' , durability = self . durability , return_changes = self . return_changes ) <EOL> return ret <EOL> def delete_document ( self ) : <EOL> doc = self . reference . get_document ( ) <EOL> return doc . delete ( durability = self . durability , return_changes = self . return_changes ) <EOL> def schema ( self ) : <EOL> return self . reference . schema <EOL> def exceptional_request ( self ) : <EOL> raise ValidationError ( "<STR_LIT>" . format ( method = self . request_method , kind = self . reference . kind , url = self . reference . url ) ) </s>
