I am creating a microservice using Flask, that needs to give me a random number.
Unfortunately I am getting this error:
AttributeError: 'function' object has no attribute 'uniform'
import random
from flask import Flask
app: Flask = Flask(__name__)
#app.route('/', methods=['GET'])
def random():
r1 = random.uniform(0, 10)
return r1
if __name__ == '__main__':
app.run(debug=True)
new to microservice and python.
It is because you redefined random. You can either change the function name or give alias to imported random library.
Method 1:
Change the function name you defined.
import random
from flask import Flask
app: Flask = Flask(__name__)
#app.route('/', methods=['GET'])
def myRandom(): //Changed here
r1 = random.uniform(0, 10)
return r1
if __name__ == '__main__':
app.run(debug=True)
Method 2
Import random using alias.
import random as r //Changed here
from flask import Flask
app: Flask = Flask(__name__)
#app.route('/', methods=['GET'])
def random():
r1 = r.uniform(0, 10)
return r1
if __name__ == '__main__':
app.run(debug=True)
Related
I ran my code on Jupyter Notebook and I wanted to return different values on the web while running the function. However, it only returned one value. I also tried yield, but it had an error on the web.
from werkzeug.wrappers import Request, Response
from flask import Flask
app = Flask(__name__)
#app.route('/')
def index():
list = [0,0,0]
for i in range(10):
list.append(i)
return str(list)
if __name__ == "__main__":
from werkzeug.serving import run_simple
run_simple('localhost', 9000, app)
Output:
[0,0,0,0]
Expected Output:
[0,0,0,0]
then change to:
[0,0,0,0,1]
then go on until it stops at:
[0,0,0,0,1,2,3,4,5,6,7,8,9]
Your indent is a little off on the return of the list. This is returning it on the first loop. Corrected Code is below:
from werkzeug.wrappers import Request, Response
from flask import Flask
app = Flask(__name__)
#app.route('/')
def index():
list = [0,0,0]
for i in range(10):
list.append(i)
return str(list)
if __name__ == "__main__":
from werkzeug.serving import run_simple
run_simple('localhost', 9000, app)
How to call my microservice-2 from microservice-1. So our result looks like this:-
Result :- {“message”: “vivek”} --> {“message”: “keviv”, “random”: 3.89}
command to access microservice-1:-
curl http://127.0.0.1:5000/reverse_random/vivek
microservice-1
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/reverse_reandom/<string:string>', methods=['GET'])
def reverse(string):
string = string[::-1]
return jsonify({'message': string })
if __name__ == '__main__':
app.run(debug = True)
microservice-2
import random
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/', methods=['GET'])
def myRandom():
r1 = random.uniform(0, 10)
return jsonify({'message': r1 })
if __name__ == '__main__':
app.run(debug=True)
you'll need to issue a GET request to service 2 in order to get the random number, I suggest to use requests for this, like
r = requests.get('url-for-service-2:port/')
data = r.json()
random_num = data['message']
keep in mind to check the data object for message key, or using .get() or equivalent
Run microservice-2 on a different port. Send request using Python standard or 3rd party library from microservice-1
to microservice-2 upon request to microservice-1.
Below is the example of using Python3 standard library only:
m1.py:
from flask import Flask, jsonify
import urllib
import json
app = Flask(__name__)
#app.route('/reverse_random/<string:string>', methods=['GET'])
def reverse(string):
content = urllib.request.urlopen('http://127.0.0.1:5001').read().decode('utf-8')
print('response from m2: ', content)
string = string[::-1]
return jsonify({'message': string, 'random' : json.loads(content)['message']})
if __name__ == '__main__':
app.run(debug = True)
m2.py:
import random
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/', methods=['GET'])
def myRandom():
r1 = random.uniform(0, 10)
return jsonify({'message': r1 })
if __name__ == '__main__':
app.run(debug=True, port=5001) # running m2 on a different port than default 5000
Run the m1: python3 m1.py
Run the m2 in a different shell: python3 m2.py
Send request to m1: curl http://127.0.0.1:5000/reverse_random/vivek
The result is:
{
"message": "keviv",
"random": 4.138115905045612
}
Observe the log of m1 and of m2 to make sure m2 was invoked.
To connect between services you can use background tasks such as celery and ramq or use nsq and nats
This question already has answers here:
Get list of all routes defined in the Flask app
(11 answers)
Closed 3 years ago.
I've created a simple API using Flask, my question is how do i make it list all of the resources or endpoints it has been assigned
from flask import Flask, request
from flask_restful import Resource, Api
from sqlalchemy import create_engine
from json import dumps
import os, random
app = Flask(__name__)
api = Api(app)
class cuddle(Resource):
def get(self):
file = random.choice(os.listdir("/path/to/dir/of/images"))
out = "https://example.com/path/" + file
return out
api.add_resource(cuddle, '/api/cuddle')
if __name__ == '__main__':
app.run(host="0.0.0.0", port=33, debug=True)
I'm wanting to be able to go to example.com/api/endpoints and for it to list all of the available endpoints, such as in the snippet cuddle
You can use app.url_map.iter_values()
Following is an example
#app.route('/')
def hi():
return 'Hello World!'
#app.route('/hi')
def hi():
return 'Hi!'
#app.route('/hello')
def hello():
return 'Hello World!'
def routes():
routes = []
for route in app.url_map.iter_rules():
routes.append('%s' % route)
print(routes)
['/hello', '/hi', '/']
I'm using Flask to expose some data-crunching code as a web service.
I'd like to have some class variables that my Flask functions can access.
Let me walk you through where I'm stuck:
from flask import Flask
app = Flask(__name__)
class MyServer:
def __init__(self):
globalData = json.load(filename)
#app.route('/getSomeData')
def getSomeData():
return random.choice(globalData) #select some random data to return
if __name__ == "__main__":
app.run(host='0.0.0.0')
When I run getSomeData() outside of Flask, it works fine. But, when I run this with Flask, I get 500 internal server error. There's no magic here, and Flask has no idea that it's supposed to initialize a MyServer object. How can I feed an instance of MyServer to the app.run() command?
I could admit defeat and put globalData into a database instead. But, is there an other way?
You can create an instance of MyServer just outside the scope of your endpoints and access its attributes. This worked for me:
class MyServer:
def __init__(self):
self.globalData = "hello"
from flask import Flask
app = Flask(__name__)
my_server = MyServer()
#app.route("/getSomeData")
def getSomeData():
return my_server.globalData
if __name__ == "__main__":
app.run(host="0.0.0.0")
I know this is a late reply, but I came across this question while facing a similar issue. I found flask-classful really good.
You inherit your class from FlaskView and register the Flask app with your MyServer class
http://flask-classful.teracy.org/#
In this case, with flask-classful, your code would look like this:
from flask import Flask
from flask_classful import FlaskView, route
app = Flask(__name__)
class MyServer(FlaskView):
def __init__(self):
globalData = json.load(filename)
#route('/getSomeData')
def getSomeData():
return random.choice(globalData) #select some random data to return
MyServer.register(app, base_route="/")
if __name__ == "__main__":
app.run(host='0.0.0.0')
The least-coupled solution is to apply the routes at runtime (instead of at load time):
def init_app(flask_app, database_interface, filesystem_interface):
server = MyServer(database_interface, filesystem_interface)
flask_app.route('get_data', methods=['GET'])(server.get_data)
This is very testable--just invoke init_app() in your test code with the mocked/faked dependencies (database_interface and filesystem_interface) and a flask app that has been configured for testing (app.config["TESTING"]=True or something like that) and you're all-set to write tests that cover your entire application (including the flask routing).
The only downside is this isn't very "Flasky" (or so I've been told); the Flask idiom is to use #app.route(), which is applied at load time and is necessarily tightly coupled because dependencies are hard-coded into the implementation instead of injected into some constructor or factory method (and thus complicated to test).
The following code is a simple solution for OOP with Flask:
from flask import Flask, request
class Server:
def __init__(self, name):
self.app = Flask(name)
#self.app.route('/')
def __index():
return self.index()
#self.app.route('/hello')
def __hello():
return self.hello()
#self.app.route('/user_agent')
def __user_agent():
return self.user_agent()
#self.app.route('/factorial/<n>', methods=['GET'])
def __factorial(n):
return self.factorial(n)
def index(self):
return 'Index Page'
def hello(self):
return 'Hello, World'
def user_agent(self):
return request.headers.get('User-Agent')
def factorial(self, n):
n = int(n)
fact = 1
for num in range(2, n + 1):
fact = fact * num
return str(fact)
def run(self, host, port):
self.app.run(host=host, port=port)
def main():
server = Server(__name__)
server.run(host='0.0.0.0', port=5000)
if __name__ == '__main__':
main()
To test the code, browse the following urls:
http://localhost:5000/
http://localhost:5000/hello
http://localhost:5000/user_agent
http://localhost:5000/factorial/10
a bit late but heres a quick implementation that i use to register routes at init time
from flask import Flask,request,render_template
from functools import partial
registered_routes = {}
def register_route(route=None):
#simple decorator for class based views
def inner(fn):
registered_routes[route] = fn
return fn
return inner
class MyServer(Flask):
def __init__(self,*args,**kwargs):
if not args:
kwargs.setdefault('import_name',__name__)
Flask.__init__(self,*args ,**kwargs)
# register the routes from the decorator
for route,fn in registered_routes.items():
partial_fn = partial(fn,self)
partial_fn.__name__ = fn.__name__
self.route(route)(partial_fn)
#register_route("/")
def index(self):
return render_template("my_template.html")
if __name__ == "__main__":
MyServer(template_folder=os.path.dirname(__file__)).run(debug=True)
if you wish to approach MyServer class as a resource
I believe that flask_restful can help you:
from flask import Flask
from flask_restful import Resource, Api
import json
import numpy as np
app = Flask(__name__)
api = Api(app)
class MyServer(Resource):
def __init__(self):
self.globalData = json.load(filename)
def get(self):
return np.random.choice(self.globalData)
api.add_resource(MyServer, '/')
if __name__ == '__main__':
app.run()
Problem has been updated to include progress made
I have the following code and my celery tasks kick off fine, I just don't know where I should store the async result so that I can look at it again later
#!/usr/bin/env python
"""Page views."""
from flask import render_template, request
from flask import Flask
from celerytest import add
from time import sleep
app = Flask(__name__)
async_res = []
#app.route('/', methods=['GET', 'POST'])
def run():
if request.method == 'GET':
return render_template("template.html")
else:
form = request.form
n1 = str(form.get("n1"))
n2 = str(form.get("n2"))
aysnc_res = add.delay(n1,n2)
return render_template("loading.html")
#app.route('/loading')
def check_if_complete():
if async_res.ready() == True:
return render_template("template2.html", val=async_res.get())
else:
sleep(5)
return render_template("loading.html")
if __name__ == '__main__':
app.run()
It appears that storing async_res as a global variable in my flask app causes server errors. So what's the best method of storing the result so that I can check on it in my "loading page"
I ended up being able to save the ID of my task in the session dictionary in Flask
See code below:
#!/usr/bin/env python
"""Page views."""
from flask import render_template, request
from flask import Flask
from celerytest import add
from time import sleep
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def run():
if request.method == 'GET':
return render_template("template.html")
else:
form = request.form
n1 = str(form.get("n1"))
n2 = str(form.get("n2"))
aysnc_res = add.delay(n1,n2)
session['TASK_ID'] = async_res.id
return render_template("loading.html")
#app.route('/loading')
def check_if_complete():
aysnc_res = session['TASK_ID']
if async_res.ready() == True:
return render_template("template2.html", val=async_res.get())
else:
sleep(5)
return render_template("loading.html")
if __name__ == '__main__':
app.run()