Repository: winter-telescope/mirar (language: python)

Issue:
Test database
Much of the database creation is not tested. Let's change that!


Discussion / hints:

Fix patch:
diff --git a/.coveragerc b/.coveragerc
index 8f7c08f67..e0de619c5 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,6 +1,8 @@
 # .coveragerc to control coverage.py
 [run]
 source = winterdrp
+omit =
+    winterdrp/__main__.py
 
 [report]
 # Regexes for lines to exclude from consideration
@@ -23,4 +25,5 @@ exclude_lines =
 
     # Don't complain if non-runnable code isn't run:
     if 0:
+    if False:
     if __name__ == .__main__.:
diff --git a/.github/workflows/continous_integration.yml b/.github/workflows/continous_integration.yml
index 0387668b3..1ad7b7b7c 100644
--- a/.github/workflows/continous_integration.yml
+++ b/.github/workflows/continous_integration.yml
@@ -60,10 +60,21 @@ jobs:
           python -m pip install --upgrade poetry coveralls
           poetry install
 
+      # Set up database
+      - name: postgres
+        run: |
+          sudo apt install postgresql
+          sudo service postgresql restart
+          sudo -u postgres psql -c "create user runner; grant all privileges on database postgres to runner; ALTER USER runner WITH SUPERUSER;"
+
       # Runs a set of commands using the runners shell
       - name: Test the code
         env:
           OUTPUT_DATA_DIR : /home/runner/
+          PG_ADMIN_USER: runner
+          PG_ADMIN_PWD: ""
+          DB_USER: runner
+          DB_PWD: ""
         run: |
           poetry run coverage run -m unittest discover tests/
 
diff --git a/winterdrp/calculate/combine.py b/winterdrp/calculate/combine.py
deleted file mode 100644
index 7ea176129..000000000
--- a/winterdrp/calculate/combine.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import numpy as np
-
-
-# Median combine with scaled normalization of individual and final frames
-def median_combine_normed(
-        img_array: np.ma.masked_array
-) -> np.ma.masked_array:
-    """
-    Median combine with normalization of individual and final frames
-    Returns the combined image
-    """
-    norm_array = np.ma.zeros(img_array.shape)
-
-    # Store normalized versions of each image
-    for i in range(len(img_array[0, 0, :])):
-        norm_array[:, :, i] = img_array[:, :, i] / np.ma.median(img_array[:, :, i])
-
-        # median combination of normalized images
-    combined_img = np.ma.median(norm_array, axis=2)
-
-    # Normalize the median combination by itself
-    combined_img = combined_img / np.ma.median(combined_img)
-
-    return combined_img
diff --git a/winterdrp/pipelines/summer/blocks.py b/winterdrp/pipelines/summer/blocks.py
index c13b5258e..13f48ae37 100644
--- a/winterdrp/pipelines/summer/blocks.py
+++ b/winterdrp/pipelines/summer/blocks.py
@@ -24,11 +24,29 @@
     summer_reference_image_resampler, summer_reference_sextractor
 from winterdrp.processors.database.database_modifier import ModifyImageDatabaseSeq
 from winterdrp.processors.utils.header_annotate import HeaderEditor
+from winterdrp.downloader.get_test_data import get_test_data_dir
 
 load_raw = [
     ImageLoader(load_image=load_raw_summer_image),
 ]
 
+load_test = [
+    ImageLoader(
+        input_img_dir=get_test_data_dir(),
+        input_sub_dir="raw",
+        load_image=load_raw_summer_image
+    ),
+]
+
+load_test_proc = [
+    ImageLoader(
+        input_img_dir=get_test_data_dir(),
+        input_sub_dir='processed',
+        load_image=load_proc_summer_image
+    ),
+    ImageSelector((base_name_key, "SUMMER_20220816_042349_Camera0.resamp.fits")),
+]
+
 build_log = [
     CSVLog(
         export_keys=[
diff --git a/winterdrp/pipelines/summer/summer_pipeline.py b/winterdrp/pipelines/summer/summer_pipeline.py
index c34ef032d..33f9012fa 100644
--- a/winterdrp/pipelines/summer/summer_pipeline.py
+++ b/winterdrp/pipelines/summer/summer_pipeline.py
@@ -9,7 +9,7 @@
 from winterdrp.pipelines.summer.config import PIPELINE_NAME, summer_cal_requirements
 from winterdrp.pipelines.summer.load_summer_image import load_raw_summer_image
 from winterdrp.pipelines.summer.blocks import load_raw, build_log, load_processed, imsub, export_raw, \
-    cal_hunter, process_raw
+    cal_hunter, process_raw, load_test, load_test_proc, subtract
 
 summer_flats_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)))
 
