I keep getting AttributeError: 'str' object has no attribute 'request' with google APIs in flask

I keep getting AttributeError: 'str' object has no attribute 'request' with google APIs in flask

我正在尝试通过 Flask 与 android-management-api 进行交互。 每次我 运行 遇到一个我不理解的错误,因为我对编码很陌生

调用device_list = androidmanagement.enterprises().devices().list(parent=enterprise_name, pageSize=200).execute() 时出现错误

我只是不明白为什么我会收到这个错误。

如果有人能解释这是怎么发生的,我会很高兴。

非常感谢

我的代码在app.py

import json
import os
import sqlite3
from datetime import datetime

# flask imports
from flask import Flask, redirect, url_for, render_template, request
from flask_login import (
    LoginManager,
    current_user,
    login_user,
    logout_user,
)

# Oauth imports
from oauthlib.oauth2 import WebApplicationClient
import requests

# database imports
from db import init_db_command
from user import User

# google imports
from googleapiclient.discovery import build

# '''End of imports'''

# '''Start of settings'''


# Configuration load environment settings
GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID", None)
GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET", None)
GOOGLE_DISCOVERY_URL = (
    "https://accounts.google.com/.well-known/openid-configuration"

)

# ''' Start of local variables'''
cloud_project_id = 'hidden'
enterprise_name = 'hidden'
# ''' End of Local variables'''


# ''' Start build service object '''
API_KEY = os.environ.get(GOOGLE_API_KEY)
API_SERVICE_NAME = 'androidmanagement'
API_VERSION = 'v1'

androidmanagement = build(API_SERVICE_NAME, API_VERSION, API_KEY)

# ''' End of service object '''


# Flask app setup
app = Flask(__name__)
app.secret_key = os.environ.get("SECRET_KEY") or os.urandom(24)

# User session management setup
# https://flask-login.readthedocs.io/en/latest
login_manager = LoginManager()
login_manager.init_app(app)

# Naive database setup
try:
    init_db_command()
except sqlite3.OperationalError:
    # Assume it's already been created
    pass

# OAuth 2 client setup
client = WebApplicationClient(GOOGLE_CLIENT_ID)


def get_google_provider_cfg():
    return requests.get(GOOGLE_DISCOVERY_URL).json()


# Flask-Login helper to retrieve a user from our db
@login_manager.user_loader
def load_user(user_id):
    return User.get(user_id)


# '''End of settings'''

# '''All view routing'''

# index
@app.route('/')
def index():
    if current_user.is_authenticated:
        return redirect(url_for('home'))

    else:
        return redirect(url_for('loginuser'))


# """Starts the login flow."""
@app.route("/login")
def login():
    # Find out what URL to hit for Google login
    google_provider_cfg = get_google_provider_cfg()
    authorization_endpoint = google_provider_cfg["authorization_endpoint"]

    # Use library to construct the request for Google login and provide
    # scopes that let you retrieve user's profile from Google
    request_uri = client.prepare_request_uri(
        authorization_endpoint,
        redirect_uri=request.base_url + "/callback",
        scope=["openid", "email", "profile"],
    )
    return redirect(request_uri)


