Project setting
Python 3.5.3
flask 0.12.2
Directory
.
├── Core
│ ├── BackgroundProcessManager.py
│ ├── FirebaseDatabaseManager.py
│ ├── LearningManager.py
│ ├── __init__.py
│
├── FrontEnd
│ ├── HomePage.py
│ ├── __init__.py
│
├── LICENSE
├── README.md
├── Route
│ ├── RouteManager.py
│ ├── __init__.py
│
├── Settings
│ ├── DefineManager.py
│ ├── __init__.py
│
├── Utils
│ ├── LoggingManager.py
│ ├── __init__.py
│
├── index.py
└── runner.sh
Expected behavior
All the route link is in Route/RouteManager.py
Flask main source is in index.py
I want send fake request and test response using pytest-flask.
Actual behavior
I don't know how to send fake post data and testing.
Source
index.py
from flask import Flask
from Settings import DefineManager
from Route import *
import imp
import sys
imp.reload(sys)
app = Flask(__name__)
app.register_blueprint(routes)
if __name__ == '__main__':
app.debug = True
app.run(host=DefineManager.SERVER_USING_HOST, port=DefineManager.SERVER_USING_PORT)
Route/RouteManager.py
#routes.route("/")
def IndexPage():
LoggingManager.PrintLogMessage("RouteManager", "IndexPage", "web page connection!", DefineManager.LOG_LEVEL_INFO)
return HomePage.RenderIndexPage()
#routes.route("/upload/", methods=['POST'])
def UploadRawDatas():
content = request.get_json(silent=True)
LoggingManager.PrintLogMessage("RouteManager", "UploadRawDatas", "json data: " + str(content), DefineManager.LOG_LEVEL_INFO)
return BackgroundProcessManager.UploadRawDatas(content['Data'], content['Date'], content['Day'])
#routes.route("/forecast/", methods=['POST'])
def ForecastDatas():
content = request.get_json(silent=True)
LoggingManager.PrintLogMessage("RouteManager", "ForecastDatas", "json data: " + str(content), DefineManager.LOG_LEVEL_INFO)
return BackgroundProcessManager.ForecastDatas(content['ProcessId'])
Test case
/upload/
Request data
header
Content-Type application/json
body
{
"Data": [20.0, 30.0, 401.0, 50.0],
"Date": ["2017-08-11", "2017-08-12", "2017-08-13", "2017-08-14"],
"Day": 4
}
Response data
header
Content-Type application/json
body
{"Result": 39}
Expect test process
Send fake post data.
Receive response data.
Assert check Result is not equal -1
pytest-flask provide several fixtures, including a client one. With it you can make a test function similar to this:
def test_upload(client):
mimetype = 'application/json'
headers = {
'Content-Type': mimetype,
'Accept': mimetype
}
data = {
'Data': [20.0, 30.0, 401.0, 50.0],
'Date': ['2017-08-11', '2017-08-12', '2017-08-13', '2017-08-14'],
'Day': 4
}
url = '/upload/'
response = client.post(url, data=json.dumps(data), headers=headers)
assert response.content_type == mimetype
assert response.json['Result'] == 39
While the accepted answer works, it can be simplified by passing the kwarg json into the post method instead of data
def test_upload(client):
data = {
'Data': [20.0, 30.0, 401.0, 50.0],
'Date': ['2017-08-11', '2017-08-12', '2017-08-13', '2017-08-14'],
'Day': 4
}
url = '/upload/'
response = client.post(url, json=data)
assert response.content_type == 'application/json'
assert response.json['Result'] == 39
Related
I have a flask app with the following structure:
/test
├── /application
│ ├── __init__.py
│ ├── routes.py
│ ├── /static
│ ├── /templates
│ └── /dashboard
│ └── __init__.py
├── db.py
├── config.py
├── requirements.txt
├── helpers.py
└── wsgi.py
I am trying to implement a dash dashboard by intitating it through calling a function in application.init.py
where the function is define in dashboard.init.py
my application.init.py
def init_app():
"""Construct core Flask application."""
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('config.Config')
# Ensure responses aren't cached
#app.after_request
def after_request(response):
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
# Custom filter
app.jinja_env.filters["usd"] = usd
Session(app)
assets = Environment()
assets.init_app(app)
with app.app_context():
# Import parts of our core Flask app
from . import routes
from .assets import compile_static_assets
# Import Dash application
from .dashboard import init_dashboard
app = init_dashboard(app)
# Compile static assets
compile_static_assets(assets)
return app
in dashboard.init.py file the function init_dashboard need to access the database and the user id, because the dashboard layout need to use values from the database so that it will show the specific dashboard for the user, but of course this does not work as it return the error "Working outside of request context".
If I will try to create the dashboard in routes for example:
#app.route("/dashapp/")
#login_required
def redirect_to_dashapp():
dash_app = dash.Dash(
server=app,
routes_pathname_prefix="/dashapp/")
"""Create a Plotly Dash dashboard."""
stocks = db.session.query(Records.symbol, Records.number_of_shares, Records.purchase_p, Records.execution_time).filter_by(user_id=session["user_id"]).all()
.....
it will return the error "A setup function was called after the first request was handled. "
As the dash layout need values from the database I can't initiate it in init_dashboard() without accessing the db, and I can't initiate in routes either.
Does anyone has a suggestion on how to properly do it?
1.I was trying to use Pymongo to connect to my MongoDB atlas database. I wrote this file into the connect.py file. Here is the tree folder structure. The connect.py contains the URL information to connect the database.
└── uploading
├── __pycache__
│ └── upload.cpython-38.pyc
└── upload.py
├── Database
│ ├── __pycache__
│ │ └── connect.cpython-38.pyc
│ └── connect.py
├── app.py
2.Here is code for connect.py
import pymongo
client = pymongo.MongoClient("URL",ssl=True, ssl_cert_reqs='CERT_NONE')
db = client.datasets
Here is the code for uplod.py
from flask import Blueprint, current_app
from Database.connect import db
sample = Blueprint('sample', __name__)
#sample.route('/')
def index():
x = current_app.config['UPLOAD_PATH']
return str(db)
Here is the code for app.py:
app = Flask(__name__)
app.secret_key = b'pj&\xe9\xd7\xd7\xabc\xe6KX\xbe\x9f<\x9f\x87'
app.config['UPLOAD_PATH'] = 'public' # to create a folder which is used to save the uploaded file
CORS(app)
app.register_blueprint(sample)
'''
Datasets and model upload
'''
#app.route('/connect-upload', methods=["POST"])
#cross_origin()
def connect_upload():
index=0
# get username
return "result"
When I tried to use : from Database.connect import db to import database in the upload.py, it showed error message :ImportError: cannot import name 'db' from 'Database.connect'. How can I solve this problem?
You are not referencing your module correctly. Your module should be the filename. You should use from connect import db.
I am trying to use Flask restful as a Blueprint in a pattern that works for other blueprints. I keep getting the following error message
I get the following error message
AttributeError: 'Blueprint' object has no attribute 'add_resource'
My project setup is as follows:
Folder structure
├── app
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ └── routes.py
│ ├── main
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ └── views.py
│ └── templates
│ ├── base.html
│ └── home.html
├── config.py
├── manage.py
└── requirements.txt
__init__.py
from flask import Flask
from flask_restful import Api
from flask_bootstrap import Bootstrap
from config import config
bootstrap = Bootstrap()
api = Api()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
api.init_app(app)
from .main import main as main_blueprint
from .api import api as api_blueprint
app.register_blueprint(main_blueprint)
app.register_blueprint(api_blueprint)
return app
api/__init__.py
from flask import Blueprint
api = Blueprint('api', __name__)
from . import routes
api/routes.py
from flask_restful import Resource
from . import api
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
api.add_resource(TodoItem, '/todos/<int:id>')
What am I doing wrong??
If you follow the instructions from https://flask-restful.readthedocs.io/en/0.3.5/intermediate-usage.html
The key points here are to create a Flask Blueprint instance & pass it to a new instance of flask-restfuls's Api class.
Lastly, make sure to register the flask-restful api blueprint within your create_app function: app.register_blueprint(api_bp)
from flask import Flask, Blueprint
from flask_restful import Api
from flask_bootstrap import Bootstrap
from config import config
bootstrap = Bootstrap()
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
from .users import main as users_blueprint
from .blogs import main as blogs_blueprint
# blueprints for blogs & users
app.register_blueprint(users_blueprint)
app.register_blueprint(blogs_blueprint)
app.register_blueprint(api_bp)
return app
Also note, you don't need to register api.init_app(app) anymore.
You're running in to trouble because of how you've named your blueprint api, whilst also using the api object from flask_restful. In your routes.py you're explicitly importing api from api/__init__.py, and this is a Blueprint object. You can't call add_resource to a Blueprint object, only to an Api object from flask_restful.
If you change your import to:
from .. import api
you'll be importing the correct object. I'd still recommend changing your blueprint name anyway to avoid this sort of confusion.
If you want to have submodules (like your /api) based on resources...
Eg: folder structure
├── app
│ ├── __init__.py
│ ├── foo
│ │ ├── __init__.py
│ │ └── routes.py
│ ├── boo
│ │ ├── __init__.py
│ │ └── routes.py
├── config.py
├── manage.py
... and register their blueprints with url_prefix to not repeat the common part in each added resource. Create new Api instance in each module and pass to it a blueprint.
foo/__init__.py
from flask import Blueprint
from flask_restful import Api
foo_bp = Blueprint('foo', __name__, url_prefix='/foo')
foo_api = Api(foo_bp)
from . import routes
in routes import foo_api and add resources to it
foo/routes.py
from flask_restful import Resource
from . import foo_api
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
foo_api.add_resource(TodoItem, '/todos/<int:id>')
Then in main application __init__.py just import modules blueprints and register it. You dont even need to add a "main" application blueprint. If you would import the api from main application __init__ then you can't register each blueprint with it's own params like url_prefix.
__init__.py
from flask import Flask
from config import config
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
from .foo import foo_bp
from .boo import boo_bp
app.register_blueprint(foo_bp)
app.register_blueprint(boo_bp)
return app
You can set the url_prefix on register blueprint (it has priority) or when you create it. To check routes you can print the app.url_map
I am using django 1.5.1 and trying to get moving the management command. I have an app called patient and here is the directory structure.
patient/
├── __init__.py
├── forms.py
├── management
│ ├── __init.py__
│ └── commands
│ ├── __init.py__
│ └── recall1.py
├── models.py
├── urls.py
├── views.py
Here is what happens when I try to run the recall1 command:
$ python manage.py recall1
Unknown command: 'recall1'
Here is how my code looks like:
from django.core.management.base import BaseCommand, CommandError
from recall.model import PatientRecalls, RecallType, RecallMessage
from patient.model import Patient
class Command(BaseCommand):
args = '<patient_id patient_id ...>'
def handle(self, *args, **options):
for patient_id in args:
try:
patient = Patient.objects.get(pk=int(patient_id))
except Patient.DoesNotExist:
raise CommandError('Patient "%s" does not exist' % patient_id)
patient.opened = False
patient.save()
self.stdout.write('Successfully closed patient "%s"' % patient_id)
What wrong do I need to correct before I can run this thing? The app is running great, except for this issue..
Your filename __init.py__ should actually be __init__.py both in the directories management/ and commands/
My project directory looks like this. settings_value.py has a template tag, named 'settings_value' in it. In my settings.py I added 'itslogical.templatetags' to INSTALLED_APPS. I try to use it in logicalhp/home.html, but it says the tag doesn't exist. I'm using code from this answer (I changed the name from 'value_from_settings' to 'settings_value').
.
├── internetparse
│ └── ...
├── itslogical
│ ├── settings.py
│ ├── templates
│ │ └── itslogical
│ │ └── base.html
│ └─── templatetags
│ ├── __init__.py
│ └── settings_value.py
├── logicalhp
│ ├── templates
│ │ └── logicalhp
│ │ └── home.html
│ └── views.py
└── manage.py
Let me know if you need anything else. What am I missing here?
Edit: added code and updated error. This is based on #Dan's answer.
500 ERROR:
'settings_value' is not a valid tag library: Template library settings_value not found
Template library settings_value not found, tried django.templatetags.settings_value ...
#!/usr/bin/env python
from django import template
from django.conf import settings
# Include settings from here in templates
register = template.Library()
# settings value
#register.tag
def settings_value(parser, token):
try:
# split_contents() knows not to split quoted strings.
tag_name, var = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents.split()[0]
return ValueFromSettings(var)
class ValueFromSettings(template.Node):
def __init__(self, var):
self.arg = template.Variable(var)
def render(self, context):
return settings.__getattr__(str(self.arg))
You shouldn't add the templatetags directory to installed apps. You should put the templatetags directory inside an existing app, and add that to installed apps.
Try to move templatetags folder to logicalhp
Part of the problem was a typo in my settings.py (wrote the 'logicalhp.templatetags' when it was in 'itslogical'). The larger problem was that it was trying to get the attribute "STATIC_URL" from my settings. It included the quotes, so it was effectively settings.__getattr__('"STATIC_URL"').
To fix it, I added a strip.
return settings.__getattr__(str(self.arg)) #before
return settings.__getattr__(str(self.arg).strip('"')) #after
(By the way, it's not like you can omit the quotes in the template; else it think's its a variable. )