Access flask app endpoints in another python file? - python

I have a python file which defines some endpoints using flask each doing some computation and return a JSON (POST method). I want to do unit testing on this in order to do this I want to be able to access the app I created in one python file in another file so I can test my endpoints.
I see a lot of this on the internet :
from source.api import app
from unittest import TestCase
class TestIntegrations(TestCase):
def setUp(self):
self.app = app.test_client()
def test_thing(self):
response = self.app.get('/')
assert <make your assertion here>
It doesn't explain how I can define and access my app in another file. This might be a stupid question but I really don't see how.
My app is defined as follows:
from flasgger import Swagger
from flask import Flask, jsonify, request
from flask_cors import CORS
import os
def init_deserializer_restful_api():
# Initiate the Flask app
app = Flask(__name__)
Swagger(app)
CORS(app)
# Handler for deserializer
#app.route("/deserialize", methods=['POST'])
def handle_deserialization_request():
pass
I have many other end points in this fashion. Should i just do:
import my_file_name
Thanks!!

Check out this question: What does if __name__ == "__main__": do?
As long as you have that in your python program, you can both treat it as a module and you can call it directly.

Related

Flask Rate Limiter not working with flask-restful

I believe I have the same problem as described here: Flask-Limiter does not work with Flask-Restful API-based application. But I still can't get it to work. Here's my problem:
I have an app.py where I import all my REST-API endpoints. I use flask-RESTful resources as described in this guide: https://flask-restful.readthedocs.io/en/latest/quickstart.html
I use the "Flask-Limiter" library for rate limiting: https://flask-limiter.readthedocs.io/en/stable/. The rate-limiter gets instantiated in a separate file, not inside app.py because this would create circular references between app.py and the REST-API endpoints. I think this could be the cause of my problem.
This is the rate-limiter file (located in: /controller/helpers/rate_limiter.py)
from flask import current_app
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(
current_app,
key_func=get_remote_address
)
This is the app.py file (located in: /):
from flask import Flask
from flask_restful import Api
from controller.actions.my_endpoint import MyEndpoint
flask_app = Flask(__name__)
api = Api(flask_app)
api.add_resource(MyEndpoint, '/endpoint')
flask_app.run(debug=True, use_reloader=True, host='0.0.0.0', port=8000)
And finally this is an example of an endpoint (located in: /controller/actions/my_endpoint):
from flask_restful import reqparse, Resource
from controller.helpers.rate_limiter import limiter
class MyEndpoint(Resource):
decorators = [limiter.limit("1/minute", methods=["POST"])]
def __init__(self):
self.parser = reqparse.RequestParser()
self.parser.add_argument(
"someData", type=int, nullable=False, required=True)
def post(self):
data = self.parser.parse_args(strict=True)
someData = data.someData
return "Got your message {0}".format(someData), 200
I would expect that after the first request I would get response 429 because the rate limit of 1/minute is reached but it doesn't do that.
However, when I instantiate the limiter inside app.py and set a default rate-limit, it works (getting that error 429):
from flask import Flask
from flask_restful import Api
from controller.db_actions.my_endpoint import MyEndpoint
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
flask_app = Flask(__name__)
limiter = Limiter(
flask_app,
key_func=get_remote_address,
default_limits=["1 per minute"]
)
api = Api(flask_app)
api.add_resource(MyEndpoint, '/endpoint')
flask_app.run(debug=True, use_reloader=True, host='0.0.0.0', port=8000)
Question: I think I'm doing something wrong with instantiating the limiter. What is it? :)

How to pytest a Flask Endpoint

I'm getting started with Flask and Pytest in order to implemente a rest service with unit test, but i'm having some troouble.
I'll like to make a simple test for my simple endpoint but i keep getting a Working outside of application context. error when running the test.
This is the end point:
from flask import jsonify, request, Blueprint
STATUS_API = Blueprint('status_api', __name__)
def get_blueprint():
"""Return the blueprint for the main app module"""
return STATUS_API
#STATUS_API.route('/status', methods=['GET'])
def get_status():
return jsonify({
'status' : 'alive'
})
And this is how I'm trying to test it (i know it should fail the test):
import pytest
from routes import status_api
def test_get_status():
assert status_api.get_status() == ''
I'm guessing I just cant try the method with out building the whole app. But if that's the case i dont really know how to aproach this problem
The Flask documentation on testing is pretty good.
Instead of importing the view functions, you should create a so called test client, e.g. as a pytest fixture.
For my last Flask app this looked like:
#pytest.fixture
def client():
app = create_app()
app.config['TESTING'] = True
with app.app_context():
with app.test_client() as client:
yield client
(create_app is my app factory)
Then you can easily create tests as follows:
def test_status(client):
rv = client.get('/stats')
assert ...
As mentioned at the beginning, the official documentation is really good.
Have you considered trying an API client/development tool? Insomnia and Postman are popular ones. Using one may be able to resolve this for you.

