shishy shishy - 1 month ago 24
Python Question

Overwriting Google Drive API v3 Argparse in Python

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...

Answer

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.

Comments