NCCOOS Trac Projects: Top | Web | Platforms | Processing | Viz | Sprints | Sandbox | (Wind)

Changeset 269

Show
Ignore:
Timestamp:
12/03/09 19:04:51
Author:
cbc
Message:

Refactor to simplify (no more read only nonsense).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • sodar/branches/scintec-branch/sodar/scintec/maindata.py

    r268 r269  
    3939    ...                     'error':'0'} 
    4040    True 
    41     >>> main_data[0][0].z 
    42     '10' 
    43     >>> main_data[0]['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    44     ...                     'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    45     ...                     'error':'0'} 
    46     True 
    47     >>> main_data[0]['10'].speed 
    48     '99.99' 
     41    >>> main_data[0](10) == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
     42    ...                      'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
     43    ...                      'error':'0'} 
     44    True 
    4945    >>> main_data[0][-1] == {'z':'200', 'speed':'99.99', 'dir':'999.9', 
    5046    ...                      'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', 
    5147    ...                      'error':'0'} 
    5248    True 
    53     >>> main_data[0][-1].dir 
    54     '999.9' 
    55     >>> main_data[0]['200'] == {'z':'200', 'speed':'99.99', 'dir':'999.9', 
    56     ...                         'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', 
    57     ...                         'error':'0'} 
    58     True 
    59     >>> main_data[0]['200'].W 
    60     '-0.07' 
     49    >>> main_data[0](200) == {'z':'200', 'speed':'99.99', 'dir':'999.9', 
     50    ...                       'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', 
     51    ...                       'error':'0'} 
     52    True 
     53    >>> main_data(datetime(2009, 11, 17, 0, 30)).stop 
     54    datetime.datetime(2009, 11, 17, 0, 30) 
     55    >>> main_data(datetime(2009, 11, 17, 0, 0),True).start 
     56    datetime.datetime(2009, 11, 17, 0, 0) 
    6157     
    6258    Parse the last profile: 
     
    7066    ['z', 'speed', 'dir', 'W', 'sigW', 'bck', 'error'] 
    7167    >>> main_data[-1][0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    72     ...                     'W':'-0.32', 'sigW':'99.99', 'bck':'9.99E+37', 
    73     ...                     'error':'0'} 
    74     True 
    75     >>> main_data[-1][0].z 
    76     '10' 
    77     >>> main_data[-1]['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    78     ...                         'W':'-0.32', 'sigW':'99.99', 'bck':'9.99E+37', 
    79     ...                         'error':'0'} 
    80     True 
    81     >>> main_data[-1]['10'].speed 
    82     '99.99' 
     68    ...                      'W':'-0.32', 'sigW':'99.99', 'bck':'9.99E+37', 
     69    ...                      'error':'0'} 
     70    True 
     71    >>> main_data[-1](10) == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
     72    ...                       'W':'-0.32', 'sigW':'99.99', 'bck':'9.99E+37', 
     73    ...                       'error':'0'} 
     74    True 
    8375    >>> main_data[-1][-1] == {'z':'200', 'speed':'15.05', 'dir':'71.8', 
    84     ...                      'W':'-0.19', 'sigW':'0.53', 'bck':'9.99E+37', 
    85     ...                      'error':'0'} 
    86     True 
    87     >>> main_data[-1][-1].dir 
    88     '71.8' 
    89     >>> main_data[-1]['200'] == {'z':'200', 'speed':'15.05', 'dir':'71.8', 
    90     ...                          'W':'-0.19', 'sigW':'0.53', 'bck':'9.99E+37', 
    91     ...                          'error':'0'} 
    92     True 
    93     >>> main_data[-1]['200'].W 
    94     '-0.19' 
     76    ...                      'W':'-0.19', 'sigW':'0.53', 'bck':'9.99E+37', 
     77    ...                      'error':'0'} 
     78    True 
     79    >>> main_data[-1](200) == {'z':'200', 'speed':'15.05', 'dir':'71.8', 
     80    ...                        'W':'-0.19', 'sigW':'0.53', 'bck':'9.99E+37', 
     81    ...                        'error':'0'} 
     82    True 
     83    >>> main_data(datetime(2009, 11, 18, 0, 0)).stop 
     84    datetime.datetime(2009, 11, 18, 0, 0) 
     85    >>> main_data(datetime(2009, 11, 17, 23, 0),True).start 
     86    datetime.datetime(2009, 11, 17, 23, 0) 
    9587    """ 
    9688     
     
    171163        Get a profile by timestamp 
    172164         
    173         maindata_instance(timestamp[,start]) -> <Profile object> 
     165        MainData_instance(timestamp[,start]) -> <Profile object> 
    174166         
    175167        Where: 
     
    196188        Traceback (most recent call last): 
    197189            ... 
    198         IndexError: 'MainData' object index out of range 
     190        ValueError: Timestamp datetime.datetime(2009, 11, 16, 0, 30) 
     191        not found in 'MainData' object 
    199192        >>> main_data('OK') 
    200193        Traceback (most recent call last): 
    201194            ... 
    202         TypeError: 'MainData' object indices must be datetime.datetime 
    203         instances 
     195        ValueError: Timestamp 'OK' not found in 'MainData' object 
    204196        """ 
    205197         
     
    211203            if boundary == timestamp: 
    212204                return profile 
    213         if isinstance(timestamp,datetime): 
    214             raise IndexError, ' '.join([repr(self.__class__.__name__), 
    215                                         'object index out of range',]) 
    216         else: 
    217             raise TypeError, ' '.join([repr(self.__class__.__name__), 
    218                                        'object indices must be', 
    219                                        'datetime.datetime instances',]) 
     205        raise ValueError, ' '.join(['Timestamp', 
     206                                    repr(timestamp), 
     207                                    'not found in', 
     208                                    repr(self.__class__.__name__), 
     209                                    'object']) 
    220210 
    221211class Profile(list): 
     
    239229    ['z', 'speed', 'dir', 'W', 'sigW', 'bck', 'error'] 
    240230     
    241     Access observations by sequence number and variables by attribute name
     231    Access observations by sequence number
    242232    >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    243233    ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    244234    ...                'error':'0'} 
    245235    True 
    246     >>> profile[0].z 
    247     '10' 
    248236    >>> profile[-1] == {'z':'200', 'speed':'99.99', 'dir':'999.9', 
    249237    ...                 'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', 
    250238    ...                 'error':'0'} 
    251239    True 
    252     >>> profile[-1].speed 
    253     '99.99' 
    254      
    255     Access observations by elevation and variables by attribute name: 
    256     >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    257     ...                   'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    258     ...                   'error':'0'} 
    259     True 
    260     >>> profile['10'].dir 
    261     '999.9' 
    262     >>> profile['200'] == {'z':'200', 'speed':'99.99', 'dir':'999.9', 
    263     ...                    'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', 
    264     ...                    'error':'0'} 
    265     True 
    266     >>> profile['200'].W 
    267     '-0.07' 
     240     
     241    Access observations by elevation: 
     242    >>> profile(10) == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
     243    ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
     244    ...                 'error':'0'} 
     245    True 
     246    >>> profile(200) == {'z':'200', 'speed':'99.99', 'dir':'999.9', 
     247    ...                  'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', 
     248    ...                  'error':'0'} 
     249    True 
    268250    """ 
    269251     
     
    292274        ['z', 'speed', 'dir', 'W', 'sigW', 'bck', 'error'] 
    293275         
    294         Access observations by sequence number and variables by attribute name
     276        Access observations by sequence number
    295277        >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    296278        ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    297279        ...                'error':'0'} 
    298280        True 
    299         >>> profile[0].z 
    300         '10' 
    301281        >>> profile[-1] == {'z':'200', 'speed':'99.99', 'dir':'999.9', 
    302282        ...                 'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', 
    303283        ...                 'error':'0'} 
    304284        True 
    305         >>> profile[-1].speed 
    306         '99.99' 
     285        >>> profile[100000] 
     286        Traceback (most recent call last): 
     287            ... 
     288        IndexError: list index out of range 
    307289        """ 
    308290         
     
    341323                                            in profile_block[2:]]) 
    342324     
    343     def __getitem__(self,key): 
    344         """ 
    345         Get a observation by elevation. 
    346          
    347         profile_instance[elevation] -> <Observation object> 
     325    def __call__(self,elevation): 
     326        """ 
     327        Get an observation by elevation. 
     328         
     329        Profile_instance(elevation) -> <Observation object> 
    348330         
    349331        Where: 
    350332         
    351             elevation is a str object object representing the elevation 
     333            elevation is a numeric or str object representing the elevation 
    352334            (value keyed by 'z') of the Observation object. 
    353335         
    354         Access observations by elevation and variables by attribute name
     336        Access observations by elevation
    355337        >>> profile = Profile(good_profile) 
    356         >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
     338        >>> profile(10) == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
     339        ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
     340        ...                 'error':'0'} 
     341        True 
     342        >>> profile(200) == {'z':'200', 'speed':'99.99', 'dir':'999.9', 
     343        ...                  'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', 
     344        ...                  'error':'0'} 
     345        True 
     346        >>> profile(100000) 
     347        Traceback (most recent call last): 
     348            ... 
     349        ValueError: Elevation 100000 not found in 'Profile' object 
     350        >>> profile('10') == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    357351        ...                   'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    358352        ...                   'error':'0'} 
    359353        True 
    360         >>> profile['10'].dir 
    361         '999.9' 
    362         >>> profile['200'] == {'z':'200', 'speed':'99.99', 'dir':'999.9', 
     354        >>> profile('200') == {'z':'200', 'speed':'99.99', 'dir':'999.9', 
    363355        ...                    'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', 
    364356        ...                    'error':'0'} 
    365357        True 
    366         >>> profile['200'].W 
    367         '-0.07' 
    368         >>> profile[100000] 
    369         Traceback (most recent call last): 
    370             ... 
    371         IndexError: list index out of range 
    372         >>> profile['100000'] 
    373         Traceback (most recent call last): 
    374             ... 
    375         TypeError: list indices must be integers 
    376         """ 
    377          
    378         try: 
    379             return super(self.__class__, self).__getitem__(key) 
    380         except TypeError: 
    381             for observation in self: 
    382                 if observation['z'] == key: 
    383                     return observation 
    384             return super(self.__class__, self).__getitem__(key) 
    385      
    386     def __setitem__(self,key,value): 
    387         """ 
    388         Protect items. 
    389          
    390         profile_instance[object1] = object2 
    391          
    392         Raise an Exception if attempting to mutate a profile: 
    393         >>> profile = Profile(good_profile) 
    394         >>> profile[0] = 'OK' 
    395         Traceback (most recent call last): 
    396             ... 
    397         TypeError: 'Profile' instance's items are read-only 
    398         >>> profile['10'] = 'OK' 
    399         Traceback (most recent call last): 
    400             ... 
    401         TypeError: 'Profile' instance's items are read-only 
    402         >>> profile[100000] = 'OK' 
    403         Traceback (most recent call last): 
    404             ... 
    405         TypeError: 'Profile' instance's items are read-only 
    406         >>> profile[100000] 
    407         Traceback (most recent call last): 
    408             ... 
    409         IndexError: list index out of range 
    410         >>> profile['100000'] = 'OK' 
    411         Traceback (most recent call last): 
    412             ... 
    413         TypeError: 'Profile' instance's items are read-only 
    414         >>> profile['100000'] 
    415         Traceback (most recent call last): 
    416             ... 
    417         TypeError: list indices must be integers 
    418          
    419         Without affecting the observation: 
    420         >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    421         ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    422         ...                'error':'0'} 
    423         True 
    424         >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    425         ...                   'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    426         ...                   'error':'0'} 
    427         True 
    428         """ 
    429          
    430         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    431                                    'instance\'s items are read-only',]) 
    432      
    433     def __delitem__(self,key): 
    434         """ 
    435         Protect items. 
    436          
    437         del profile_instance[object] 
    438          
    439         Raise an Exception if attempting to mutate a profile: 
    440         >>> profile = Profile(good_profile) 
    441         >>> del profile[0] 
    442         Traceback (most recent call last): 
    443             ... 
    444         TypeError: 'Profile' instance's items are read-only 
    445         >>> del profile['10'] 
    446         Traceback (most recent call last): 
    447             ... 
    448         TypeError: 'Profile' instance's items are read-only 
    449         >>> del profile[100000] 
    450         Traceback (most recent call last): 
    451             ... 
    452         TypeError: 'Profile' instance's items are read-only 
    453         >>> del profile['100000'] 
    454         Traceback (most recent call last): 
    455             ... 
    456         TypeError: 'Profile' instance's items are read-only 
    457          
    458         Without affecting the observation: 
    459         >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    460         ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    461         ...                'error':'0'} 
    462         True 
    463         >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    464         ...                   'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    465         ...                   'error':'0'} 
    466         True 
    467         """ 
    468          
    469         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    470                                    'instance\'s items are read-only',]) 
    471      
    472     def __setslice__(self,i,j,seq): 
    473         """ 
    474         Protect items. 
    475          
    476         profile_instance[i:j] = seq 
    477          
    478         Raise an Exception if attempting to mutate a profile: 
    479         >>> profile = Profile(good_profile) 
    480         >>> profile[0:10] = 'OK' 
    481         Traceback (most recent call last): 
    482             ... 
    483         TypeError: 'Profile' instance's items are read-only 
    484          
    485         Without affecting the observations: 
    486         >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    487         ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    488         ...                'error':'0'} 
    489         True 
    490         >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    491         ...                   'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    492         ...                   'error':'0'} 
    493         True 
    494         """ 
    495          
    496         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    497                                    'instance\'s items are read-only',]) 
    498      
    499     def __delslice__(self,i,j): 
    500         """ 
    501         Protect items. 
    502          
    503         del profile_instance[i:j] 
    504          
    505         Raise an Exception if attempting to mutate a profile: 
    506         >>> profile = Profile(good_profile) 
    507         >>> del profile[0:10] 
    508         Traceback (most recent call last): 
    509             ... 
    510         TypeError: 'Profile' instance's items are read-only 
    511          
    512         Without affecting the observations: 
    513         >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    514         ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    515         ...                'error':'0'} 
    516         True 
    517         >>> profile['10'] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    518         ...                   'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    519         ...                   'error':'0'} 
    520         True 
    521         """ 
    522          
    523         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    524                                    'instance\'s items are read-only',]) 
    525      
    526     def append(self,item): 
    527         """ 
    528         Protect items. 
    529          
    530         Raise an Exception if attempting to mutate a profile: 
    531         >>> profile = Profile(good_profile) 
    532         >>> profile.append('OK') 
    533         Traceback (most recent call last): 
    534             ... 
    535         TypeError: 'Profile' instance's items are read-only 
    536          
    537         Without affecting the observations: 
    538         >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    539         ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    540         ...                'error':'0'} 
    541         True 
    542         """ 
    543          
    544         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    545                                    'instance\'s items are read-only',]) 
    546      
    547     def extend(self,seq): 
    548         """ 
    549         Protect items. 
    550          
    551         Raise an Exception if attempting to mutate a profile: 
    552         >>> profile = Profile(good_profile) 
    553         >>> profile.extend('OK') 
    554         Traceback (most recent call last): 
    555             ... 
    556         TypeError: 'Profile' instance's items are read-only 
    557          
    558         Without affecting the observations: 
    559         >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    560         ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    561         ...                'error':'0'} 
    562         True 
    563         """ 
    564          
    565         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    566                                    'instance\'s items are read-only',]) 
    567      
    568     def insert(self,i,item): 
    569         """ 
    570         Protect items. 
    571          
    572         Raise an Exception if attempting to mutate a profile: 
    573         >>> profile = Profile(good_profile) 
    574         >>> profile.insert(0,'OK') 
    575         Traceback (most recent call last): 
    576             ... 
    577         TypeError: 'Profile' instance's items are read-only 
    578          
    579         Without affecting the observations: 
    580         >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    581         ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    582         ...                'error':'0'} 
    583         True 
    584         """ 
    585          
    586         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    587                                    'instance\'s items are read-only',]) 
    588      
    589     def pop(self,*args): 
    590         """ 
    591         Protect items. 
    592          
    593         Raise an Exception if attempting to mutate a profile: 
    594         >>> profile = Profile(good_profile) 
    595         >>> profile.pop() 
    596         Traceback (most recent call last): 
    597             ... 
    598         TypeError: 'Profile' instance's items are read-only 
    599         >>> profile.pop(0) 
    600         Traceback (most recent call last): 
    601             ... 
    602         TypeError: 'Profile' instance's items are read-only 
    603          
    604         Without affecting the observations: 
    605         >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    606         ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    607         ...                'error':'0'} 
    608         True 
    609         >>> profile[-1] == {'z':'200', 'speed':'99.99', 'dir':'999.9', 
    610         ...                 'W':'-0.07', 'sigW':'99.99', 'bck':'9.99E+37', 
    611         ...                 'error':'0'} 
    612         True 
    613         """ 
    614          
    615         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    616                                    'instance\'s items are read-only',]) 
    617      
    618     def remove(self,i): 
    619         """ 
    620         Protect items. 
    621          
    622         Raise an Exception if attempting to mutate a profile: 
    623         >>> profile = Profile(good_profile) 
    624         >>> observation = profile[0] 
    625         >>> profile.remove(observation) 
    626         Traceback (most recent call last): 
    627             ... 
    628         TypeError: 'Profile' instance's items are read-only 
    629          
    630         Without affecting the observations: 
    631         >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    632         ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    633         ...                'error':'0'} 
    634         True 
    635         """ 
    636          
    637         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    638                                    'instance\'s items are read-only',]) 
    639      
    640     def reverse(self): 
    641         """ 
    642         Protect items. 
    643          
    644         Raise an Exception if attempting to mutate a profile: 
    645         >>> profile = Profile(good_profile) 
    646         >>> profile.reverse() 
    647         Traceback (most recent call last): 
    648             ... 
    649         TypeError: 'Profile' instance's items are read-only 
    650          
    651         Without affecting the observations: 
    652         >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    653         ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    654         ...                'error':'0'} 
    655         True 
    656         """ 
    657          
    658         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    659                                    'instance\'s items are read-only',]) 
    660      
    661     def sort(self,**kwargs): 
    662         """ 
    663         Protect items. 
    664          
    665         Raise an Exception if attempting to mutate a profile: 
    666         >>> profile = Profile(good_profile) 
    667         >>> profile.sort() 
    668         Traceback (most recent call last): 
    669             ... 
    670         TypeError: 'Profile' instance's items are read-only 
    671         >>> profile.sort(cmp=lambda x,y: cmp(x.lower(), y.lower())) 
    672         Traceback (most recent call last): 
    673             ... 
    674         TypeError: 'Profile' instance's items are read-only 
    675         >>> profile.sort(cmp=lambda x,y: cmp(x.lower(), y.lower()), 
    676         ...              key=str.lower) 
    677         Traceback (most recent call last): 
    678             ... 
    679         TypeError: 'Profile' instance's items are read-only 
    680         >>> profile.sort(cmp=lambda x,y: cmp(x.lower(), y.lower()), 
    681         ...              key=str.lower, 
    682         ...              reverse=True) 
    683         Traceback (most recent call last): 
    684             ... 
    685         TypeError: 'Profile' instance's items are read-only 
    686          
    687         Without affecting the observations: 
    688         >>> profile[0] == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    689         ...                'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    690         ...                'error':'0'} 
    691         True 
    692         """ 
    693          
    694         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    695                                    'instance\'s items are read-only',]) 
     358        >>> profile('100000') 
     359        Traceback (most recent call last): 
     360            ... 
     361        ValueError: Elevation '100000' not found in 'Profile' object 
     362        """ 
     363         
     364        for observation in self: 
     365            if observation['z'] == str(int(elevation)): 
     366                return observation 
     367        raise ValueError, ' '.join(['Elevation', 
     368                                    repr(elevation), 
     369                                    'not found in', 
     370                                    repr(self.__class__.__name__), 
     371                                    'object']) 
    696372 
    697373class Observation(dict): 
     
    709385    ...                 'error':'0'} 
    710386    True 
    711      
    712     Access observation variables as attributes: 
    713     >>> observation.z 
    714     '10' 
    715     >>> observation.speed 
    716     '99.99' 
    717     >>> observation.dir 
    718     '999.9' 
    719     >>> observation.W 
    720     '-0.05' 
    721     >>> observation.sigW 
    722     '0.40' 
    723     >>> observation.bck 
    724     '5.46E+03' 
    725     >>> observation.error 
    726     '0' 
    727387    """ 
    728388     
     
    737397            data is a list of str object representing variable values, 
    738398             
    739             variables is a list of str objects representing variable labels. 
     399            variables is a list of str objects representing variable names. 
    740400         
    741401        Parse a known good observation: 
     
    751411        Traceback (most recent call last): 
    752412            ... 
    753         AttributeError: Same number of attributes and values required in 
     413        ValueError: Same number of variable names and values required in 
    754414        'Observation' object 
    755415         
     
    759419        Traceback (most recent call last): 
    760420            ... 
    761         AttributeError: Same number of attributes and values required in 
     421        ValueError: Same number of variable names and values required in 
    762422        'Observation' object 
    763423        """ 
     
    770430        else: 
    771431            # Unless there are an unequal number of variable names/values. 
    772             raise AttributeError, ' '.join(['Same number of attributes', 
    773                                             'and values required in', 
    774                                             repr(self.__class__.__name__), 
    775                                             'object',]) 
    776      
    777     def __getattr__(self,name): 
    778         """ 
    779         Get a variable value by name. 
    780          
    781         observation_instance.variable_name -> variable_value 
    782          
    783         Access observation variables as attributes: 
    784         >>> observation = Observation(good_observation,good_variables) 
    785         >>> observation.z 
    786         '10' 
    787         >>> observation.speed 
    788         '99.99' 
    789         >>> observation.dir 
    790         '999.9' 
    791         >>> observation.W 
    792         '-0.05' 
    793         >>> observation.sigW 
    794         '0.40' 
    795         >>> observation.bck 
    796         '5.46E+03' 
    797         >>> observation.error 
    798         '0' 
    799          
    800         Raise an Exception for an undefined attribute: 
    801         >>> observation.y 
    802         Traceback (most recent call last): 
    803             ... 
    804         AttributeError: 'Observation' object has no attribute 'y' 
    805          
    806         Allow the creation and access of attributes other than variables. 
    807         >>> observation.y = 'OK' 
    808         >>> observation.y 
    809         'OK' 
    810          
    811         Without affecting the variables: 
    812         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    813         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    814         ...                 'error':'0'} 
    815         True 
    816         """ 
    817          
    818         # Attempt attribute access by dictionary key. 
    819         if name in self: 
    820             return self[name] 
    821         else: 
    822             raise AttributeError, ' '.join([repr(self.__class__.__name__), 
    823                                             'object has no attribute', 
    824                                             repr(name),]) 
    825      
    826     def __setattr__(self,name,value): 
    827         """ 
    828         Protect variable values from overwriting. 
    829          
    830         observation_instance.variable_name = variable_value 
    831          
    832         But retrieve any other bound attribute values. 
    833          
    834         Raise an Exception if attempting to rebind a variable: 
    835         >>> observation = Observation(good_observation,good_variables) 
    836         >>> observation.z = 'OK' 
    837         Traceback (most recent call last): 
    838             ... 
    839         AttributeError: Rebinding attribute 'z' disallowed in 
    840         'Observation' object 
    841          
    842         However, allow attributes other than variables to be bound: 
    843         >>> observation.y = 'OK' 
    844         >>> observation.y 
    845         'OK' 
    846          
    847         Without affecting the variables: 
    848         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    849         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    850         ...                 'error':'0'} 
    851         True 
    852         """ 
    853          
    854         if name in self: 
    855             # Protect observation variables 
    856             raise AttributeError, ' '.join(['Rebinding attribute', 
    857                                             repr(name), 
    858                                             'disallowed in', 
    859                                             repr(self.__class__.__name__), 
    860                                             'object',]) 
    861         else: 
    862             # Otherwise, do it the normal way. 
    863             super(self.__class__, self).__setattr__(name,value) 
    864      
    865     def __delattr__(self,name): 
    866         """ 
    867         Protect variable values from deletion. 
    868          
    869         del observation_instance.variable_name 
    870          
    871         But delete any other bound attribute values. 
    872          
    873         Raise an Exception if attempting to unbind a variable: 
    874         >>> observation = Observation(good_observation,good_variables) 
    875         >>> del observation.z 
    876         Traceback (most recent call last): 
    877             ... 
    878         AttributeError: Unbinding attribute 'z' disallowed in 
    879         'Observation' object 
    880          
    881         Raise an Exception for attempting to unbind an undefined attribute: 
    882         >>> del observation.y 
    883         Traceback (most recent call last): 
    884             ... 
    885         AttributeError: 'Observation' object has no attribute 'y' 
    886          
    887         However, allow attributes other than variables to be unbound: 
    888         >>> observation.y = 'OK' 
    889         >>> del observation.y 
    890         >>> del observation.y 
    891         Traceback (most recent call last): 
    892             ... 
    893         AttributeError: y 
    894          
    895         Without affecting the variables: 
    896         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    897         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    898         ...                 'error':'0'} 
    899         True 
    900         """ 
    901          
    902         if name in self: 
    903             # Protect observation variables 
    904             raise AttributeError, ' '.join(['Unbinding attribute', 
    905                                             repr(name), 
    906                                             'disallowed in', 
    907                                             repr(self.__class__.__name__), 
    908                                             'object',]) 
    909         else: 
    910             # Otherwise, do it the normal way. 
    911             super(self.__class__, self).__delattr__(name) 
    912      
    913     def __setitem__(self,key,value): 
    914         """ 
    915         Protect items. 
    916          
    917         observation_instance[variable_name] = variable_value 
    918          
    919         Raise an Exception if attempting to mutate an observation: 
    920         >>> observation = Observation(good_observation,good_variables) 
    921         >>> observation['z'] = 'OK' 
    922         Traceback (most recent call last): 
    923             ... 
    924         TypeError: 'Observation' instance's items are read-only 
    925         >>> observation['y'] = 'OK' 
    926         Traceback (most recent call last): 
    927             ... 
    928         TypeError: 'Observation' instance's items are read-only 
    929         >>> observation.y 
    930         Traceback (most recent call last): 
    931             ... 
    932         AttributeError: 'Observation' object has no attribute 'y' 
    933         >>> observation.y = 'OK' 
    934         >>> observation['y'] = 'Not OK' 
    935         Traceback (most recent call last): 
    936             ... 
    937         TypeError: 'Observation' instance's items are read-only 
    938         >>> observation.y 
    939         'OK' 
    940          
    941         Without affecting the variables: 
    942         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    943         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    944         ...                 'error':'0'} 
    945         True 
    946         """ 
    947          
    948         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    949                                    'instance\'s items are read-only',]) 
    950      
    951     def __delitem__(self,key): 
    952         """ 
    953         Protect items. 
    954          
    955         observation_instance[variable_name] = variable_value 
    956          
    957         Raise an Exception if attempting to mutate an observation: 
    958         >>> observation = Observation(good_observation,good_variables) 
    959         >>> del observation['z'] 
    960         Traceback (most recent call last): 
    961             ... 
    962         TypeError: 'Observation' instance's items are read-only 
    963         >>> observation.y = 'OK' 
    964         >>> del observation['y'] 
    965         Traceback (most recent call last): 
    966             ... 
    967         TypeError: 'Observation' instance's items are read-only 
    968          
    969         Without affecting the variables: 
    970         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    971         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    972         ...                 'error':'0'} 
    973         True 
    974         """ 
    975          
    976         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    977                                    'instance\'s items are read-only',]) 
    978      
    979     def clear(self): 
    980         """ 
    981         Protect items. 
    982          
    983         Raise an Exception if attempting to mutate an observation: 
    984         >>> observation = Observation(good_observation,good_variables) 
    985         >>> observation.clear() 
    986         Traceback (most recent call last): 
    987             ... 
    988         TypeError: 'Observation' instance's items are read-only 
    989          
    990         Without affecting the variables: 
    991         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    992         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    993         ...                 'error':'0'} 
    994         True 
    995         """ 
    996          
    997         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    998                                    'instance\'s items are read-only',]) 
    999      
    1000     def pop(self,key,*args): 
    1001         """ 
    1002         Protect items. 
    1003          
    1004         Raise an Exception if attempting to mutate an observation: 
    1005         >>> observation = Observation(good_observation,good_variables) 
    1006         >>> observation.pop('z') 
    1007         Traceback (most recent call last): 
    1008             ... 
    1009         TypeError: 'Observation' instance's items are read-only 
    1010         >>> observation.pop('y') 
    1011         Traceback (most recent call last): 
    1012             ... 
    1013         TypeError: 'Observation' instance's items are read-only 
    1014         >>> observation.pop('y','OK') 
    1015         Traceback (most recent call last): 
    1016             ... 
    1017         TypeError: 'Observation' instance's items are read-only 
    1018          
    1019         Without affecting the variables: 
    1020         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    1021         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    1022         ...                 'error':'0'} 
    1023         True 
    1024         """ 
    1025          
    1026         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    1027                                    'instance\'s items are read-only',]) 
    1028      
    1029     def popitem(self): 
    1030         """ 
    1031         Protect items. 
    1032          
    1033         Raise an Exception if attempting to mutate an observation: 
    1034         >>> observation = Observation(good_observation,good_variables) 
    1035         >>> observation.popitem() 
    1036         Traceback (most recent call last): 
    1037             ... 
    1038         TypeError: 'Observation' instance's items are read-only 
    1039          
    1040         Without affecting the variables: 
    1041         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    1042         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    1043         ...                 'error':'0'} 
    1044         True 
    1045         """ 
    1046          
    1047         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    1048                                    'instance\'s items are read-only',]) 
    1049      
    1050     def setdefault(self,key,*args): 
    1051         """ 
    1052         Protect items. 
    1053          
    1054         Raise an Exception if attempting to mutate an observation: 
    1055         >>> observation = Observation(good_observation,good_variables) 
    1056         >>> observation.setdefault('z') 
    1057         Traceback (most recent call last): 
    1058             ... 
    1059         TypeError: 'Observation' instance's items are read-only 
    1060         >>> observation.setdefault('y') 
    1061         Traceback (most recent call last): 
    1062             ... 
    1063         TypeError: 'Observation' instance's items are read-only 
    1064         >>> observation.setdefault('y','OK') 
    1065         Traceback (most recent call last): 
    1066             ... 
    1067         TypeError: 'Observation' instance's items are read-only 
    1068          
    1069         Without affecting the variables: 
    1070         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    1071         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    1072         ...                 'error':'0'} 
    1073         True 
    1074         """ 
    1075          
    1076         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    1077                                    'instance\'s items are read-only',]) 
    1078      
    1079     def update(self,*args,**kwargs): 
    1080         """ 
    1081         Protect items. 
    1082          
    1083         Raise an Exception if attempting to mutate an observation: 
    1084         >>> observation = Observation(good_observation,good_variables) 
    1085         >>> observation.update({'UP':'up','DOWN':'down',}) 
    1086         Traceback (most recent call last): 
    1087             ... 
    1088         TypeError: 'Observation' instance's items are read-only 
    1089          
    1090         Without affecting the variables: 
    1091         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    1092         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    1093         ...                 'error':'0'} 
    1094         True 
    1095          
    1096         Raise an Exception if attempting to mutate an observation: 
    1097         >>> observation.update((('UP','up'),('DOWN','down'),)) 
    1098         Traceback (most recent call last): 
    1099             ... 
    1100         TypeError: 'Observation' instance's items are read-only 
    1101  
    1102         Without affecting the variables: 
    1103         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    1104         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    1105         ...                 'error':'0'} 
    1106         True 
    1107          
    1108         Raise an Exception if attempting to mutate an observation: 
    1109         >>> observation.update(UP='up',DOWN='down') 
    1110         Traceback (most recent call last): 
    1111             ... 
    1112         TypeError: 'Observation' instance's items are read-only 
    1113          
    1114         Without affecting the variables: 
    1115         >>> observation == {'z':'10', 'speed':'99.99', 'dir':'999.9', 
    1116         ...                 'W':'-0.05', 'sigW':'0.40', 'bck':'5.46E+03', 
    1117         ...                 'error':'0'} 
    1118         True 
    1119         """ 
    1120          
    1121         raise TypeError, ' '.join([repr(self.__class__.__name__), 
    1122                                    'instance\'s items are read-only',]) 
     432            raise ValueError, ' '.join(['Same number of variable', 
     433                                        'names and values required in', 
     434                                        repr(self.__class__.__name__), 
     435                                        'object',]) 
    1123436 
    1124437def _test():