def put(self): """Insert new orders from the csv data provided in the data parameter.""" get_imports() try: lines = request.form['data'] except KeyError: abort(400, message='Param `data` is required to insert orders') if '|' not in lines: abort(400, message='Expected csv data to be separated with `|`.') try: csvreader = csv.reader(lines.split('\\n'), delimiter='|') except Exception as e: abort( 400, message= 'Error found in reading data as `|` separated csv data. Error is: %s' % str(e)) headers = csvreader.next() ids_inserted_updated = [] for row in csvreader: values = {'valid': True, 'errors': None} for i, item in enumerate(row): # create dictionary of column-name:field-value values.update({headers[i]: item}) # validate the whole row first try: values = schema(values) except MultipleInvalid as e: # errors were found, loop through keys to validate and get the value to store and the errors for individual fields # validate the required fields first for field_name in schema.schema.keys(): if str(field_name) in order_fields[ 'order_fields_validators']['required_fields'].keys( ): field_name = str(field_name) field_schema = create_schema_from_config({ field_name: order_fields['order_fields_validators'] ['required_fields'][field_name] }) try: values.update( field_schema({field_name: values[field_name]})) except KeyError: # a required field is not present, abort abort( 400, message='missing `%s` which is a required field' % field_name) except MultipleInvalid as e: # a required field does not validate, abort abort( 400, message= 'problem validating required field `%s`, error message is: %s' % (field_name, e.errors[0].error_message)) # now validate the optional fields for field_name in schema.schema.keys(): if field_name in order_fields['order_fields_validators'][ 'optional_fields'].keys(): field_schema = create_schema_from_config({ field_name: order_fields['order_fields_validators'] ['optional_fields'][field_name] }) try: values.update( field_schema({field_name: values[field_name]})) except MultipleInvalid as e: values['valid'] = False # loops through each field in the schema that raised errors for error in e.errors: self.add_to_error_list(values, field_name, error) # check if the field requires a default when validation to coerce it fails if error.path and len(error.path) == 1: order_fields_defaults = order_fields[ 'order_fields_defaults'] if field_name in order_fields_defaults: # this is a field that requires a replacement value if order_fields_defaults[field_name][ 'coerce_failure_msg'] == error.error_message: # the error message corresponds to the coercion error message, update with replacement value values[ field_name] = order_fields_defaults[ field_name][ 'failure_value'] else: # the coercion was successul but another validation requirement failed. # coerce again to avoid database Type Errors upon insertion coerce_schema = create_schema_from_config({ field_name: { 'functions': { 'CoerceTo': order_fields[ 'order_fields_validators'] ['optional_fields'] [field_name] ['functions'] ['CoerceTo'] } } }) values.update( coerce_schema({ field_name: values[field_name] })) else: pass # field name not in schema at all, a future implementation would add the database field here # validation that depends on more than one field if dependent_schema: try: dependent_schema(values) except MultipleInvalid as e: values['valid'] = False for error in e.errors: self.add_to_error_list(values, 'multiple fields', error) # validation is complete, now do some prep and then add the record to the db session if 'errors' in values and values['errors']: values['errors'] = json.dumps(values['errors']) order = Order(**values) db.session.merge(order) ids_inserted_updated.append(order.id) db.session.commit() return { "results": marshal( db.session.query(Order).filter( Order.id.in_(ids_inserted_updated)).all(), full_resource_fields) }, 201 #
app = Flask(__name__) if 'FLASKR_SETTINGS' in os.environ: app.config.from_envvar('FLASKR_SETTINGS', silent=True) else: app.config.from_object('api.settings') rest_api = Api(app) db = SQLAlchemy(app) # set up validation, parse yaml config file validate_with = dict( (const, eval(const)) for const in VALIDATION_CONSTANTS + VALIDATION_ERRORS) order_fields_file = open( os.path.abspath( os.path.join(app.config['PROJECT_DIR'], 'api/config/field_validators.yaml'))) s = Template(order_fields_file.read()) s = s.substitute(**validate_with) order_fields = yaml.load(s) order_fields_file.close() schema, dependent_schema = create_schema_from_config( order_fields['order_fields_validators'], simple=False) # set up restful Routes rest_api.add_resource(resources.OrderImport, '/orders/import/') rest_api.add_resource(resources.Orders, '/orders/') rest_api.add_resource(resources.FullOrder, '/orders/<string:order_id>/') if __name__ == '__main__': app.run()
def put(self): """Insert new orders from the csv data provided in the data parameter.""" get_imports() try: lines = request.form["data"] except KeyError: abort(400, message="Param `data` is required to insert orders") if "|" not in lines: abort(400, message="Expected csv data to be separated with `|`.") try: csvreader = csv.reader(lines.split("\\n"), delimiter="|") except Exception as e: abort(400, message="Error found in reading data as `|` separated csv data. Error is: %s" % str(e)) headers = csvreader.next() ids_inserted_updated = [] for row in csvreader: values = {"valid": True, "errors": None} for i, item in enumerate(row): # create dictionary of column-name:field-value values.update({headers[i]: item}) # validate the whole row first try: values = schema(values) except MultipleInvalid as e: # errors were found, loop through keys to validate and get the value to store and the errors for individual fields # validate the required fields first for field_name in schema.schema.keys(): if str(field_name) in order_fields["order_fields_validators"]["required_fields"].keys(): field_name = str(field_name) field_schema = create_schema_from_config( {field_name: order_fields["order_fields_validators"]["required_fields"][field_name]} ) try: values.update(field_schema({field_name: values[field_name]})) except KeyError: # a required field is not present, abort abort(400, message="missing `%s` which is a required field" % field_name) except MultipleInvalid as e: # a required field does not validate, abort abort( 400, message="problem validating required field `%s`, error message is: %s" % (field_name, e.errors[0].error_message), ) # now validate the optional fields for field_name in schema.schema.keys(): if field_name in order_fields["order_fields_validators"]["optional_fields"].keys(): field_schema = create_schema_from_config( {field_name: order_fields["order_fields_validators"]["optional_fields"][field_name]} ) try: values.update(field_schema({field_name: values[field_name]})) except MultipleInvalid as e: values["valid"] = False # loops through each field in the schema that raised errors for error in e.errors: self.add_to_error_list(values, field_name, error) # check if the field requires a default when validation to coerce it fails if error.path and len(error.path) == 1: order_fields_defaults = order_fields["order_fields_defaults"] if field_name in order_fields_defaults: # this is a field that requires a replacement value if ( order_fields_defaults[field_name]["coerce_failure_msg"] == error.error_message ): # the error message corresponds to the coercion error message, update with replacement value values[field_name] = order_fields_defaults[field_name]["failure_value"] else: # the coercion was successul but another validation requirement failed. # coerce again to avoid database Type Errors upon insertion coerce_schema = create_schema_from_config( { field_name: { "functions": { "CoerceTo": order_fields["order_fields_validators"][ "optional_fields" ][field_name]["functions"]["CoerceTo"] } } } ) values.update(coerce_schema({field_name: values[field_name]})) else: pass # field name not in schema at all, a future implementation would add the database field here # validation that depends on more than one field if dependent_schema: try: dependent_schema(values) except MultipleInvalid as e: values["valid"] = False for error in e.errors: self.add_to_error_list(values, "multiple fields", error) # validation is complete, now do some prep and then add the record to the db session if "errors" in values and values["errors"]: values["errors"] = json.dumps(values["errors"]) order = Order(**values) db.session.merge(order) ids_inserted_updated.append(order.id) db.session.commit() return ( { "results": marshal( db.session.query(Order).filter(Order.id.in_(ids_inserted_updated)).all(), full_resource_fields ) }, 201, ) #
import resources app = Flask(__name__) if 'FLASKR_SETTINGS' in os.environ: app.config.from_envvar('FLASKR_SETTINGS', silent=True) else: app.config.from_object('api.settings') rest_api = Api(app) db = SQLAlchemy(app) # set up validation, parse yaml config file validate_with = dict((const,eval(const)) for const in VALIDATION_CONSTANTS + VALIDATION_ERRORS) order_fields_file = open(os.path.abspath(os.path.join(app.config['PROJECT_DIR'], 'api/config/field_validators.yaml'))) s = Template(order_fields_file.read()) s = s.substitute(**validate_with) order_fields = yaml.load(s) order_fields_file.close() schema, dependent_schema = create_schema_from_config(order_fields['order_fields_validators'], simple=False) # set up restful Routes rest_api.add_resource(resources.OrderImport, '/orders/import/') rest_api.add_resource(resources.Orders, '/orders/') rest_api.add_resource(resources.FullOrder, '/orders/<string:order_id>/') if __name__ == '__main__': app.run()