Flask/Flasgger - Document does not appear if `endpoint` parameter is set - python-3.x

I have a Blueprint which I wrote an OpenAPI documentation for. Without the endpoint definition, it's working just fine but it doesn't with the endpoint definition.
Working code:
#my_blueprint.route('/')
#swag_from('open_api/root.yml')
def main():
return str('This is the root api')
Not Working (notice how I defined the endpoint in parameters):
#my_blueprint.route('/', endpoint='foo')
#swag_from('open_api/root.yml', endpoint='foo')
def main():
return str('This is the root api')
You have working code, why'd you ask?
The use case for me is when I have multi-endpoint for just a single function which I have to define multiple yml file for each docs.
#my_blueprint.route('/', endpoint='foo')
#my_blueprint.route('/<some_id>', endpoint='foo_with_id')
#swag_from('open_api/root.yml', endpoint='foo')
#swag_from('open_api/root_with_id.yml', endpoint='foo_with_id')
def main(some_id):
if (some_id):
return str('Here's your ID')
return str('This is the root api')

Setting an endpoint in #swag_from should also contain the name of the Blueprint. Example: #swag_from('my_yaml.yml', endpoint='{}.your_endpoint'.format(my_blueprint.name))
Full example:
#my_blueprint.route('/', endpoint='foo') # endpoint is foo
#my_blueprint.route('/<some_id>', endpoint='foo_with_id') # endpoint is foo_with_id
#swag_from('open_api/root.yml', endpoint='{}.foo'.format(my_blueprint.name)) # blueprint is set as the prefix for the endpoint
#swag_from('open_api/root_with_id.yml', endpoint='{}.foo_with_id'.format(my_blueprint.name)) # same goes here
def main(some_id):
if (some_id):
return str("Here's your ID")
return str('This is the root api')

Related

InvalidTemplateEngineError in oscar

I am using django-oscar for my development.
I have created a new app as per my requirement
views.py
class MediaImportView(TemplateView):
template_name = 'lookup/import_media_file.html'
def get(self, request):
ctx = {}
return render(self.template_name, ctx, request, using=request)
getting the error as below.
InvalidTemplateEngineError at /import_media_file
Could not find config for '<WSGIRequest: GET '/import_media_file'>' in settings.TEMPLATES
From the documentation, the using argument takes:
The NAME of a template engine to use for loading the template.
Instead of passing the name of a template engine, you are passing a request object, hence the error. In addition, all your other arguments are wrong as well - the signature of this function is:
render(request, template_name, context=None, content_type=None, status=None, using=None)
So the first argument needs to be a request, the second a template name, and the third the context. Something like this:
return render(request, self.template_name, ctx)

Call Method of another class in Flask API

I am trying to expose a data service as an API for a PHP application. I have written the API logic in a file called APILogic.py. The code in this looks like this
class APILogic(object):
def __init__(self):
# the initialization is done here
...
def APIfunction(self):
# the API logic is built here, it uses the class variables and methods
...
I have created another file for the API purpose. Its called API.py. The code in this file looks like this
import APILogic from APILogic
class MyFlask:
def __init__(self):
self.test = APILogic()
from flask import Flask
app = Flask(__name__)
my_flask = MyFlask()
#app.route("/Test")
def Test():
return my_flask.test.APIfunction
if __name__ == "__main__":
app.run(debug=True,port=9999)
When I run the code, I get the error
> TypeError: APIfunction() takes 1 positional argument but 3 were given
The view function did not return a valid response. The return type must be a string, dict, tuple, Response instance, or WSGI callable, but it was a method.
There are no arguments for the APIfunction though.
Please help.
The view function did not return a valid response. The return type must be a string, dict, tuple, Response instance, or WSGI callable, but it was a method.
Looks like you're returning the method, but it sounds like you want to return the result of that method:
#app.route("/Test")
def Test():
return my_flask.test.APIfunction()
View function should return valid response.
Sample API code
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()

Unexpected AssertionError: single test not using logged in user from previous step

I am following the tutorial by http://www.patricksoftwareblog.com/flask-tutorial/, which I believe is based on https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world. Great stuff for a beginner.
I am getting different results when testing my code through frontend manually (which works fine) v.s. through pytest.
My test tries to show the "groups" endpoint which requires a login (standard #login_required decorator).
I initially test the user getting a login page ("Knock knock") when trying to get the endpoint without a login. This works manually and through pytest.
I login a user. If I inspect the response from the login I can clearly see a "Welcome back Pete!" success message.
My second assert receives a response from URL /login?next=%2Fgroups indicating the /groups endpoint is called without a login/authentication preceding it and the assert fails. Testing this manually works as expected. Why is that single test not using the same user/session combination in the next step(s)?
Test with the problem is the first snippet below:
def test_groups(app):
assert b'Knock knock' in get(app, "/groups").data
login(app, "pete#testmail.com", "pete123")
assert b'Test group 1' in get(app, "/groups").data
My "get" function for reference:
def get(app, endpoint: str):
return app.test_client().get(endpoint, follow_redirects=True)
My "login" function for reference:
def login(app, email="testuser#testmail.com", password="testing"):
return app.test_client().post('/login', data=dict(email=email, password=password), follow_redirects=True)
The app (from a conftest fixture imported in the test module by #pytest.mark.usefixtures('app')) for reference:
#pytest.fixture
def app():
"""An application for the tests."""
_app = create_app(DevConfig)
ctx = _app.test_request_context()
ctx.push()
yield _app
ctx.pop()
The login route for reference:
#app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm(request.form)
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user is not None and user.is_correct_password(form.password.data):
user.authenticated = True
user.last_login = user.current_login
user.current_login = datetime.now()
user.insert_user()
login_user(user)
flash(f'Welcome back {user.name}!', 'success')
return redirect(url_for('our_awesome_group.index'))
else:
flash('Incorrect credentials! Did you already register?', 'error')
else:
flash_errors(form)
return render_template('login.html', form=form)
The groups route for reference:
#app.route('/groups')
#login_required
def groups():
groups_and_users = dict()
my_group_uuids = Membership.list_groups_per_user(current_user)
my_groups = [Group.query.filter_by(uuid=group).first() for group in my_group_uuids]
for group in my_groups:
user_uuids_in_group = Membership.list_users_per_group(group)
users_in_group = [User.query.filter_by(uuid=user).first() for user in user_uuids_in_group]
groups_and_users[group] = users_in_group
return render_template('groups.html', groups_and_users=groups_and_users)
Im going to sum up the comments I made that gave the answer on how to solve this issue.
When creating a test app using Pytest and Flask there are a few different ways to go about it.
The suggested way to create a test client with proper app context is to use something like:
#pytest.fixture
def client():
""" Creates the app from testconfig, activates test client and context then makes the db and allows the test client
to be used """
app = create_app(TestConfig)
client = app.test_client()
ctx = app.app_context()
ctx.push()
db.create_all()
yield client
db.session.close()
db.drop_all()
ctx.pop()
That creates the client while pushing the app context so you can register things like your database and create the tables to the test client.
The second way is show in OP's question where use app.test_request context
#pytest.fixture
def app():
"""An application for the tests."""
_app = create_app(DevConfig)
ctx = _app.test_request_context()
ctx.push()
yield _app
ctx.pop()
and then create the test client in another pytest fixture
#pytest.fixture
def client(app):
return app.test_client()
Creating a test client allows you to use various testing features and gives access to flask requests with the proper app context.

Python: Request handler in Flask

I'm learning Flask, and the request handling seems to be like:
#app.route("/")
def hello():
return "Hello World!"
So I end up defining the functions for all my routes in a single file. I'd much rather have functions for a model in its own file, e.g. get_user, create_user in user.py. I've used Express (node.js) in the past, and I can do:
user = require('./models/user')
app.get('/user', user.list)
where user.coffee (or .js) has a list function.
How do I do the same in Flask?
From the docs:
A decorator that is used to register a view function for a given URL rule. This does the same thing as add_url_rule() but is intended for decorator usage
The add_url_rule docs elaborate:
#app.route('/')
def index():
pass
Is equivalent to the following:
def index():
pass
app.add_url_rule('/', 'index', index)
You can just as easily import your view functions into a urls.py file and call add_url_rule once for each view function there instead of defining the rules along side the functions or use the lazy loading pattern.

How to test Pyramid security setup?

Is there a recommended way to test the security setup in a Pyramid application? More specifically I'm using routes and custom routes factories. With fine grained ACLs the security setup is splitted in different spots: the config setup, factories, permission set in the #view_config, and event explicit check of permissions inside views.
The page on unit and functionnal testing (http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/testing.html) does not seem to indicate a way to test if user A can only see and modify data he is allowed to.
This is functional testing. Webtest can preserve session cookies so you can use it to login and visit various pages as a user.
myapp = pyramid.paster.get_app('testing.ini')
app = TestApp(myapp)
resp = app.post('/login', params={'login': 'foo', 'password': 'seekrit'})
# this may be a redirect in which case you may want to follow it
resp = app.get('/protected/resource')
assert resp.status_code == 200
As far as testing just certain parts of your app, you can override the authentication policy with something custom (or just use a custom groupfinder).
def make_test_groupfinder(principals=None):
def _groupfinder(u, r):
return principals
return _groupfinder
You can then use this function to simulate various principals. This doesn't handle the userid though, if your app also relies on authenticated_userid(request) anywhere. For that, you'll have to replace the authentication policy with a dummy one.
class DummyAuthenticationPolicy(object):
def __init__(self, userid, extra_principals=()):
self.userid = userid
self.extra_principals = extra_principals
def authenticated_userid(self, request):
return self.userid
def effective_principals(self, request):
principals = [Everyone]
if self.userid:
principals += [Authenticated]
principals += list(self.extra_principals)
return principals
def remember(self, request, userid, **kw):
return []
def forget(self, request):
return []
I think both the question and answer might be old at this point: with current versions of Pyramid, there's a testing_securitypolicy method (docs here) that allows easy access to setting things like authenticated_userid, effective_principals, results of remember and forget, etc.
Here's an example of usage if need was to set authenticated_userid on a request.
from pyramid.testing import (setUp, tearDown, DummyRequest)
def test_some_view():
config = setUp()
config.testing_securitypolicy(userid='mock_user') # Sets authenticated_userid
dummy_request = DummyRequest()
print(dummy_request.authenticated_userid) # Prints 'mock_user'
# Now ready to test something that uses request.authenticated_userid
from mypyramidapp.views.secure import some_auth_view
result = some_auth_view(dummy_request)
expected = 'Hello mock_user!'
assert result == expected
# Finally, to avoid security changes leaking to other tests, use tearDown
tearDown() # Undo the effects of pyramid.testing.setUp()

Resources