From: Sam Moore Date: Thu, 9 Aug 2012 03:00:03 +0000 (+0800) Subject: Automatic commit. Thu Aug 9 11:00:03 WST 2012 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=56f525e2d01cb9e01d8a5d38130729c0a2072cd1;p=matches%2Fhonours.git Automatic commit. Thu Aug 9 11:00:03 WST 2012 Q: What do you call a WASP who doesn't work for his father, isn't a lawyer, and believes in social causes? A: A failure. --- diff --git a/research/TCS/2012-08-08/checklist b/research/TCS/2012-08-08/checklist new file mode 100644 index 00000000..999e436d --- /dev/null +++ b/research/TCS/2012-08-08/checklist @@ -0,0 +1,19 @@ +# Accelerating Voltage = 38.4 +# Focus Voltage = 0.17 +# Deflection Voltage = 1.346 +# Venault Voltage = 12.0 +# Initial Voltage = Sweep +# Heating Current = 1.140 +# Heating Voltage = 1.141 +# Chamber Pressure = 3.89e-8 +# 610B Zero = 0.00 +# 602 Zero = 0.00 +# 610B Scale = 1e-7 x 0.03 +# 602 Scale = 1e-5 x 0.3 +# 602 0.1 Battery = 8.40 +# 602 0.03 Battery = 7.85 +# 602 0.01 Battery = 8.05 +# 602 0.003 Battery = 8.00 +# 602 0.001 Battery = 8.10 +# ADC Regulator = 3.30 +# Checklist updated 2012-08-09 10:32 diff --git a/research/TCS/2012-08-09/105433.dat b/research/TCS/2012-08-09/105433.dat new file mode 100644 index 00000000..4c0fe948 --- /dev/null +++ b/research/TCS/2012-08-09/105433.dat @@ -0,0 +1,46 @@ +# File opened at 2012-08-09 10:54:33.262534 +# aquire[DAC_Sweep] = 0.0 + 50.0*int(step/60) +# aquire[ADC_Averages] = 200 +# aquire[DAC_Settle] = 0.0 +# aquire[ADC_Ie] = 4 +# aquire[open_files] = [, ] +# aquire[ADC_Vi] = 5 +# aquire[start_date] = 2012-08-09 +# aquire[ADC_Is] = 4 +# Parameters: +# Accelerating Voltage = 38.4 +# Focus Voltage = 0.17 +# Deflection Voltage = 1.346 +# Venault Voltage = 12.0 +# Initial Voltage = Sweep +# Heating Current = 1.140 +# Heating Voltage = 1.141 +# Chamber Pressure = 3.89e-8 +# 610B Zero = 0.00 +# 602 Zero = 0.00 +# 610B Scale = 1e-7 x 0.03 +# 602 Scale = 1e-5 x 0.3 +# 602 0.1 Battery = 8.40 +# 602 0.03 Battery = 7.85 +# 602 0.01 Battery = 8.05 +# 602 0.003 Battery = 8.00 +# 602 0.001 Battery = 8.10 +# ADC Regulator = 3.30 +# Title = Testing +# Comment = test +# Data = TEST +# Update Parameters = 2012-08-09 10:32 + +# Experiment 2012-08-09 10:54:33.263732 +# Polling for Nones. + +# Data: +# time DAC ADC4 ADC5 +0.792319536209 0 8.0 7.56 914.9 111.90 +1.472417593 0 7.56 6.80 913.88 112.16 +2.151907444 0 7.44 7.39 913.9 112.9 +2.83043909073 0 7.90 7.88 914.20 112.15 +3.51444911957 0 9.28 8.47 910.77 112.90 +4.19797611237 0 9.13 7.97 914.16 112.9 +# Program exits. +# File closed at 2012-08-09 10:54:41.063138 diff --git a/research/TCS/2012-08-09/105927.dat b/research/TCS/2012-08-09/105927.dat new file mode 100644 index 00000000..6658feef --- /dev/null +++ b/research/TCS/2012-08-09/105927.dat @@ -0,0 +1,40 @@ +# File opened at 2012-08-09 10:59:27.786538 +# aquire[DAC_Sweep] = 0.0 + 50.0*int(step/60) +# aquire[ADC_Averages] = 200 +# aquire[DAC_Settle] = 0.0 +# aquire[ADC_Ie] = 4 +# aquire[open_files] = [, ] +# aquire[ADC_Vi] = 5 +# aquire[start_date] = 2012-08-09 +# aquire[ADC_Is] = 4 +# Parameters: +# Accelerating Voltage = 38.4 +# Focus Voltage = 0.17 +# Deflection Voltage = 1.346 +# Venault Voltage = 12.0 +# Initial Voltage = Sweep +# Heating Current = 1.140 +# Heating Voltage = 1.141 +# Chamber Pressure = 3.89e-8 +# 610B Zero = 0.00 +# 602 Zero = 0.00 +# 610B Scale = 1e-7 x 0.03 +# 602 Scale = 1e-5 x 0.3 +# 602 0.1 Battery = 8.40 +# 602 0.03 Battery = 7.85 +# 602 0.01 Battery = 8.05 +# 602 0.003 Battery = 8.00 +# 602 0.001 Battery = 8.10 +# ADC Regulator = 3.30 +# Title = Testing +# Comment = test +# Data = TEST +# Parameters last checked = None + +# Experiment 2012-08-09 10:59:27.787749 +# Polling for Nones. + +# Data: +# time DAC ADC4 ADC5 +0.792268037796 0 7.89 7.42 913.27 111.80 +1.47629332542 0 7.48 7.16 913.85 111.99 diff --git a/research/TCS/2012-08-09/105938.dat b/research/TCS/2012-08-09/105938.dat new file mode 100644 index 00000000..44f65f51 --- /dev/null +++ b/research/TCS/2012-08-09/105938.dat @@ -0,0 +1,41 @@ +# File opened at 2012-08-09 10:59:38.870702 +# aquire[DAC_Sweep] = 0.0 + 50.0*int(step/60) +# aquire[ADC_Averages] = 200 +# aquire[DAC_Settle] = 0.0 +# aquire[ADC_Ie] = 4 +# aquire[open_files] = [, , ] +# aquire[ADC_Vi] = 5 +# aquire[start_date] = 2012-08-09 +# aquire[ADC_Is] = 4 +# Parameters: +# Accelerating Voltage = 38.4 +# Focus Voltage = 0.17 +# Deflection Voltage = 1.346 +# Venault Voltage = 12.0 +# Initial Voltage = Sweep +# Heating Current = 1.140 +# Heating Voltage = aasdf +# Chamber Pressure = 3.89e-8 +# 610B Zero = 0.00 +# 602 Zero = 0.00 +# 610B Scale = 1e-7 x 0.03 +# 602 Scale = 1e-5 x 0.3 +# 602 0.1 Battery = 8.40 +# 602 0.03 Battery = 7.85 +# 602 0.01 Battery = 8.05 +# 602 0.003 Battery = 8.00 +# 602 0.001 Battery = 8.10 +# ADC Regulator = 3.30 +# Title = Testing +# Comment = adsf +# Data = TEST +# Parameters last checked = 2012-08-09 10:59:38.865447 + +# Experiment 2012-08-09 10:59:38.871908 +# Polling for Nones. + +# Data: +# time DAC ADC4 ADC5 +0.785655975342 0 8.30 7.56 913.95 111.67 +# Recieved KILL signal. +# Reason: test again# File closed at 2012-08-09 10:59:41.581763 diff --git a/research/TCS/2012-08-09/checklist b/research/TCS/2012-08-09/checklist new file mode 100644 index 00000000..7f273a62 --- /dev/null +++ b/research/TCS/2012-08-09/checklist @@ -0,0 +1,23 @@ +# File opened at 2012-08-09 10:59:38.865710 +# Accelerating Voltage = 38.4 +# Focus Voltage = 0.17 +# Deflection Voltage = 1.346 +# Venault Voltage = 12.0 +# Initial Voltage = Sweep +# Heating Current = 1.140 +# Heating Voltage = aasdf +# Chamber Pressure = 3.89e-8 +# 610B Zero = 0.00 +# 602 Zero = 0.00 +# 610B Scale = 1e-7 x 0.03 +# 602 Scale = 1e-5 x 0.3 +# 602 0.1 Battery = 8.40 +# 602 0.03 Battery = 7.85 +# 602 0.01 Battery = 8.05 +# 602 0.003 Battery = 8.00 +# 602 0.001 Battery = 8.10 +# ADC Regulator = 3.30 +# Title = Testing +# Comment = adsf +# Data = TEST +# Parameters last checked = 2012-08-09 10:59:38.865447 diff --git a/research/TCS/2012-08-09/checklist.old b/research/TCS/2012-08-09/checklist.old new file mode 100644 index 00000000..f2a8467b --- /dev/null +++ b/research/TCS/2012-08-09/checklist.old @@ -0,0 +1,26 @@ +# File opened at 2012-08-09 10:59:34.993650 +# Accelerating Voltage = 38.4 +# Focus Voltage = 0.17 +# Deflection Voltage = 1.346 +# Venault Voltage = 12.0 +# Initial Voltage = Sweep +# Heating Current = 1.140 +# Heating Voltage = 1.141 +# Chamber Pressure = 3.89e-8 +# 610B Zero = 0.00 +# 602 Zero = 0.00 +# 610B Scale = 1e-7 x 0.03 +# 602 Scale = 1e-5 x 0.3 +# 602 0.1 Battery = 8.40 +# 602 0.03 Battery = 7.85 +# 602 0.01 Battery = 8.05 +# 602 0.003 Battery = 8.00 +# 602 0.001 Battery = 8.10 +# ADC Regulator = 3.30 +# Title = Testing +# Comment = test +# Data = TEST +# Parameters last checked = None + +# Recieved KILL signal. +# Reason: test again# File closed at 2012-08-09 10:59:41.581576 diff --git a/research/TCS/interface.py b/research/TCS/interface.py index 86c5e823..11ed9b29 100755 --- a/research/TCS/interface.py +++ b/research/TCS/interface.py @@ -12,7 +12,7 @@ import time import serial import datetime -import collections +import odict # TODO: Insert variables for calibration purposes here. @@ -57,7 +57,7 @@ ser = serial.Serial( rtscts=0 ) -parameters = OrderedDict([ +parameters = odict.odict([ ("Accelerating Voltage" , None), ("Focus Voltage" , None), ("Deflection Voltage" , None), @@ -75,11 +75,11 @@ parameters = OrderedDict([ ("602 0.01 Battery" , None), ("602 0.003 Battery" , None), ("602 0.001 Battery" , None), - ("ADC Battery" , None), ("ADC Regulator" , None), ("Title" , None), ("Comment" , None), ("Data" , None), + ("Parameters last checked", None) ]) def getTime(): @@ -95,17 +95,48 @@ def set_exit_handler(func): import win32api win32api.SetConsoleCtrlHandler(func, True) except ImportError: - version = “.”.join(map(str, sys.version_info[:2])) - raise Exception(”pywin32 not installed for Python ” + version) + version = ".".join(map(str, sys.version_info[:2])) + raise Exception("pywin32 not installed for Python " + version) else: import signal signal.signal(signal.SIGTERM, func) + signal.signal(signal.SIGINT, func) + +def killed_handler(signal, frame): + reason = "" + sys.stdout.write("\n# Reason for killing program? ") + reason = sys.stdin.readline().strip("\r\n ") + for out in aquire["open_files"]: + sys.stdout.write("# Closing file " + str(out) + "\n") + out.write("# Recieved KILL signal.\n# Reason: " + str(reason)) + log_close(out) -def exit_handler(): -def init(): +def cleanup(): + for out in aquire["open_files"]: + out.write("# Program exits.\n") + log_close(out) + +def log_open(a, b): + result = open(a, b,0) + if (b == "w"): + result.write("# File opened at " + str(datetime.datetime.now()) + "\n") + aquire["open_files"].append(result) + return result + +def log_close(afile): + if (afile in aquire["open_files"]): + afile.write("# File closed at " + str(datetime.datetime.now()) + "\n") + aquire["open_files"].remove(afile) + + afile.close() + +def init(): + #import atexit + #atexit.register(cleanup) + set_exit_handler(killed_handler) aquire["start_date"] = getDate() @@ -126,19 +157,19 @@ def init(): print(ser.readline().strip("\r\n")) print(ser.readline().strip("\r\n")) - print("Writing config information to config.dat...") - output = open("config.dat", "w", 1) + #print("Writing config information to config.dat...") + #output = log_open("config.dat", "w", 1) - output.write("# Initialise " + str(datetime.datetime.now()) + "\n") + #output.write("# Initialise " + str(datetime.datetime.now()) + "\n") #for field in calibrate: # output.write("# calibrate["+str(field)+"] = "+str(calibrate[field]) + "\n") #output.write("\n") - for field in aquire: - output.write("# aquire["+str(field)+"] = "+str(aquire[field]) + "\n") + #for field in aquire: + # output.write("# aquire["+str(field)+"] = "+str(aquire[field]) + "\n") - output.write("# Ready " + str(datetime.datetime.now()) + "\n# EOF\n") - output.close() + #output.write("# Ready " + str(datetime.datetime.now()) + "\n# EOF\n") + #output.close() def main(): @@ -178,46 +209,55 @@ def main(): sweep += 1 -def checkList(output_file): +def checkList(): try: - input_file = open(getDate()+"/checklist", "r") + input_file = log_open(getDate()+"/checklist", "r") except: input_file = None if (input_file != None): for line in input_file: k = line.split("=") - item = k[0].strip(" \r\n") - value = k[1].strip(" \r\n") + item = None + if (len(k) >= 2): + item = k[0].strip("# \r\n") + value = k[1].strip("# \r\n") + if (item in parameters): parameters[item] = value print("Checklist found. Overwrite? [Y/n]") response = sys.stdin.readline().strip(" \r\n") if (response == "" or response == "y" or response == "Y"): + input_file = log_open(getDate()+"/checklist.old", "w") + for item in parameters: + input_file.write("# " + str(item) + " = " + str(parameters[item]) + "\n") + input_file.write("\n") input_file = None if (input_file == None): for item in parameters: + if item == "Parameters last checked": + continue sys.stdout.write("\""+str(item)+"\" = " + str(parameters[item]) + " New value?: ") response = sys.stdin.readline().strip("\r\n ") if (response != ""): parameters[item] = response sys.stdout.write("\n") + parameters["Parameters last checked"] = str(datetime.datetime.now()) - checklist = open(getDate()+"/checklist", "w", 0) + checklist = log_open(getDate()+"/checklist", "w") for item in parameters: checklist.write("# "+str(item) + " = " + str(parameters[item]) + "\n") - output_file.write("# "+str(item) + " = " + str(parameters[item]) + "\n") - + #output_file.write("# "+str(item) + " = " + str(parameters[item]) + "\n") + def record_data(ADC_channels, output, pollTime = None, dac_max = None): if (output != None): - output = [open(output, "w", 0), sys.stdout] - checkList(output[0]) + output = [log_open(output, "w"), sys.stdout] else: output = [sys.stdout] @@ -226,11 +266,11 @@ def record_data(ADC_channels, output, pollTime = None, dac_max = None): out.write("# aquire["+str(field)+"] = "+str(aquire[field]) + "\n") for out in output: - out.write("# Checklist:\n") + out.write("# Parameters:\n") - for field in checklist: + for field in parameters: for out in output: - out.write("# "+str(field)+" = " + str(checklist[field]) + "\n") + out.write("# "+str(field)+" = " + str(parameters[field]) + "\n") start_time = time.time() @@ -271,8 +311,11 @@ def record_data(ADC_channels, output, pollTime = None, dac_max = None): for channel in ADC_channels: read = readADC(channel) if read == False: - print("Abort data collection") - return False + for out in output: + print("# Abort data collection due to failed ADC read") + if out != sys.stdout: + log_close(out) + return False raw_adc.append((channel, read[0], read[1])) end_time = time.time() @@ -287,12 +330,12 @@ def record_data(ADC_channels, output, pollTime = None, dac_max = None): for out in output: if out != sys.stdout: - out.close() + log_close(out) return True def loadCalibration_ADC(channel): try: - input_file = open("calibrateADC"+str(channel)+".dat") + input_file = log_open("calibrateADC"+str(channel)+".dat") except: print("Couldn't find calibration file for ADC " + str(channel)) return False @@ -305,7 +348,7 @@ def loadCalibration_ADC(channel): else: split_line = l.split("\t") calibrate["ADC"][channel].append((float(split_line[0]), float(split_line[1]))) - input_file.close() + log_close(input_file) if (len(calibrate["ADC"][channel]) <= 0): print("Empty calibration file for ADC " + str(channel)) @@ -314,7 +357,7 @@ def loadCalibration_ADC(channel): def loadCalibration_DAC(): try: - input_file = open("calibrateDAC.dat") + input_file = log_open("calibrateDAC.dat") except: print("Couldn't find calibration file for DAC") return False @@ -333,7 +376,7 @@ def loadCalibration_DAC(): calibrate["DAC"].append((int(split_line[0]), float(split_line[1]))) - input_file.close() + log_close(input_file) if (len(calibrate["DAC"]) <= 0): print("Empty calibration file for DAC") @@ -442,7 +485,7 @@ def calibrateADC_usingDAC(channel, gain = True): return False calibrate["ADC"][channel] = [] - outfile = open("calibrateADC"+str(channel)+".dat", "w", 1) + outfile = log_open("calibrateADC"+str(channel)+".dat", "w") outfile.write("# Calibrate ADC " + str(channel) + "\n") outfile.write("# Start " + str(datetime.datetime.now()) + "\n") @@ -481,7 +524,7 @@ def calibrateADC_usingDAC(channel, gain = True): calibrate["ADC"][channel].append((value[0], input_value, value[1])) outfile.write("# Stop " + str(datetime.datetime.now()) + "\n# EOF\n") - outfile.close() + log_close(outfile) if (setDAC(0) == False): return False if (len(calibrate["ADC"][channel]) <= 0): @@ -491,7 +534,7 @@ def calibrateADC_usingDAC(channel, gain = True): def calibrateADC(channel): calibrate["ADC"][channel] = [] - outfile = open("calibrateADC"+str(channel)+".dat", "w", 1) + outfile = log_open("calibrateADC"+str(channel)+".dat", "w") outfile.write("# Calibrate ADC " + str(channel) + "\n") outfile.write("# Start " + str(datetime.datetime.now()) + "\n") @@ -516,7 +559,7 @@ def calibrateADC(channel): outfile.write("# Stop " + str(datetime.datetime.now()) + "\n# EOF\n") - outfile.close() + log_close(outfile) if (len(calibrate["ADC"][channel]) <= 0): print("Error: No calibration points taken for ADC " + str(channel)) return False @@ -526,7 +569,7 @@ def calibrateADC(channel): def calibrateDAC(): calibrate["DAC"] = [] - outfile = open("calibrateDAC.dat", "w", 1) + outfile = log_open("calibrateDAC.dat", "w") outfile.write("# Calibrate DAC\n") outfile.write("# Start " + str(datetime.datetime.now()) + "\n") @@ -568,7 +611,7 @@ def calibrateDAC(): level += stepSize outfile.write("# Stop " + str(datetime.datetime.now()) + "\n# EOF\n") - outfile.close() + log_close(outfile) if (len(calibrate["DAC"]) <= 0): print("Error: No calibration points taken for DAC") return False diff --git a/research/TCS/interface.pyc b/research/TCS/interface.pyc new file mode 100644 index 00000000..d7ce380c Binary files /dev/null and b/research/TCS/interface.pyc differ diff --git a/research/TCS/odict.py b/research/TCS/odict.py new file mode 100644 index 00000000..3bf708a7 --- /dev/null +++ b/research/TCS/odict.py @@ -0,0 +1,328 @@ +# -*- coding: utf-8 -*- +""" + odict + ~~~~~ + + This module is an example implementation of an ordered dict for the + collections module. It's not written for performance (it actually + performs pretty bad) but to show how the API works. + + + Questions and Answers + ===================== + + Why would anyone need ordered dicts? + + Dicts in python are unordered which means that the order of items when + iterating over dicts is undefined. As a matter of fact it is most of + the time useless and differs from implementation to implementation. + + Many developers stumble upon that problem sooner or later when + comparing the output of doctests which often does not match the order + the developer thought it would. + + Also XML systems such as Genshi have their problems with unordered + dicts as the input and output ordering of tag attributes is often + mixed up because the ordering is lost when converting the data into + a dict. Switching to lists is often not possible because the + complexity of a lookup is too high. + + Another very common case is metaprogramming. The default namespace + of a class in python is a dict. With Python 3 it becomes possible + to replace it with a different object which could be an ordered dict. + Django is already doing something similar with a hack that assigns + numbers to some descriptors initialized in the class body of a + specific subclass to restore the ordering after class creation. + + When porting code from programming languages such as PHP and Ruby + where the item-order in a dict is guaranteed it's also a great help + to have an equivalent data structure in Python to ease the transition. + + Where are new keys added? + + At the end. This behavior is consistent with Ruby 1.9 Hashmaps + and PHP Arrays. It also matches what common ordered dict + implementations do currently. + + What happens if an existing key is reassigned? + + The key is *not* moved. This is consitent with existing + implementations and can be changed by a subclass very easily:: + + class movingodict(odict): + def __setitem__(self, key, value): + self.pop(key, None) + odict.__setitem__(self, key, value) + + Moving keys to the end of a ordered dict on reassignment is not + very useful for most applications. + + Does it mean the dict keys are sorted by a sort expression? + + That's not the case. The odict only guarantees that there is an order + and that newly inserted keys are inserted at the end of the dict. If + you want to sort it you can do so, but newly added keys are again added + at the end of the dict. + + I initializes the odict with a dict literal but the keys are not + ordered like they should! + + Dict literals in Python generate dict objects and as such the order of + their items is not guaranteed. Before they are passed to the odict + constructor they are already unordered. + + What happens if keys appear multiple times in the list passed to the + constructor? + + The same as for the dict. The latter item overrides the former. This + has the side-effect that the position of the first key is used because + the key is actually overwritten: + + >>> odict([('a', 1), ('b', 2), ('a', 3)]) + odict.odict([('a', 3), ('b', 2)]) + + This behavor is consistent with existing implementation in Python + and the PHP array and the hashmap in Ruby 1.9. + + This odict doesn't scale! + + Yes it doesn't. The delitem operation is O(n). This is file is a + mockup of a real odict that could be implemented for collections + based on an linked list. + + Why is there no .insert()? + + There are few situations where you really want to insert a key at + an specified index. To now make the API too complex the proposed + solution for this situation is creating a list of items, manipulating + that and converting it back into an odict: + + >>> d = odict([('a', 42), ('b', 23), ('c', 19)]) + >>> l = d.items() + >>> l.insert(1, ('x', 0)) + >>> odict(l) + odict.odict([('a', 42), ('x', 0), ('b', 23), ('c', 19)]) + + :copyright: (c) 2008 by Armin Ronacher and PEP 273 authors. + :license: modified BSD license. +""" +from itertools import izip, imap +from copy import deepcopy + +missing = object() + + +class odict(dict): + """ + Ordered dict example implementation. + + This is the proposed interface for a an ordered dict as proposed on the + Python mailinglist (proposal_). + + It's a dict subclass and provides some list functions. The implementation + of this class is inspired by the implementation of Babel but incorporates + some ideas from the `ordereddict`_ and Django's ordered dict. + + The constructor and `update()` both accept iterables of tuples as well as + mappings: + + >>> d = odict([('a', 'b'), ('c', 'd')]) + >>> d.update({'foo': 'bar'}) + >>> d + odict.odict([('a', 'b'), ('c', 'd'), ('foo', 'bar')]) + + Keep in mind that when updating from dict-literals the order is not + preserved as these dicts are unsorted! + + You can copy an odict like a dict by using the constructor, `copy.copy` + or the `copy` method and make deep copies with `copy.deepcopy`: + + >>> from copy import copy, deepcopy + >>> copy(d) + odict.odict([('a', 'b'), ('c', 'd'), ('foo', 'bar')]) + >>> d.copy() + odict.odict([('a', 'b'), ('c', 'd'), ('foo', 'bar')]) + >>> odict(d) + odict.odict([('a', 'b'), ('c', 'd'), ('foo', 'bar')]) + >>> d['spam'] = [] + >>> d2 = deepcopy(d) + >>> d2['spam'].append('eggs') + >>> d + odict.odict([('a', 'b'), ('c', 'd'), ('foo', 'bar'), ('spam', [])]) + >>> d2 + odict.odict([('a', 'b'), ('c', 'd'), ('foo', 'bar'), ('spam', ['eggs'])]) + + All iteration methods as well as `keys`, `values` and `items` return + the values ordered by the the time the key-value pair is inserted: + + >>> d.keys() + ['a', 'c', 'foo', 'spam'] + >>> d.values() + ['b', 'd', 'bar', []] + >>> d.items() + [('a', 'b'), ('c', 'd'), ('foo', 'bar'), ('spam', [])] + >>> list(d.iterkeys()) + ['a', 'c', 'foo', 'spam'] + >>> list(d.itervalues()) + ['b', 'd', 'bar', []] + >>> list(d.iteritems()) + [('a', 'b'), ('c', 'd'), ('foo', 'bar'), ('spam', [])] + + Index based lookup is supported too by `byindex` which returns the + key/value pair for an index: + + >>> d.byindex(2) + ('foo', 'bar') + + You can reverse the odict as well: + + >>> d.reverse() + >>> d + odict.odict([('spam', []), ('foo', 'bar'), ('c', 'd'), ('a', 'b')]) + + And sort it like a list: + + >>> d.sort(key=lambda x: x[0].lower()) + >>> d + odict.odict([('a', 'b'), ('c', 'd'), ('foo', 'bar'), ('spam', [])]) + + .. _proposal: http://thread.gmane.org/gmane.comp.python.devel/95316 + .. _ordereddict: http://www.xs4all.nl/~anthon/Python/ordereddict/ + """ + + def __init__(self, *args, **kwargs): + dict.__init__(self) + self._keys = [] + self.update(*args, **kwargs) + + def __delitem__(self, key): + dict.__delitem__(self, key) + self._keys.remove(key) + + def __setitem__(self, key, item): + if key not in self: + self._keys.append(key) + dict.__setitem__(self, key, item) + + def __deepcopy__(self, memo=None): + if memo is None: + memo = {} + d = memo.get(id(self), missing) + if d is not missing: + return d + memo[id(self)] = d = self.__class__() + dict.__init__(d, deepcopy(self.items(), memo)) + d._keys = self._keys[:] + return d + + def __getstate__(self): + return {'items': dict(self), 'keys': self._keys} + + def __setstate__(self, d): + self._keys = d['keys'] + dict.update(d['items']) + + def __reversed__(self): + return reversed(self._keys) + + def __eq__(self, other): + if isinstance(other, odict): + if not dict.__eq__(self, other): + return False + return self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self.__eq__(other) + + def __cmp__(self, other): + if isinstance(other, odict): + return cmp(self.items(), other.items()) + elif isinstance(other, dict): + return dict.__cmp__(self, other) + return NotImplemented + + @classmethod + def fromkeys(cls, iterable, default=None): + return cls((key, default) for key in iterable) + + def clear(self): + del self._keys[:] + dict.clear(self) + + def copy(self): + return self.__class__(self) + + def items(self): + return zip(self._keys, self.values()) + + def iteritems(self): + return izip(self._keys, self.itervalues()) + + def keys(self): + return self._keys[:] + + def iterkeys(self): + return iter(self._keys) + + def pop(self, key, default=missing): + if default is missing: + return dict.pop(self, key) + elif key not in self: + return default + self._keys.remove(key) + return dict.pop(self, key, default) + + def popitem(self, key): + self._keys.remove(key) + return dict.popitem(key) + + def setdefault(self, key, default=None): + if key not in self: + self._keys.append(key) + dict.setdefault(self, key, default) + + def update(self, *args, **kwargs): + sources = [] + if len(args) == 1: + if hasattr(args[0], 'iteritems'): + sources.append(args[0].iteritems()) + else: + sources.append(iter(args[0])) + elif args: + raise TypeError('expected at most one positional argument') + if kwargs: + sources.append(kwargs.iteritems()) + for iterable in sources: + for key, val in iterable: + self[key] = val + + def values(self): + return map(self.get, self._keys) + + def itervalues(self): + return imap(self.get, self._keys) + + def index(self, item): + return self._keys.index(item) + + def byindex(self, item): + key = self._keys[item] + return (key, dict.__getitem__(self, key)) + + def reverse(self): + self._keys.reverse() + + def sort(self, *args, **kwargs): + self._keys.sort(*args, **kwargs) + + def __repr__(self): + return 'odict.odict(%r)' % self.items() + + __copy__ = copy + __iter__ = iterkeys + + +if __name__ == '__main__': + import doctest + doctest.testmod() diff --git a/research/TCS/odict.pyc b/research/TCS/odict.pyc new file mode 100644 index 00000000..3ade9ba7 Binary files /dev/null and b/research/TCS/odict.pyc differ