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...
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:
And at the beginning when I read the command line with my inputs, I simply used parser_known_flags() as hpaulj suggested!
Thanks, shishy
I think there have been other questions about
argparse
and thegoogle 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 editsys.argv
to remove the extra strings. Usingparse_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.