I'm testing various oath2 workflows and the one I'm strugglink to, is Authorization Code Grant.
I can successfully get a token If I copy/paste urls in a straight forward way.
I mean request access, copy paste given URl, enter it in a browser, accept authorization, copy paste back callback url -> access resources. Like in this example:
from requests_oauthlib import OAuth2Session
class ClientSecrets:
"""
The structure of this class follows Google convention for `client_secrets.json`:
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
Bitbucket does not emit this structure so it must be manually constructed.
"""
client_id = "myid"
client_secret = "mysecret"
auth_uri = "https://bitbucket.org/site/oauth2/authorize"
token_uri = "https://bitbucket.org/site/oauth2/access_token"
server_base_uri = "https://api.bitbucket.org/"
def main():
c = ClientSecrets()
# Fetch a request token
bitbucket = OAuth2Session(c.client_id)
# Redirect user to Bitbucket for authorization
authorization_url = bitbucket.authorization_url(c.auth_uri)
print('Please go here and authorize: {}'.format(authorization_url[0]))
# Get the authorization verifier code from the callback url
redirect_response = raw_input('Paste the full redirect URL here:')
# Fetch the access token
bitbucket.fetch_token(
c.token_uri,
authorization_response=redirect_response,
username=c.client_id,
password=c.client_secret)
# Fetch a protected resource, i.e. user profile
r = bitbucket.get(c.server_base_uri + '1.0/user')
print(r.content)
Though if I try to do that using Flask imitating actual web app that tries to get access to bitbucket, it fails to get access.
My Flask app implementation sample looks like this:
from flask import Flask, redirect, request, session
from requests_oauthlib import OAuth2Session
app = Flask(__name__)
client_id = 'myid'
client_secret = 'mysecret'
authorization_base_url = 'https://bitbucket.org/site/oauth2/authorize'
token_url = 'https://bitbucket.org/site/oauth2/access_token'
redirect_uri = 'https://127.0.0.1:5000/callback'
#app.route('/login')
def login():
oauth2 = OAuth2Session(client_id, redirect_uri=redirect_uri)
authorization_url, state = oauth2.authorization_url(
authorization_base_url,
)
# State is used to prevent CSRF, keep this for later.
session['oauth_state'] = state
return redirect(authorization_url)
#app.route("/callback")
def callback():
bitbucket = OAuth2Session(client_id, state=session['oauth_state'])
bitbucket.fetch_token(
token_url,
client_secret=client_secret,
authorization_response=request.url)
return bitbucket.get('some_resource_url').content
if __name__ == '__main__':
# Certificate and key files.
context = ('cert/server.crt', 'cert/server.key')
app.run(debug=True, ssl_context=context)
If I run app like in example, then I get this error when trying to access URL: https://127.0.0.1:5000/login
File "/home/oerp/python-programs/flask-app/bitiface/test.py", line 23, in login
session['oauth_state'] = state
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/werkzeug/local.py", line 350, in __setitem__
self._get_current_object()[key] = value
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/sessions.py", line 130, in _fail
raise RuntimeError('The session is unavailable because no secret '
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
It looks like that something todo with oath_state. If I comment oath_state assigning and try to run app like before. Then I get this error:
Traceback (most recent call last):
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1994, in __call__
return self.wsgi_app(environ, start_response)
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1985, in wsgi_app
response = self.handle_exception(e)
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/oerp/python-programs/flask-app/bitiface/test.py", line 33, in callback
authorization_response=request.url)
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/requests_oauthlib/oauth2_session.py", line 244, in fetch_token
self._client.parse_request_body_response(r.text, scope=self.scope)
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 409, in parse_request_body_response
self.token = parse_token_response(body, scope=scope)
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 376, in parse_token_response
validate_token_parameters(params)
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 383, in validate_token_parameters
raise_from_error(params.get('error'), params)
File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/errors.py", line 325, in raise_from_error
raise cls(**kwargs)
InvalidClientIdError: (invalid_request) redirect_uri does not match
It looks like if I skip oath_session, then it actually starts new session on callback and redirect_uri will not match or something like that.
Does anyone know what could be the problem?
Update
I updated Flask with secret_key, so error regarding no secret_key is gone, but the second error is still there. This error: InvalidClientIdError: (invalid_request) redirect_uri does not match is raised at this part of code:
...
...
bitbucket.fetch_token(
token_url,
client_secret=client_secret,
authorization_response=request.url)
...
...
I do not know if this is related, but printing request.url, it gives me this: https://127.0.0.1:5000/callback?state=[bunch_of_random_symbols]. So the first part https://127.0.0.1:5000/callback is exactly the same as I I set on consumer to be callback URL. To me it looks like it is actually matching.
`
P.S. Full traceback is provided.
The reason of the main error is redirect_uri argument which is present in authorization URL but not passed in access token request. As RFC 6749 describes:
redirect_uri
REQUIRED, if the "redirect_uri" parameter was included in the authorization request as described in Section 4.1.1, and their values MUST be identical.
So you need to initialize your callback OAuth session with redirect_uri:
#app.route("/callback")
def callback():
bitbucket = OAuth2Session(
client_id, state=session['oauth_state'], redirect_uri=redirect_uri
)
It is rather common question among developers why we need to send redirect_uri for getting access token. This discussion on Security.Stackexchange could be helpful.
As for the first error:
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
It is raised when you try to save some information in Flask session but secret key for Flask application was not set.
Related
I made a flask app which detects messages received on whatsapp using Twilio Webhooks. After receiving a message, the app sends a message back to the same phone number. This works perfectly using Flask and Ngrok to deploy the server and expose it. Once I deploy it to PythonAnywhere however, I get a 11200 error in the Twilio console. Here's the code.
from flask import Flask, request
import requests
from twilio.rest import Client
account_sid = 'xxxxx'
auth_token = 'xxxxx'
client = Client(account_sid, auth_token)
def mmsg(phono, body):
message = client.messages.create(
from_='whatsapp:+14155238886',
body=body,
to=phono,
)
app = Flask(__name__)
#app.route('/post', methods=['POST'])
def bot():
incoming_msg = request.values.get('Body', '').lower()
phono = request.values.get('From', "")
if incoming_msg == 'hi':
mmsg(phono, 'hello!')
if __name__ == '__main__':
app.run()
When I check the PythonAnywhere error logs, I get this
2020-07-19 13:50:46,569: POST Request: https://api.twilio.com/2010-04-01/Accounts/AC84a8b5837227246efc0c6f9440b6e12c/Messages.json
2020-07-19 13:50:46,570: PAYLOAD: {'To': 'whatsapp:{myphonenumber}', 'From': 'whatsapp:+14155238886', 'Body': 'hello!'}
2020-07-19 13:50:49,576: Exception on /post [POST]
Traceback (most recent call last):
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.twilio.com', port=443): Max retries exceeded with url: /2010-04-01/Accounts/AC84a8b5837227246efc0c6f9440b6e12c/Messages.json (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fc0504362e8>: Failed to establish a new connection: [Errno 111] Connection refused',))
I have tried adding another key and value to the message = client.messages.create like this.
message = client.messages.create(
from_='whatsapp:+14155238886',
body=item,
to=phono,
AC84a8b5837227246efc0c6f9440b6e12c='83ce0b901ff353f9b9a77222e001d71d'
)
When I try that, I get this error on PythonAnywhere.
2020-07-19 14:09:51,030: Exception on /post [POST]
Traceback (most recent call last):
File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/home/AbhayAysola/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/AbhayAysola/bot.py", line 46, in bot
mmsg(phono, ou)
File "/home/AbhayAysola/bot.py", line 24, in mmsg
AC84a8b5837227246efc0c6f9440b6e12c='83ce0b901ff353f9b9a77222e001d71d'
TypeError: create() got an unexpected keyword argument 'AC84a8b5837227246efc0c6f9440b6e12c'
Free accounts on PythonAnywhere have restricted Internet access; you can only access a specific set of sites (listed here, but this is a list of sites that you can access, not a list of sites that you can't access), and you have to use a proxy server to access them.
For most libraries that is completely transparent -- they pick up the proxy settings from the system environment and use it without you having to do anything extra. But the Twilio library needs a little bit of extra configuration. There's a help page explaining what this is here, but the specific change to your code would be to replace this:
client = Client(account_sid, auth_token)
...with this:
import os
from twilio.http.http_client import TwilioHttpClient
proxy_client = TwilioHttpClient(proxy={'http': os.environ['http_proxy'], 'https': os.environ['https_proxy']})
client = Client(account_sid, auth_token, http_client=proxy_client)
I'm building an SMS based chatbot using Python, Twilio, Flask, IBM Watson and Google App Engine. It works fine for a few minutes but then inevitably sends up an Internal Response Error.
I've tried editing the yaml file so it has a default expiration of 1 day. It doesn't do anything.
Edit: Currently on automatic scaling, but I've tried changing from autmatic to basic scaling, and changing min_instances to 1.
Here's the log:
2019-07-06 08:57:09 default[20190706t180659]
Traceback (most recent call last):
File "/env/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/env/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/env/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/env/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/env/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/env/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/srv/main.py", line 81, in incoming_sms
r = Watson(b)
File "/srv/main.py", line 42, in Watson
input = message_input
File "/srv/ibm_watson/assistant_v2.py", line 244, in message
accept_json=True)
File "/srv/ibm_cloud_sdk_core/base_service.py", line 358, in request
raise ApiException(response.status_code, error_message, http_response=response)
ibm_cloud_sdk_core.api_exception.ApiException: Error: NotFound: session id 2900da9f-dd77-480a-a939-1a5b060b3f82 for agent instance 6656a86c-ad0e-4463-8344-5f7fdcb4a6fe, Code: 404 , X-global-transaction-id: 5a3699f1cd4e3409e9f89f4fcd87735f
Code to take inputs on Twilio, feed them through Watson and respond.
from flask import Flask, request, make_response
from twilio.twiml.messaging_response import MessagingResponse
import os
from twilio import twiml
import ibm_watson
# Set up Assistant service.
service = ibm_watson.AssistantV2(
iam_apikey = 'xxx', # replace with API key
version = '2019-02-28',
url = 'https://gateway-syd.watsonplatform.net/assistant/api')
assistant_id = 'xxx' #Under Assistant Settings
# Create session.
session_id = service.create_session(
assistant_id = assistant_id
).get_result()['session_id']
def Watson(b):
# Initialize with empty value to start the conversation.
message_input = {
'message_type:': 'text',
'text': str(b)
}
# Main input/output loop
while message_input['text'] != 'quitt':
# Send message to assistant.
response = service.message(
assistant_id,
session_id,
input = message_input
).get_result()
# If an intent was detected, print it to the console.
if response['output']['intents']:
print('Detected intent: #' + response['output']['intents'][0]['intent'])
# Print the output from dialog, if any. Supports only a single
# text response.
if response['output']['generic']:
if response['output']['generic'][0]['response_type'] == 'text':
return(response['output']['generic'][0]['text'])
# Prompt for next round of input.
message_input = {
'text': str(b)
}
# We're done, so we delete the session.
service.delete_session(
assistant_id = assistant_id,
session_id = session_id
)
app = Flask(__name__)
#app.route("/sms", methods=['GET', 'POST'])
def incoming_sms():
"""Send a dynamic reply to an incoming text message"""
#Get the message the user sent our Twilio number
body = request.values.get('Body', None)
b = str(body)
b = b.lower()
resp = MessagingResponse()
r = Watson(b)
resp.message(r)
# response.append(r)
return str(resp)
if __name__ == "__main__":
app.run(debug=True)
You're getting an exception from the ibm_cloud_sdk_core package. This could possibly be due to App Engine scaling up to multiple instances, but session IDs not being shared across instances. So instance A might have a session ID, but a subsequent request might go to instance B which does not have this session ID.
You should reach out to the library maintainers to understand how to either pool session IDs, or determine whether you have a valid session ID for a request before making the request to their API.
I am writing a script that uses Google's authenticated login. I am currently getting an access token and the user's email address and passing it to my function that connects to gmail using imap and then does some stuff with the emails. I'm generating the auth string like i've seen others do online however I am receiving this error:
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/flask/app.py", line 2000, in __call__
return self.wsgi_app(environ, start_response)
File "/Library/Python/2.7/site-packages/flask/app.py", line 1991, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/Library/Python/2.7/site-packages/flask/app.py", line 1567, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Library/Python/2.7/site-packages/flask/app.py", line 1988, in wsgi_app
response = self.full_dispatch_request()
File "/Library/Python/2.7/site-packages/flask/app.py", line 1641, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Library/Python/2.7/site-packages/flask/app.py", line 1544, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Library/Python/2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
rv = self.dispatch_request()
File "/Library/Python/2.7/site-packages/flask/app.py", line 1625, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/Harrison/Desktop/Uber/UberStats.py", line 60, in index
return Uber_Cost(email_address, access_token)
File "/Users/Harrison/Desktop/Uber/UberStats.py", line 103, in Uber_Cost
mail.authenticate('XOAUTH2', lambda x: auth_string)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/imaplib.py", line 364, in authenticate
raise self.error(dat[-1])
error: [AUTHENTICATIONFAILED] Invalid credentials (Failure)
I am printing out the access code as well as the email address that i'm logging in with, so I know those values aren't null. Am I generating the auth string wrong? Am I not authenticating with imap properly?
Here's my code:
from flask import Flask, request, url_for, session, redirect, jsonify
from flask_oauth import OAuth
import json
import imaplib
import email
from bs4 import BeautifulSoup
import base64
GOOGLE_CLIENT_ID = '****'
GOOGLE_CLIENT_SECRET = '***'
REDIRECT_URI = '/authorized' # one of the Redirect URIs from Google APIs console
SECRET_KEY = 'Uber'
DEBUG = True
app = Flask(__name__)
app.secret_key = 'Uber'
oauth = OAuth()
google = oauth.remote_app('google',
base_url='https://www.google.com/accounts/',
authorize_url='https://accounts.google.com/o/oauth2/auth',
request_token_url=None,
request_token_params={'scope': 'https://www.googleapis.com/auth/userinfo.email',
'response_type': 'code'},
access_token_url='https://accounts.google.com/o/oauth2/token',
access_token_method='POST',
access_token_params={'grant_type': 'authorization_code'},
consumer_key=GOOGLE_CLIENT_ID,
consumer_secret=GOOGLE_CLIENT_SECRET)
#app.route('/')
def index():
access_token = session.get('access_token')
if access_token is None:
return redirect(url_for('login'))
access_token = access_token[0]
from urllib2 import Request, urlopen, URLError
headers = {'Authorization': 'OAuth '+access_token}
req = Request('https://www.googleapis.com/oauth2/v1/userinfo',
None, headers)
try:
res = urlopen(req)
except URLError, e:
if e.code == 401:
# Unauthorized - bad token
session.pop('access_token', None)
return redirect(url_for('login'))
return res.read()
j = json.loads(res.read())
email_address = j['email']
print email_address, access_token
return Uber_Cost(email_address, access_token)
#app.route('/login')
def login():
callback=url_for('authorized', _external=True)
return google.authorize(callback=callback)
#app.route(REDIRECT_URI)
#google.authorized_handler
def authorized(resp):
access_token = resp['access_token']
session['access_token'] = access_token, ''
return redirect(url_for('index'))
#google.tokengetter
def get_access_token():
return session.get('access_token')
def GenerateOAuth2String(username, access_token, base64_encode=True):
auth_string = 'user=%s\1auth=Bearer %s\1\1' % (username, access_token)
if base64_encode:
auth_string = base64.b64encode(auth_string)
return auth_string
def Uber_Cost(email_address, access_token):
auth_string = GenerateOAuth2String(email_address, access_token, base64_encode=False)
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.debug = 4
mail.authenticate('XOAUTH2', lambda x: auth_string)
mail.select('INBOX')
It looks like you've got the authenticate() method down based on your latest code.
You also need the https://mail.google.com/ OAuth scope to authenticate with the IMAP and SMTP servers.
That is add it to your scope request, and make sure your app is configured for this scope on the Google App Console:
request_token_params={'scope': 'https://www.googleapis.com/auth/userinfo.email https://mail.google.com/',
'response_type': 'code'},
The Google OAUTH2 protocol and scopes are documented at their developer page.
Good evening, i've been trying to migrate my blogger python app to oauth2 since the good old Clientlogin() has been deprecated and erased.
So, basically i searched through the entire web and couldn't manage to make my application to work correctly.
This is the basic code im using for testing:
FLOW = flow_from_clientsecrets('/home/b/client_secret.json',scope='https://www.googleapis.com/auth/blogger',message="Client Secrets Not Found")
storage = Storage('blogger.dat')
credentials = storage.get()
parser = argparse.ArgumentParser(parents=[tools.argparser])
flags = parser.parse_args()
if credentials is None or credentials.invalid:
credentials = run_flow(FLOW, storage, flags)
if credentials.access_token_expired:
credentials.refresh(httplib2.Http())
SCOPE = 'https://www.blogger.com/feeds'
token = gdata.gauth.OAuth2TokenFromCredentials(credentials)
client = gdata.blogger.client.BloggerClient()
token.authorize(client)
post = client.add_post(blog_id, title="blah", body="blah", labels="label", draft=False, title_type="xhtml", body_type="html")
I get a 401 error code, unauthorized everytime i try to do this.
Traceback (most recent call last):
File "/home/b/.eclipse/org.eclipse.platform_4.4.2_1473617060_linux_gtk_x86_64/plugins/org.python.pydev_4.0.0.201504132356/pysrc/pydevd.py", line 2278, in <module>
globals = debugger.run(setup['file'], None, None)
File "/home/b/.eclipse/org.eclipse.platform_4.4.2_1473617060_linux_gtk_x86_64/plugins/org.python.pydev_4.0.0.201504132356/pysrc/pydevd.py", line 1704, in run
pydev_imports.execfile(file, globals, locals) # execute the script
File "/home/b/workspace/BloggerPy/simpleblogger.py", line 53, in <module>
post = client.add_post(blog_id, title="hola", body="holaaa", labels="label", draft=False, title_type="xhtml", body_type="html", token=token)
File "/usr/local/lib/python2.7/dist-packages/gdata/blogger/client.py", line 111, in add_post
return self.post(new_entry, BLOG_POST_URL % blog_id, auth_token=auth_token, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/gdata/client.py", line 690, in post
desired_class=desired_class, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/gdata/client.py", line 298, in request
**kwargs)
File "/usr/local/lib/python2.7/dist-packages/gdata/client.py", line 307, in request
response, Unauthorized)
gdata.client.Unauthorized: Unauthorized - Server responded with: 401, User does not have permission to create new post
Can someone help me out with this? I'd really appreciate it :)
Greetings
Finally i've fixed my issue with gdata.gauth:
I used auth2token = gdata.gauth.OAuth2Token(client_id,client_secret,scope,user_agent)
After getting the authorization token i generate an authorized url to get an access code with auth2token.generate_authorize_url(redirect_uri=URL,approval_prompt="force").
once you get this url, you manually get the code and generate a refresh token, with which you generate an access token:
token = auth2token.get_access_token(code). Easy enough. For any other information as to how to save the token to a blob string in a file here's the reference:
gdata-python-api + Analytics with simple auth
I was not able to implement a working minimal example with the Python Micro-Webframework Flask using a neo4j graphdatabase via the embedded python bindings (neo4j / python-embedded, version 1.6). What I have (on the basis of this Stack-Overflow-thread) is:
import os
import jpype
from neo4j import GraphDatabase
from flask import Flask, g
# configuration
DATABASE = 'graphdatabase'
DEBUG = True
SECRET_KEY = 'blubber'
USERNAME = 'tobias'
PASSWORD = 'bla'
ADMIN = 'admin'
app = Flask(__name__)
app.config.from_object(__name__)
def connectDB():
return GraphDatabase(app.config['DATABASE'])
def initDB():
db = connectDB()
with db.transaction:
users = db.node()
userIndex = db.node.indexes.create('users')
user = db.node(name=app.config['ADMIN'])
userIndex['name'][app.config['ADMIN']] = user
db.shutdown()
print "Database initialized."
#app.before_request
def before_request():
jpype.attachThreadToJVM()
g.db = connectDB()
#app.teardown_request
def teardown_request(exception):
jpype.attachThreadToJVM()
g.db.shutdown()
#app.route('/')
def index():
with g.db.transaction:
userIndex = g.db.node.indexes.get('users')
user = userIndex['name'][app.config['ADMIN']].single
username = user['name']
return render_template('index.html', name=username)
if os.path.exists(app.config['DATABASE']) == False:
initDB()
if __name__ == '__main__':
app.run()
Unfortunately, it throws:
File "/home/tobias/Esk/Dev/adhocracyLight/venv/lib/python2.7/site-packages/flask/app.py", line 1518, in __call__
return self.wsgi_app(environ, start_response)
File "/home/tobias/Esk/Dev/adhocracyLight/venv/lib/python2.7/site-packages/flask/app.py", line 1506, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/tobias/Esk/Dev/adhocracyLight/venv/lib/python2.7/site-packages/flask/app.py", line 1504, in wsgi_app
response = self.full_dispatch_request()
File "/home/tobias/Esk/Dev/adhocracyLight/venv/lib/python2.7/site-packages/flask/app.py", line 1264, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/tobias/Esk/Dev/adhocracyLight/venv/lib/python2.7/site-packages/flask/app.py", line 1262, in full_dispatch_request
rv = self.dispatch_request()
File "/home/tobias/Esk/Dev/adhocracyLight/venv/lib/python2.7/site-packages/flask/app.py", line 1248, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/tobias/Esk/Dev/adhocracyLight/adhocracyLight.py", line 73, in index
userIndex = g.db.node.indexes.get('users')
File "/home/tobias/Esk/Dev/adhocracyLight/venv/lib/python2.7/site-packages/neo4j/index.py", line 36, in get
return self._index.forNodes(name)
java.lang.RuntimeExceptionPyRaisable: java.lang.IllegalArgumentException: No index provider 'lucene' found. Maybe the intended provider (or one more of its dependencies) aren't on the classpath or it failed to load.
I guess the problem is due to the threading (g is thread-local and contains a pointer to the neo4j-Database, maybe that's a bad idea?).
Neo4j Embedded is not intended to be used in a Web server environment -- you should use Neo4j Server and a Neo4j Server client.
Bulbs (http://bulbflow.com) is a Neo4j Server client that was designed with Flask in mind, in fact bulbflow.com is running on Flask on Heroku, using the Neo4j Heroku Add On (which is currently free).
You use Gremlin or Cypher for queries and transactional requests.
For an example of how to structure your app, see the Lightbulb (https://github.com/espeed/lightbulb) blog example, esp:
https://github.com/espeed/lightbulb/blob/master/lightbulb/model.py
https://github.com/espeed/lightbulb/blob/master/lightbulb/bulbsconf.py
Notice this line in bulbsconf.py:
bulbs_config.set_neo4j_heroku()
Lightbulb is designed to run on Heroku with the Neo4j Heroku Add On -- leave that line out if you are not running on Heroku.
Then in your Flask views or your app.py, do:
from bulbsconf import graph