I use Flask:
from flask import Flask, render_template, session
I want to package some session operation methods in a class like this:
class Session:
def __init__(self):
self.ip = request.remote_addr
self.name = request.remote_user
session['ip'] = self.ip
session['name'] = self.name
in order to render these two attributes in templates by the function below:
#app.route('/', methods=['GET'], strict_slashes=False)
def indexpage():
return render_template('index.html',s=Session())
However, different devices get the same output which means Session.ip and Session.name are the same from different devices. I think class Session is not initialized properly.
Related
I'm learning Flask and am a bit confused about how to structure my code. So I tried to extend Flask main class as follows:
from flask import Flask, ...
class App(Flask):
def __init__(self, import_name, *args, **kwargs):
super(App, self).__init__(import_name, *args, **kwargs)
Note that I am aware of that this may be a completely wrong approach.
So that when I want to start the app I do:
app = App(__name__)
if __name__ == '__main__':
app.run()
This way I can order my methods and routes in the class, but the problem is when using self-decorators:
#route('/')
def home(self, context=None):
context = context or dict()
return render_template('home.html', **context)
Which raises an error as unresolved reference 'route'. I guess this is not the way I should be structuring the app. How should I do it instead or how do I get the error fixed?
Doing this doesn't make sense. You would subclass Flask to change its internal behavior, not to define your routes as class methods.
Instead, you're looking for blueprints and the app factory pattern. Blueprints divide your views into groups without requiring an app, and the factory creates and sets up the app only when called.
my_app/users/__init__.py
from flask import Blueprint
bp = Blueprint('users', __name__, url_prefix='/users')
my_app/users/views.py
from flask import render_template
from my_app.users import bp
#bp.route('/')
def index():
return render_template('users/index.html')
my_app/__init__.py
def create_app():
app = Flask(__name__)
# set up the app here
# for example, register a blueprint
from my_app.users import bp
app.register_blueprint(bp)
return app
run.py
from my_app import create_app
app = create_app()
Run the dev server with:
FLASK_APP=run.py
FLASK_DEBUG=True
flask run
If you need access to the app in a view, use current_app, just like request gives access to the request in the view.
from flask import current_app
from itsdangerous import URLSafeSerializer
#bp.route('/token')
def token():
s = URLSafeSerializer(current_app.secret_key)
return s.dumps('secret')
If you really want to define routes as methods of a Flask subclass, you'll need to use self.add_url_rule in __init__ rather than decorating each route locally.
class MyFlask(Flask):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.add_url_rule('/', view_func=self.index)
def index(self):
return render_template('index.html')
The reason route (and self) won't work is because it's an instance method, but you don't have an instance when you're defining the class.
I'm trying to create a hello world example for a flask application with socketio, that is wrapped into a class.
I want to wrap the whole application into a class, that can be embedded into other applications. For this purpose, I am creating the Flask application in the constructor of my class, and also create the SocketIO instance as a member too.
The problem is that I get a NameError exception tellimg me that 'socketio' is not defined.
I have tried to adapt the minimum working example from : the flask-socketio tutorial (https://flask-socketio.readthedocs.io/en/latest/)
Here is the example code I'm trying to get to work:
from flask import Flask
from flask_socketio import SocketIO, emit
class ApplicationExample:
def __init__(self):
self.app = Flask(__name__)
self.socketio = SocketIO(self.app)
#socketio.on('ping')
def pongResponse(self, message):
emit('pong')
def run(self):
self.socketio.run(service.app, host='0.0.0.0')
if __name__ == '__main__':
service = ApplicationExample()
service.run()
I would like to bind the pongResponse function to the socketio instance inside my class. How is it possible to decorate the function while having the SocketIO class as a member?
According to the documentation you can use the below instead of a decorator
def my_function_handler(data):
pass
socketio.on_event('my event', my_function_handler, namespace='/test')
Which would become something like
from flask import Flask
from flask_socketio import SocketIO, emit
class ApplicationExample:
def __init__(self):
self.app = Flask(__name__)
self.socketio = SocketIO(self.app)
self.socketio.on_event('ping', self.pongResponse, namespace='/test')
def pongResponse(self, message):
emit('pong')
def run(self):
self.socketio.run(service.app, host='0.0.0.0')
Since decorating a function simply calls the decorator and passes the decorated function as the first argument you can write:
def __init__(self):
...
self.pongResponse = self.socketio.on('ping')(self._pongResponse)
def _pongResponse(self, message):
...
A method beginning with a _ denotes that is not part of the public API of the class (thus this simply is a convention). Also note that in python you should use snake_caseinstead of camelCase to name your functions and variables, although this is also just a convention.
I created a simple Server Interceptor that retrieves the user based on the JWT token.
But now I would like to make it available to all the methods of my services.
At the moment im using decorators. But I would like to avoid having to decorate all the methods. In case, decorate only those that do not need the user.
Some one can give me a clue ?
here is my code:
class AuthInterceptor(grpc.ServerInterceptor):
"""Authorization Interceptor"""
def __init__(self, loader):
self._loader = loader
def intercept_service(self, continuation, handler_call_details):
# Authenticate if we not requesting token.
if not handler_call_details.method.endswith('GetToken'):
# My Authentication class.
auth = EosJWTAuth()
# Authenticate using the headers tokens to get the user.
user = auth.authenticate(
dict(handler_call_details.invocation_metadata))[0]
# Do something here to pass the authenticated user to the functions.
cont = continuation(handler_call_details)
return cont
And I'd like my methods can to access the user in a way like this.
class UserService(BaseService, users_pb2_grpc.UserServicer):
"""User service."""
def get_age(self, request, context):
"""Get user's age"""
user = context.get_user()
# or user = context.user
# or user = self.user
# os user = request.get_user()
return pb.UserInfo(name=user.name, age=user.age)
This is a common need for web servers, and it is a good idea to add decorators to the handlers to explicitly set requirement for authentication/authorization. It helps readability, and reduces the overall complexity.
However, here is a workaround to solve your question. It uses Python metaclass to automatically decorate every servicer method.
import grpc
import functools
import six
def auth_decorator(func):
#functools.wraps(func)
def wrapper(request, context):
if not func.__name__.endswith('GetToken'):
auth = FooAuthClass()
try:
user = auth.authenticate(
dict(context.invocation_metadata)
)[0]
request.user = user
except UserNotFound:
context.abort(
grpc.StatusCode.UNAUTHENTICATED,
'Permission denied.',
)
return func(request, context)
return wrapper
class AuthMeta:
def __new__(self, class_name, bases, namespace):
for key, value in list(namespace.items()):
if callable(value):
namespace[key] = auth_decorator(value)
return type.__new__(self, class_name, bases, namespace)
class BusinessServer(FooServicer, six.with_metaclass(AuthMeta)):
def LogicA(self, request, context):
# request.user accessible
...
def LogicGetToken(self, request, context):
# request.user not accessible
...
I am trying to rewrite some working code as a class.
A minimal working code:
from flask import Flask
app = Flask(__name__)
#app.route("/1")
def func_1():
return "view 1"
#app.route("/2")
def func_2():
return "view 2"
app.run()
How to write it as a class with the route defined during the object instantiation?
I only want it clean: after instantiating an object I want the respective route already working with no extra lines of code.
This is the closest I get to:
from flask import Flask
class NewView:
def __init__(self, url, string):
self.string = string
self.server = Flask(__name__)
self.server.add_url_rule(url, 'index', self.index)
def index(self):
return self.string
v1 = NewView("/1", "view 1")
v2 = NewView("/2", "view 2")
v1.server.run()
This, of course, recognizes /1 as route for v1.index(), but /2 doesn't work.
The ideal would be something like the following but I cannot make it work:
from flask import Flask
app = Flask(__name__)
class NewView:
def __init__(self, url, string):
....
app.add_url_rule(url, ...?..., self.index)
def index(self):
return self.string
v1 = NewView("/1", "view 1")
v2 = NewView("/2", "view 2")
app.run()
First, your mistake:
def __init__(self, url, string):
self.string = string
self.server = Flask(__name__)
self.server.add_url_rule(url, 'index', self.index)
Because you have two instances of this class, there are two Flask objects. You only run the second one.
What you're immediately trying to do can be done like this:
import flask
# There can be only one!
app = flask.Flask(__name__)
class MyView:
def __init__(self, url, name, string):
self.url = url
self.string = string
app.add_url_rule(url, name, self.serve)
def serve(self):
return self.string
view1 = MyView('/1', name='view1', string='This is View 1.')
view2 = MyView('/2', name='view2', string='This is View 2, not view 1.')
app.run()
The above code will work and do what you expect. Something to note is that, since Flask likes names for unique routes, I have you passing in a name for each route. That way, url_for('view1') and url_for('view2') work.
Having said all that, the community has largely already accomplished much of this Pluggable Views. Check it out.
I think that if your goal is to keep code clean, you should avoid creating objects that are never used. The class based views in flask. The as_view() method that is being passes is class method, so also here there is no need to create a never used object. The process of registring urls belongs to creation of an app, not separate objects (that's how it works in Django for instance). If I were you I would go with something similar to this:
from flask import Flask
from flask.views import View
def init_app():
app = Flask(__name__)
app.add_url_rule('/', view_func=NewView.as_view('index'))
return app
class NewView(View):
def dispatch_request(self):
return 'Test'
app = init_app()
app.run()
I think my problem is related on the way I structured my pyramid project.
What I want to accomplish is to make my code runs on all views, I don't want to paste same codes on all views. Its like I will include the code in all views by just simply calling it. This is my code.
my wizard module
from pyramid.view import view_config, view_defaults
from .models import *
from datetime import datetime
from pyramid.response import Response
from bson import ObjectId
from pyramid.httpexceptions import HTTPFound
import json
class WizardView:
def __init__(self, request):
self.request = request
#view_config(route_name='wizard', renderer='templates/wizard.jinja2')
def wizard(self):
session = self.request.session
if session:
return {'fullname':session['name'],'userrole':session['userrole']}
else:
url = self.request.route_url('login')
return HTTPFound(location=url)
my bill module
from pyramid.view import view_config, view_defaults
from .models import *
from datetime import datetime
from pyramid.response import Response
from bson import ObjectId
from pyramid.httpexceptions import HTTPFound
class BillView:
def __init__(self, request):
self.request = request
#view_config(route_name='bills', renderer='templates/bills.jinja2')
def bills(self):
session = self.request.session
if session:
return {'fullname':session['name'],'userrole':session['userrole']}
else:
url = self.request.route_url('login')
return HTTPFound(location=url)
As you can see I have to paste this code twice (this code checks if session exist, if not, then redirect user to login page)
session = self.request.session
if session:
return {'fullname':session['name'],'userrole':session['userrole']}
else:
url = self.request.route_url('login')
return HTTPFound(location=url)
I've tried to search and I think what I need is some sort of auto loader? How can I apply this on pyramid? Or should I stick with this process?
If you wish to return exactly the same thing from both (many) views, then the best way is to use inheritance.
class GenericView:
def __init__(self, request):
self.request = request
def generic_response(self):
session = self.request.session
if session:
return {'fullname':session['name'],'userrole':session['userrole']}
else:
url = self.request.route_url('login')
return HTTPFound(location=url)
Use generic_response in WizardView and BillView
class WizardView(GenericView):
def __init__(self, request):
super().__init__(request)
# Do wizard specific initialization
#view_config(route_name='wizard', renderer='templates/wizard.jinja2')
def wizard(self):
return self.generic_response()
class BillView(GenericView):
def __init__(self, request):
super().__init__(request)
# Do bill specific initialization
#view_config(route_name='bills', renderer='templates/bills.jinja2')
def bills(self):
return self.generic_response()
If you want to just check (and redirect) when session does not exists and otherwise proceed normally you could use custom exceptions and corresponding views.
First define custom exception
class SessionNotPresent(Exception):
pass
And view for this exception
#view_config(context=SessionNotPresent)
def handle_no_session(context, request):
# context is our custom exception, request is normal request
request.route_url('login')
return HTTPFound(location=url)
Then just check if session exists in parent constructor
class SessionView:
def __init__(self, request):
self.request = request
if not self.request.session:
raise SessionNotPresent() # Pyramid will delegate request handilng to handle_no_request
In views simply extend SessionView and non existing sessions will be handeled by handle_no_session.
class WizardView(SessionView):
def __init__(self, request):
super().__init__(request)
# Do wizard specific initialization
#view_config(route_name='wizard', renderer='templates/wizard.jinja2')
def wizard(self):
session = self.request.session
return {'fullname':session['name'],'userrole':session['userrole']}
class BillView(SessionView):
def __init__(self, request):
super().__init__(request)
# Do bill specific initialization
#view_config(route_name='bills', renderer='templates/bills.jinja2')
def bills(self):
session = self.request.session
return {'fullname':session['name'],'userrole':session['userrole']}
You could easily add additional parameters to exception (redirect_url, ...)
For exception handling see http://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/pylons/exceptions.html
You can use events: http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/events.html
Example:
from pyramid.events import subscriber, NewRequest
#subscriber(NewRequest)
def check_session(event):
if not event.request.session:
raise HTTPFound(location=event.request.route_path('login'))