@@ -23,8 +23,10 @@ class SummerPipeline(Pipeline):
 
     all_pipeline_configurations = {
         "default": load_raw + export_raw + cal_hunter + process_raw,
+        "test": load_test + export_raw + process_raw,
         "postprocess": build_log,
         'imsub': load_processed + imsub,
+        "test_imsub": load_test_proc + subtract,
         "full": load_raw + export_raw + cal_hunter + process_raw + imsub,
         "realtime": export_raw + process_raw,
         "log": load_raw + build_log,
diff --git a/winterdrp/processors/database/ingest_database.py b/winterdrp/processors/database/ingest_database.py
deleted file mode 100644
index 2633e0e14..000000000
--- a/winterdrp/processors/database/ingest_database.py
+++ /dev/null
@@ -1,399 +0,0 @@
-import psycopg
-import getpass
-from astropy.coordinates import SkyCoord
-import astropy.units as u
-from astropy.io import fits, ascii
-import os
-from glob import glob
-from astropy.time import Time
-
-
-def ingest_raw(user, password, rawimlist, reingest=False):
-	conn = psycopg.connect(database='commissioning', user=user, password=password)#, host='127.0.0.1', port='5432')
-	conn.autocommit = True
-	cursor = conn.cursor()
-	for l in rawimlist:
-
-		#Check if entry exists before
-		command = '''SELECT raw.rawid FROM raw WHERE raw.filename = '%s' '''%(l)
-		cursor.execute(command)
-		match_id = cursor.fetchall()
-		if len(match_id)>0:
-			if not reingest:
-				continue
-			if reingest:
-				raw_matchid = match_id[0][0]
-				command = '''DELETE FROM raw WHERE raw.rawid = %i'''%(raw_matchid)
-				cursor.execute(command)
-				print('Deleted 1 row')
-
-		img = fits.open(l)
-		header = img[0].header
-		img.close()
-
-		filename = l
-
-		if 'UTCISO' in header.keys():
-			obs_utc = header['UTCISO']
-			obsdate = int(Time(obs_utc).isot.split('T')[0].replace('-',''))
-		
-		filesize = os.stat(filename).st_size
-		
-		if 'OBJECT' in header.keys():
-			object_name = header['OBJECT']
-		else:
-			object_name = ''
-
-		if 'OBSTYPE' in header.keys():
-			obstype = header['OBSTYPE']
-		else:
-			obstype = ''
-
-		if 'RA' in header.keys():
-			obj_ra = header['RA']
-			obj_dec = header['DEC']
-			obj_crds = SkyCoord(ra=obj_ra, dec=obj_dec, unit=(u.deg,u.deg))
-			obj_ra, obj_dec = obj_crds.ra.deg, obj_crds.dec.deg
-		else:
-			obj_ra, obj_dec = -99, -99
-
-		if 'TELRA' in header.keys():
-			tel_ra = header['TELRA']
-			tel_dec = header['TELDEC']
-			tel_crds = SkyCoord(ra=tel_ra,dec=tel_dec,unit=(u.deg,u.deg))
-			tel_ra, tel_dec = tel_crds.ra.deg, tel_crds.dec.deg
-		else:
-			tel_ra, tel_dec = -99,-99
-
-		if 'HA' in header.keys():
-			ha = header['HA']
-		else:
-			ha = -99
-
-		if 'AIRMASS' in header.keys():
-			airmass = header['AIRMASS']
-		else:
-			airmass = -99
-
-		if 'ALTITUDE' in header.keys():
-			alt = header['ALTITUDE']
-			az = header['AZIMUTH']
-		else:
-			alt,az = -99, -99
-
-		if 'MOONANGLE' in header.keys():
-			moon_angle = header['MOONANGLE']
-		else:
-			moon_angle = -99
-
-		if 'FIELDID' in header.keys():
-			if header['FIELDID'] == '':
-				field_id = -99
-			else:
-				field_id = header['FIELDID']
-		else:
-			field_id = -99
-
-		field_id = -99
-		#print(field_id)
-
-		if 'FOCPOS' in header.keys():
-			focuser_position = header['FOCPOS']
-		else:
-			focuser_position = -99
-
-		if 'ROTFIELD' in header.keys():
-			rot_field_angle = header['ROTFIELD']
-		else:
-			rot_field_angle = -999
-
-		if 'ROTMECH' in header.keys():
-			rot_position = header['ROTMECH']
-		else:
-			rot_position = -999
-
-		if 'DOME_AZ' in header.keys():
-			dome_az = header['DOME_AZ']
-		else:
-			dome_az = -999
-
-		if 'DOME_SHUTTER' in header.keys():
-			dome_shutter = header['DOME_SHUTTER']
-		else:
-			dome_shutter = ''
-
-		if 'FILTERID' in header.keys():
-			filt = header['FILTERID'][:10]
-			if 'other' in filt:
-				filt = 'r'
-		else:
-			filt = ''
-
-
-		if 'SHUTOPEN' in header.keys():
-			exp_start = header['SHUTOPEN']
-			try:
-				exp_start_mjd = Time(exp_start).mjd
-			except ValueError:
-				exp_start_mjd = -99
-		else:
-			exp_start_mjd = -99
-
-
-
-		if 'EXPTIME' in header.keys():
-			exptime = header['EXPTIME']
-		else:
-			exptime = -99
-
-
-		if 'CCD_TEMP' in header.keys():
-			ccd_temp = header['CCD_TEMP']
-		else:
-			ccd_temp = -99
-
-
-		if 'GAIN' in header.keys():
-			ccd_gain = header['GAIN']
-		else:
-			ccd_gain = -99
-
-
-		if 'FREQ' in header.keys():
-			ccd_freq = header['FREQ']
-		else:
-			ccd_freq = -99
-		
-		progid = 1
-		camera = 'SUMMER'
-		#telescop = 'WINTER'
-		print(filename,obsdate,filesize,object_name,obj_ra,obj_dec,tel_ra, tel_dec,ha, airmass, alt, az, moon_angle, field_id, focuser_position, rot_field_angle, rot_position, dome_az, dome_shutter, filt, exp_start_mjd, exptime, ccd_temp, ccd_gain, ccd_freq, camera, obstype, progid)
-		command = '''INSERT INTO raw (FILENAME, OBSDATE, FILESIZE, OBJECT, OBJ_RA, OBJ_DEC, TEL_RA, TEL_DEC, HA, AIRMASS, ALT, AZ, MOON_ANGLE, FIELD_ID, FOCUSER_POSITION, ROT_FIELD_ANGLE,  ROT_POSITION, DOME_AZ, DOME_SHUTTER, FILTER, EXP_START_MJD, EXPTIME, CCD_TEMP, CCD_GAIN, CCD_READOUT_FREQ, CAMERA, OBSTYPE, PROGID) VALUES ('%s',%i,%.2f, '%s',%.5f, %.5f,%.5f, %.5f,%.2f, %.3f, %.2f, %.2f, %.3f, %i, %.2f, %.3f, %.3f, %.2f, '%s','%s', %.4f, %.2f,%.1f, %.2f, %.2f, '%s', '%s',%i);'''%(filename,obsdate,filesize,object_name,obj_ra,obj_dec,tel_ra, tel_dec,ha, airmass, alt, az, moon_angle, field_id, focuser_position, rot_field_angle, rot_position, dome_az, dome_shutter, filt, exp_start_mjd, exptime, ccd_temp, ccd_gain, ccd_freq, camera, obstype, progid)
-		cursor.execute(command)
-		#'''CREATE TABLE raw ( rawid SERIAL PRIMARY KEY, FILENAME VARCHAR(255) NOT NULL, OBSDATE INT, FILESIZE REAL, OBJECT VARCHAR(30), OBJ_RA FLOAT, OBJ_DEC FLOAT, TEL_RA FLOAT, TEL_DEC FLOAT, HA FLOAT, AIRMASS FLOAT, ALT FLOAT, AZ FLOAT, MOON_ANGLE FLOAT, FIELD_ID VARCHAR(30), FOCUSER_POSITION FLOAT, ROT_FIELD_ANGLE FLOAT, ROT_POSITION FLOAT, DOME_AZ FLOAT, DOME_SHUTTER VARCHAR(5), FILTER VARCHAR(5), EXP_START_MJD FLOAT, EXPTIME FLOAT, CCD_TEMP FLOAT, CCD_GAIN FLOAT, CCD_READOUT_FREQ FLOAT  );'''
-		print('Ingested %s'%(l))
-	return 0	
-
-
-def ingest_proc(user, password, procimlist, reingest=False):
-	conn = psycopg.connect(database='commissioning', user=user, password=password)#, host='127.0.0.1', port='5432')
-	conn.autocommit = True
-	cursor = conn.cursor()
-
-	for l in procimlist:
-		img = fits.open(l)
-		header = img[0].header
-		img.close()
-		proc_filename = l
-
-		#Check if entry exists previously
-		command = '''SELECT proc.procid FROM proc WHERE proc.proc_imagename = '%s' '''%(proc_filename)
-		cursor.execute(command)
-		match_id = cursor.fetchall()
-		if len(match_id)>0:
-			if not reingest:
-				continue
-			if reingest:
-				proc_matchid = match_id[0][0]
-				command = '''DELETE FROM proc WHERE proc.procid = %i'''%(proc_matchid)
-				cursor.execute(command)
-				print('Deleted 1 row')
-
-		raw_filename = proc_filename.replace('.proc.autoastrom.scampastrom.resamp.fits','.fits').replace('/proc','')
-		command = '''SELECT raw.rawid FROM raw WHERE raw.filename = '%s' '''%(raw_filename)
-		cursor.execute(command)
-		rawid = cursor.fetchall()[0][0]
-
-		if 'UTCISO' in header.keys():
-			obs_utc = header['UTCISO']
-			obsdate = int(Time(obs_utc).isot.split('T')[0].replace('-',''))
-
-		if 'FILTERID' in header.keys():
-			filt = header['FILTERID'][:10]
-		else:
-			filt = ''
-
-		if 'EXPTIME' in header.keys():
-			exptime = header['EXPTIME']
-		else:
-			exptime = -99
-
-		if 'FIELDID' in header.keys():
-			field_id = header['FIELDID']
-			if field_id == '':
-				field_id = -99
-		else:
-			field_id = -99
-		
-		field_id = -99
-
-		if 'FWHM_MED' in header.keys():
-			fwhm = header['FWHM_MED']
-		else:
-			fwhm = -99
-
-		if 'FLAT' in header.keys():
-			flatfilename = header['FLAT']
-		else:
-			flatfilename = ''
-
-		if 'BIAS' in header.keys():
-			biasfilename = header['BIAS']
-		else:
-			biasfilename = ''
-
-		if 'DARK' in header.keys():
-			darkfilename = header['DARK']
-		else:
-			darkfilename = ''
-
-
-		if 'LIMMAG' in header.keys():
-			maglim = header['LIMMAG']
-		else:
-			maglim = -99
-
-		#obj = header['OBJECT']
-		camera = 'SUMMER'
-		
-		cd1_1 = header['CD1_1']
-		cd1_2 = header['CD1_2']
-		cd2_1 = header['CD2_1']
-		cd2_2 = header['CD2_2']
-		crval1 = header['CRVAL1']
-		crval2 = header['CRVAL2']
-		crpix1 = header['CRPIX1']
-		crpix2 = header['CRPIX2']
-		astr_dpa = header['ASTR_DPA']
-		astr_off = header['ASTR_OFF']
-		if 'FLXSCALE' in header.keys():
-			flxscale = header['FLXSCALE']
-		else:
-			flxscale = -99
-		
-		pv1_0, pv1_1, pv1_4, pv1_7, pv2_0, pv2_1, pv2_2, pv2_6, pv2_10 = -99, -99, -99, -99, -99, -99, -99, -99, -99
-		if 'PV1_0' in header.keys():
-			pv1_0 = header['PV1_0']
-		if 'PV1_1' in header.keys():
-			pv1_1 = header['PV1_1']
-		if 'PV1_4' in header.keys():
-			pv1_4 = header['PV1_4']
-		if 'PV1_7' in header.keys():
-			pv1_7 = header['PV1_7']
-		if 'PV2_0' in header.keys():
-			pv2_0 = header['PV2_0']
-		if 'PV2_1' in header.keys():
-			pv2_1 = header['PV2_1']
-		if 'PV2_2' in header.keys():
-			pv2_2 = header['PV2_2']
-		if 'PV2_6' in header.keys():
-			pv2_6 = header['PV2_6']
-		if 'PV2_10' in header.keys():
-			pv2_10 = header['PV2_10']
-
-		if 'ZP_AUTO' in header.keys():
-			zp = header['ZP_AUTO']
-		else:
-			zp = -99
-
-		if 'ZP_AUTO_NSTARS' in header.keys():
-			zp_nstars = header['ZP_AUTO_NSTARS']
-		else:
-			zp_nstars = -99
-
-		if 'ZP_AUTO_STD' in header.keys():
-			zp_std = header['ZP_AUTO_STD']
-		else:
-			zp_std= -99
-		
-		if 'SHUTOPEN' in header.keys():
-			exp_start = header['SHUTOPEN']
-			exp_start_mjd = Time(exp_start).mjd
-		else:
-			exp_start_mjd = -99
-
-		#resamp_img = l.replace('.proc.autoastrom.scampastrom.fits','.fits')
-		#raw_l = l1.replace('proc/','')
-		#zp = header['ZP_AUTO']
-		
-		#img = fits.open(raw_l)
-		#header = img[0].header
-		#img.close()
-		#obsdate = header['UTCSTART']
-		#object_name = header['OBJECT']
-		#exposure_length = header['EXPTIME']
-
-		command = '''INSERT INTO proc (rawid, RAW_IMAGENAME, PROC_IMAGENAME, OBSDATE, FILTER,  EXPTIME, FIELD_ID, CD1_1, CD1_2, CD2_1, CD2_2, CRVAL1, CRVAL2, CRPIX1, CRPIX2, ZP, FWHM, MAGLIM, FLATFILENAME, DARKFILENAME, BIASFILENAME, ASTR_DPA, ASTR_OFF, FLXSCALE, PV1_0, PV1_1, PV1_4, PV1_7, PV2_0, PV2_1, PV2_2, PV2_6, PV2_10, ZP_NSTARS, ZP_STD, EXP_MJD) VALUES (%i, '%s', '%s', %i,'%s',%.3f,%i,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.4f,%.2f,%.2f,'%s','%s','%s',%.2f,%.2f,%.4f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%i,%.4f,%.4f);'''%(rawid,raw_filename,proc_filename,obsdate,filt,exptime,field_id,cd1_1,cd1_2,cd2_1,cd2_2,crval1,crval2,crpix1,crpix2,zp,fwhm,maglim,flatfilename,darkfilename,biasfilename,astr_dpa,astr_off,flxscale,pv1_0,pv1_1,pv1_4,pv1_7,pv2_0,pv2_1,pv2_2,pv2_6,pv2_10,zp_nstars,zp_std,exp_start_mjd)
-		cursor.execute(command)
-		print('Ingested %s'%(l))
-	return 0
-
-
-def create_db(user, password, dbname='commissioning'):
-	conn = psycopg2.connect(database='postgres', user=user, password=password)#, host='127.0.0.1', port='5432')
-	cursor = conn.cursor()
-	conn.autocommit = True
-	sql = '''CREATE database %s'''%(dbname)
-	cursor.execute(sql)
-	print('Created db %s'%(dbname))
-	
-	
-def create_tables(user, password, dbname='commissioning'):
-	conn = psycopg2.connect(database=dbname, user=user, password=password)#, host='127.0.0.1', port='5432')
-	cursor = conn.cursor()
-	conn.autocommit = True
-	
-	command = '''CREATE TABLE raw ( rawid SERIAL PRIMARY KEY, FILENAME VARCHAR(255) NOT NULL, OBSDATE INT, 
-	FILESIZE REAL, OBJECT VARCHAR(30), OBJ_RA FLOAT, OBJ_DEC FLOAT, TEL_RA FLOAT, TEL_DEC FLOAT, HA FLOAT, 
-	AIRMASS FLOAT, ALT FLOAT, AZ FLOAT, MOON_ANGLE FLOAT, FIELD_ID VARCHAR(30), FOCUSER_POSITION FLOAT, 
-	ROT_FIELD_ANGLE FLOAT, ROT_POSITION FLOAT, DOME_AZ FLOAT, DOME_SHUTTER VARCHAR(5), FILTER VARCHAR(5), 
-	EXP_START_MJD FLOAT, EXPTIME FLOAT, CCD_TEMP FLOAT, CCD_GAIN FLOAT, CCD_READOUT_FREQ FLOAT, CAMERA VARCHAR(15), 
-	OBSTYPE VARCHAR(15)  ); '''
-	cursor.execute(command)
-
-	print('Created table raw in ', dbname)
-
-	command = '''CREATE TABLE proc ( procid SERIAL PRIMARY KEY, rawid SERIAL, RAW_IMAGENAME VARCHAR(255), 
-	PROC_IMAGENAME VARCHAR(255), OBSDATE INT, FILTER VARCHAR(10),  EXPTIME INT, FIELD_ID VARCHAR(30), CD1_1 REAL, 
-	CD1_2 REAL, CD2_1 REAL, CD2_2 REAL, CRVAL1 REAL, CRVAL2 REAL, CRPIX1 REAL, CRPIX2 REAL, ZP REAL, FWHM REAL, 
-	MAGLIM REAL, FLATFILENAME VARCHAR(255), DARKFILENAME VARCHAR(255), BIASFILENAME VARCHAR(255), ASTR_DPA FLOAT, 
-	ASTR_OFF FLOAT, FLXSCALE FLOAT, PV1_0 FLOAT, PV1_1 FLOAT, PV1_4 FLOAT, PV1_7 FLOAT, PV2_0 FLOAT, PV2_1 FLOAT, 
-	PV2_2 FLOAT, PV2_6 FLOAT, PV2_10 FLOAT, ZP_NSTARS INT, ZP_STD FLOAT, EXP_MJD FLOAT);''' #add which flats were used
-	# and which darks were used
-	cursor.execute(command)
-	print('Created table proc in ', dbname)
-
-
-if __name__ == '__main__':
-	import argparse
-	parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
-	parser.add_argument("--d", type=str, default='data',help='Path to the directory where raw images are stored')
-	parser.add_argument("--procdir", type=str, default='proc',help='Name of output subdirectory for processed images')
-	parser.add_argument("--create_db", action="store_true")
-	parser.add_argument("--raw", action="store_true")
-	parser.add_argument("--proc", action="store_true")
-	parser.add_argument("--reingest", action="store_true")
-	parser.add_argument("--dbname", type=str, default='commissioning',help='Name of database')
-
-
-	args = parser.parse_args()
-
-	user = "rd"
-
-	# password = getpass.getpass(f"Enter password for user {user}: ")
-	password = "nothingfornow"
-
-	if args.create_db:
-		create_db(user, password, args.dbname)
-
-		create_tables(user, password, args.dbname)
-
-	if args.raw:
-		rawimlist = glob('%s/*.fits'%(args.d))
-		print('Found %s raw files'%(len(rawimlist)))
-		ingest_raw(user, password, rawimlist,reingest=args.reingest)
-
-	if args.proc:
-		procimlist = glob('%s/proc/*.resamp.fits'%(args.d))
-		print('Found %s processed (scamped) files'%(len(procimlist)))
-		ingest_proc(user, password, procimlist,reingest=args.reingest)
diff --git a/winterdrp/processors/reduce.py b/winterdrp/processors/reduce.py
deleted file mode 100644
index 36cf7fcb4..000000000
--- a/winterdrp/processors/reduce.py
+++ /dev/null
@@ -1,88 +0,0 @@
-import os
-import logging
-import numpy as np
-from winterdrp.io import create_fits
-from winterdrp.paths import reduced_img_dir, reduced_img_path, cal_output_dir
-from winterdrp.processors.bias import load_master_bias
-from winterdrp.processors.dark import load_master_darks, select_master_dark
-from winterdrp.processors.flat import load_master_flats, select_master_flat
-
-logger = logging.getLogger(__name__)
-
-
-def apply_reduction(raw_images, open_fits, sub_dir="", master_bias=None, master_dark=None, master_flat=None,
-                    use_norm_dark=False, flat_nan_threshold=0.1, reprocess=True):
-    
-    cal_dir = cal_output_dir(sub_dir)
-
-    with open_fits(raw_images[0]) as img:
-        header = img[0].header
-
-    # Try making output directory, unless it exists
-    
-    output_dir = reduced_img_dir(sub_dir)
-    
-    try:
-        os.makedirs(output_dir)
-    except OSError:
-        pass   
-    
-    # Load up calibration images, if not specified already
-    
-    if master_bias is None:
-    
-        master_bias = load_master_bias(cal_dir, header)
-        
-    if master_dark is None:
-        
-        master_dark = load_master_darks(cal_dir, header, use_norm=use_norm_dark)
-    
-    if master_flat is None:
-        
-        master_flat = load_master_flats(cal_dir, header)
-        
-    nframes = len(raw_images)
-    
-    proccessed_list = []
-        
-    # Loop over science images
-        
-    for i, raw_img_path in enumerate(raw_images):
-        
-        img_name = os.path.basename(raw_img_path)
-
-        logger.debug(f"Processing image {i+1}/{nframes} ({img_name})")
-        
-        output_path = reduced_img_path(img_name, sub_dir=sub_dir)
-        
-        if np.logical_and(os.path.exists(output_path), reprocess is False):
-            logger.debug(f"Skipping image {img_name}, because it has already "
-                         f"been processed and 'reprocess' is False.")
-            continue
-        
-        with open_fits(raw_img_path) as img:
-            data = img[0].data
-            header = img[0].header
-        
-        if header['OBSTYPE'] not in ['science', "object"]:
-            logger.debug(f'Obstype is not science, skipping {raw_img_path}')
-            continue
-        
-        mdark = select_master_dark(master_dark, header)
-        mflat = select_master_flat(master_flat, header, flat_nan_threshold=flat_nan_threshold)
-
-        # Master dark????
-        
-        data_redux = (data - master_bias)/mflat
-        proc_hdu = create_fits(data_redux)  # Create a new HDU with the processed image data
-        proc_hdu.header = header      # Copy over the header from the raw file
-        proc_hdu.header.add_history('Bias corrected and flat-fielded') # Add a note to the header
-        proc_hdu.header['BZERO'] = 0
-        # Write the reduced frame to disk
-
-        logger.info(f"Saving processed image to {output_path}")
-        proccessed_list.append(output_path)
-        proc_hdu.writeto(output_path, overwrite=True)
-
-    return proccessed_list
-        
\ No newline at end of file
diff --git a/winterdrp/swarp.xml b/winterdrp/swarp.xml
deleted file mode 100644
index 983f05a57..000000000
--- a/winterdrp/swarp.xml
+++ /dev/null
@@ -1,139 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="file:///usr/local/share/swarp/swarp.xsl"?>
-<VOTABLE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.ivoa.net/xml/VOTable/v1.1">
-<DESCRIPTION>produced by SWarp</DESCRIPTION>
-<!-- VOTable description at http://www.ivoa.net/Documents/latest/VOT.html -->
-<RESOURCE ID="SWarp" name="ZTF21aagppzg_J_stack_1_20210330.resamp.fits">
- <DESCRIPTION>Data related to SWarp</DESCRIPTION>
- <INFO name="QUERY_STATUS" value="OK" />
- <COOSYS ID="J2000" equinox="J2000" epoch="J2000" system="ICRS"/>
- <RESOURCE ID="MetaData" name="MetaData">
-  <DESCRIPTION>SWarp meta-data</DESCRIPTION>
-  <INFO name="QUERY_STATUS" value="OK" />
-  <PARAM name="Software" datatype="char" arraysize="*" ucd="meta.title;meta.software" value="SWarp"/>
-  <PARAM name="Version" datatype="char" arraysize="*" ucd="meta.version;meta.software" value="2.41.5"/>
-  <PARAM name="Soft_URL" datatype="char" arraysize="*" ucd="meta.ref.url;meta.software" value="http://astromatic.net/software/swarp/"/>
-  <PARAM name="Soft_Auth" datatype="char" arraysize="*" ucd="meta.bib.author;meta.software" value="Emmanuel Bertin"/>
-  <PARAM name="Soft_Ref" datatype="char" arraysize="*" ucd="meta.bib.bibcode;meta.software" value="2002ASPC..281..228B"/>
-  <PARAM name="NThreads" datatype="int" ucd="meta.number;meta.software" value="40"/>
-  <PARAM name="Date" datatype="char" arraysize="*" ucd="time.event.end;meta.software" value="2022-07-28"/>
-  <PARAM name="Time" datatype="char" arraysize="*" ucd="time.event.end;meta.software" value="11:59:25"/>
-  <PARAM name="Duration" datatype="float" ucd="time.event;meta.software" value="0.40" unit="s"/>
-  <PARAM name="User" datatype="char" arraysize="*" ucd="meta.curation" value="idun"/>
-  <PARAM name="Host" datatype="char" arraysize="*" ucd="meta.curation" value="winter"/>
-  <PARAM name="Path" datatype="char" arraysize="*" ucd="meta.dataset" value="/data/sulekha/winterdrp/winterdrp"/>
-  <PARAM name="Image_Name" datatype="char" arraysize="*" ucd="obs.image;meta.fits" value="/data/sulekha/test/wirc_imsub/20220420/subtract/ZTF21aagppzg_J_stack_1_20210330.resamp.fits"/>
-  <PARAM name="Weight_Name" datatype="char" arraysize="*" ucd="obs.image;meta.fits" value="/data/sulekha/test/wirc_imsub/20220420/subtract/ZTF21aagppzg_J_stack_1_20210330.resamp.weight.fits"/>
-  <PARAM name="NOverlap_Max" datatype="int" ucd="meta.number;stat.max;obs.image" value="0"/>
-  <PARAM name="ExpTime_Max" datatype="float" ucd="time.expo;stat.max;obs.image" value="0" unit="s"/>
-  <PARAM name="Gain_Max" datatype="float" ucd="instr.calib;stat.max;obs.image" value="0" unit="photon/ADU"/>
-  <TABLE ID="Input_Image_Data" name="Input_Image_Data">
-   <DESCRIPTION>Data gathered by SWarp for every FITS input image</DESCRIPTION>
-   <!-- NFrames may be 0 if an error occurred early in the processing -->
-   <PARAM name="NFrames" datatype="int" ucd="meta.number;meta.dataset" value="1"/>
-   <!-- CurrFrame may differ from NFrames if an error occurred -->
-   <PARAM name="CurrFrame" datatype="int" ucd="meta.number;meta.dataset" value="1"/>
-   <FIELD name="Frame_Index" datatype="int" ucd="meta.record"/>
-   <FIELD name="Image_Name" datatype="char" arraysize="*" ucd="obs.image;meta.fits"/>
-   <FIELD name="Weight_Name" datatype="char" arraysize="*" ucd="obs.image;meta.fits"/>
-   <FIELD name="External_Header" datatype="boolean" ucd="meta.code;obs.param"/>
-   <FIELD name="Image_Ident" datatype="char" arraysize="*" ucd="meta.id;obs"/>
-   <FIELD name="Extension" datatype="int" ucd="meta.record"/>
-   <FIELD name="Date" datatype="char" arraysize="*" ucd="meta.record;time.event.end"/>
-   <FIELD name="Time" datatype="char" arraysize="*" ucd="meta.record;time.event.end"/>
-   <FIELD name="Duration" datatype="float" ucd="meta.record;time.event.end" unit="s"/>
-   <FIELD name="Background_Mean" datatype="float" ucd="instr.skyLevel;obs.image;stat.median" unit="adu"/>
-   <FIELD name="Background_StDev" datatype="float" ucd="stat.stdev;obs.image;stat.median" unit="adu"/>
-   <FIELD name="Subtract_Back" datatype="boolean" ucd="meta.code;obs.param"/>
-   <FIELD name="Back_Type" datatype="char" arraysize="*" ucd="meta.code;obs.param"/>
-   <FIELD name="Back_Size" datatype="int" ucd="obs.param" unit="pix"/>
-   <FIELD name="Back_FilterSize" datatype="int" ucd="obs.param" unit="pix"/>
-   <FIELD name="Back_Default" datatype="float" ucd="obs.param" unit="adu"/>
-   <FIELD name="Weight_Type" datatype="boolean" arraysize="*" ucd="stat.weight;meta.code"/>
-   <FIELD name="Rescale_Weights" datatype="char" arraysize="*" ucd="stat.weight;meta.code"/>
-   <FIELD name="Weight_Thresh" datatype="float" ucd="instr.sensitivity;obs.param" unit="adu"/>
-   <FIELD name="Weight_Scaling" datatype="float" ucd="arith.factor;obs.image;stat.median"/>
-   <FIELD name="Interpolate" datatype="boolean" ucd="meta.code;obs.param"/>
-   <FIELD name="Gain" datatype="float" ucd="instr.calib;obs.image" unit="photon/adu"/>
-   <FIELD name="Saturation" datatype="float" ucd="instr.calib;obs.image" unit="adu"/>
-   <FIELD name="ExpTime" datatype="float" ucd="time.expo;obs.image" unit="s"/>
-   <FIELD name="Photometric_Flux_Scaling" datatype="float" ucd="phot.calib;obs.image"/>
-   <FIELD name="Astrometric_Flux_Scaling" datatype="float" ucd="phot.calib;obs.image"/>
-   <FIELD name="Field_Coordinates" datatype="double" arraysize="2" ucd="pos.eq;obs.image" unit="pix"/>
-   <FIELD name="Pixel_Scale" datatype="float" ucd="instr.pixel;obs.image;stat.mean" unit="arcsec"/>
-   <FIELD name="ObsDate" datatype="double" ucd="time.start;obs" unit="yr"/>
-   <FIELD name="Equinox" datatype="double" ucd="time.equinox;obs" unit="yr"/>
-   <FIELD name="Epoch" datatype="double" ucd="time.epoch;obs" unit="yr"/>
-   <FIELD name="COOSYS" datatype="char" arraysize="*" ucd="meta.code;pos"/>
-   <DATA><TABLEDATA>
-    <TR>
-     <TD>1</TD><TD>/data/sulekha/test/wirc_imsub/20220420/subtract/temp_ZTF21aagppzg_J_stack_1_20210330.fits</TD><TD>/data/sulekha/test/wirc_imsub/20220420/subtract/temp_ZTF21aagppzg_J_stack_1_20210330.mask.fits</TD><TD>F</TD><TD>ZTF21aagppzg</TD>
-     <TD>0</TD><TD>2022-07-28</TD><TD>11:59:25</TD><TD>0.00</TD>
-     <TD>0.00158692</TD><TD>0.813738</TD><TD>T</TD><TD>AUTO</TD><TD>128</TD><TD>3</TD><TD>0</TD>
-     <TD>MAP_WEIGHT</TD><TD>T</TD><TD>0</TD><TD>0.813738</TD><TD>F</TD>
-     <TD>120.57</TD><TD>456.099</TD><TD>315</TD><TD>1</TD>
-     <TD>1</TD><TD>160.6101024 34.39769938</TD><TD>0.248743</TD><TD>2021.242611</TD><TD>2000</TD><TD>2000</TD>
-     <TD>ICRS</TD>
-    </TR>
-   </TABLEDATA></DATA>
-  </TABLE>
-  <TABLE ID="Warnings" name="Warnings">
-   <DESCRIPTION>SWarp warnings (limited to the last 1000)</DESCRIPTION>
-   <FIELD name="Date" datatype="char" arraysize="*" ucd="meta;time.event.end"/>
-   <FIELD name="Time" datatype="char" arraysize="*" ucd="meta;time.event.end"/>
-   <FIELD name="Msg" datatype="char" arraysize="*" ucd="meta"/>
-   <DATA><TABLEDATA>
-    <TR><TD>2022-07-28</TD><TD>11:59:25</TD><TD>winterdrp/pipelines/wirc_imsub/wirc_imsub_files/config/config.swarp not found, using internal defaults</TD></TR>
-    <TR><TD>2022-07-28</TD><TD>11:59:25</TD><TD>GAIN keyword unknown</TD></TR>
-   </TABLEDATA></DATA>
-  </TABLE>
-  <RESOURCE ID="Config" name="Config">
-   <DESCRIPTION>SWarp configuration</DESCRIPTION>
-   <PARAM name="Command_Line" datatype="char" arraysize="*" ucd="obs.param" value="swarp -c winterdrp/pipelines/wirc_imsub/wirc_imsub_files/config/config.swarp @/data/sulekha/test/wirc_imsub/20220420/subtract/ZTF21aagppzg_J_stack_1_20210330_swarp_img_list.txt -IMAGEOUT_NAME /data/sulekha/test/wirc_imsub/20220420/subtract/ZTF21aagppzg_J_stack_1_20210330.resamp.fits -RESAMPLE Y -RESAMPLE_DIR /data/sulekha/test/wirc_imsub/20220420/subtract -SUBTRACT_BACK Y -COMBINE N -WEIGHT_TYPE MAP_WEIGHT -WEIGHT_IMAGE @/data/sulekha/test/wirc_imsub/20220420/subtract/ZTF21aagppzg_J_stack_1_20210330_swarp_weight_list.txt -WEIGHTOUT_NAME /data/sulekha/test/wirc_imsub/20220420/subtract/ZTF21aagppzg_J_stack_1_20210330.resamp.weight.fits -PIXELSCALE_TYPE MANUAL -PIXEL_SCALE 0.24874313967302397 -COPY_KEYWORDS TMC_ZP,TMC_ZPSD -CENTER 160.6518235617976,34.44413592422457 -IMAGE_SIZE 2277,2281 -GAIN 120.5702367581"/>
-   <PARAM name="Prefs_Name" datatype="char" arraysize="*" ucd="obs.param;meta.file" value="winterdrp/pipelines/wirc_imsub/wirc_imsub_files/config/config.swarp"/>
-   <PARAM name="ImageOut_Name" datatype="char" arraysize="*" ucd="meta.dataset;meta.file" value="/data/sulekha/test/wirc_imsub/20220420/subtract/ZTF21aagppzg_J_stack_1_20210330.resamp.fits"/>
-   <PARAM name="WeightOut_Name" datatype="char" arraysize="*" ucd="meta.dataset;meta.file" value="/data/sulekha/test/wirc_imsub/20220420/subtract/ZTF21aagppzg_J_stack_1_20210330.resamp.weight.fits"/>
-   <PARAM name="Header_Only" datatype="boolean" ucd="meta.code;obs.param" value="F"/>
-   <PARAM name="Header_Suffix" datatype="char" arraysize="*" ucd="meta.dataset;meta.file" value=".head"/>
-   <PARAM name="Weight_Suffix" datatype="char" arraysize="*" ucd="meta.dataset;meta.file" value=".weight.fits"/>
-   <PARAM name="Combine" datatype="boolean" ucd="meta.code" value="F"/>
-   <PARAM name="Combine_Type" datatype="char" arraysize="*" ucd="meta.code;obs.param" value="MEDIAN"/>
-   <PARAM name="Blank_BadPixels" datatype="boolean" ucd="meta.code;obs.param" value="F"/>
-   <PARAM name="Celestial_Type" datatype="char" arraysize="*" ucd="meta;pos;obs.param" value="NATIVE"/>
-   <PARAM name="Projection_Type" datatype="char" arraysize="*" ucd="meta;pos;obs.param" value="TAN"/>
-   <PARAM name="Projection_Err" datatype="float" arraysize="2" ucd="pos.angDistance;stat.max;obs.param" value="0.001 0" unit="pix"/>
-   <PARAM name="Center_Type" datatype="char" arraysize="*" ucd="meta.code;pos;obs.param" value="ALL"/>
-   <PARAM name="Center" datatype="double" arraysize="2" ucd="pos;obs.param" value="    160.6101024     34.39769938" unit="pix"/>
-   <PARAM name="PixelScale_Type" datatype="char" arraysize="*" ucd="meta.code;pos;obs.param" value="MANUAL"/>
-   <PARAM name="Pixel_Scale" datatype="float" arraysize="1" ucd="instr.scale;instr.pixel;obs.param" value="0.248743"/>
-   <PARAM name="Image_Size" datatype="int" arraysize="2" ucd="instr.scale;instr.pixel;obs.param" value="2277 2281"/>
-   <PARAM name="Resample" datatype="boolean" ucd="meta.code" value="T"/>
-   <PARAM name="Resample_Dir" datatype="char" arraysize="*" ucd="meta.dataset" value="/data/sulekha/test/wirc_imsub/20220420/subtract"/>
-   <PARAM name="Resample_Suffix" datatype="char" arraysize="*" ucd="meta.dataset;meta.file" value=".resamp.fits"/>
-   <PARAM name="Resampling_Type" datatype="char" arraysize="*" ucd="meta.code;pos;obs.param" value="LANCZOS3"/>
-   <PARAM name="Oversampling" datatype="int" arraysize="1" ucd="arith.factor;instr.pixel;obs.param" value="1"/>
-   <PARAM name="FScalAstro_Type" datatype="char" arraysize="*" ucd="phot.calib;obs.param" value="FIXED"/>
-   <PARAM name="FScale_Keyword" datatype="char" arraysize="*" ucd="meta.code;phot.calib;obs.param" value="FLXSCALE"/>
-   <PARAM name="FScale_Default" datatype="float" ucd="phot.calib;obs.param" value="1"/>
-   <PARAM name="Gain_Keyword" datatype="char" arraysize="*" ucd="meta.code;phot.calib;obs.param" value="GAIN"/>
-   <PARAM name="Gain_Default" datatype="float" ucd="phot.calib;obs.param" value="0"/>
-   <PARAM name="SatLev_Keyword" datatype="char" arraysize="*" ucd="meta.code;instr.saturation;obs.param" value="SATURATE"/>
-   <PARAM name="SatLev_Default" datatype="float" ucd="instr.saturation;obs.param" value="50000"/>
-   <PARAM name="Subtract_Back" datatype="boolean" ucd="meta.code" value="T"/>
-   <PARAM name="Back_Type" datatype="char" arraysize="*" ucd="meta.code;obs.param" value="NONE"/>
-   <PARAM name="Back_Size" datatype="int" ucd="obs.param" value="128"/>
-   <PARAM name="Back_FilterSize" datatype="int" ucd="obs.param" value="3"/>
-   <PARAM name="Back_Default" datatype="float" ucd="obs.param" value="0" unit="adu"/>
-   <PARAM name="Back_FiltThresh" datatype="float" ucd="phot.count;arith.ratio;obs.param" value="0"/>
-   <PARAM name="VMem_Dir" datatype="char" arraysize="*" ucd="meta" value="."/>
-   <PARAM name="VMem_Max" datatype="int" ucd="meta.number;stat.max" value="2047" unit="Mbyte"/>
-   <PARAM name="Mem_Max" datatype="int" ucd="meta.number;stat.max" value="256" unit="Mbyte"/>
-   <PARAM name="Combine_BufSize" datatype="int" ucd="meta.number;stat.max" value="256" unit="Mbyte"/>
-   <PARAM name="Delete_TmpFiles" datatype="boolean" ucd="meta.code" value="T"/>
-   <PARAM name="Copy_Keywords" datatype="char" arraysize="*" ucd="meta;meta.fits" value="TMC_ZP  ,TMC_ZPSD"/>
-   <PARAM name="Write_FileInfo" datatype="boolean" ucd="meta.code" value="F"/>
-   <PARAM name="Verbose_Type" datatype="char" arraysize="*" ucd="meta.code" value="NORMAL"/>
-  </RESOURCE>
- </RESOURCE>
-</RESOURCE>
-</VOTABLE>


Test patch:
diff --git a/tests/test_summer_imsub_pipeline.py b/tests/test_summer_imsub_pipeline.py
index f243c0e4f..864246ced 100644
--- a/tests/test_summer_imsub_pipeline.py
+++ b/tests/test_summer_imsub_pipeline.py
@@ -10,17 +10,6 @@
 
 logger = logging.getLogger(__name__)
 
-test_data_dir = get_test_data_dir()
-
-test_configuration = [
-    ImageLoader(
-        input_img_dir=test_data_dir,
-        input_sub_dir='processed',
-        load_image=load_proc_summer_image
-    ),
-    ImageSelector((base_name_key, "SUMMER_20220816_042349_Camera0.resamp.fits")),
-] + subtract
-
 
 expected_values = {
     'SCORSTD': 1.120988782614284,
@@ -28,10 +17,7 @@
     'SCORMEAN': -0.0027870992375066423
 }
 
-test_config_name = "test_imsub"
-
-pipeline = SummerPipeline(night="20220815", selected_configurations=[test_config_name])
-pipeline.add_configuration(configuration_name=test_config_name, configuration=test_configuration)
+pipeline = SummerPipeline(night="20220815", selected_configurations=["test_imsub"])
 
 
 class TestSummerPipeline(unittest.TestCase):
diff --git a/tests/test_summer_pipeline.py b/tests/test_summer_pipeline.py
index 9bddac823..982930e1c 100644
--- a/tests/test_summer_pipeline.py
+++ b/tests/test_summer_pipeline.py
@@ -1,63 +1,12 @@
 import unittest
 import logging
-from winterdrp.processors.autoastrometry import AutoAstrometry
-from winterdrp.processors.astromatic import Sextractor, Scamp, Swarp
-from winterdrp.pipelines.summer.config import summer_mask_path, summer_weight_path, \
-    sextractor_astrometry_config, sextractor_photometry_config, scamp_path, swarp_config_path
-from winterdrp.processors.utils import ImageSaver
-from winterdrp.processors.utils.image_loader import ImageLoader
-from winterdrp.processors.utils.image_selector import ImageSelector, ImageBatcher
-from winterdrp.processors.photcal import PhotCalibrator
-from winterdrp.processors import MaskPixels, BiasCalibrator, FlatCalibrator
-from winterdrp.processors.csvlog import CSVLog
-from winterdrp.paths import core_fields, base_name_key
-from winterdrp.pipelines.summer.summer_pipeline import load_raw_summer_image, SummerPipeline
-from winterdrp.pipelines.summer.generator import summer_astrometric_catalog_generator, \
-    summer_photometric_catalog_generator
-from winterdrp.pipelines.summer.config import SUMMER_PIXEL_SCALE
+from winterdrp.pipelines.summer.summer_pipeline import SummerPipeline
 from winterdrp.downloader.get_test_data import get_test_data_dir
 
 logger = logging.getLogger(__name__)
 
 test_data_dir = get_test_data_dir()
 
-test_configuration = [
-    ImageLoader(
-        input_img_dir=test_data_dir,
-        input_sub_dir="raw",
-        load_image=load_raw_summer_image
-    ),
-    CSVLog(
-        export_keys=[
-                        "UTC", 'FIELDID', "FILTERID", "EXPTIME", "OBSTYPE", "RA", "DEC", "TARGTYPE",
-                        base_name_key
-                    ] + core_fields
-    ),
-    MaskPixels(mask_path=summer_mask_path),
-    BiasCalibrator(),
-    ImageBatcher(split_key="filter"),
-    FlatCalibrator(),
-    ImageSelector(("OBSTYPE", "SCIENCE")),
-    AutoAstrometry(pa=0, inv=True, pixel_scale=SUMMER_PIXEL_SCALE),
-    Sextractor(
-        output_sub_dir="test",
-        weight_image=summer_weight_path,
-        checkimage_name=None,
-        checkimage_type=None,
-        **sextractor_astrometry_config
-    ),
-    Scamp(
-        ref_catalog_generator=summer_astrometric_catalog_generator,
-        scamp_config_path=scamp_path,
-    ),
-    Swarp(swarp_config_path=swarp_config_path, imgpixsize=2400),
-    Sextractor(output_sub_dir="test",
-               checkimage_type='BACKGROUND_RMS',
-               **sextractor_photometry_config),
-    PhotCalibrator(ref_catalog_generator=summer_photometric_catalog_generator),
-    ImageSaver(output_dir_name="test")
-]
-
 expected_zp = {
     "ZP_2.0": 24.381802801640834,
     "ZP_2.0_std": 0.08222868531222044,
@@ -84,9 +33,7 @@
 
 test_config_name = "test"
 
-pipeline = SummerPipeline(night="20220402", selected_configurations=[test_config_name])
-pipeline.add_configuration(configuration_name=test_config_name, configuration=test_configuration)
-
+pipeline = SummerPipeline(night="20220402", selected_configurations=["test"])
 
 class TestSummerPipeline(unittest.TestCase):
     def setUp(self):