from flask import Flask
from flask_dynamo import Dynamo
import os
os.environ['AWS_ACCESS_KEY_ID'] = ''
os.environ['AWS_SECRET_ACCESS_KEY'] = ''
os.environ['AWS_REGION'] = 'ap-south-1'
app = Flask(__name__)
app.config['DYNAMO_TABLES'] = [
{
'TableName': 'users',
'KeySchema': [dict(AttributeName='username', KeyType='HASH')],
'AttributeDefinitions': [dict(AttributeName='username', AttributeType='S')],
'ProvisionedThroughput': dict(ReadCapacityUnits=5, WriteCapacityUnits=5)
}, {
'TableName': 'groups',
'KeySchema': [dict(AttributeName='name', KeyType='HASH')],
'AttributeDefinitions': [dict(AttributeName='name', AttributeType='S')],
'ProvisionedThroughput': dict(ReadCapacityUnits=5, WriteCapacityUnits=5)
}
]
app.config['DYNAMO_ENABLE_LOCAL'] = True
app.config['DYNAMO_LOCAL_HOST'] = 'localhost'
app.config['DYNAMO_LOCAL_PORT'] = 9000
dynamo = Dynamo()
The table configuration for flask-dynamo has been defined and dynamo instance created,when i try to get the create all tables get error of builtins.AttributeError AttributeError: 'Dynamo' object has no attribute 'tables'
#app.route('/', methods=['GET'])
def hello_world():
with app.app_context():
dynamo.create_all()
return 'table created!'
environment
python3
flask-dynamo
Thanks in advance
This line:
dynamo = Dynamo()
should be:
dynamo = Dynamo(app)
That way, the dynamo instance can access the tables and other configurations you defined on the app object.
Related
So I have this flask application and I'm trying to test it with pytest
app.py:
import os
from flask import Flask, jsonify
from flask_smorest import Api
from flask_jwt_extended import JWTManager
from flask_migrate import Migrate
from db import db
from resources.item import blp as ItemBlueprint
from resources.store import blp as StoreBlueprint
from resources.tag import blp as TagBlueprint
from resources.user import blp as UserBlueprint
from blocklist import BLOCKLIST
def create_app(db_url=None):
app = Flask(__name__)
app.config["PROPAGATE_EXCEPTIONS"] = True
app.config["API_TITLE"] = "Stores REST API"
app.config["API_VERSION"] = "v1"
app.config["OPENAPI_VERSION"] = "3.0.3"
app.config["OPENAPI_URL_PREFIX"] = "/"
app.config["OPENAPI_SWAGGER_UI_PATH"] = "/swagger-ui"
app.config["OPENAPI_SWAGGER_UI_URL"] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist/"
app.config["SQLALCHEMY_DATABASE_URI"] = db_url or os.getenv("DATABASE_URL", "sqlite:///data.db")
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
db.init_app(app)
api = Api(app)
migrate = Migrate(app, db)
app.config['JWT_SECRET_KEY'] = '69490938337699758397870296439802775085'
jwt = JWTManager(app)
#jwt.needs_fresh_token_loader
def token_not_fresh_callback(jwt_header, jwt_payload):
return (
jsonify(
{
"description": "The token is not fresh.",
"error": "fresh_token_required",
}
),
401,
)
#jwt.token_in_blocklist_loader
def check_if_token_in_blocklist(jwt_header, jwt_payload):
return jwt_payload['jti'] in BLOCKLIST
#jwt.revoked_token_loader
def revoked_token_callback(jwt_header, jwt_payload):
return (
jsonify(
{
"description": "The token has been revoked.",
"error": "token_revoked"
}
)
)
#jwt.additional_claims_loader
def add_claims_to_jwt(identity):
if identity == 1:
return {"is_admin": True}
return {"is_admin": False}
#jwt.expired_token_loader
def expired_token_callback(jwt_header, jwt_payload):
return (
jsonify(
{
"message": "The token has expired.",
"error": "token_expired"
}
),
401,
)
#jwt.invalid_token_loader
def invalid_token_callback(error):
return (
jsonify(
{
"message": "Signature verification failed.",
"error": "invalid_token"
}
), 401,
)
#jwt.unauthorized_loader
def missing_token_callback(error):
return (
jsonify(
{
"description": "Request does not contain an access token.",
"error": "authorization_required",
}
), 401,
)
# #app.before_first_request
# def create_tables():
# db.create_all()
api.register_blueprint(ItemBlueprint)
api.register_blueprint(StoreBlueprint)
api.register_blueprint(TagBlueprint)
api.register_blueprint(UserBlueprint)
return app
And I am trying to test some endpoints like create a store, so I'm doing this in the tests/conftest.py
from app import create_app
#pytest.fixture(scope='module')
def client():
flask_app = create_app()
flask_app.testing = True
flask_app.testing = True
with flask_app.test_client() as testing_client:
with flask_app.app_context():
yield testing_client
And there is the test for creation of a store
from flask_jwt_extended import create_access_token
def test_store_creation(client):
"""
GIVEN a Store model
WHEN a new Store is created
THEN check the name field is defined correctly
"""
access_token = create_access_token('admin')
headers = {
'Authorization': 'Bearer {}'.format(access_token)
}
response = client.post('/store', data={"name": "test_store"}, headers=headers)
print(response.get_json())
assert response.status_code == 201
The Store schema
class PlainItemSchema(Schema):
id = fields.Str(dump_only=True)
name = fields.Str(required=True)
price = fields.Float(required=True)
class PlainTagSchema(Schema):
id = fields.Int(dump_only=True)
name = fields.Str()
class PlainStoreSchema(Schema):
id = fields.Str(dump_only=True)
name = fields.Str(required=True)
class StoreSchema(PlainStoreSchema):
items = fields.List(fields.Nested(PlainItemSchema()), dump_only=True)
tags = fields.List(fields.Nested(PlainTagSchema()), dump_only=True)
My Store Blueprint
from flask.views import MethodView
from flask_smorest import abort, Blueprint
from sqlalchemy.exc import SQLAlchemyError, IntegrityError
from flask_jwt_extended import jwt_required, get_jwt
from schemas import StoreSchema
from db import db
from models import StoreModel
blp = Blueprint('stores', __name__, description='Operations on stores')
#blp.route('/store/<int:store_id>')
class Store(MethodView):
#blp.response(200, StoreSchema)
def get(self, store_id):
store = StoreModel.query.get_or_404(store_id)
return store
#jwt_required(fresh=True)
def delete(self, store_id):
"""Only admins can delete stores"""
jwt = get_jwt()
if not jwt.get('is_admin'):
abort(400, message='Admin privilege required.')
store = StoreModel.query.get_or_404(store_id)
db.session.delete(store)
db.session.commit()
return {"message": "Store deleted"}
#blp.route("/store")
class StoreList(MethodView):
#blp.response(200, StoreSchema(many=True))
def get(self):
return StoreModel.query.all()
#jwt_required()
#blp.arguments(StoreSchema)
#blp.response(201, StoreSchema)
def post(self, store_data):
store = StoreModel(**store_data)
try:
db.session.add(store)
db.session.commit()
except IntegrityError:
abort(
400,
message="A store with that name already exists.",
)
except SQLAlchemyError:
abort(500, message="An error occurred creating the store.")
return store
The error I'm getting is this
============================= test session starts ==============================
collecting ... collected 1 item
test_stores.py::test_store_creation FAILED [100%]{'code': 422, 'errors': {'json': {'name': ['Missing data for required field.']}}, 'status': 'Unprocessable Entity'}
test_stores.py:4 (test_store_creation)
422 != 201
Expected :201
Actual :422
<Click to see difference>
client = <FlaskClient <Flask 'app'>>
def test_store_creation(client):
"""
GIVEN a Store model
WHEN a new Store is created
THEN check the name field is defined correctly
"""
data = {
"name": "test"
}
access_token = create_access_token('admin')
headers = {
'Authorization': 'Bearer {}'.format(access_token)
}
response = client.post('/store', headers=headers, data=data)
print(response.get_json())
> assert response.status_code == 201
E assert 422 == 201
E + where 422 = <WrapperTestResponse 109 bytes [422 UNPROCESSABLE ENTITY]>.status_code
test_stores.py:22: AssertionError
It's like I'm not sending any data in the cliet.post() method, In fact if I remove the 'data={'name': 'test'}' I get the same result.
I tried to put data dict outside the method and convert it to json with json.dumps(data) still getting the result
flask-smorest is expecting you to post json data as default, so automatically send it as json OR adjust your header manually to reflect the data your are sending.
Fix your code as:
response = client.post("/store", json={"name": "test_store"}, headers=headers)
Following code runs instances as per given requirement e.g 3, but it create tags, add loadbalancer target group to only one instance also return only one instance ID, and skips the remaining two instances.
I don't understand why, can you help me?
import boto3
import json
import botocore
import os
import sys
from collections import defaultdict
AMI = 'ami-047a51fa27710816e'
INSTANCE_TYPE = 't2.micro'
KEY_NAME = 'mikey'
REGION = 'us-east-1'
client = boto3.client('ec2', region_name=REGION)
client= boto3.client('ec2')
def lambda_handler(event, context):
instance = client.run_instances(
ImageId=AMI,
InstanceType=INSTANCE_TYPE,
KeyName=KEY_NAME,
MaxCount=3,
MinCount=3
)
print ("New instance created:", instance)
instance_id = instance['Instances'][0]['InstanceId']
waiter = client.get_waiter('instance_running')
waiter.wait(InstanceIds=[instance_id],
WaiterConfig={
'Delay': 15
})
print (instance_id)
response_tags = client.create_tags(
Resources=[
instance_id,
],
Tags=[
{
'Key': 'Name',
'Value': 'test'
},
]
)
print ("Tags added")
clients=boto3.client('elbv2')
response_tg = clients.register_targets(
TargetGroupArn='arn:aws:elasticloadbalancing:us-east-1:123456789123:targetgroup/target-demo/c64e6bfc00b4658f',
Targets=[
{
'Id': instance_id
},
]
)
return ('Instance created', instance_id)
The run_instances call will actually return all instance ids, you're just only processing one of them.
This is where you explicitly only extract a single instance id.
instance_id = instance['Instances'][0]['InstanceId']
What you should do is process all of them with something like this:
instance = client.run_instances() # Your full call here
instance_ids = [item['InstanceId'] for item in instance['Instances']]
waiter = client.get_waiter('instance_running')
waiter.wait(InstanceIds=instance_ids)
#... now all your instances are running
response_tags = client.create_tags(
Resources=instance_ids,
Tags=[{"Key": "Name", "Value": "Test"}]
)
elb_client = boto3.client("elbv2")
response_tg = elb_client.register_targets(
TargetGroupArn="arn...",
Targets=[{"Id": instance_id} for instance_id in instance_ids]
)
The variable instance_ids is now a list with the three instance ids and you'll have to update the register_targets and create_tags calls as well to reflect this.
I am creating a API endpoints using flask-sqlalchemy and marshmallow in python. For example I have two collections/tables one is items and other is stores. Items will have attributes like item_id, item_name, item_price and available stores_list. Store will have attributes like store_id, store_name, store_location and available items_list. I require the following JSON response when i request list of items.
[
{
item_id:1,
item_name:"Laptop",
item_price:"20",
store_list:[
{
store_id:1,
store_name:"ABC",
store_location:"USA"
},
{
store_id:2,
store_name:"BBC",
store_location:"USA"
},
{
store_id:3,
store_name:"CBC",
store_location:"USA"
}
]
},
{
item_id:2,
item_name:"Laptop",
item_price:"20",
store_list:[
{
store_id:1,
store_name:"ABC",
store_location:"USA"
},
{
store_id:2,
store_name:"BBC",
store_location:"USA"
},
{
store_id:3,
store_name:"CBC",
store_location:"USA"
}
]
}
......... and so on
]
I require the following JSON response when i request list of stores.
[
{
store_id:1,
store_name:"ABC",
store_location:"USA",
items_list:[
{
items_id:1,
items_name:"Laptop",
items_price:"65"
},
{
items_id:2,
items_name:"Keyboard",
items_price:"56"
},
{
items_id:3,
items_name:"Mouse",
items_price:"56"
}
]
},
{
store_id:2,
store_name:"BBC",
store_location:"UK",
items_list:[
{
items_id:1,
items_name:"Laptop",
items_price:"23"
},
{
items_id:2,
items_name:"BBC",
items_price:"Speaker"
},
{
items_id:3,
items_name:"Mouse",
items_price:"24"
}
]
}
......... and so on
]
So far I have tried the following
#ITEMS MODEL
from requests import Response
from flask import request, url_for
from datetime import datetime
from typing import List
from db import db
from models.store import Stores
#Bartiny Ingredients Generic Types Model
class Items(db.Model):
__tablename__ = "items"
item_id = db.Column(db.Integer, primary_key=True)
item_name = db.Column(db.String(100), nullable=False,)
item_price = db.Column(db.String(10), nullable=False,)
store_lsit = db.relationship('Stores', backref=db.backref('items'))
#classmethod
def find_by_name(cls, name: str) -> "Items":
return cls.query.filter_by(gen_type_name=name).first()
#classmethod
def find_by_id(cls, _id: int) -> "Items":
return cls.query.filter_by(id=_id).first()
#classmethod
def find_all(cls) -> List["Items"]:
return cls.query.all()
def save_to_db(self) -> None:
db.session.add(self)
db.session.commit()
def delete_from_db(self) -> None:
db.session.delete(self)
db.session.commit()
STORE MODEL
from requests import Response
from flask import request, url_for
from datetime import datetime
from typing import List
from db import db
from models.items import Items
#Bartiny Ingredients Generic Types Model
class Stores(db.Model):
__tablename__ = "stores"
store_id = db.Column(db.Integer, primary_key=True)
store_name = db.Column(db.String(100), nullable=False,)
store_locations = db.Column(db.String(10), nullable=False,)
items_list = db.relationship('Items', backref=db.backref('stores'))
#classmethod
def find_by_name(cls, name: str) -> "Stores":
return cls.query.filter_by(gen_type_name=name).first()
#classmethod
def find_by_id(cls, _id: int) -> "Stores":
return cls.query.filter_by(id=_id).first()
#classmethod
def find_all(cls) -> List["Stores"]:
return cls.query.all()
def save_to_db(self) -> None:
db.session.add(self)
db.session.commit()
def delete_from_db(self) -> None:
db.session.delete(self)
db.session.commit()
SCHEMAS
# Items Schema
from ma import ma
from marshmallow import pre_dump
from models.item import Items
class ItemsSchema(ma.ModelSchema):
class Meta:
model = Items
# Store Schema
from ma import ma
from marshmallow import pre_dump
from models.store import Stores
class StoresSchema(ma.ModelSchema):
class Meta:
model = Stores
Resources
# Store Resource
from flask_restful import Resource
from models.store import Stores
from schemas.store import StoresSchema
store_list_schema = StoreSchema(many=True)
class StoreList(Resource):
#classmethod
def get(cls):
return {"stores": store_list_schema.dump(Stores.find_all())}, 200
# Items Resource
from flask_restful import Resource
from models.item import Items
from schemas.item import ItemsSchema
item_list_schema = ItemsSchema(many=True)
class StoreList(Resource):
#classmethod
def get(cls):
return {"items": item_list_schema.dump(Items.find_all())}, 200
The following is the code for app starting
from flask import Flask, jsonify
from flask_restful import Api
from marshmallow import ValidationError
from db import db
from ma import ma
from resources.item import Item, ItemList
from resources.store import Store, StoreList
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///data.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
api = Api(app)
#app.before_first_request
def create_tables():
db.create_all()
#app.errorhandler(ValidationError)
def handle_marshmallow_validation(err):
return jsonify(err.messages), 400
jwt = JWTManager(app)
api.add_resource(StoreList, "/stores")
api.add_resource(ItemList, "/items")
if __name__ == "__main__":
db.init_app(app)
ma.init_app(app)
app.run(port=5000, debug=True)
Looks like jsonify is your friend...
https://www.google.com/search?q=flask+sqlalchemy+to+json
Using automap_base from sqlalchemy.ext.automap to map my tables.
Not able to shema.dumps(result);
getting
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Decimal is not JSON serializable
Tried using JSON custom decoders, but no use.
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import Session
from sqlalchemy.ext.automap import automap_base
from flask_marshmallow import Marshmallow
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
db = SQLAlchemy(app)
ma = Marshmallow(app)
engine = db.engine
session = Session(engine)
Base = automap_base()
Base.prepare(engine, reflect=True)
MyTable = Base.classes.my_table
class MyTableSchema(ma.ModelSchema):
class Meta:
model = MyTable
#app.route("/")
def api():
all_rows = session.query(MyTable).all()
schema = MyTableSchema(many=True)
response = schema.dumps(all_rows)
return response
if __name__ == '__main__':
app.run(debug=True)
An easy workaround to transform an SQLAlchemy result object in JSON is using simplejson.
You just need to import it (import simplejson) and it works.
Using your example:
import simplejson
...
#app.route("/")
def api():
all_rows = session.query(MyTable).all()
response = simplejson.dumps(all_rows)
Add .data to response like below
def api():
all_rows = session.query(MyTable).all()
schema = MyTableSchema(many=True)
response = schema.dumps(all_rows)
return response.data
I need to compare two values in data format
import groovy.sql.*
com.eviware.soapui.support.GroovyUtils.registerJdbcDriver( "oracle.jdbc.driver.OracleDriver" )
def messageId1 = context.expand( '${#Project#Id1}' )
def messageId2 = context.expand( '${#Project#Id2}' )
def first = sql.firstRow("select timestamp from table where Messageid = '"+messageId1+"'")
def second = sql.firstRow("select timestamp from table where Messageid = '"+messageId2+"'")
assert first < second, 'OK'
I get following error:
error: groovy.lang.MissingPropertyException No such property: sql for class: Script9
I had the same issue and the mistake that I made is, I didn't create a SQL Instance...So this would help you
def DBurl = '<Your database URL>'
def DBuser = '<Database user name>'
def DBpassword = '<Database Password>'
def DBdriver = '< Your database driver>'
def sql = Sql.newInstance(DBurl, DBuser, DBpassword, DBdriver)