HTTP endpoint that causes string to write to a file

the api should include one function called "write text to file" and inputs a string parameter
as for the function to write to the disk I have no problem and I implemented the code my problem is how to set the rest API using python.
EDIT:
this is my code:
from flask import (
Flask,
render_template
)
import SocketServer
import SimpleHTTPServer
import re
app = Flask(__name__, template_folder="templates")
#app.route('/index', methods=['GET'])
def index():
return 'Welcome'
#app.route('/write_text_to_file', methods=['POST'])
def write_text_to_file():
f = open("str.txt", "w+")
f.write("hello world")
f.close()
if __name__ == '__main__':
app.run(debug=True)
anyhow when I try to test my rest api:
http://127.0.0.1:5000/write_text_to_file
I am getting the following error:
Now I'm trying to test my rest-api , however how can I make my code to start the server and to the test the post request api, this is my test_class:
import requests
import unittest
API_ENDPOINT="http://127.0.0.1:5000/write_text_to_file"
class test_my_rest_api(unittest.TestCase):
def test_post_request(self):
"""start the server"""
r = requests.post(API_ENDPOINT)
res = r.text
print(res)
also when runnning my request using postman I am getting internal_server_error:
You're doing a GET request for this url, but you've specified that this endpoint can only accept POST:
#app.route('/write_text_to_file', methods=['POST'])
Also, the SocketServer and SimpleHTTPServer imports are not needed with Flask.
The method is not allowed because Chrome (or any browser) makes GET requests.
Whereas, you defined it as POST
#app.route('/write_text_to_file', methods=['POST'])
Either change it to a GET method, or use a tool such as POSTMan to perform other HTTP call types

python flask return prior execution of reboot

for reasons I want to trigger the reboot of an raspberry pi using a REST api.
My REST api is coded in python flask like this:
from flask import Flask
from flask import jsonify
import subprocess
app = Flask(__name__)
#app.route('/api/reboot')
def reboot():
subprocess.call("/sbin/reboot")
return jsonify(triggered='reboot')
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
the code is working perfectly fine. But due to its a reboot the return will not be send (because the system is rebooting obviously).
Is there a way to trigger the reboot some kind of async with a delay of a couple milliseconds, that allows to return some value (in my case just an custom 'ack') prior the actual reboot?
Try threading.Timer:
For example:
from flask import Flask
from flask import jsonify
import subprocess
import threading
app = Flask(__name__)
def _reboot():
subprocess.call("/sbin/reboot")
#app.route('/api/reboot')
def reboot():
t = threading.Timer(1, _reboot)
t.start()
return jsonify(triggered='reboot')
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")

No response from a Flask application using Apache server

I have created a flask application and am hosting it on a Ubuntu server. I know that my apache config is correct since I am able serve the example flask application. However, this one seems to be giving me trouble. The code is below:
from flask import Flask, render_template, request, url_for
import pickle
import engine
import config
# Initialize the Flask application
app = Flask(__name__)
model = pickle.load(open(config.MODEL_PATH, "rb"))
collection = engine.Collection(config.DATABASE_PATH)
search_engine = engine.SearchEngine(model, collection)
#app.route('/')
def form():
return render_template('index.html')
#app.route('/search/', methods=['POST'])
def search():
query = request.form['query']
results = search_engine.query(query)
return render_template('form_action.html', query=query, results=results)
#app.route('/retrieve/<int:item_number>', methods=['GET'])
def retrieve(item_number):
item = engine.Product(item_number, collection.open_document(str(item_number)))
return render_template('document.html', item=item)
if __name__ == '__main__':
app.run()
When running the file directly through the python interpreter, it works fine and I can access. However, when starting through apache and wsgi, I get no response from the server. It just hangs when making a request and nothing is available on the logs.
I suspect that my issue may have something to do with the three objects I initialize at the beginning of the program. Perhaps it gets stuck running those?
Update: I have tried commenting out certain parts of the code to see what is causing it to stall. Tracing it out to the engine module, importing NearestNeighbors seems to be causing the issue.
import sqlite3
import config
from sklearn.neighbors import NearestNeighbors
from preprocessor import preprocess_document
from collections import namedtuple

Categories

Resources