# auth flow callback.
@app.route("/login/callback")
def callback():
    # Get authorization code Google sent back to you
    code = request.args.get("code")

    # Find out what URL to hit to get tokens that allow you to ask for
    # things on behalf of a user
    google_provider_cfg = get_google_provider_cfg()
    token_endpoint = google_provider_cfg["token_endpoint"]

    # Prepare and send request to get tokens! Yay tokens!
    token_url, headers, body = client.prepare_token_request(
        token_endpoint,
        authorization_response=request.url,
        redirect_url=request.base_url,
        code=code,
    )
    token_response = requests.post(
        token_url,
        headers=headers,
        data=body,
        auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET),
    )

    # Parse the tokens!
    client.parse_request_body_response(json.dumps(token_response.json()))

    # Now that we have tokens (yay) let's find and hit URL
    # from Google that gives you user's profile information,
    # including their Google Profile Image and Email
    userinfo_endpoint = google_provider_cfg["userinfo_endpoint"]
    uri, headers, body = client.add_token(userinfo_endpoint)
    userinfo_response = requests.get(uri, headers=headers, data=body)

    # We want to make sure their email is verified.
    # The user authenticated with Google, authorized our
    # app, and now we've verified their email through Google!
    if userinfo_response.json().get("email_verified"):
        unique_id = userinfo_response.json()["sub"]
        users_email = userinfo_response.json()["email"]
        picture = userinfo_response.json()["picture"]
        users_name = userinfo_response.json()["given_name"]
    else:
        return "User email not available or not verified by Google.", 400

    # Create a user in our db with the information provided
    # by Google
    user = User(
        id_=unique_id, name=users_name, email=users_email, profile_pic=picture
    )

    # Doesn't exist? Add to database
    if not User.get(unique_id):
        User.create(unique_id, users_name, users_email, picture)

    # Begin user session by logging the user in
    login_user(user)

    # Send user back to homepage
    return redirect(url_for("home"))


@app.route('/logout')
def logout():
    if current_user.is_authenticated:
        logout_user()
        return render_template(
            'logoutuser.html',
            title='log out',
            year=datetime.now().year,
        )
    else:
        return redirect(url_for("index"))


# Renders the login page.
@app.route('/loginuser')
def loginuser():
    if current_user.is_authenticated:
        return redirect(url_for('home'))
    else:
        return render_template('loginuser.html')


# base web routing start here
# Renders the home page.
# @app.route('/')
@app.route('/home')
def home():
    if current_user.is_authenticated:
        return render_template(
            'index.html',
            title='Home Page',
            year=datetime.now().year,
        )
    else:
        return redirect(url_for('loginuser'))


# Renders the devices page.
@app.route('/devices')
def devices():
    if current_user.is_authenticated:
        device_list = androidmanagement.enterprises().devices().list(parent=enterprise_name, pageSize=200).execute()

        return render_template(
            'devices.html',
            title='Devices',
            year=datetime.now().year,
            device_list=device_list.items()

        )
    else:
        return redirect(url_for('loginuser'))


# Renders the policies page.
@app.route('/policies')
def policies():
    if current_user.is_authenticated:
        return render_template(
            'policies.html',
            title='Policies',
            year=datetime.now().year,
        )
    else:
        return redirect(url_for('loginuser'))


# Renders the enterprise page.
@app.route('/enterprises')
def enterprises():
    if current_user.is_authenticated:
        return render_template(
            'enterprises.html',
            title='Enterprises',
            year=datetime.now().year,
        )
    else:
        return redirect(url_for('loginuser'))


# Renders the contact page.
@app.route('/contact')
def contact():
    if current_user.is_authenticated:
        return render_template(
            'contact.html',
            title='Contact',
            year=datetime.now().year,
            message='ICS-Vertex'
        )
    else:
        return redirect(url_for('loginuser'))


# Renders the about page.
@app.route('/about')
def about():
    if current_user.is_authenticated:
        return render_template(
            'about.html',
            title='About',
            year=datetime.now().year,
            message='Your application description page.'
        )
    else:
        return redirect(url_for('loginuser'))


# '''end of view routing'''

# Starts application with all above code
if __name__ == '__main__':
    # app.run()
    app.debug = True
    app.run(ssl_context="adhoc", debug=True)

我的堆栈跟踪说明如下:

File "C:[=11=]0 Projects\Applications\PY\flaskProjects\MDM\venv\Lib\site-packages\flask\app.py", line 2069, in __call__
    def __call__(self, environ: dict, start_response: t.Callable) -> t.Any:
        """The WSGI server calls the Flask application object as the
        WSGI application. This calls :meth:`wsgi_app`, which can be
        wrapped to apply middleware.
        """
        return self.wsgi_app(environ, start_response)
 
    def _request_blueprints(self) -> t.Iterable[str]:
        if _request_ctx_stack.top.request.blueprint is None:
            return []
        else:
