I have a web.py app I'm running through mod_wsgi locally (http://localhost/...). I've gotten to the point of adding authentication to my app and wanted to use web.py's builtin module. I started with a brief example found here: http://log.liminastudio.com/programming/howto-use-openid-with-web-py
import web, web.webopenid
urls = (
r'/openid', 'web.webopenid.host',
r'/', 'Index'
)
app = web.application(urls, globals())
class Index:
def GET(self):
body = '''
<html><head><title>Web.py OpenID Test</title></head>
<body>
%s
</body>
</html>
''' % (web.webopenid.form('/openid'))
return body
if __name__ == "__main__": app.run()
This works well enough running in the terminal and going to http://localhost:8080/. Another example http://c-farrell.blogspot.com/2010/11/usrbinenv-pythonimport-webfrom-web.html does a similar technique but makes more sense to me.
#!/usr/bin/env python
import web
from web import webopenid
urls = (
'/', 'index',
'/openid', 'webopenid.host',
)
... more code ...
class index:
def GET(self):
oid = webopenid.status()
if not oid:
return 'please log in: ' + \
webopenid.form('/openid')
else:
return 'you are logged in as:' + \
webopenid.form('/openid')
Here's where I get a little lost. From what I can tell, the argument passed to form is the return URL after signing in. For example, if I put 'http://www.yahoo.com/' it will take me there after every login attempt. I feel like this should point back to my own controller and just check there, but the convention seems to be to use the web.webopenid.host controller, which I guess handles the id and returns to the base '/' url. I think I'm getting there, but the status returned is always None.
From what I gather then, this is either a code issue, or there's something in my apache configuration that is keeping the authentication from working. In web.webopenid, the library creates a .openid_secret_key file in the same directory as the web server. When I run the example code, this gets created. When I run my code through apache, it does not (at least not in the cgi-bin. Somewhere else?) Anyway, if this file isn't being generated or being regenerated every time, it will keep me from logging in. I believe it's an apache issue as I tried running my app through the web.py webserver and I did get the file created and I can authenticate. All I can conclude is this file isn't being written and every subsequent query tries a new file and I can never authentication. Can any apache/mod_wsgi gurus explain to me where this file is being written or if this is the actual problem?
Most likely obvious causes for this were given in answer to same question on mod_wsgi list. See:
https://groups.google.com/d/msg/modwsgi/iL65jNeY5jA/KgEq33E8548J
It is probably a combination of the first two, current working directory and Apache user access rights.
Related
I'm trying to serve some simple service using flask and flask_restx (a forked project of flask-restplus, that would be eventually served on AWS.
When it is served, I want to generate swagger page for others to test it easily.
from flask import Flask
from flask_restx import Api
from my_service import service_namespace
app = Flask(__name__)
api = Api(app, version='1.0')
api.add_namespace(service_namespace)
if __name__ == '__main__':
app.run(debug=True)
When I test it locally (e.g. localhost:5000), it works just fine. Problem is, when it is hosted on AWS, because it has a specific domain (gets redirected?) (e.g. my-company.com/chris-service to a container), the document page is unable to find its required files like css and so:
What I've looked and tried
Python (Flask + Swagger) Flasgger throwing 404 error
flask python creating swagger document error
404 error in Flask
Also tried adding Blueprint (albeit without knowing exactly what it does):
app = Flask(__name__)
blueprint = Blueprint("api", __name__,
root_path="/chris-service",
# url_prefix="/chris-service", # doesn't work
)
api = Api(blueprint)
app.register_blueprint(blueprint)
...
And still no luck.
Update
So here's more information as per the comments (pseudo, but technically identical)
Access point for the swagger is my-company.com/chris (with or without http:// or https:// doesn't make difference)
When connecting to the above address, the request URL for the assets are my-company.com/swaggerui/swagger-ui.css
You can access the asset in my-company.com/chris/swaggerui/swagger-ui.css
So I my resolution (which didn't work) was to somehow change the root_path (not even sure if it's the correct wording), as shown in What I've looked and tried.
I've spent about a week to solve this but can't find a way.
Any help will be greatful :) Thanks
Swagger parameters defined at apidoc.py file. Default apidoc object also created in this file. So if you want to customize it you have change it before app and api initialization.
In your case url_prefix should be changed (I recommend to use environment variables to be able set url_prefix flexibly):
$ export URL_PREFIX='/chris'
from os import environ
from flask import Flask
from flask_restx import Api, apidoc
if (url_prefix := environ.get('URL_PREFIX', None)) is not None:
apidoc.apidoc.url_prefix = url_prefix
app = Flask(__name__)
api = Api(app)
...
if __name__ == '__main__':
app.run()
Always very frustrating when stuff is working locally but not when deployed to AWS. Reading this github issue, these 404 errors on swagger assets are probably caused by:
Missing javascript swagger packages
Probably not the case, since flask-restx does this for you. And running it locally should also not work in this case.
Missing gunicorn settings
Make sure that you are also setting gunicorn up correctly as well with
--forwarded-allow-ips if deploying with it (you should be). If you are in a kubernetes cluster you can set this to *
https://docs.gunicorn.org/en/stable/settings.html#forwarded-allow-ips
According to this post, you also have to explicitly set
settings.FLASK_SERVER_NAME to something like http://ec2-10-221-200-56.us-west-2.compute.amazonaws.com:5000
If that does not work, try to deploy a flask-restx example, that should definetely work. This rules out any errors on your end.
I am working on a flutter app for creating schedules for teachers. I created a Django project to generate a schedule based on the data in the post request from the user. This post request is sent from the flutter app. The Django project doesn't use a database or anything, It simply receives the input data, creates the schedule and returns the output data back to the user.
The problem is that the process of creating the schedule only works 1 time after starting the Django server. So when I want another user to send a request and receive a schedule I have to restart the server... Maybe the server remembers part of the data from the previous request?? I don't know. Is there somekind of way to make it forget everything after a request is done?
When I try to repeatedly run the scheduler without being in a Django project it works flawlessly. The Scheduler is based on the Google cp_model sat solver. (from ortools.sat.python import cp_model). The error I get when running the scheduler the second time in a Django project is 'TypeError: LonelyDuoLearner_is_present_Ss9QV7qFVvXBzTe3R6lmHkMBEWn1_0 is not a boolean variable'.
Is there some kind of way to fix this or mimic the effect of restarting the server?
The django view looks like this:
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from .scheduler.planning import Planning
from .scheduler.planning import print_json
import json
# Convert the data and creates the schedule.
#csrf_exempt
def generate_schedule(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
planning = Planning()
planning.from_json(data)
output_json = planning.output_to_json()
print_json(output_json)
response = json.dumps(output_json)
except Exception as e:
print(e)
print("The data provided doesn't have the right structure.")
response = json.dumps([{'Error': "The data provided doesn't have the right structure."}])
else:
response = json.dumps([{'Error': 'Nothing to see here, please leave.'}])
return HttpResponse(response, content_type='text/json')
There is no beautiful way to restart the server (aside from just killing it by force, which is hardly beautiful).
You're probably using some global state somewhere in the code you're not showing, and it gets screwed up.
You should fix that instead, or if you can't do so, run the solving in a subprocess (using e.g. subprocess.check_call(), or multiprocessing.Process()).
The CP-SAT solver is stateless. The only persistent/shared object is the Ctrl-C handler, which can be disabled with a sat parameter. (catch_sigint if my memory is correct).
I am creating a REST API using python flask. The API is ready and works on port number 8000 of my localhost. Now I intend to give this REST API a user friendly interface for which I decided to go with python - restplus. I thought of calling this service (running on 8000) internally from swagger application running on 5000
I was able to create the basic structure of the API (Swagger). The code for which looks like this:
import flask
from flask import Flask, request
from flask_restplus import Resource, Api
app = Flask(__name__)
api = Api(app)
#api.route('/HybridComparator/<string:url2>/<string:url1>')
class HybridComparator(Resource):
def get(self, url1, url2):
print(url1)
print(url2)
return url1 + ' ' + url2
if __name__ == '__main__':
app.run(debug=True)
The application as a whole runs seamlessly (with random strings as parameters) on port 5000. But when the URLs I pass are actual links, the application returns a response of 404 - Not found. Further to my investigation I realized the culprit being '/' embedded within the links I try to provide. Is there a way to handle URLs in particular?
Should I encode them before sending a request. (This will make my parameters look ugly). Is there something I am missing?
This is an entirely old question and I am sure you solved your problem by now.
But for new searchers, this may come in handy;
replace <string:url2>/<string:url1> with <path:url2>/<path:url1>
it seems that :
#api.route('/HybridComparator/<path:url2>/<path:url1>')
should fix it ,it fixes the 404 but i am getting only "http:/" part of the param
I'm writing an app using Flask.
I have a set of routes and they work.
What I want to do on the client side is to ignore any requests to invalid URLs. That is I do not want to render any 404/error pages in the app. I would like an alert that says the URL is invalid and for the browser to simply stay on the same page.
I don't want to be checking the URLs in JavaScript on the client, as this would expose them.
I have a route which responds correctly to unknown URLs:
#app.errorhandler(404)
def non_existant_route(error):
return jsonify({"no":"such page"})
If I delete the return statement I get a 500 error.
I can't use abort()
Does this idea violate some HTTP principle?
Thanks
It sounds like you need a "catch-all" endpoint. Typically, it seems a catch-all endpoint would return a generic 404, but in your case, you probably want to return a 200 with some contextual information. Here's basically how you can do it (credit goes to http://flask.pocoo.org/snippets/57/):
from flask import Flask
app = Flask(__name__)
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def catch_all(path):
# returns a 200 (not a 404) with the following contents:
return 'your custom error content\n'
# This is just one of your other valid routes:
#app.route('/stuff')
def stuff():
return 'stuff\n'
if __name__ == '__main__':
app.run()
If you run this and curl various endpoints of the test app, here's what you get:
$ curl localhost:5000/stuff
stuff
$ curl localhost:5000/foo/bar
your custom error content
$ curl localhost:5000/otherstuff
your custom error content
As you can see, your other routes will still work as you expect.
I've decided a solution to this is too hard! I can not find any way to get the browser to ignore a response. There is no response header for 'do nothing'. If there was we would probably never see a webserver error again, which would not be good.
I could ajaxify all the requests as a way to grab the response headers and analyze them before any rendering or redirecting happens. That starts to break all the navigation (back buttons at least) and the pretty URLs. I could bung in a JS routing framework etc, and while I'm leaning how it works I'm not building my app (I already have enough to learn!)
#app.errorhandler(404)
def page_not_found(error):
return redirect(url_for('index'))
If you come up with something great post it anyway, I'm not the first to ask this question, and probably not the last.
Thanks
I remember reading about a javascript library some days ago (but I don't remember the name...). The clou with this library was, that all links and form submits were loaded not directly into the browser "_top" frame/window but into a hidden div and afterwards, when done, the content of the page was replaced by the content of this hidden div.
So if you want to catch bad links and such on client side you could hook up all links and submits and check the http response code. If it is not 200 (ok) you display an error. If it is okay you decide, if you replace the old page with the new content.
But there are two problems with this solution:
1. You would have to change the browsers location (in the address bar) without reloading the page of course!
2. It might get tricky to post some file uploads with javascript.
If I find the link or name of the js-library I saw, I will tell you!
Is there a way to call a python function when a certain link is clicked within a html page?
Thanks
You'll need to use a web framework to route the requests to Python, as you can't do that with just HTML. Flask is one simple framework:
server.py:
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('template.html')
#app.route('/my-link/')
def my_link():
print 'I got clicked!'
return 'Click.'
if __name__ == '__main__':
app.run(debug=True)
templates/template.html:
<!doctype html>
<title>Test</title>
<meta charset=utf-8>
Click me
Run it with python server.py and then navigate to http://localhost:5000/. The development server isn't secure, so for deploying your application, look at http://flask.pocoo.org/docs/0.10/quickstart/#deploying-to-a-web-server
Yes, but not directly; you can set the onclick handler to invoke a JavaScript function that will construct an XMLHttpRequest object and send a request to a page on your server. That page on your server can, in turn, be implemented using Python and do whatever it would need to do.
Yes. If the link points to your web server, then you can set up your web server to run any kind of code when that link is clicked, and return the result of that code to the user's browser. There are many ways to write a web server like this. For example, see Django. You might also want to use AJAX.
If you want to run code in the user's browser, use Javascript.
There are several ways to do this, but the one that has worked best for me is to use CherryPy. CherryPy is a minimalist python web framework that allows you to run a small server on any computer. There is a very similiar question to yours on stackoverflow - Using the browser for desktop UI.
The code below will do what you want. Its example 2 from the CherryPy tutorial.
import cherrypy
class HelloWorld:
def index(self):
# Let's link to another method here.
return 'We have an important message for you!'
index.exposed = True
def showMessage(self):
# Here's the important message!
return "Hello world!"
showMessage.exposed = True
import os.path
tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
if __name__ == '__main__':
# CherryPy always starts with app.root when trying to map request URIs
# to objects, so we need to mount a request handler root. A request
# to '/' will be mapped to HelloWorld().index().
cherrypy.quickstart(HelloWorld(), config=tutconf)
else:
# This branch is for the test suite; you can ignore it.
cherrypy.tree.mount(HelloWorld(), config=tutconf)
I personally use CherryPy in combination with several other modules and tools:
Mako (template library)
py2exe (convert into Windows executable)
GccWinBinaries (used in combination with py2exe)
I wrote an article about Browser as Desktop UI with CherryPy that introduces modules and tools used plus some further links that might help.
In addition to running Python scripts on a server, you can run Python scripts on the client-side using Skulpt.