[NbConvertApp] Converting notebook /home/aavsonet/scripts/reports/pipeline_report.ipynb to HTML
[NbConvertApp] Executing notebook with kernel: python3
[NbConvertApp] ERROR | Error while converting '/home/aavsonet/scripts/reports/pipeline_report.ipynb'
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/nbconvert/nbconvertapp.py", line 410, in export_single_notebook
output, resources = self.exporter.from_filename(notebook_filename, resources=resources)
File "/usr/lib/python3/dist-packages/nbconvert/exporters/exporter.py", line 179, in from_filename
return self.from_file(f, resources=resources, **kw)
File "/usr/lib/python3/dist-packages/nbconvert/exporters/exporter.py", line 197, in from_file
return self.from_notebook_node(nbformat.read(file_stream, as_version=4), resources=resources, **kw)
File "/usr/lib/python3/dist-packages/nbconvert/exporters/html.py", line 95, in from_notebook_node
return super(HTMLExporter, self).from_notebook_node(nb, resources, **kw)
File "/usr/lib/python3/dist-packages/nbconvert/exporters/templateexporter.py", line 307, in from_notebook_node
nb_copy, resources = super(TemplateExporter, self).from_notebook_node(nb, resources, **kw)
File "/usr/lib/python3/dist-packages/nbconvert/exporters/exporter.py", line 139, in from_notebook_node
nb_copy, resources = self._preprocess(nb_copy, resources)
File "/usr/lib/python3/dist-packages/nbconvert/exporters/exporter.py", line 316, in _preprocess
nbc, resc = preprocessor(nbc, resc)
File "/usr/lib/python3/dist-packages/nbconvert/preprocessors/base.py", line 47, in __call__
return self.preprocess(nb, resources)
File "/usr/lib/python3/dist-packages/nbconvert/preprocessors/execute.py", line 405, in preprocess
nb, resources = super(ExecutePreprocessor, self).preprocess(nb, resources)
File "/usr/lib/python3/dist-packages/nbconvert/preprocessors/base.py", line 69, in preprocess
nb.cells[index], resources = self.preprocess_cell(cell, resources, index)
File "/usr/lib/python3/dist-packages/nbconvert/preprocessors/execute.py", line 448, in preprocess_cell
raise CellExecutionError.from_cell_and_msg(cell, out)
nbconvert.preprocessors.execute.CellExecutionError: An error occurred while executing the following cell:
------------------
#!/usr/bin/python3
'''
Created on Feb 5, 2020
@author: CLKotnik
This notebook prototypes textual and graphical reporting on the images
and photometry produced during a pipeline run.
It is assumed the image_info database has been updated with the extended metrics
on each image for the date/telescope.
KCLA Changes for pypline phase 3
Obtain config file location, observatory(=telescope) and datenite from environment
'''
import os
import glob
import requests
import sys
from simplejson.errors import JSONDecodeError
import json
import fnmatch
import astropy.io.fits as pyfits
import string
import datetime
import MySQLdb
import time
import configargparse
import numpy as np
import math
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
#%matplotlib notebook
import logging
from tabulate import tabulate
from IPython.display import display, HTML
from IPython.display import Image
import fileinput
import datetime
import pytz
import re
from shutil import move, copymode
from astroplan import Observer
from astropy.coordinates import EarthLocation
import astropy.units as u
from datetime import datetime
from astropy.time import Time
from astropy.coordinates import get_sun, get_moon, AltAz
def setup_logging(verbose,filename):
"""
Setup the logging subsystem configuration
"""
if (verbose):
lev = logging.DEBUG
else:
lev = logging.INFO
mode = 'a'
form = '%(asctime)s - %(levelname)s - %(module)s - %(funcName)s - %(lineno)d - %(message)s'
# Following to log to stdout
#logging.basicConfig(level=lev,stream=sys.stdout, filemode = mode,format=form)
logging.basicConfig(level=lev,filename = filename, filemode = mode,format=form)
#def create_link(filename):
# # create a link to JPG image
# return 'http://occam.aavso.org/' + \
# telescope + '/' + \
# telescope + '_' + yymmdd + '_images/' + \
# filename[:-4] + 'jpg'
def create_imglink(imgurl):
# create a link to JPG image
link = ''.format(imgurl)
#''
return link
def create_tnlink(imgurl):
# create a link to JPG image
tn=''.format(imgurl)
tnlink = '{}'.format(imgurl,tn)
return tnlink
def create_dual_imglink(imgurl,cenurl):
figlink = """""".format(imgurl,cenurl)
return figlink
def create_imgurl(filename,center):
# create a URL to JPG image
path = 'http://occam.aavso.org/' + \
telescope + '/' + \
telescope + '_' + yymmdd + '_images/' + \
filename[:-5]
if center:
path = path + 'c.jpg'
else:
path = path + '.jpg'
return path
def create_review(comments,reviewer):
# create a URL to JPG image
if (comments == ""):
if (reviewer == ""):
return "not reviewed"
else:
return "reviewed"
else:
return comments
def get_directory(telescope,yymmdd,img_base_dir,doYyyy=False):
"""
Construct the directory name that corresponds to the telescope and date.
Check that the directory exists.
If doYyyy is true, look within a yyyy directory for the yymmdd directory
Input:
telescope: name of telescope
yymmdd: date
img_base_dir : base path name of images
doYyyy : boolean, true to look for directory /yyyy/yymmdd
Return the directory name
or None if it does not exist
"""
yyyy = '20' + yymmdd[:2]
if telescope.lower() == 'sro50':
telescope = 'sro'
else:
telescope = telescope.lower()
if (len(telescope) > 0) and (len(yymmdd) > 0):
if not doYyyy:
imgdir = img_base_dir + '/' + telescope + '/' + yymmdd
if os.path.exists(imgdir):
return imgdir
else:
# Sometimes the yymmdd directory is within a yyyy directory
return get_directory(telescope,yymmdd,img_base_dir,True)
else:
imgdir = img_base_dir + '/' + telescope + '/' + yyyy + '/' + yymmdd
if os.path.exists(imgdir):
return imgdir
else:
return None
else:
return None
def isActive(x,bins,temps,filters):
if x.imagetyp == 'flat':
if int(x.binning) in bins and x['filter'] in filters:
return 'Y'
else:
return ' '
else:
if int(x.binning) in bins and int(x.set_temp) in temps:
return 'Y'
else:
return ' '
def get_telescope_parms(parms):
"""
Issue the web service call to the telescopes service and return the list
of telescops returned or None if nothing is returned or there is an
exception doing the call.
"""
url=r'https://aavso.org/apps/aavsonet/telescopes2/'
try:
r1= requests.get(url= url, params= parms)
except requests.exceptions.RequestException as e:
logging.exception("Exception issuing the telescopes web service call")
logging.critical("URL {}; params {}".format(url,parms))
return None
if r1 is None:
logging.error("Nothing returned - URL {}; params {}".format(url,parms))
return None
try:
d1= r1.json()
logging.info("URL {}; params {} returned {} telescopes".format(url,parms,len(d1)))
except JSONDecodeError as e:
logging.exception("JSONDecodeError URL {}; params {}; resp {}".format(self.url,parms,r1))
return None
return d1
def get_telescope_datenite(yyyymmdd,observatory,args):
"""
Return the telescop info for the most recent date
that has changed date on or before the specified datenite.
Return None if not found. Name is case
insensitive. The telescop information is a dictionary.
"""
parms={'name':observatory}
telescopes = get_telescope_parms(parms)
# list of telescopes is order most recent date first
errmsg = "Failed to find telescopes for {} datenite {}".format(observatory,yyyymmdd)
if telescopes is None:
logging.error(errmsg)
haltwarn(args,True,errmsg)
return None
yyyy_mm_dd = yyyymmdd[:4] + '-' + yyyymmdd[4:6] + '-' + yyyymmdd[6:8]
for telescop in telescopes:
if telescop['changed'] < yyyy_mm_dd:
logging.debug("Obs {}, datenite {} found {}".format(
observatory,yyyy_mm_dd,telescop))
return telescop
logging.error(errmsg)
haltwarn(args,True,errmsg)
return None
def new_exp(lin_limit,exp,maxadu):
if maxadu is None or math.isnan(maxadu) or maxadu == 'None' or maxadu == '' or maxadu <= lin_limit:
return math.nan
target_adu = 0.7 * lin_limit
new_exp = (target_adu / maxadu) * exp
return new_exp
def format_jd(x):
try:
JD = "{0:.5f}".format(float(x[3:]))
except ValueError:
JD = ''
return JD
def get_pgm_parms():
"""
Get the programs config file and command line arguments.
Return a configargparse arguments object
"""
parser = configargparse.ArgumentParser(description='AAVSOnet pipeline daily report')
parser.add_argument('-c', '--my-config', required=True, is_config_file=True, help='config file path', env_var="MY_CONFIG")
parser.add_argument('-o', '--observatory', required=True, help='observatory name', env_var ='OBSERVATORY')
parser.add_argument('-d', '--yyyymmdd', required=True, help='datenite process date yyyymmdd', env_var = 'YYYYMMDD')
parser.add_argument('-D', '--procdir', required=True, help='base directory for processed images')
parser.add_argument('-n','--df_export',help='Filename to (im)export dataframe to excluding path')
parser.add_argument('-l','--logfile', required=True, help='Filename to log messages to')
parser.add_argument('-v', '--verbose', help='Turn on verbose output', action='store_true',default=False, env_var='VERBOSE')
parser.add_argument('-m', '--homedir', required=True, help='home directory')
parser.add_argument('-t', '--thumbdir', required=True, help='base directory for thumbnails')
parser.add_argument('-E', '--haltfile', required=True, help='filename to signal HALT completion')
parser.add_argument('-W', '--warnfile', required=True, help='filename to signal WARNING completion')
args,unknown = parser.parse_known_args()
logname = os.path.join(args.homedir,args.observatory)
logname = os.path.join(logname,args.logfile)
setup_logging(args.verbose,filename=logname)
for arg in vars(args):
attr = getattr(args, arg)
if isinstance(attr, str) and arg.startswith("db_"):
t = attr.split(";")
if len(t) == 4:
attr = "{};{};;{}".format(t[0],t[1],t[3])
logging.debug (" {} {}".format(arg, attr))
return args
def get_scheduler_rpt(args):
"""
Form this night's pathname for scheduler report and return it if it exists. If not
return None
"""
pathname = os.path.join(args.thumbdir,args.observatory)
filename = "{}_{}_schedrpt.txt".format(args.observatory,args.yyyymmdd[2:])
pathaname = os.path.join(pathname,filename)
if os.path.exists(pathname):
return os.path.join(args.observatory,filename)
else:
logging.warning("No scheduler report found - {}".format(pathname))
return None
def haltwarn(args,isHalt,desc):
# Write a HALT or WARN message
if isHalt:
filepath = os.path.join(args.homedir,args.observatory)
filepath = os.path.join(filepath,args.haltfile)
else:
filepath = os.path.join(args.homedir,args.observatory)
filepath = os.path.join(filepath,args.warnfile)
with open(filepath, 'a') as hfile:
hfile.write(desc+'\n')
if isHalt:
logging.error("HALTing {}".format(desc))
else:
logging.warning("WARNing {}".format(desc))
return
#######################################################################################
#### MAIN PROCESSING STARTS HERE ######################################################
#######################################################################################
# Get program parameters and setup logging
args = get_pgm_parms()
telescope = args.observatory
yymmdd = args.yyyymmdd[2:]
# Get telescope parameters from JSon web service
telescop = get_telescope_datenite('20' + yymmdd,telescope,args)
# Get pathname for scheduler report if it exists
schedrpt = get_scheduler_rpt(args)
if schedrpt is not None:
display(HTML("Scheduler Report ".format(schedrpt)))
# Get UTC offset and stick in telescop
d= datetime.strptime(yymmdd, '%y%m%d')
tz = pytz.timezone(telescop['timezone']) # eg. 'US/Aleutian'
telescop['utc_offset']= tz.localize(d).utcoffset().total_seconds()/3600
# sunrise and sunset times
location = EarthLocation.from_geodetic(telescop['longitude']*u.deg, telescop['latitude']*u.deg, telescop['elevation']*u.m)
observatory = Observer(location=location, name= telescop['name_long'], timezone= telescop['timezone'])
#now = Time(datetime.strptime(yymmdd, '%y%m%d'), location= location)
#telescop['sunset']= observatory.sun_set_time(now, which="next")
#telescop['sunrise']= observatory.sun_rise_time(now+ 1, which="next")
tr= observatory.datetime_to_astropy_time(datetime.strptime(yymmdd+ ' 13', '%y%m%d %H')) # 1300 of datenite (local) as utc
telescop['sunset']= observatory.astropy_time_to_datetime(observatory.sun_set_time(tr, which="next"))
telescop['sunrise']= observatory.astropy_time_to_datetime(observatory.sun_rise_time(tr, which="next"))
#Use the following when running from the command line
#args,unknown = parser.parse_known_args()
logging.info("Begin execution, telescope {}, date {}".format(args.observatory,args.yyyymmdd))
hdf_file = get_directory(telescope,yymmdd,args.procdir)
if hdf_file is None:
logging.error("Cannot locate image directory {} {} {}".format(args.procdir,telescope,yymmdd))
got_images = False
else:
hdf_file += "/" + args.df_export
if not os.path.exists(hdf_file):
logging.error("Cannot locate HDF file {} {} {} {}".format(args.procdir,telescope,yymmdd,args.df_export))
got_images = False
else:
got_images = True
if got_images:
df = pd.read_hdf(hdf_file,key='science')
logging.info("Loaded {} science images from {}".format(len(df),hdf_file))
cdf = pd.read_hdf(hdf_file,key='calibration')
logging.info("Loaded {} calibration images from {}".format(len(cdf),hdf_file))
# Adjust for new database based calibration files
if 'rel_filepath' in cdf.columns:
cdf.rename(columns = {'rel_filepath':'filename'}, inplace = True)
bins = [int(b) for b in df.xbinning.unique()]
temps = [int(t) for t in df.set_temp.unique()]
filters = df['filter'].unique()
cdf['Active'] = cdf.apply(lambda x: isActive(x,bins,temps,filters),axis=1)
cdf=cdf.sort_values(["Active", "imagetyp","Age(d)"], ascending = (False, True, True))
# Make booleans 1=true, 0-false
df['has_wcs'] = df.apply(lambda x: 1 if x['has_wcs'] == 'True' else 0,axis=1)
df['image_available'] = df['image_available'].fillna(0)
# Review columns blank is null
if 'comments' not in df.columns:
df['comments'] = ""
df['reviewer'] = ""
else:
df['comments'] = df['comments'].fillna("")
df['reviewer'] = df['reviewer'].fillna("")
df['xbinning'] = df['xbinning'].fillna (0)
df['ybinning'] = df['ybinning'].fillna (0)
df['img_type'] = df['img_type'].fillna ("")
# Convert strings to floats
for col in ['set_temp','ccd_temp','obj_ra_deg', 'obj_dec_deg', 'center_ra_deg', 'center_dec_deg',
'fov_radius_amin', 'center2obj', 'hr_ang','airmass', 'amb_temp', 'bjd','gain', 'focallen', 'fwhm',
'exptime', 'ccd_tpwr',
]:
df[col]=df.apply(lambda x: float(x[col]) if ((x[col] != 'None') and (x[col] != '') and (x[col] is not None)) else None,axis=1)
# Calculate how much warmer CCD was than the set point
df['deltaT']= abs(df['ccd_temp']-df['set_temp'])
# CLKotnik 10/30/23 Change required by upgrade to Pandas 2
#df['DateTime'] = pd.to_datetime(df['date_obs'],format='%Y-%m-%dT%H:%M:%S')
df['DateTime'] = pd.to_datetime(df['date_obs'],format='ISO8601')
# URL column for image
df['imgurl'] = df.apply(lambda x: create_imgurl(x['filename'],False),axis=1)
# URL column for center cutout image (if available)
img_first = df['filename'].iloc[0]
cenpath = '/raid/aavsonet_TNimages/' + telescope + '/' + \
telescope + '_' + yymmdd + '_images/' + \
img_first[:-5] + 'c.jpg'
got_center = os.path.exists(cenpath)
df['tnurl'] = df.apply(lambda x: create_imgurl(x['filename'],got_center),axis=1)
# Create review column
# URL column for image
df['review'] = df.apply(lambda x: create_review(x['comments'],x['reviewer']),axis=1)
# Inline image link
df['tnimage'] = df.apply(lambda x: create_tnlink(x['tnurl']),axis=1)
#Inline image
df['image'] = df.apply(lambda x: create_imglink(x['imgurl']),axis=1)
# Side by side image
df['sxsimage'] = df.apply(lambda x: create_dual_imglink(x['imgurl'],x['tnurl']),axis=1)
# Combined X and Y binning
df['binning'] = df.apply(lambda x: str(int(x.xbinning)) + 'x' + str(int(x.ybinning)),axis=1)
# Format JD as string
df['jd'] = df['jd'].fillna(0)
df['JD'] = df.apply(lambda x: format_jd(x.jd) ,axis=1)
# Create a display version of the project column with spaces so it will line wrap
df['project_'] = df.apply(lambda x: x['project'].replace("_","_ "),axis=1)
# Rename some columns
# Fixup so even if no astrometry at all we still run
for c in ["obj_mag","obj_mag_err","obj_maxadu"]:
if c not in df.columns:
df[c] = None
df = df.rename(columns={"obj_mag": "instmag", "obj_mag_err": "err","obj_maxadu":"maxadu"})
#******************** New exposure detect and computation ****************************
# Is saturated, calculate recommended new exposure
df['OE'] = df.apply(lambda x: "!OE!" if x['maxadu'] is not None and x['maxadu'] != 'None' and x['maxadu'] != '' and x['maxadu'] > telescop['linearitylimit'] else '',axis=1)
df['new_exp'] = df.apply(lambda x: new_exp(telescop['linearitylimit'],x['exptime'],x['maxadu']),axis=1)
df['UE'] = df.apply(lambda x: "!UE!" if x['err'] is not None and x['err'] != 'None' and x['err'] != '' and x['err'] > 0.05 else '',axis=1) # snr < 20
------------------
[0;31m---------------------------------------------------------------------------[0m
[0;31mJSONDecodeError[0m Traceback (most recent call last)
[0;32m[0m in [0;36mget_telescope_parms[0;34m(parms)[0m
[1;32m 187[0m [0;32mtry[0m[0;34m:[0m[0;34m[0m[0;34m[0m[0m
[0;32m--> 188[0;31m [0md1[0m[0;34m=[0m [0mr1[0m[0;34m.[0m[0mjson[0m[0;34m([0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[0m[1;32m 189[0m [0mlogging[0m[0;34m.[0m[0minfo[0m[0;34m([0m[0;34m"URL {}; params {} returned {} telescopes"[0m[0;34m.[0m[0mformat[0m[0;34m([0m[0murl[0m[0;34m,[0m[0mparms[0m[0;34m,[0m[0mlen[0m[0;34m([0m[0md1[0m[0;34m)[0m[0;34m)[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[0;32m/usr/lib/python3/dist-packages/requests/models.py[0m in [0;36mjson[0;34m(self, **kwargs)[0m
[1;32m 896[0m [0;32mpass[0m[0;34m[0m[0;34m[0m[0m
[0;32m--> 897[0;31m [0;32mreturn[0m [0mcomplexjson[0m[0;34m.[0m[0mloads[0m[0;34m([0m[0mself[0m[0;34m.[0m[0mtext[0m[0;34m,[0m [0;34m**[0m[0mkwargs[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[0m[1;32m 898[0m [0;34m[0m[0m
[0;32m/usr/lib/python3/dist-packages/simplejson/__init__.py[0m in [0;36mloads[0;34m(s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, use_decimal, **kw)[0m
[1;32m 517[0m and not use_decimal and not kw):
[0;32m--> 518[0;31m [0;32mreturn[0m [0m_default_decoder[0m[0;34m.[0m[0mdecode[0m[0;34m([0m[0ms[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[0m[1;32m 519[0m [0;32mif[0m [0mcls[0m [0;32mis[0m [0;32mNone[0m[0;34m:[0m[0;34m[0m[0;34m[0m[0m
[0;32m/usr/lib/python3/dist-packages/simplejson/decoder.py[0m in [0;36mdecode[0;34m(self, s, _w, _PY3)[0m
[1;32m 369[0m [0ms[0m [0;34m=[0m [0mstr[0m[0;34m([0m[0ms[0m[0;34m,[0m [0mself[0m[0;34m.[0m[0mencoding[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[0;32m--> 370[0;31m [0mobj[0m[0;34m,[0m [0mend[0m [0;34m=[0m [0mself[0m[0;34m.[0m[0mraw_decode[0m[0;34m([0m[0ms[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[0m[1;32m 371[0m [0mend[0m [0;34m=[0m [0m_w[0m[0;34m([0m[0ms[0m[0;34m,[0m [0mend[0m[0;34m)[0m[0;34m.[0m[0mend[0m[0;34m([0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[0;32m/usr/lib/python3/dist-packages/simplejson/decoder.py[0m in [0;36mraw_decode[0;34m(self, s, idx, _w, _PY3)[0m
[1;32m 399[0m [0midx[0m [0;34m+=[0m [0;36m3[0m[0;34m[0m[0;34m[0m[0m
[0;32m--> 400[0;31m [0;32mreturn[0m [0mself[0m[0;34m.[0m[0mscan_once[0m[0;34m([0m[0ms[0m[0;34m,[0m [0midx[0m[0;34m=[0m[0m_w[0m[0;34m([0m[0ms[0m[0;34m,[0m [0midx[0m[0;34m)[0m[0;34m.[0m[0mend[0m[0;34m([0m[0;34m)[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[0m
[0;31mJSONDecodeError[0m: Expecting value: line 1 column 1 (char 0)
During handling of the above exception, another exception occurred:
[0;31mNameError[0m Traceback (most recent call last)
[0;32m[0m in [0;36m[0;34m[0m
[1;32m 342[0m [0;34m[0m[0m
[1;32m 343[0m [0;31m# Get telescope parameters from JSon web service[0m[0;34m[0m[0;34m[0m[0;34m[0m[0m
[0;32m--> 344[0;31m [0mtelescop[0m [0;34m=[0m [0mget_telescope_datenite[0m[0;34m([0m[0;34m'20'[0m [0;34m+[0m [0myymmdd[0m[0;34m,[0m[0mtelescope[0m[0;34m,[0m[0margs[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[0m[1;32m 345[0m [0;34m[0m[0m
[1;32m 346[0m [0;31m# Get pathname for scheduler report if it exists[0m[0;34m[0m[0;34m[0m[0;34m[0m[0m
[0;32m[0m in [0;36mget_telescope_datenite[0;34m(yyyymmdd, observatory, args)[0m
[1;32m 202[0m """
[1;32m 203[0m [0mparms[0m[0;34m=[0m[0;34m{[0m[0;34m'name'[0m[0;34m:[0m[0mobservatory[0m[0;34m}[0m[0;34m[0m[0;34m[0m[0m
[0;32m--> 204[0;31m [0mtelescopes[0m [0;34m=[0m [0mget_telescope_parms[0m[0;34m([0m[0mparms[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[0m[1;32m 205[0m [0;31m# list of telescopes is order most recent date first[0m[0;34m[0m[0;34m[0m[0;34m[0m[0m
[1;32m 206[0m [0;34m[0m[0m
[0;32m[0m in [0;36mget_telescope_parms[0;34m(parms)[0m
[1;32m 189[0m [0mlogging[0m[0;34m.[0m[0minfo[0m[0;34m([0m[0;34m"URL {}; params {} returned {} telescopes"[0m[0;34m.[0m[0mformat[0m[0;34m([0m[0murl[0m[0;34m,[0m[0mparms[0m[0;34m,[0m[0mlen[0m[0;34m([0m[0md1[0m[0;34m)[0m[0;34m)[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[1;32m 190[0m [0;32mexcept[0m [0mJSONDecodeError[0m [0;32mas[0m [0me[0m[0;34m:[0m[0;34m[0m[0;34m[0m[0m
[0;32m--> 191[0;31m [0mlogging[0m[0;34m.[0m[0mexception[0m[0;34m([0m[0;34m"JSONDecodeError URL {}; params {}; resp {}"[0m[0;34m.[0m[0mformat[0m[0;34m([0m[0mself[0m[0;34m.[0m[0murl[0m[0;34m,[0m[0mparms[0m[0;34m,[0m[0mr1[0m[0;34m)[0m[0;34m)[0m[0;34m[0m[0;34m[0m[0m
[0m[1;32m 192[0m [0;34m[0m[0m
[1;32m 193[0m [0;32mreturn[0m [0;32mNone[0m[0;34m[0m[0;34m[0m[0m
[0;31mNameError[0m: name 'self' is not defined
NameError: name 'self' is not defined