Related
I have updated the Django version for my project from Django-2.2.16 --> Django3.2.14.
But with this update, some of my test cases are failing and I cannot understand the reason for the failure.
My test-case file:
import json
from os import access
from unittest import mock
from unittest.mock import patch
import asyncio
from app.models import UserProfile
from django.test import TestCase, TransactionTestCase
from requests.models import Response
from services.check_status import check_status
loop = asyncio.get_event_loop()
#mock.patch("services.check_status.save_status")
#mock.patch("services..check_status.send_wss_message")
class TestUserStatus(TransactionTestCase):
def setUp(self):
super().setUp()
self.account_id = 4
self.sim_profile = UserProfile.objects.create()
def test_check_status_completed(
self,
mock_send_wss_message,
mock_save_status,
):
mock_save_status.return_value = {}
send_wss_message_future = asyncio.Future()
send_wss_message_future.set_result(True)
mock_send_wss_message.return_value = send_wss_message_future
loop.run_until_complete(
check_status(
self.sim_profile.id,
)
)
self.assertTrue(mock_save_status.called)
self.assertTrue(mock_send_wss_message.called)
My pseudo check_status file is :-
import logging
from app.models import UserProfile, UserStatus
from services.constants import WebsocketGroups
from services.user.constants import USER
from app.api.serializers import UserStatusSerializer
from services.utils import send_wss_message, Client
logger = logging.getLogger(__name__)
def save_status(**kwargs):
status = UserStatus.objects.filter(
status_id=kwargs.get("status_id")
).first()
data = kwargs
user_status_serializer = UserStatusSerializer(status, data, partial=True)
if user_status_serializer.is_valid():
user_status_serializer.save()
async def check_status(
profile_id
):
user_profile = UserProfile.objects.get(id=profile_id)
login_token = get_login_token(user_profile)
user_creds = env["user_api"]
headers = USER["headers"]
subscription_details = Client.get(
USER["url"], headers
)
transaction_status = subscription_details.json()["Status"]
subscription_data = subscription_details.json()["Data"][0]
transaction_status_details = subscription_data["TransactionStatusDetails"]
error_message = ""
status = ""
if transaction_status == "Success":
#perform some actions and save status...
message = {
"type": "user_profile",
"data": [user_profile.id, transaction_status, {"results": {}},],
}
await send_wss_message(
user_profile.id, message=message, group_name=WebsocketGroups.USER_PROFILE,
)
else:
#perform some actions ...
When I am running my test-case file it's creating the UserProfile object but when control goes to the check_status function in int UserProfile.objects.all returns <QuerySet []>.
I made a temporary sync function to return a list of all user profiles and called it inside my test_check_status_completed and it returned the list. But for async functions that are called through the loop.run_until_complete, they all returned <QuerySet []>.
i am trying to make a function that uses multiple aws services in a lambda function :
import os
import boto3
import hmac, hashlib, base64, copy
def lambda_handler(event, context):
secretsmanager = boto3.client('secretsmanager')
secret_response = secretsmanager.get_secret_value(SecretId = os.environ.get('cognitoSecretID'))
cognito = boto3.client('cognito-idp')
cognito_pool_id = os.environ.get('cognitoPoolID')
event_body = event['body']
username = event_body['email']
secret = secret_response['SecretString']
raw_message = username + cognito_pool_id
message = bytes(raw_message, 'utf-8')
secret = bytes(secret,'utf-8')
secret_hash = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest()).decode()
authParameters = {
'USERNAME': username,
'PASSWORD': event_body['password'],
'SECRET_HASH': secret_hash
}
cognito.admin_initiate_auth(UserPoolId = cognito_pool_id, ClientId = os.environ.get('cognitoClientID'), AuthFlow = "ADMIN_USER_PASSWORD_AUTH", AuthParameters = authParameters )
return True
i am testing git with pytest as follows :
import os
import pytest
from unittest.mock import call
import boto3
import hmac, hashlib, base64
from src.DacAdminsLogin import lambda_handler
from __mocks__.SecretsManagerMock import SecretsManagerMock
MockLambdaHandlerEvent = {
'body' : {
'email': "abdelouahedelhariri#gmail.com",
'password': "test"
}
}
#pytest.fixture
def dummy_secret(monkeypatch):
dummySecret = 'adummytest'
monkeypatch.setenv('cognitoSecretID', dummySecret, prepend=False)
return dummySecret
#pytest.fixture
def dummy_cognito_id(monkeypatch):
dummyCognitoID = 'adummycognitoid'
monkeypatch.setenv('cognitoClientID', dummyCognitoID, prepend=False)
return 'adummycognitoid'
#pytest.fixture
def dummy_cognito_pool_id(monkeypatch):
dummyCognitoPoolID = 'adummycognitopoolid'
monkeypatch.setenv('cognitoPoolID', dummyCognitoPoolID, prepend=False)
return 'adummycognitopoolid'
#pytest.fixture
def secret_manager(mocker, dummy_secret):
mock = mocker.patch('__mocks__.SecretsManagerMock.SecretsManagerMock')
mock.get_secret_value.return_value = {'SecretString' : dummy_secret}
return mock
#pytest.fixture
def cognito(mocker):
return mocker.patch('__mocks__.CognitoMock.CognitoMock', return_value= "Test secret")
#pytest.fixture
def client(mocker, secret_manager, cognito):
return mocker.patch('boto3.client', side_effect= [secret_manager, cognito])
def test_create_secrets_manager_client(client):
lambda_handler(MockLambdaHandlerEvent,1)
client.assert_has_calls([call('secretsmanager')])
def test_get_secret_value_call(client ,secret_manager, dummy_secret):
lambda_handler(MockLambdaHandlerEvent,1)
secret_manager.get_secret_value.assert_called_once_with(SecretId= dummy_secret)
def test_create_cognito_client(client ,secret_manager, dummy_secret):
lambda_handler(MockLambdaHandlerEvent,1)
client.assert_has_calls([call('secretsmanager'), call('cognito')])
def test_admin_initiate_auth_call(client, monkeypatch , cognito, dummy_secret, dummy_cognito_id, dummy_cognito_pool_id):
MockLambdaHandlerEventBody = MockLambdaHandlerEvent['body']
username = MockLambdaHandlerEventBody['email']
app_client_id = dummy_cognito_pool_id
key = dummy_secret
message = bytes(username+app_client_id,'utf-8')
key = bytes(dummy_secret,'utf-8')
secret_hash = base64.b64encode(hmac.new(key, message, digestmod=hashlib.sha256).digest()).decode()
authParameters = {
'USERNAME': username,
'PASSWORD': MockLambdaHandlerEventBody['password'],
'SECRET_HASH': secret_hash
}
lambda_handler(MockLambdaHandlerEvent,1)
cognito.admin_initiate_auth.assert_called_once_with(UserPoolId = dummy_cognito_pool_id, ClientId = dummy_cognito_id, AuthFlow = "ADMIN_USER_PASSWORD_AUTH", AuthParameters = authParameters )
I am new to python and i don't know why i keep getting the following error : TypeError: can only concatenate str (not "NoneType") to str, coming from the raw_message concatenation.
When i comment out the cognito.admin_initiate_auth.assert_called_once_with(UserPoolId = dummy_cognito_pool_id, ClientId = dummy_cognito_id, AuthFlow = "ADMIN_USER_PASSWORD_AUTH", AuthParameters = authParameters )
or change for example the UserPoolId to another value the error disappears.
I have a chalice project (1.26.2) which is always exiting with a time out when deployed, chalice local works fine.
This is my project structure:
This is the code in my app.py:
from datetime import datetime
from decimal import Decimal
import boto3
import firebase_admin
from chalice import Chalice, AuthResponse
from chalice.app import AuthRequest
from firebase_admin import credentials, auth
from chalicelib import crud
from chalicelib import models
from chalicelib import schemas
from chalicelib.auth import full_user_from_context, user_from_context
from chalicelib.db import SessionLocal, engine
app = Chalice(app_name='server-aws')
BUCKET = 'meet-app'
s3_client = boto3.client('s3')
cred = credentials.Certificate('chalicelib/serviceAccountKey.json')
firebase_admin.initialize_app(cred)
models.Base.metadata.create_all(bind=engine)
DISTANCE_IN_METERS = 100
_DB = None
def get_db():
global _DB
if _DB is None:
_DB = SessionLocal()
return _DB
#app.lambda_function(name='test-function')
def create_user(event, context):
return {'hello': 'world'}
#app.route('/health')
def health():
return {'status': 'ok'}
#app.authorizer()
def token_authorizer(auth_request: AuthRequest) -> AuthResponse:
token = auth_request.token
try:
decoded_token = auth.verify_id_token(token)
decoded = decoded_token
allowed_routes = [
'/auth',
'/me',
]
if 'permission_verified' in decoded and decoded['permission_verified'] is True:
allowed_routes.append('/me/location')
allowed_routes.append('/nearby')
allowed_routes.append('/me/profile-image')
print('routes', allowed_routes)
return AuthResponse(routes=allowed_routes, principal_id=decoded['sub'], context=decoded)
except Exception as e:
print('error', e)
return AuthResponse(routes=[], principal_id='non-user')
#app.route('/auth', methods=['GET'], authorizer=token_authorizer)
def authorize():
u = user_from_context(app.current_request.context)
user = crud.get_user(get_db(), u['uid'])
if user is None:
user = crud.create_user(get_db(), schemas.UserCreate(
uid=u['uid'],
phone=u['phone_number'],
permission_verified=True # TODO: find verification method
))
token = auth.create_custom_token(user.uid, {
"permission_verified": user.permission_verified,
"uid": user.uid,
"phone": user.phone,
"name": user.name,
"linkedin": user.linkedin,
"instagram": user.instagram,
})
return {
'user': user.__json__(),
'token': token.decode()
}
#app.route('/me', methods=["PUT"], authorizer=token_authorizer)
def update_me():
r = app.current_request
u = full_user_from_context(r.context)
data = r.json_body
u = crud.update_user(get_db(), schemas.UserUpdate(
uid=u.uid,
name=data.get('name'),
phone=data.get('phone'),
instagram=data.get('instagram'),
linkedin=data.get('linkedin'),
))
if u is None: # todo: code
return {
"error": "could not update"
}
return {
"user": u.__json__()
}
#app.route('/me/profile-image', methods=["PUT"], content_types=['application/octet-stream'],
authorizer=token_authorizer)
def update_me():
r = app.current_request
u = full_user_from_context(r.context)
data = r.raw_body
file_name = u.uid
tmp_file_name = '/tmp/' + file_name + '.jpg'
with open(tmp_file_name, 'wb') as tmp_file:
tmp_file.write(data)
key = 'profile-images/' + file_name
try:
s3_client.upload_file(tmp_file_name, BUCKET, key, ExtraArgs={'ACL': 'public-read'})
except Exception as e:
app.log.error(e)
return {
"error": str(e)
}
url = f'https://{BUCKET}.s3.amazonaws.com/{key}'
u = crud.update_user(get_db(), schemas.UserUpdate(
uid=u.uid,
profile_image_url=url
))
return {
"url": url
}
#app.route('/me/location', methods=["PUT"], authorizer=token_authorizer)
def update_me_location():
r = app.current_request
u = full_user_from_context(r.context)
data = r.json_body
lat = Decimal(str(data.get('latitude')))
lng = Decimal(str(data.get('longitude')))
loc = crud.update_user_location(get_db(), schemas.UserLocationUpdate(
uid=u.uid,
latitude=lat,
longitude=lng,
timestamp=datetime.now(),
geo=f'POINT({lng} {lat})'
))
if loc is None:
loc = crud.create_user_location(get_db(), schemas.UserLocationCreate(
uid=u.uid,
latitude=lat,
longitude=lng
))
loc = schemas.UserLocationGet(
uid=u.uid,
user=schemas.UserGet(
uid=u.uid,
name=u.name,
linkedin=u.linkedin,
instagram=u.instagram,
profile_image_url=u.profile_image_url
),
latitude=loc.latitude,
longitude=loc.longitude,
timestamp=loc.timestamp.isoformat()
)
return {
'loc': loc.json()
}
#app.route('/nearby', methods=["GET"], authorizer=token_authorizer)
def nearby():
r = app.current_request
u = full_user_from_context(r.context)
user_location = crud.get_user_location(get_db(), u.uid)
if user_location is None:
return {
"error": "no user location"
} # todo: better errro
nearby_users = crud.get_nearby_users(get_db(), u.uid, schemas.UserLocationGet(
uid=user_location.user_id,
latitude=user_location.latitude,
longitude=user_location.longitude,
user=u,
timestamp=user_location.timestamp.isoformat()
), DISTANCE_IN_METERS)
return {
"nearby_distance_in_meters": DISTANCE_IN_METERS,
"nearby_users": list(map(lambda x: schemas.UserLocationGet(
uid=x.user_id,
latitude=x.latitude,
longitude=x.longitude,
timestamp=x.timestamp.isoformat(),
user=schemas.UserGet(
uid=x.user.uid,
name=x.user.name,
instagram=x.user.instagram,
linkedin=x.user.linkedin,
profile_image_url=x.user.profile_image_url
)
).dict(), nearby_users))
}
This is the response when I invoke the test-function from the AWS console:
This is what I get when I do chalice logs:
Traceback (most recent call last):[ERROR] Runtime.ImportModuleError: Unable to import module 'app': No module named 'crud'
Traceback (most recent call last):[ERROR] Runtime.ImportModuleError: Unable to import module 'app': No module named 'crud'
2021-11-14 19:29:04.197000 88eb68 2021-11-14T19:29:04.197Z c143dcd4-e212-41f1-a786-7d86e4b58e59 Task timed out after 60.06 seconds
This is my requirements.txt:
chalice~=1.26.2
firebase-admin
boto3~=1.18.53
botocore
sqlalchemy
pydantic
# psycopg2
GeoAlchemy2
psycopg2-binary
I need to use psycopg2 so maybe that's the problem.
Every http request results in a 504 time out.
In local mode everything works fine.
Thanks in advance.
your chalicelib package folder's __init__.py (it must be written like this) has an extra underscore at the end of it. So python import system doesn't recognize such folder as a package, hence the error.
I am trying to make a website that allows a user to create their own "to-watch" list and also can randomly select a title from the created list, showing the movie's plot, genre, and IMDb rating using an API. I've encountered a "NoneType' object is not subscriptable" error message when trying to run this function and am not sure how to overcome it. Here are the relevant parts of my code:
application.py
import os
from cs50 import SQL
from flask import Flask, flash, jsonify, redirect, render_template, request, session
from flask_session import Session
from tempfile import mkdtemp
from werkzeug.exceptions import default_exceptions, HTTPException, InternalServerError
from werkzeug.security import check_password_hash, generate_password_hash
from helpers import apology, login_required, imdb
app = Flask(__name__)
app.config["TEMPLATES_AUTO_RELOAD"] = True
#app.after_request
def after_request(response):
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
app.config["SESSION_FILE_DIR"] = mkdtemp()
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
db = SQL("sqlite:///project.db")
#app.route("/select", methods=["GET", "POST"])
#login_required
def select():
if request.method == "POST":
"""Randomly pick a movie to watch"""
therearemovies = db.execute("SELECT uniqueid FROM movies WHERE id=:id", id=session["user_id"])
if therearemovies:
chosen = db.execute("SELECT * FROM movies WHERE id=:id ORDER BY RANDOM() LIMIT 1", id=session["user_id"])
for uniqueindex in chosen:
suggestion = uniqueindex["title"]
**info = imdb(suggestion)
plot = info["plot"]
genre = info["genre"]
rating = info["rating"]**
return render_template("select.html", suggestion=suggestion, plot=plot, genre=genre, rating=rating)
else:
return apology("You don't have any movies in your list")
else:
return render_template("/")
helper.py:
import os
import requests
import urllib.parse
def imdb(title):
try:
response=requests.get(f"http://www.omdbapi.com/?t={urllib.parse.quote_plus(title)}&apikey=12345678")
response.raise_for_status()
except requests.RequestException:
return None
try:
data = response.json()
return
{
"plot": data["plot"],
"genre": data["genre"],
"rating": data["imdbRating"]
}
except (KeyError, TypeError, ValueError):
return None
Error Message:
File "/home/ubuntu/finalproject/helpers.py", line 32, in decorated_function
return f(*args, **kwargs)
File "/home/ubuntu/finalproject/application.py", line 126, in select
plot = info["plot"]
TypeError: 'NoneType' object is not subscriptable
Hello Stackoveflow members
I am making a Google Plus user authentication using Oauth and at the same time I need to fetch user profile, pics and drive information as well. The best way to do this is to use Oauth. So I am using flask_googlelogin.
I am trying to use the example.py of this library but What I found that the API works well and my Application pages comes up with information and Cancel and Accept button. But when I push accept button, I get the flask error
TypeError: 'instancemethod' object has no attribute 'getitem'
Now please have a look at the example.py code and flask_googlelogin.py code
here
import json
from flask import Flask, url_for, redirect, session
from flask_login import (UserMixin, login_required, login_user, logout_user,
current_user)
from flask_googlelogin import GoogleLogin
users = {}
app = Flask(__name__)
app.config.update(
SECRET_KEY='<secret_key>',
GOOGLE_LOGIN_CLIENT_ID='<client_id>',
GOOGLE_LOGIN_CLIENT_SECRET='<client_secret>',
GOOGLE_LOGIN_REDIRECT_URI='<redirection_url>')
googlelogin = GoogleLogin(app)
class User(UserMixin):
def __init__(self, userinfo):
self.id = userinfo['id']
self.name = userinfo['name']
self.picture = userinfo.get('picture')
#googlelogin.user_loader
def get_user(userid):
return users.get(userid)
#app.route('/')
def index():
return """
<p><a href="%s">Login</p>
<p><a href="%s">Login with extra params</p>
<p><a href="%s">Login with extra scope</p>
""" % (
googlelogin.login_url(approval_prompt='force'),
googlelogin.login_url(approval_prompt='force',
params=dict(extra='large-fries')),
googlelogin.login_url(
approval_prompt='force',
scopes=['https://www.googleapis.com/auth/drive'],
access_type='offline',
),
)
#app.route('/profile')
#login_required
def profile():
return """
<p>Hello, %s</p>
<p><img src="%s" width="100" height="100"></p>
<p>Token: %r</p>
<p>Extra: %r</p>
<p>Logout</p>
""" % (current_user.name, current_user.picture, session.get('token'),
session.get('extra'))
#app.route('/oauth2callback')
#googlelogin.oauth2callback
def login(token, userinfo, **params):
user = users[userinfo['id']] = User(userinfo)
login_user(user)
session['token'] = json.dumps(token)
session['extra'] = params.get('extra')
return redirect(params.get('next', url_for('.profile')))
#app.route('/logout')
def logout():
logout_user()
session.clear()
return """
<p>Logged out</p>
<p>Return to /</p>
"""
app.run(debug=True)
and flask_googlelogin.py code here
"""
Flask-GoogleLogin
"""
from base64 import (urlsafe_b64encode as b64encode,
urlsafe_b64decode as b64decode)
from urllib import urlencode
from urlparse import parse_qsl
from functools import wraps
from flask import request, redirect, abort, current_app, url_for
from flask_login import LoginManager, make_secure_token
import requests
GOOGLE_OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth'
GOOGLE_OAUTH2_TOKEN_URL = 'https://accounts.google.com/o/oauth2/token'
GOOGLE_OAUTH2_USERINFO_URL = 'https://www.googleapis.com/oauth2/v1/userinfo'
USERINFO_PROFILE_SCOPE = 'https://www.googleapis.com/auth/userinfo.profile'
class GoogleLogin(object):
"""
Main extension class
"""
def __init__(self, app=None, login_manager=None):
if login_manager:
self.login_manager = login_manager
else:
self.login_manager = LoginManager()
if app:
self._app = app
self.init_app(app)
def init_app(self, app, add_context_processor=True, login_manager=None):
"""
Initialize with app configuration. Existing
`flask_login.LoginManager` instance can be passed.
"""
if login_manager:
self.login_manager = login_manager
else:
self.login_manager = LoginManager()
# Check if login manager has been init
if not hasattr(app, 'login_manager'):
self.login_manager.init_app(
app,
add_context_processor=add_context_processor)
# Clear flashed messages since we redirect to auth immediately
self.login_manager.login_message = None
self.login_manager.needs_refresh_message = None
# Set default unauthorized callback
self.login_manager.unauthorized_handler(self.unauthorized_callback)
#property
def app(self):
return getattr(self, '_app', current_app)
#property
def scopes(self):
return self.app.config.get('GOOGLE_LOGIN_SCOPES', '')
#property
def client_id(self):
return self.app.config['GOOGLE_LOGIN_CLIENT_ID']
#property
def client_secret(self):
return self.app.config['GOOGLE_LOGIN_CLIENT_SECRET']
#property
def redirect_uri(self):
return self.app.config.get('GOOGLE_LOGIN_REDIRECT_URI')
#property
def redirect_scheme(self):
return self.app.config.get('GOOGLE_LOGIN_REDIRECT_SCHEME', 'http')
def sign_params(self, params):
return b64encode(urlencode(dict(sig=make_secure_token(**params),
**params)))
def parse_state(self, state):
return dict(parse_qsl(b64decode(str(state))))
def login_url(self, params=None, **kwargs):
"""
Return login url with params encoded in state
Available Google auth server params:
response_type: code, token
prompt: none, select_account, consent
approval_prompt: force, auto
access_type: online, offline
scopes: string (separated with commas) or list
redirect_uri: string
login_hint: string
"""
kwargs.setdefault('response_type', 'code')
kwargs.setdefault('access_type', 'online')
if 'prompt' not in kwargs:
kwargs.setdefault('approval_prompt', 'auto')
scopes = kwargs.pop('scopes', self.scopes.split(','))
if USERINFO_PROFILE_SCOPE not in scopes:
scopes.append(USERINFO_PROFILE_SCOPE)
redirect_uri = kwargs.pop('redirect_uri', self.redirect_uri)
state = self.sign_params(params or {})
return GOOGLE_OAUTH2_AUTH_URL + '?' + urlencode(
dict(client_id=self.client_id,
scope=' '.join(scopes),
redirect_uri=redirect_uri,
state=state,
**kwargs))
def unauthorized_callback(self):
"""
Redirect to login url with next param set as request.url
"""
return redirect(self.login_url(params=dict(next=request.url)))
def exchange_code(self, code, redirect_uri):
"""
Exchanges code for token/s
"""
token = requests.post(GOOGLE_OAUTH2_TOKEN_URL, data=dict(
code=code,
redirect_uri=redirect_uri,
grant_type='authorization_code',
client_id=self.client_id,
client_secret=self.client_secret,
)).json
if not token: # or token.get('error'):
abort(400)
return token
def get_userinfo(self, access_token):
userinfo = requests.get(GOOGLE_OAUTH2_USERINFO_URL, params=dict(
access_token=access_token,
)).json
if not userinfo: # or userinfo.get('error'):
abort(400)
return userinfo
def get_access_token(self, refresh_token):
"""
Use a refresh token to obtain a new access token
"""
token = requests.post(GOOGLE_OAUTH2_TOKEN_URL, data=dict(
refresh_token=refresh_token,
grant_type='refresh_token',
client_id=self.client_id,
client_secret=self.client_secret,
)).json
if not token: # or token.get('error'):
return
return token
def oauth2callback(self, view_func):
"""
Decorator for OAuth2 callback. Calls `GoogleLogin.login` then
passes results to `view_func`.
"""
#wraps(view_func)
def decorated(*args, **kwargs):
params = {}
# Check sig
if 'state' in request.args:
params.update(**self.parse_state(request.args.get('state')))
if params.pop('sig', None) != make_secure_token(**params):
return self.login_manager.unauthorized()
code = request.args.get('code')
# Web server flow
if code:
token = self.exchange_code(
code,
url_for(
request.endpoint,
_external=True,
_scheme=self.redirect_scheme,
),
)
#received = get_access_token(token['access_token'])
userinfo = self.get_userinfo(token['access_token'])
params.update(token=token, userinfo=userinfo)
# Browser flow
else:
if params:
params.update(dict(request.args.items()))
else:
return '''
<script>
window.onload = function() {
location.href = '?' + window.location.hash.substr(1);
};
</script>
'''
return view_func(**params)
return decorated
def user_loader(self, func):
"""
Shortcut for `login_manager`'s `flask_login.LoginManager.user_loader`
"""
self.login_manager.user_loader(func)
Please Note down there may be some disturbed code in def oauth2callback and the condition if code the line is
userinfo = self.get_userinfo(token['access_token'])
Here token['access_token'] produces the error names "TypeError: 'instancemethod' object has no attribute 'getitem'"
Please let me know how can I fix it
Looks like a bug or api change.
In exchange_code
token = requests.post(GOOGLE_OAUTH2_TOKEN_URL, data=dict(
code=code,
redirect_uri=redirect_uri,
grant_type='authorization_code',
client_id=self.client_id,
client_secret=self.client_secret,
)).json
token is now the json function. In newer versions of flask_googlelogin this is json().