Index: sodar/branches/scintec-branch/sodar/scintec/maindata.py =================================================================== --- sodar/branches/scintec-branch/sodar/scintec/maindata.py (revision 265) +++ sodar/branches/scintec-branch/sodar/scintec/maindata.py (revision 266) @@ -10,4 +10,6 @@ __license__ = 'GPL2' +from datetime import datetime, timedelta + class MainData(list): """ @@ -20,16 +22,4 @@ >>> main_data = MainData(good_mnd) - Parse the format header: - >>> len(main_data._format_header_spec) - 4 - >>> main_data._format_header_spec[0] - 'FORMAT-1' - - Parse the file header after the format header: - >>> len(main_data._file_header_body) - 26 - >>> main_data._file_header_body[1] - '# file information' - Parse the profile data: >>> len(main_data) @@ -39,6 +29,8 @@ >>> len(main_data[0]) 39 - >>> main_data[0].timestamp - '2009-11-17 00:30:00 00:30:00' + >>> main_data[0].start + datetime.datetime(2009, 11, 17, 0, 0) + >>> main_data[0].stop + datetime.datetime(2009, 11, 17, 0, 30) >>> main_data[0].variables ['z', 'speed', 'dir', 'W', 'sigW', 'bck', 'error'] @@ -47,14 +39,32 @@ ... 'error':'0'} True + >>> main_data[0][0].z + '10' + >>> main_data[0]['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + >>> main_data[0]['10'].speed + '99.99' >>> main_data[0][-1] == {'z':'200', 'speed':'99.99', 'dir':'999.9', ... 'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', ... 'error':'0'} True + >>> main_data[0][-1].dir + '999.9' + >>> main_data[0]['200'] == {'z':'200', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', + ... 'error':'0'} + True + >>> main_data[0]['200'].W + '-0.07' Parse the last profile: >>> len(main_data[-1]) 39 - >>> main_data[-1].timestamp - '2009-11-18 00:00:00 00:30:00' + >>> main_data[-1].start + datetime.datetime(2009, 11, 17, 23, 30) + >>> main_data[-1].stop + datetime.datetime(2009, 11, 18, 0, 0) >>> main_data[-1].variables ['z', 'speed', 'dir', 'W', 'sigW', 'bck', 'error'] @@ -99,5 +109,5 @@ """ - super(MainData, self).__init__() + super(self.__class__, self).__init__() self.file_name = '' @@ -113,34 +123,32 @@ # Divide the data into blocks # across boundaries separated by blank lines. - self._blocks = [self._block.strip() - for self._block - in mnd.split('\n\n') - if self._block.strip()] + blocks = [block.strip() + for block + in mnd.split('\n\n') + if block.strip()] # The first block is the specification of the format header. # Divide it into lines. - self._format_header_spec = [self._line.strip() - for self._line - in self._blocks[0].split('\n') - if self._line.strip()] + format_header_spec = [line.strip() + for line + in blocks[0].split('\n') + if line.strip()] # The second block is the body of the format header. # Divide it into lines. - self._file_header_body = [self._line.strip() - for self._line - in self._blocks[1].split('\n') - if self._line.strip()] + file_header_body = [line.strip() + for line + in blocks[1].split('\n') + if line.strip()] # All the remaing blocks are individual profiles # in chronological order. - self.extend([Profile([self._line.strip() - for self._line - in self._block.split('\n') - if self._line.strip()]) - for self._block - in self._blocks[2:]]) - - # No need to haul around bookkeeping storage used for initialization. - del self._blocks, self._block, self._line + self.extend([Profile([line.strip() + for line + in block.split('\n') + if line.strip()]) + for block + in blocks[2:]]) + class Profile(list): @@ -153,16 +161,42 @@ Parse a known good profile block: >>> profile = Profile(good_profile) - >>> profile.timestamp - '2009-11-17 00:30:00 00:30:00' + + Access the timestamp attributes: + >>> profile.start + datetime.datetime(2009, 11, 17, 0, 0) + >>> profile.stop + datetime.datetime(2009, 11, 17, 0, 30) + + Access the variable list: >>> profile.variables ['z', 'speed', 'dir', 'W', 'sigW', 'bck', 'error'] + + Access profiles by sequence number and variables by attribute name: >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', ... 'error':'0'} True + >>> profile[0].z + '10' >>> profile[-1] == {'z':'200', 'speed':'99.99', 'dir':'999.9', ... 'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', ... 'error':'0'} True + >>> profile[-1].speed + '99.99' + + Access profiles by elevation and variables by attribute name: + >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + >>> profile['10'].dir + '999.9' + >>> profile['200'] == {'z':'200', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', + ... 'error':'0'} + True + >>> profile['200'].W + '-0.07' """ @@ -174,28 +208,57 @@ Where: - + profile_block is a list of str objects containing all the lines from a single profile in a Scintec .mnd daily sodar file. - + Parse a known good profile block: >>> profile = Profile(good_profile) - >>> profile.timestamp - '2009-11-17 00:30:00 00:30:00' + + Access the timestamp attributes: + >>> profile.start + datetime.datetime(2009, 11, 17, 0, 0) + >>> profile.stop + datetime.datetime(2009, 11, 17, 0, 30) + + Access the variable list: >>> profile.variables ['z', 'speed', 'dir', 'W', 'sigW', 'bck', 'error'] - >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', - ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', - ... 'error':'0'} - True + + Access profiles by sequence number and variables by attribute name: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + >>> profile[0].z + '10' >>> profile[-1] == {'z':'200', 'speed':'99.99', 'dir':'999.9', ... 'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', ... 'error':'0'} True - """ - - super(Profile, self).__init__() + >>> profile[-1].speed + '99.99' + """ + + super(self.__class__, self).__init__() # The first line in the profile block is the timestamp. - self.timestamp = profile_block[0] + timestamp = profile_block[0] + date, stop, duration = timestamp.split() + date_year, date_month, date_day = date.split('-') + stop_hour, stop_minute, stop_second = stop.split(':') + duration_hour, duration_minute, duration_second = duration.split(':') + interval = timedelta(0, # days + int(duration_second), + 0, # microseconds + 0, # milliseconds + int(duration_minute), + int(duration_hour)) # omit optional weeks + self.stop = datetime(int(date_year), + int(date_month), + int(date_day), + int(stop_hour), + int(stop_minute), # omit optional microseconds + int(stop_second)) # and tzinfo + self.start = self.stop - interval # The second line in the profile block is @@ -206,6 +269,355 @@ # individual obervation columns in the same order # as the variable names. - self.extend([Observation(observation.split(),self.variables) - for observation in profile_block[2:]]) + super(self.__class__, self).extend([Observation(observation.split(), + self.variables) + for observation + in profile_block[2:]]) + + def __getitem__(self,key): + """ + Get a profile by elevation. + + profile_instance[elevation] -> + + Where: + + elevation is a str object object representing the elevation + (value keyed by 'z') of the Observation object. + + Access profiles by elevation and variables by attribute name: + >>> profile = Profile(good_profile) + >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + >>> profile['10'].dir + '999.9' + >>> profile['200'] == {'z':'200', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', + ... 'error':'0'} + True + >>> profile['200'].W + '-0.07' + """ + + try: + return super(self.__class__, self).__getitem__(key) + except TypeError: + for observation in self: + if observation['z'] == key: + return observation + return super(self.__class__, self).__getitem__(key) + + def __setitem__(self,key,value): + """ + Protect items. + + profile_instance[object1] = object2 + + Raise an Exception if attempting to mutate a profile: + >>> profile = Profile(good_profile) + >>> profile[0] = 'OK' + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + >>> profile['10'] = 'OK' + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + >>> profile[100000] = 'OK' + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + >>> profile[100000] + Traceback (most recent call last): + ... + IndexError: list index out of range + >>> profile['100000'] = 'OK' + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + >>> profile['100000'] + Traceback (most recent call last): + ... + TypeError: list indices must be integers + + Without affecting the observation: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) + + def __delitem__(self,key): + """ + Protect items. + + del profile_instance[object] + + Raise an Exception if attempting to mutate a profile: + >>> profile = Profile(good_profile) + >>> del profile[0] + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + >>> del profile['10'] + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + >>> del profile[100000] + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + >>> del profile['100000'] + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + + Without affecting the observation: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) + + def __setslice__(self,i,j,seq): + """ + Protect items. + + profile_instance[i:j] = seq + + Raise an Exception if attempting to mutate a profile: + >>> profile = Profile(good_profile) + >>> profile[0:10] = 'OK' + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + + Without affecting the observations: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) + + def __delslice__(self,i,j): + """ + Protect items. + + del profile_instance[i:j] + + Raise an Exception if attempting to mutate a profile: + >>> profile = Profile(good_profile) + >>> del profile[0:10] + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + + Without affecting the observations: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) + + def append(self,item): + """ + Protect items. + + Raise an Exception if attempting to mutate a profile: + >>> profile = Profile(good_profile) + >>> profile.append('OK') + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + + Without affecting the observations: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) + + def extend(self,seq): + """ + Protect items. + + Raise an Exception if attempting to mutate a profile: + >>> profile = Profile(good_profile) + >>> profile.extend('OK') + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + + Without affecting the observations: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) + + def insert(self,i,item): + """ + Protect items. + + Raise an Exception if attempting to mutate a profile: + >>> profile = Profile(good_profile) + >>> profile.insert(0,'OK') + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + + Without affecting the observations: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) + + def pop(self,*args): + """ + Protect items. + + Raise an Exception if attempting to mutate a profile: + >>> profile = Profile(good_profile) + >>> profile.pop() + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + >>> profile.pop(0) + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + + Without affecting the observations: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + >>> profile[-1] == {'z':'200', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) + + def remove(self,i): + """ + Protect items. + + Raise an Exception if attempting to mutate a profile: + >>> profile = Profile(good_profile) + >>> observation = profile[0] + >>> profile.remove(observation) + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + + Without affecting the observations: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) + + def reverse(self): + """ + Protect items. + + Raise an Exception if attempting to mutate a profile: + >>> profile = Profile(good_profile) + >>> profile.reverse() + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + + Without affecting the observations: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) + + def sort(self,**kwargs): + """ + Protect items. + + Raise an Exception if attempting to mutate a profile: + >>> profile = Profile(good_profile) + >>> profile.sort() + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + >>> profile.sort(cmp=lambda x,y: cmp(x.lower(), y.lower())) + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + >>> profile.sort(cmp=lambda x,y: cmp(x.lower(), y.lower()), + ... key=str.lower) + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + >>> profile.sort(cmp=lambda x,y: cmp(x.lower(), y.lower()), + ... key=str.lower, + ... reverse=True) + Traceback (most recent call last): + ... + TypeError: 'Profile' instance's items are read-only + + + Without affecting the observations: + >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) class Observation(dict): @@ -223,4 +635,6 @@ ... 'error':'0'} True + + Access observation variables as attributes: >>> observation.z '10' @@ -257,4 +671,6 @@ ... 'error':'0'} True + + Raise an Exception if more variable names than values: >>> extra_variables = good_variables + ['extra'] >>> observation = Observation(good_observation,extra_variables) @@ -263,4 +679,6 @@ AttributeError: Same number of attributes and values required in 'Observation' object + + Raise an Exception if more variable values than names: >>> extra_observation = good_observation + ['extra'] >>> observation = Observation(extra_observation,good_variables) @@ -289,4 +707,5 @@ observation_instance.variable_name -> variable_value + Access observation variables as attributes: >>> observation = Observation(good_observation,good_variables) >>> observation.z @@ -304,11 +723,17 @@ >>> observation.error '0' + + Raise an Exception for an undefined attribute: >>> observation.y Traceback (most recent call last): ... AttributeError: 'Observation' object has no attribute 'y' + + Allow the creation and access of attributes other than variables. >>> observation.y = 'OK' >>> observation.y 'OK' + + Without affecting the variables: >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', @@ -332,5 +757,6 @@ But retrieve any other bound attribute values. - + + Raise an Exception if attempting to rebind a variable: >>> observation = Observation(good_observation,good_variables) >>> observation.z = 'OK' @@ -339,7 +765,11 @@ AttributeError: Rebinding attribute 'z' disallowed in 'Observation' object + + However, allow attributes other than variables to be bound: >>> observation.y = 'OK' >>> observation.y 'OK' + + Without affecting the variables: >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', @@ -366,5 +796,6 @@ But delete any other bound attribute values. - + + Raise an Exception if attempting to unbind a variable: >>> observation = Observation(good_observation,good_variables) >>> del observation.z @@ -373,8 +804,12 @@ AttributeError: Unbinding attribute 'z' disallowed in 'Observation' object + + Raise an Exception for attempting to unbind an undefined attribute: >>> del observation.y Traceback (most recent call last): ... AttributeError: 'Observation' object has no attribute 'y' + + However, allow attributes other than variables to be unbound: >>> observation.y = 'OK' >>> del observation.y @@ -383,4 +818,6 @@ ... AttributeError: y + + Without affecting the variables: >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', @@ -406,21 +843,35 @@ observation_instance[variable_name] = variable_value + Raise an Exception if attempting to mutate an observation: >>> observation = Observation(good_observation,good_variables) >>> observation['z'] = 'OK' Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only + TypeError: 'Observation' instance's items are read-only >>> observation['y'] = 'OK' Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only - >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', - ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', - ... 'error':'0'} - True - """ - - raise TypeError, ' '.join([repr(self.__class__.__name__), - 'object\'s items are read-only',]) + TypeError: 'Observation' instance's items are read-only + >>> observation.y + Traceback (most recent call last): + ... + AttributeError: 'Observation' object has no attribute 'y' + >>> observation.y = 'OK' + >>> observation['y'] = 'Not OK' + Traceback (most recent call last): + ... + TypeError: 'Observation' instance's items are read-only + >>> observation.y + 'OK' + + Without affecting the variables: + >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) def __delitem__(self,key): @@ -430,21 +881,25 @@ observation_instance[variable_name] = variable_value + Raise an Exception if attempting to mutate an observation: >>> observation = Observation(good_observation,good_variables) >>> del observation['z'] Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only + TypeError: 'Observation' instance's items are read-only + >>> observation.y = 'OK' >>> del observation['y'] Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only - >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', - ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', - ... 'error':'0'} - True - """ - - raise TypeError, ' '.join([repr(self.__class__.__name__), - 'object\'s items are read-only',]) + TypeError: 'Observation' instance's items are read-only + + Without affecting the variables: + >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) def clear(self): @@ -452,17 +907,20 @@ Protect items. + Raise an Exception if attempting to mutate an observation: >>> observation = Observation(good_observation,good_variables) >>> observation.clear() Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only - >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', - ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', - ... 'error':'0'} - True - """ - - raise TypeError, ' '.join([repr(self.__class__.__name__), - 'object\'s items are read-only',]) + TypeError: 'Observation' instance's items are read-only + + Without affecting the variables: + >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) def pop(self,key,*args): @@ -470,25 +928,28 @@ Protect items. + Raise an Exception if attempting to mutate an observation: >>> observation = Observation(good_observation,good_variables) >>> observation.pop('z') Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only + TypeError: 'Observation' instance's items are read-only >>> observation.pop('y') Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only + TypeError: 'Observation' instance's items are read-only >>> observation.pop('y','OK') Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only - >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', - ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', - ... 'error':'0'} - True - """ - - raise TypeError, ' '.join([repr(self.__class__.__name__), - 'object\'s items are read-only',]) + TypeError: 'Observation' instance's items are read-only + + Without affecting the variables: + >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) def popitem(self): @@ -496,17 +957,20 @@ Protect items. + Raise an Exception if attempting to mutate an observation: >>> observation = Observation(good_observation,good_variables) >>> observation.popitem() Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only - >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', - ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', - ... 'error':'0'} - True - """ - - raise TypeError, ' '.join([repr(self.__class__.__name__), - 'object\'s items are read-only',]) + TypeError: 'Observation' instance's items are read-only + + Without affecting the variables: + >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) def setdefault(self,key,*args): @@ -514,25 +978,28 @@ Protect items. + Raise an Exception if attempting to mutate an observation: >>> observation = Observation(good_observation,good_variables) >>> observation.setdefault('z') Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only + TypeError: 'Observation' instance's items are read-only >>> observation.setdefault('y') Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only + TypeError: 'Observation' instance's items are read-only >>> observation.setdefault('y','OK') Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only - >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', - ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', - ... 'error':'0'} - True - """ - - raise TypeError, ' '.join([repr(self.__class__.__name__), - 'object\'s items are read-only',]) + TypeError: 'Observation' instance's items are read-only + + Without affecting the variables: + >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) def update(self,*args,**kwargs): @@ -540,33 +1007,44 @@ Protect items. + Raise an Exception if attempting to mutate an observation: >>> observation = Observation(good_observation,good_variables) >>> observation.update({'UP':'up','DOWN':'down',}) Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only - >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', - ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', - ... 'error':'0'} - True + TypeError: 'Observation' instance's items are read-only + + Without affecting the variables: + >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + + Raise an Exception if attempting to mutate an observation: >>> observation.update((('UP','up'),('DOWN','down'),)) Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only - >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', - ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', - ... 'error':'0'} - True + TypeError: 'Observation' instance's items are read-only + + Without affecting the variables: + >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + + Raise an Exception if attempting to mutate an observation: >>> observation.update(UP='up',DOWN='down') Traceback (most recent call last): ... - TypeError: 'Observation' object's items are read-only - >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', - ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', - ... 'error':'0'} - True - """ - - raise TypeError, ' '.join([repr(self.__class__.__name__), - 'object\'s items are read-only',]) + TypeError: 'Observation' instance's items are read-only + + Without affecting the variables: + >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', + ... 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', + ... 'error':'0'} + True + """ + + raise TypeError, ' '.join([repr(self.__class__.__name__), + 'instance\'s items are read-only',]) def _test():