I'm trying to run a python scrtipt to stop services, but I'm getting the following error message : "No JSON object could be decoded" . My server uses https protocol thru port 6443. I'm using the file "StartStopServices.py" available at following path: https://github.com/WestonSF/ArcGISAdminToolkit/commit/a183df77441956e515105b2b166b11eb4e525873
#-------------------------------------------------------------
# Name: Start or Stop Services
# Purpose: Starts or stops GIS services. Can start/stop all GIS services for an ArcGIS server site or just the ones
# that are specified.
# Author: Shaun Weston (shaun_weston@eagle.co.nz)
# Date Created: 07/10/2014
# Last Updated: 06/11/2014
# Copyright: (c) Eagle Technology
# ArcGIS Version: 10.1+
# Python Version: 2.7
#--------------------------------
# Import modules
import os
import sys
import logging
import smtplib
import arcpy
import httplib
import json
import urllib
import urllib2
import urlparse
# Enable data to be overwritten
arcpy.env.overwriteOutput = True
# Set global variables
enableLogging = "false" # Use logger.info("Example..."), logger.warning("Example..."), logger.error("Example...")
logFile = "" # os.path.join(os.path.dirname(__file__), "Example.log")
sendErrorEmail = "false"
emailTo = ""
emailUser = ""
emailPassword = ""
emailSubject = ""
emailMessage = ""
output = None
# Start of main function
def mainFunction(agsServerSite,username,password,startStop,allServices,userServices): # Get parameters from ArcGIS Desktop tool by seperating by comma e.g. (var1 is 1st parameter,var2 is 2nd parameter,var3 is 3rd parameter)
try:
# Logging
if (enableLogging == "true"):
# Setup logging
logger, logMessage = setLogging(logFile)
# Log start of process
logger.info("Process started.")
# --------------------------------------- Start of code --------------------------------------- #
# Get the server site details
protocol, serverName, serverPort, context = splitSiteURL(agsServerSite)
# If any of the variables are blank
if (serverName == None or serverPort == None or protocol == None or context == None):
return -1
# Add on slash to context if necessary
if not context.endswith('/'):
context += '/'
# Add on admin to context if necessary
if not context.endswith('admin/'):
context += 'admin/'
# Get token
token = getToken(username, password, serverName, serverPort)
# If token received
if (token != -1):
services = []
folder = ''
# If task is for all services
if (allServices == "true"):
# Query the root level for services
url = "http://{}:{}/arcgis/admin/services{}?f=pjson&token={}".format(serverName, serverPort, folder, token)
# Make the request
try:
serviceList = json.loads(urllib2.urlopen(url).read())
except urllib2.URLError, error:
arcpy.AddError(error)
# Logging
if (enableLogging == "true"):
logger.error(error)
sys.exit()
# Add the services at the root level
for single in serviceList["services"]:
services.append(single['serviceName'] + '.' + single['type'])
# Build up list of folders and remove the System and Utilities folder
folderList = serviceList["folders"]
folderList.remove("Utilities")
folderList.remove("System")
# If there is any folders
if len(folderList) > 0:
# For each folder in the list
for folder in folderList:
# Query the folder for map services
URL = "http://{}:{}/arcgis/admin/services/{}?f=pjson&token={}".format(serverName, serverPort, folder, token)
fList = json.loads(urllib2.urlopen(URL).read())
for single in fList["services"]:
# Add the services found to the list
services.append(folder + "/" + single['serviceName'] + '.' + single['type'])
# Just for the user defined list of services
else:
services = userServices.split(",")
# For each of the services
for service in services:
# Start or stop the map service
op_service_url = "http://{}:{}/arcgis/admin/services/{}/{}?token={}&f=json".format(serverName, serverPort, service, startStop, token)
status = urllib2.urlopen(op_service_url, ' ').read()
# If successfully started/stopped
if 'success' in status:
arcpy.AddMessage(startStop + " successfully performed on " + service)
# Logging
if (enableLogging == "true"):
logger.error(startStop + " successfully performed on " + service)
# If there is an error
else:
arcpy.AddError("Failed to perform operation. Returned message from the server:")
arcpy.AddError(status)
# Logging
if (enableLogging == "true"):
logger.error("Failed to perform operation. Returned message from the server:")
logger.error(status)
# --------------------------------------- End of code --------------------------------------- #
# If called from gp tool return the arcpy parameter
if __name__ == '__main__':
# Return the output if there is any
if output:
arcpy.SetParameterAsText(1, output)
# Otherwise return the result
else:
# Return the output if there is any
if output:
return output
# Logging
if (enableLogging == "true"):
# Log end of process
logger.info("Process ended.")
# Remove file handler and close log file
logging.FileHandler.close(logMessage)
logger.removeHandler(logMessage)
pass
# If arcpy error
except arcpy.ExecuteError:
# Build and show the error message
errorMessage = arcpy.GetMessages(2)
arcpy.AddError(errorMessage)
# Logging
if (enableLogging == "true"):
# Log error
logger.error(errorMessage)
# Remove file handler and close log file
logging.FileHandler.close(logMessage)
logger.removeHandler(logMessage)
if (sendErrorEmail == "true"):
# Send email
sendEmail(errorMessage)
# If python error
except Exception as e:
errorMessage = ""
# Build and show the error message
for i in range(len(e.args)):
if (i == 0):
errorMessage = unicode(e.args[i]).encode('utf-8')
else:
errorMessage = errorMessage + " " + unicode(e.args[i]).encode('utf-8')
arcpy.AddError(errorMessage)
# Logging
if (enableLogging == "true"):
# Log error
logger.error(errorMessage)
# Remove file handler and close log file
logging.FileHandler.close(logMessage)
logger.removeHandler(logMessage)
if (sendErrorEmail == "true"):
# Send email
sendEmail(errorMessage)
# End of main function
# Start of get token function
def getToken(username, password, serverName, serverPort):
query_dict = {'username': username,
'password': password,
'expiration': "60",
'client': 'requestip'}
query_string = urllib.urlencode(query_dict)
url = "http://{}:{}/arcgis/admin/generateToken?f=json".format(serverName, serverPort)
try:
token = json.loads(urllib2.urlopen(url, query_string).read())
if "token" not in token or token == None:
arcpy.AddError("Failed to get token, return message from server:")
arcpy.AddError(token['messages'])
# Logging
if (enableLogging == "true"):
logger.error("Failed to get token, return message from server:")
logger.error(token['messages'])
sys.exit()
else:
# Return the token to the function which called for it
return token['token']
except urllib2.URLError, error:
arcpy.AddError("Could not connect to machine {} on port {}".format(serverName, serverPort))
arcpy.AddError(error)
# Logging
if (enableLogging == "true"):
logger.error("Could not connect to machine {} on port {}".format(serverName, serverPort))
logger.error(error)
sys.exit()
# End of get token function
# Start of HTTP POST request to the server function
def postToServer(serverName, serverPort, protocol, url, params):
# If on standard port
if (serverPort == -1 and protocol == 'http'):
serverPort = 80
# If on secure port
if (serverPort == -1 and protocol == 'https'):
serverPort = 6443
if (protocol == 'http'):
httpConn = httplib.HTTPConnection(serverName, int(serverPort))
if (protocol == 'https'):
httpConn = httplib.HTTPSConnection(serverName, int(serverPort))
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain",'referer':'backuputility','referrer':'backuputility'}
# URL encode the resource URL
url = urllib.quote(url.encode('utf-8'))
# Build the connection to add the roles to the server
httpConn.request("POST", url, params, headers)
response = httpConn.getresponse()
data = response.read()
httpConn.close()
# Return response
return (response, data)
# End of HTTP POST request to the server function
# Start of split URL function
def splitSiteURL(siteURL):
try:
serverName = ''
serverPort = -1
protocol = 'http'
context = '/arcgis'
# Split up the URL provided
urllist = urlparse.urlsplit(siteURL)
# Put the URL list into a dictionary
d = urllist._asdict()
# Get the server name and port
serverNameAndPort = d['netloc'].split(":")
# User did not enter the port number, so we return -1
if (len(serverNameAndPort) == 1):
serverName = serverNameAndPort[0]
else:
if (len(serverNameAndPort) == 2):
serverName = serverNameAndPort[0]
serverPort = serverNameAndPort[1]
# Get protocol
if (d['scheme'] is not ''):
protocol = d['scheme']
# Get path
if (d['path'] is not '/' and d['path'] is not ''):
context = d['path']
# Return variables
return protocol, serverName, serverPort, context
except:
arcpy.AddError("The ArcGIS Server site URL should be in the format http(s)://<host>:<port>/arcgis")
# Logging
if (enableLogging == "true"):
logger.error("The ArcGIS Server site URL should be in the format http(s)://<host>:<port>/arcgis")
sys.exit()
return None, None, None, None
# End of split URL function
# Start of status check JSON object function
def assertJsonSuccess(data):
obj = json.loads(data)
if 'status' in obj and obj['status'] == "error":
if ('messages' in obj):
errMsgs = obj['messages']
for errMsg in errMsgs:
arcpy.AddError(errMsg)
# Logging
if (enableLogging == "true"):
logger.error(errMsg)
sys.exit()
return False
else:
return True
# End of status check JSON object function
# Start of set logging function
def setLogging(logFile):
# Create a logger
logger = logging.getLogger(os.path.basename(__file__))
logger.setLevel(logging.DEBUG)
# Setup log message handler
logMessage = logging.FileHandler(logFile)
# Setup the log formatting
logFormat = logging.Formatter("%(asctime)s: %(levelname)s - %(message)s", "%d/%m/%Y - %H:%M:%S")
# Add formatter to log message handler
logMessage.setFormatter(logFormat)
# Add log message handler to logger
logger.addHandler(logMessage)
return logger, logMessage
# End of set logging function
# Start of send email function
def sendEmail(message):
# Send an email
arcpy.AddMessage("Sending email...")
# Server and port information
smtpServer = smtplib.SMTP("smtp.gmail.com",587)
smtpServer.ehlo()
smtpServer.starttls()
smtpServer.ehlo
# Login with sender email address and password
smtpServer.login(emailUser, emailPassword)
# Email content
header = 'To:' + emailTo + '\n' + 'From: ' + emailUser + '\n' + 'Subject:' + emailSubject + '\n'
body = header + '\n' + emailMessage + '\n' + '\n' + message
# Send the email and close the connection
smtpServer.sendmail(emailUser, emailTo, body)
# End of send email function
# This test allows the script to be used from the operating
# system command prompt (stand-alone), in a Python IDE,
# as a geoprocessing script tool, or as a module imported in
# another script
if __name__ == '__main__':
# Arguments are optional - If running from ArcGIS Desktop tool, parameters will be loaded into *argv
argv = tuple(arcpy.GetParameterAsText(i)
for i in range(arcpy.GetArgumentCount()))
mainFunction(*argv)
It looks like the script gets information about the input Server on line 54:
protocol, serverName, serverPort, context = splitSiteURL(agsServerSite)
But then it's hardcoding the http protocol when retrieving the token on line 215:
url = "http://{}:{}/arcgis/admin/generateToken?f=json".format(serverName, serverPort)
. If the server site entered is using https and 6443, then that is going to be a problem. The script should really take the protocol as well instead of hardcoding http.
Hi Jonathan,
From the line 242 to 294 there is addition to the script to allow secured servers. Do you have any suggestion to overcome this hardcoding issue?
I will try to change this line.
Thank you!
DK
It doesn't seem like you're using that function to submit any requests. I'd try to replace any hardcoded protocols, (seems like it's http throughout), with the protocol derived from the splitSiteURL function:
Ex.
url = "{}://{}:{}/arcgis/admin/generateToken?f=json".format(protocol,serverName, serverPort)
Hi Jonathan,
After applying your suggested modifications, it's works. Thank you very much, find below the code that is working for me:
#-------------------------------------------------------------
# Name: Start or Stop Services
# Purpose: Starts or stops GIS services. Can start/stop all GIS services for an ArcGIS server site or just the ones
# that are specified.
# Author: Shaun Weston (shaun_weston@eagle.co.nz)
# Date Created: 07/10/2014
# Last Updated: 06/11/2014
# Copyright: (c) Eagle Technology
# ArcGIS Version: 10.1+
# Python Version: 2.7
#--------------------------------
# Import modules
import os
import sys
import logging
import smtplib
import arcpy
import httplib
import json
import urllib
import urllib2
import urlparse
import socket
# Enable data to be overwritten
arcpy.env.overwriteOutput = True
# Set global variables
enableLogging = "false" # Use logger.info("Example..."), logger.warning("Example..."), logger.error("Example...")
logFile = "" # os.path.join(os.path.dirname(__file__), "Example.log")
sendErrorEmail = "false"
emailTo = ""
emailUser = ""
emailPassword = ""
emailSubject = ""
emailMessage = ""
output = None
protocol = "https"
# Start of main function
def mainFunction(agsServerSite,username,password,startStop,allServices,userServices): # Get parameters from ArcGIS Desktop tool by seperating by comma e.g. (var1 is 1st parameter,var2 is 2nd parameter,var3 is 3rd parameter)
try:
# Logging
if (enableLogging == "true"):
# Setup logging
logger, logMessage = setLogging(logFile)
# Log start of process
logger.info("Process started.")
# --------------------------------------- Start of code --------------------------------------- #
# Get the server site details
protocol, serverName, serverPort, context = splitSiteURL(agsServerSite)
# If any of the variables are blank
if (serverName == None or serverPort == None or protocol == None or context == None):
return -1
# Add on slash to context if necessary
if not context.endswith('/'):
context += '/'
# Add on admin to context if necessary
if not context.endswith('admin/'):
context += 'admin/'
# Get token
token = getToken(username, password, serverName, serverPort)
# If token received
if (token != -1):
services = []
folder = ''
# If task is for all services
if (allServices == "true"):
# Query the root level for services
url = "{}://{}:{}/arcgis/admin/services{}?f=pjson&token={}".format(protocol,serverName, serverPort, folder, token)
# Make the request
try:
serviceList = json.loads(urllib2.urlopen(url).read())
except urllib2.URLError, error:
arcpy.AddError(error)
# Logging
if (enableLogging == "true"):
logger.error(error)
sys.exit()
# Add the services at the root level
for single in serviceList["services"]:
services.append(single['serviceName'] + '.' + single['type'])
# Build up list of folders and remove the System and Utilities folder
folderList = serviceList["folders"]
folderList.remove("Utilities")
folderList.remove("System")
# If there is any folders
if len(folderList) > 0:
# For each folder in the list
for folder in folderList:
# Query the folder for map services
URL = "{}://{}:{}/arcgis/admin/services/{}?f=pjson&token={}".format(protocol,serverName, serverPort, folder, token)
fList = json.loads(urllib2.urlopen(URL).read())
for single in fList["services"]:
# Add the services found to the list
services.append(folder + "/" + single['serviceName'] + '.' + single['type'])
# Just for the user defined list of services
else:
services = userServices.split(",")
# For each of the services
for service in services:
# Start or stop the map service
op_service_url = "{}://{}:{}/arcgis/admin/services/{}/{}?token={}&f=json".format(protocol,serverName, serverPort, service, startStop, token)
status = urllib2.urlopen(op_service_url, ' ').read()
# If successfully started/stopped
if 'success' in status:
arcpy.AddMessage(startStop + " successfully performed on " + service)
# Logging
if (enableLogging == "true"):
logger.error(startStop + " successfully performed on " + service)
# If there is an error
else:
arcpy.AddError("Failed to perform operation. Returned message from the server:")
arcpy.AddError(status)
# Logging
if (enableLogging == "true"):
logger.error("Failed to perform operation. Returned message from the server:")
logger.error(status)
# --------------------------------------- End of code --------------------------------------- #
# If called from gp tool return the arcpy parameter
if __name__ == '__main__':
# Return the output if there is any
if output:
arcpy.SetParameterAsText(1, output)
# Otherwise return the result
else:
# Return the output if there is any
if output:
return output
# Logging
if (enableLogging == "true"):
# Log end of process
logger.info("Process ended.")
# Remove file handler and close log file
logging.FileHandler.close(logMessage)
logger.removeHandler(logMessage)
pass
# If arcpy error
except arcpy.ExecuteError:
# Build and show the error message
errorMessage = arcpy.GetMessages(2)
arcpy.AddError(errorMessage)
# Logging
if (enableLogging == "true"):
# Log error
logger.error(errorMessage)
# Remove file handler and close log file
logging.FileHandler.close(logMessage)
logger.removeHandler(logMessage)
if (sendErrorEmail == "true"):
# Send email
sendEmail(errorMessage)
# If python error
except Exception as e:
errorMessage = ""
# Build and show the error message
for i in range(len(e.args)):
if (i == 0):
errorMessage = unicode(e.args[i]).encode('utf-8')
else:
errorMessage = errorMessage + " " + unicode(e.args[i]).encode('utf-8')
arcpy.AddError(errorMessage)
# Logging
if (enableLogging == "true"):
# Log error
logger.error(errorMessage)
# Remove file handler and close log file
logging.FileHandler.close(logMessage)
logger.removeHandler(logMessage)
if (sendErrorEmail == "true"):
# Send email
sendEmail(errorMessage)
# End of main function
# Start of get token function
def getToken(username, password, serverName, serverPort):
query_dict = {'username': username,
'password': password,
'expiration': "60",
'client': 'requestip'}
query_string = urllib.urlencode(query_dict)
url = "{}://{}:{}/arcgis/admin/generateToken?f=json".format(protocol,serverName, serverPort)
try:
token = json.loads(urllib2.urlopen(url, query_string).read())
if "token" not in token or token == None:
arcpy.AddError("Failed to get token, return message from server:")
arcpy.AddError(token['messages'])
# Logging
if (enableLogging == "true"):
logger.error("Failed to get token, return message from server:")
logger.error(token['messages'])
sys.exit()
else:
# Return the token to the function which called for it
return token['token']
except urllib2.URLError, error:
arcpy.AddError("Could not connect to machine {} on port {}".format(protocol,serverName, serverPort))
arcpy.AddError(error)
# Logging
if (enableLogging == "true"):
logger.error("Could not connect to machine {} on port {}".format(protocol,serverName, serverPort))
logger.error(error)
sys.exit()
# End of get token function
# Start of HTTP POST request to the server function
def postToServer(serverName, serverPort, protocol, url, params):
# If on standard port
if (serverPort == -1 and protocol == 'http'):
serverPort = 80
# If on secure port
if (serverPort == -1 and protocol == 'https'):
serverPort = 6443
if (protocol == 'http'):
httpConn = httplib.HTTPConnection(serverName, int(serverPort))
if (protocol == 'https'):
httpConn = httplib.HTTPSConnection(serverName, int(serverPort))
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain",'referer':'backuputility','referrer':'backuputility'}
# URL encode the resource URL
url = urllib.quote(url.encode('utf-8'))
# Build the connection to add the roles to the server
httpConn.request("POST", url, params, headers)
response = httpConn.getresponse()
data = response.read()
httpConn.close()
# Return response
return (response, data)
# End of HTTP POST request to the server function
# Start of split URL function
def splitSiteURL(siteURL):
try:
serverName = ''
serverPort = -1
protocol = 'http'
context = '/arcgis'
# Split up the URL provided
urllist = urlparse.urlsplit(siteURL)
# Put the URL list into a dictionary
d = urllist._asdict()
# Get the server name and port
serverNameAndPort = d['netloc'].split(":")
# User did not enter the port number, so we return -1
if (len(serverNameAndPort) == 1):
serverName = serverNameAndPort[0]
else:
if (len(serverNameAndPort) == 2):
serverName = serverNameAndPort[0]
serverPort = serverNameAndPort[1]
# Get protocol
if (d['scheme'] is not ''):
protocol = d['scheme']
# Get path
if (d['path'] is not '/' and d['path'] is not ''):
context = d['path']
# Return variables
return protocol, serverName, serverPort, context
except:
arcpy.AddError("The ArcGIS Server site URL should be in the format http(s)://<host>:<port>/arcgis")
# Logging
if (enableLogging == "true"):
logger.error("The ArcGIS Server site URL should be in the format http(s)://<host>:<port>/arcgis")
sys.exit()
return None, None, None, None
# End of split URL function
# Start of status check JSON object function
def assertJsonSuccess(data):
obj = json.loads(data)
if 'status' in obj and obj['status'] == "error":
if ('messages' in obj):
errMsgs = obj['messages']
for errMsg in errMsgs:
arcpy.AddError(errMsg)
# Logging
if (enableLogging == "true"):
logger.error(errMsg)
sys.exit()
return False
else:
return True
# End of status check JSON object function
# Start of set logging function
def setLogging(logFile):
# Create a logger
logger = logging.getLogger(os.path.basename(__file__))
logger.setLevel(logging.DEBUG)
# Setup log message handler
logMessage = logging.FileHandler(logFile)
# Setup the log formatting
logFormat = logging.Formatter("%(asctime)s: %(levelname)s - %(message)s", "%d/%m/%Y - %H:%M:%S")
# Add formatter to log message handler
logMessage.setFormatter(logFormat)
# Add log message handler to logger
logger.addHandler(logMessage)
return logger, logMessage
# End of set logging function
# Start of send email function
def sendEmail(message):
# Send an email
arcpy.AddMessage("Sending email...")
# Server and port information
smtpServer = smtplib.SMTP("smtp.gmail.com",587)
smtpServer.ehlo()
smtpServer.starttls()
smtpServer.ehlo
# Login with sender email address and password
smtpServer.login(emailUser, emailPassword)
# Email content
header = 'To:' + emailTo + '\n' + 'From: ' + emailUser + '\n' + 'Subject:' + emailSubject + '\n'
body = header + '\n' + emailMessage + '\n' + '\n' + message
# Send the email and close the connection
smtpServer.sendmail(emailUser, emailTo, body)
# End of send email function
# This test allows the script to be used from the operating
# system command prompt (stand-alone), in a Python IDE,
# as a geoprocessing script tool, or as a module imported in
# another script
if __name__ == '__main__':
# Arguments are optional - If running from ArcGIS Desktop tool, parameters will be loaded into *argv
argv = tuple(arcpy.GetParameterAsText(i)
for i in range(arcpy.GetArgumentCount()))
mainFunction(*argv)
Hi all,
I'm running into a similar issue where I have the following script which stops a particular service. When run I get the same error message: "No JSON object could be decoded". Any assistance would be appreciated.
Thanks,
# Required imports
import urllib
import urllib2
import json
import contextlib
## context manager to clean up resources when exiting a 'with' block
def main(): ## Entry point into the script
# Local variables
## Authentication
adminUser = r"xxxxx"
adminPass = r"xxxxxx"
## ArcGIS Server Machine
server = "cc.xx.xxxx.xx.us"
port = "6443"
## Services ("FolderName/ServiceName.ServiceType")
svc = "xxxxx/xxxxxx.MapServer"
try:
# Get ArcGIS Server token
expiration = 60 ## Token timeout in minutes; default is 60 minutes.
token = getToken(adminUser, adminPass, server, port, expiration)
# Perform action on service
action = "stop" ## "start" or "stop"
jsonOuput = serviceStartStop(server, port, svc, action, token)
## Validate JSON object result
if jsonOuput['status'] == "success":
print "{} {} successful".format(action.title(), str(svc))
else:
print "Failed to {} {}".format(action, str(svc))
raise Exception(jsonOuput)
except Exception, err:
print err
# Function to generate a token from ArcGIS Server; returns token.
## http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000000m5000000.htm
def getToken(adminUser, adminPass, server, port, expiration):
# Build URL
url = "https://{}:{}/arcgis/admin/generateToken?f=json".format(server, port)
# Encode the query string
query_dict = {
'username': adminUser,
'password': adminPass,
'expiration': str(expiration),
'client': 'requestip'
}
query_string = urllib.urlencode(query_dict)
try:
# Request the token
with contextlib.closing(urllib2.urlopen(url, query_string)) as jsonResponse:
getTokenResult = json.loads(jsonResponse.read())
## Validate result
if "token" not in getTokenResult or getTokenResult == None:
raise Exception("Failed to get token: {}".format(getTokenResult['messages']))
else:
return getTokenResult['token']
except urllib2.URLError, e:
raise Exception("Could not connect to machine {} on port {}\n{}".format(server, port, e))
# Function to start or stop a service on ArcGIS Server; returns JSON response.
## http://resources.arcgis.com/en/help/arcgis-rest-api/02r3/02r3000001s6000000.htm
def serviceStartStop(server, port, svc, action, token):
# Build URL
url = "https://{}:{}/arcgis/admin/generateToken?f=json".format(server, port)
requestURL = url + "/services/{}/{}".format(svc, action)
# Encode the query string
query_dict = {
"token": token,
"f": "json"
}
query_string = urllib.urlencode(query_dict)
# Send the server request and return the JSON response
with contextlib.closing(urllib.urlopen(requestURL, query_string)) as jsonResponse:
return json.loads(jsonResponse.read())
if __name__ == '__main__':
main()
What line is it failing on? Right before you convert the string to JSON, print the variable that stores the string to make sure it's JSON. This could happen on either line 56 or 82.
It appears that it is failing around line 56 already.
So add print(jsonResponse.read()) after line 55 so you can see what the variable stores, and determine why it's not JSON, (or at least the string representation of JSON).
Jonathan,
Thanks for the feedback. I added this to my script and it outputted a token and expiration but am still getting the error JSON error.