File "C:[=11=]0 Projects\Applications\PY\flaskProjects\MDM\venv\Lib\site-packages\flask\app.py", line 2054, in wsgi_app
            try:Open an interactive python shell in this frame
                ctx.push()
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except:  # noqa: B001
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
File "C:[=11=]0 Projects\Applications\PY\flaskProjects\MDM\venv\Lib\site-packages\flask\app.py", line 2051, in wsgi_app
        ctx = self.request_context(environ)
        error: t.Optional[BaseException] = None
        try:
            try:
                ctx.push()
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except:  # noqa: B001
                error = sys.exc_info()[1]
File "C:[=11=]0 Projects\Applications\PY\flaskProjects\MDM\venv\Lib\site-packages\flask\app.py", line 1501, in full_dispatch_request
            request_started.send(self)
            rv = self.preprocess_request()
            if rv is None:
                rv = self.dispatch_request()
        except Exception as e:
            rv = self.handle_user_exception(e)
        return self.finalize_request(rv)
 
    def finalize_request(
        self,
        rv: t.Union[ResponseReturnValue, HTTPException],
File "C:[=11=]0 Projects\Applications\PY\flaskProjects\MDM\venv\Lib\site-packages\flask\app.py", line 1499, in full_dispatch_request
        self.try_trigger_before_first_request_functions()
        try:
            request_started.send(self)
            rv = self.preprocess_request()
            if rv is None:
                rv = self.dispatch_request()
        except Exception as e:
            rv = self.handle_user_exception(e)
        return self.finalize_request(rv)
 
    def finalize_request(
File "C:[=11=]0 Projects\Applications\PY\flaskProjects\MDM\venv\Lib\site-packages\flask\app.py", line 1485, in dispatch_request
            getattr(rule, "provide_automatic_options", False)
            and req.method == "OPTIONS"
        ):
            return self.make_default_options_response()
        # otherwise dispatch to the handler for that endpoint
        return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
 
    def full_dispatch_request(self) -> Response:
        """Dispatches the request and on top of that performs request"""
        pre and postprocessing as well as HTTP exception catching and
        error handling.
File "C:[=11=]0 Projects\Applications\PY\flaskProjects\MDM\app.py", line 226, in devices
 
# Renders the devices page.
@app.route('/devices')
def devices():
    if current_user.is_authenticated:
        device_list = androidmanagement.enterprises().devices().list(parent=enterprise_name, pageSize=200).execute()
 
        return render_template(
            'devices.html',
            title='Devices',
            year=datetime.now().year,
File "C:[=11=]0 Projects\Applications\PY\flaskProjects\MDM\venv\Lib\site-packages\googleapiclient\_helpers.py", line 134, in positional_wrapper
                )
                if positional_parameters_enforcement == POSITIONAL_EXCEPTION:
                    raise TypeError(message)
                elif positional_parameters_enforcement == POSITIONAL_WARNING:
                    logger.warning(message)
            return wrapped(*args, **kwargs)
 
        return positional_wrapper
 
    if isinstance(max_positional_args, six.integer_types):
        return positional_decorator
File "C:[=11=]0 Projects\Applications\PY\flaskProjects\MDM\venv\Lib\site-packages\googleapiclient\http.py", line 920, in execute
            )
            self.body = parsed.query
            self.headers["content-length"] = str(len(self.body))
 
        # Handle retries for server-side errors.
        resp, content = _retry_request(
            http,
            num_retries,
            "request",
            self._sleep,
            self._rand,
File "C:[=11=]0 Projects\Applications\PY\flaskProjects\MDM\venv\Lib\site-packages\googleapiclient\http.py", line 191, in _retry_request
            )
            sleep(sleep_time)
 
        try:
            exception = None
            resp, content = http.request(uri, method, *args, **kwargs)
        # Retry on SSL errors and socket timeout errors.
        except _ssl_SSLError as ssl_error:
            exception = ssl_error
        except socket.timeout as socket_timeout:
            # Needs to be before socket.error as it's a subclass of OSError
AttributeError: 'str' object has no attribute 'request'

所以我发现问题是如何出现的:

有 3 个模块在执行相同的任务 google API 客户端 烧瓶要求 请求

这导致代码冲突。

将在我的 API 通话正常后更新