Overwriting Google Drive API v3 Argparse in Python

2019-01-26 19:33发布

I'm trying to use the Google Drive API (v3) with Python to obtain and upload files to my Google Drive account.

I used this guide to setup my authentication: https://developers.google.com/drive/v3/web/quickstart/python

But for my program, I would like to take commandline input for username, filename, and output_filename. I modified the google doc code and did the following:

  from __future__ import print_function
    import httplib2
    import os
    from sys import argv 
    from apiclient import discovery
    from oauth2client import client
    from oauth2client import tools
    from oauth2client.file import Storage
    from apiclient.http import MediaIoBaseDownload, MediaIoBaseUpload 
    import io  

    try:
        import argparse
        parser = argparse.ArgumentParser(description="I want your name, the file ID, and the folder you want to dump output to")
        parser.add_argument('-u', '--username', help='User Name', required=True)
        parser.add_argument('-f', '--filename', help='File Name', required=True)
        parser.add_argument('-d', '--dirname', help = 'Directory Name', required=True)
        flags = parser.parse_args()

    except ImportError:
        flags = None

    SCOPES = 'https://www.googleapis.com/auth/drive'
    CLIENT_SECRET_FILE = 'client_secret.json'
    APPLICATION_NAME = 'Drive API Python Quickstart'
    ...#rest of the code is from the Google Drive Documentation (see above)

def get_credentials():
    """Gets valid user credentials from storage.

    If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.

    Returns:
        Credentials, the obtained credential.
    """

    home_dir = os.path.expanduser('~')

    credential_dir = os.path.join(home_dir, '.credentials')
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)
    credential_path = os.path.join(credential_dir,
                                   'drive-python-quickstart.json')

    store = Storage(credential_path)
    credentials = store.get()
    #Credentials returns NONE
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if args:
          credentials = tools.run_flow(flow, store)
        else: # Needed only for compatibility with Python 2.6
            credentials = tools.run(flow, store)
        print('Storing credentials to ' + credential_path)

    print("check")
    return credentials

The problem is that in the get_credentials method, there is a line that says:

if flags:
  credentials = tools.run_flow(flow, store, flags)
else: # Needed only for compatibility with Python 2.6
  credentials = tools.run(flow, store)

The run_flow method though uses a different argparser that google wrote (see: http://oauth2client.readthedocs.io/en/latest/source/oauth2client.tools.html)

So whenever I run this script with my own inputs with username, filename, etc. I keep getting an error that says "Unrecognized Arguments".

How do I make my argparser over-write the one in run_flow?

EDIT:

Someone suggested using parse_known_args().

Well, I modified my code to parse by saying args, flags = parser.parse_known_args() because that way, any misc. inputs would go into flags.

The idea is that if I run the script and give it my 3 args, it should pull them into "args".

But the problem with this again is that later on when I call the run_flow method in get_credentials, it throws an error saying:

Usage: name.py [--auth_host_name AUTH_HOST_NAME] [--noauth_local_webserver] [--auth_host_port [AUTH_HOST_PORT ...]]] [--logging_level {DEBUG, INFO, WARNING, ERROR, CRITICAL}] Unrecognized arguments: -u shishy -f fname -d random_name

I think it's still passing my command line input to the get_info method and the parser there has no idea what to do with it...

2条回答
仙女界的扛把子
2楼-- · 2019-01-26 19:40

Nevermind, I figured it out. hpaulj had it right.

In the get_credentials() method, right before it called run_flow(), I simply had to add a line saying:

flags=tools.argparser.parse_args(args=[])
credentials=tools.run_flow(flow, store, flags)

And at the beginning when I read the command line with my inputs, I simply used parser_known_flags() as hpaulj suggested!

Thanks, shishy

查看更多
Explosion°爆炸
3楼-- · 2019-01-26 19:46

I think there have been other questions about argparse and the google api, but I haven't used the latter.

Parsers are independent and can't be over written. But they all (as a default anyways) use sys.argv[1:]. So if your code runs before the other one, you can edit sys.argv to remove the extra strings. Using parse_known_args is a handy way of separating your arguments from ones the other parser(s) should use.

Often the parser is invoked from a if __name__ block. That way imported modules don't do parsing, only ones used as scripts. But I don't if the google api makes this distinction.

查看更多
登录 后发表回答