#!/usr/bin/python # MODULE: # tablemanipulation.py # DESCRIPTION: # This module provides a class hierarchy for formatting data extracted from # PNT files by removedstarsearch.py. The classes provided in this module # were deemed important and general enough to place them in their # own module. # # The classes are divided based on two superclasses: FormattingException # and FormattingCommand. All of the exceptions provided by this module # are derived from FormattingException. All of the "command classes" are # derived from FormattingCommand. # # The general idea behind this class structuring is relatively simple. # PNT files are text files that contain alphanumerical data arranged # in a space-separated table. Each line in the file corresponds to a # row of data, while each column of data is separated from other columns # by space characters. Each column may or may not have a caption # and comments (a comment is delineated by a leading semicolon). The # captions are placed within a comment immediately prior to the first # row of data. The first datum in each noncomment line is the name # of a star (e.g., HD 15318 or V* Zet Tau). # # When removedstarsearch.py needs to create a command to extract (and # possibly format) data from a particular column in PNT files # (e.g., the data corresponding to the observed brightness of a star), the # program instantiates a "command class" corresponding to the desired # extraction and formatting command. The arguments for the particular # command are passed to the command class's constructor (__init__) as a # list of strings, where each element is an argument. How many and what # kinds of arguments should be provided depends on which command class is # instantiated; see the class documentation for details about instantiating # command classes. # # When removedstarsearch.py reads in a line of data from a PNT file, the # line of data is parsed by whitespace into a list of strings, where each # represents a single datum from the line, which is then passed to the # execute method of an instantiated command class. (NOTE: The star name # appearing at the beginning of each line of data is not broken up by # the whitespace parsing. This is done to preserve the star name # through the parsing.) The execute method performs actions # that the command class instance is designed to do # (each command class performs a different function; see the # classes's documentation texts for more information). The # execute method returns a single string representing the result of the # execution of the command on the given list of data. # removedstarsearch.py writes this string to a .TXT file corresponding # to the PNT file from which the extracted data came. Thus command # classes provide a means for removedstarsearch.py to select and # manipulate particular data from PNT files. # # (Note that not all command classes need to have execute return data # to be outputted to text files: an implementation of execute may return # the null string to output no data. However, all command classes # provided in this module return non-null strings when execute is # invoked.) # # For example, suppose that a run of removedstarsearch.py reads # instructions for creating particular formatting commands from a text file # and needs to instantiate a command class such that the instance will # extract the data of PNT files corresponding to the brightness of a star. # The ExtractCommand command class performs just this function. # In order to create an instance of ExtractCommand, removedstarsearch.py # executes a statement similar to the following: # # formattingCommands.append(ExtractCommand(commandParameters)) # # Here commandParameters is the string list of command arguments (assumed # here to come from the text file mentioned at the beginning of the # previous paragraph). The instantiated command is then appended to the # list formattingCommands. When a line of data is inputted from a PNT # file, removedstarsearch.py executes the command represented by the # ExtractCommand instance on the data by executing a statement similar to # the following: # # formattingCommands[k].execute(columnarData) # # Here columnarData is the string list containing the data parsed from # the inputted line from the PNT file. The return value of this call # (the datum in the inputted line corresponding to the brightness of a # particular star) can then be written to a .TXT file by # removedstarsearch.py. # # The instantiation-execution scheme can be represented by the following # flow diagram: # # # removedstarsearch.py tablemanipulation.py # ---------------------- ---------------------- # # Need to create a command based # on specific parameters # | # v # Instantiate corresponding ---> __init__ method of # command class with specific corresponding command class # parameters called with parameters # | # v # Command class instance stored <--- Instance of command class # created # # # [Later in removedstarsearch.py...] # # # Need to extract and format a # piece of data in a line read # from a PNT file # | # v # Call execute method of stored ---> execute method of # command class instance corresponding command class # instance called with parsed # line data # | # v # Data extracted and formatted # | # v # Returned string written to <--- Return formatted data as a # .TXT file string # # # An example of this process is as follows: imagine a PNT file that looks # like the following when opened in a regular text editor: # # # ; Sample PNT file # ; C YYYY_DOY_hhmmss PSFangle # HD 15318 eq 2 2006_052_205350 7.8408 # HD 21754 eq 2 2006_052_205437 5.6271 # HD 28305 eq 2 2006_052_205611 1.3935 # HD 29763 eq 2 2006_052_205712 -0.5564 # # # Furthermore, suppose that we run removedstarsearch.py on this file to # extract and manipulate different columns of data. Suppose we have a list # of command class instances to run on each line of data from the above # file. The list looks like the following (in order from the first element # of the list [index 0] to the last element of the list): # # # Smei2daysCommand # Arguments passed to constructor (in order): # "3" # "Time (days)" # "11" # "l" # "2003" # "148" # "1" # "5" # "5" # "5" # SpaceCommand # Arguments passed to constructor (in order): # "3" # ExtractCommand # Arguments passed to constructor (in order): # "4" # "PSF Angle" # "10" # "r" # # # If this list of commands were to be executed (in the listed order) on # each line of the PNT file above and the results were outputted to a # .TXT file, then the .TXT file would look as follows: # # # Time (days) PSF Angle # 1000.82552 7.8408 # 1000.82606 5.6271 # 1000.82715 1.3935 # 1000.82786 -0.5564 # # # (Note that removedstarsearch.py would output these lines to different # files, one for each star name encountered when executing the commands # on the lines of the above PNT file.) # # For information on the different command classes and how to construct # them, consult their documentation comments below. # # There are many unique terms and phrases used throughout this module's # documentation. Here is a list of them along with their definitions: # # "Command class" # A class derived from FormattingCommand # "Columnar data" # Data contained within one or more columns within a PNT file # "Instantiated" # Constructed # "Instance" # Object # # It is also important to note that column indicies are zero-based and # start at the first column following the star names in PNT files. # # Classes provided in this module: # # CaptionedFormattingCommand # ExtractCommand # FormatExecutionException # FormattingCommand # FormattingException # MultiplyFloatExtractCommand # Smei2daysCommand # SpaceCommand # SumFloatExtractCommand # # LANGUAGE: # Python 2.4.3 # REVISION HISTORY: # April 11, 2007 (Jordan T. Vaughan, jtvaugha@ucsd.edu) # + Finalized module code for v1.00 # + Added documentation # import re from string import ljust from string import rjust from string import center # CLASS: # FormattingException # SUPERCLASSES: # Exception # DESCRIPTION: # FormatException is the superclass of all exceptions defined within the # tablemanipulation.py module. A command class should raise a # FormattingException if an error occurs within its constructor, NOT during # execution of the execute method. If a command class needs to raise an # exception while execute is being invoked, then a FormatExecutionException # should be raised instead of a FormattingException. (The exception to # this rule is that a FormattingException is raised when execute, # getNumberOfRequiredArguments, or getFieldCaption is invoked for a # command class that does not override the invoked method.) # # The methods defined within this class are simple and straightforward: a # basic constructor that stores the exception's "arguments" and a method # for converting the exception object to a string. It thus fulfills the # most basic requirements for a derived class of Exception. # DEFINED METHODS: # __init__ # __str__ # OVERRIDDEN METHODS: # None # NONOVERRIDDEN INHERITED METHODS: # None # class FormattingException(Exception): def __init__(self, args): self.args = args def __str__(self): return repr(self.args) # CLASS: # FormatExecutionException # SUPERCLASSES: # FormattingException # DESCRIPTION: # FormatExecutionException represents an exception thrown when an error # occurs during an invocation of a command class's execute method. # This is the only case in which FormatExecutionExceptions should be # raised. # # This class inherits all of its methods from FormattingException and is # structurally no different from its parent class. # DEFINED METHODS: # None # OVERRIDDEN METHODS: # None # NONOVERRIDDEN INHERITED METHODS: # FormattingException.__str__ # class FormatExecutionException(FormattingException): pass # CLASS: # FormattingCommand # SUPERCLASSES: # object # DESCRIPTION: # FormattingCommand is the base class for all columnar data formatting # commands in tablemanipulation.py. It defines two essential methods: # execute and getNumberOfRequiredArguments. execute is invoked when data # from a line of text from a PNT file needs to be extracted (and possibly # formatted). getNumberOfRequiredArguments returns the minimum number of # string elements for the arguments parameter in the constructor # (the __init__ method) of a command class. Both execute and # getNumberOfRequiredArguments should be overridden in command classes. # Details on these methods can be found in their documentation # comments. # # Additionally, every command class must have a constructor (i.e., an # __init__ method) that has the following definition/signature: # # def __init__(self, arguments) # # self refers to the object being instantiated and arguments is # an indexed structure, usually a list or tuple, of string elements # ("arguments") used to specify the behavior of the new instance's # execute method. Examples of possible arguments include the size of the # returned data (in characters) and how the outputted data should be # justified. How many arguments are required and what the arguments mean # depend on which command class is instantiated. # DEFINED METHODS: # execute # getNumberOfRequiredArguments # OVERRIDDEN METHODS: # None # NONOVERRIDDEN INHERITED METHODS: # None # class FormattingCommand(object): # METHOD: # execute # DESCRIPTION: # execute is an abstract method that is called when a program needs # to execute the command class's extraction and formatting function # on a line of data from a PNT file. # PARAMETERS: # self # A reference to the FormattingCommand (or subclass of # FormattingCommand) instance being constructed. # lineEntryArray # An indexed data structure, usually a list or tuple, that contains # all of the data entries from a line of text from a PNT file. # For example, if we use the example PNT file within # the documentation for this module (see the beginning of this # file), then if we instantiate a command class and call # that instance's execute method on the third line of the PNT file # (the one for the star HD 21754), then lineEntryArray would be # ["HD 21754", "eq", "2", "2006_052_205437", "5.6271"]. # RETURN VALUE: # None. However, each subclass of FormattingCommand should return a # string. The string represents the output of the # execution of the command on a line of data. In # removedstarsearch.py, this string value is outputted to a formatted # text file. # EXCEPTIONS: # Unless self refers to an instance of a command class, # FormattingException is raised, for execute is abstract. # However, command classes may throw other exceptions; see the # documentation for such subclasses for more information. # def execute(self, lineEntryArray): raise FormattingException, ('Cannot call execute in abstract class ' + 'FormattingCommand.') # METHOD: # getNumberOfRequiredArguments # DESCRIPTION: # getNumberOfRequiredArguments returns the minimum number of elements # for the arguments parameter for the constructors of command classes. # This method is primarily used within constructors of command classes # to ensure that programs have passed in all of the required arguments. # PARAMETERS: # self # A reference to the FormattingCommand (or subclass of # FormattingCommand) instance whose getNumberOfRequiredArguments # method is being invoked. # RETURN VALUE: # An integer representing the minimum number of string elements for # the arguments parameter for the constructor of the class that self # is an instance of. # EXCEPTIONS: # Unless self refers to an instance of a subclass of # FormattingCommand, FormattingException is raised, for # getNumberOfRequiredArguments is abstract. However, command classes # that override getNumberOfRequiredArguments may throw other # exceptions; see the documentation for such command classes for more # information. # def getNumberOfRequiredArguments(self): raise FormattingException, ('Cannot call method ' + 'getNumberOfRequiredArguments in abstract class ' + 'FormattingCommand.') # CLASS: # CaptionedFormattingCommand # SUPERCLASSES: # FormattingCommand # DESCRIPTION: # CaptionedFormattingCommand is meant to be the abstract superclass of # all command classes that format data to be outputted as # columns in text files (i.e., all command classes provided in this # module). Subclasses of CaptionedFormattingCommand override # the method getFieldCaption, which returns the title of the # data returned by the execute method. # DEFINED METHODS: # getFieldCaption # OVERRIDDEN METHODS: # None # NONOVERRIDDEN INHERITED METHODS: # FormattingCommand.execute # FormattingCommand.getNumberOfRequiredArguments # class CaptionedFormattingCommand(FormattingCommand): # METHOD: # getFieldCaption # DESCRIPTION: # getFieldCaption returns a string containing the caption (the title) # for the data returned by execute. # PARAMETERS: # self # A reference to the CaptionedFormattingCommand (or subclass of # CaptionedFormattingCommand) object whose getFieldCaption # method is being invoked. # RETURN VALUE: # A string representing the caption (title) of the data that the # execute method returns. # EXCEPTIONS: # Unless self refers to an instance of a subclass of # CaptionedFormattingCommand, FormattingException is raised, for # getFieldCaption is meant to be abstract. However, command classes # that override getFieldCaption may throw other exceptions; see the # documentation for such command classes for more information. # def getFieldCaption(self): raise FormattingException, ('Cannot call method getFieldCaption in ' + 'abstract class CaptionedFormattingCommand.') # CLASS: # ExtractCommand # SUPERCLASSES: # CaptionedFormattingCommand # DESCRIPTION: # ExtractCommand is the simplest data extraction command class. When its # execute command is invoked with a list of data from a line from a PNT # file, it returns the datum found at a particular zero-based index (a # "columnar index") into the list. Thus ExtractCommand functions like a # fattened array access command. ExtractCommand is also the superclass of # all (or at least most) command classes that extract and manipulate # data. # DEFINED METHODS: # __init__ # OVERRIDDEN METHODS: # FormattingCommand.execute # FormattingCommand.getNumberOfRequiredArguments # CaptionedFormattingCommand.getFieldCaption # NONOVERRIDDEN INHERITED METHODS: # None # class ExtractCommand(CaptionedFormattingCommand): # Some class constants justifications = {'l': ljust, 'r': rjust, 'c': center} __num_arguments = 4 # METHOD: # __init__ # DESCRIPTION: # __init__ constructs a new instance of ExtractCommand. It requires # four string values (arguments) in its arguments parameter. The # required arguments are listed under "arguments" in the PARAMETERS # section below. # PARAMETERS: # self # A reference to the ExtractCommand instance being constructed. # arguments # A list or tuple of arguments used in constructing the new # instance of ExtractCommand. These arguments are used to # specify how the new instance will behave when its execute method # is invoked with a line of data. The required arguments # are as follows: # # arguments[0] # A string containing the integral, zero-based index of # the column whose data is to be extracted. # arguments[1] # A string specifying the caption (title) of the extracted # data (this can differ from the data's caption in the # PNT file; i.e., this is the NEW caption for the data). # arguments[2] # A string containing a positive integer specifying the # size (in characters) of the string returned by # the execute method. # arguments[3] # A string determining how the data within the string # returned by the execute method should be justified. # Acceptable values are "l" (left-justified), "r" # (right-justified), and "c" (center-justified), all # case-sensitive. # # For example, if you desire to construct an ExtractCommand # instance that extracts data from the sixth column # for every line of data in a PNT file and output it in a right- # justified field of 8 characters under the caption "Time", then # construct the ExtractCommand object as follows: # # instance = ExtractCommand(["5", "Time", "8", "r"]) # # Additional arguments are ignored: only the first four are # taken into account. # RETURN VALUE: # Returns a newly constructed instance of ExtractCommand conforming # to the specified arguments. # EXCEPTIONS: # If any of the provided arguments are invalid (for example, providing # a string containing alphabetical characters instead of an integer) # or if not enough arguments are provided, then a FormattingException # is raised. # def __init__(self, arguments): # Is the correct number of arguments present? if len(arguments) != self.__num_arguments: raise FormattingException, ('extract requires ' + str(self.__num_arguments) + ' arguments (number provided: ' + str(len(arguments)) + ')') # Parse and store the arguments. try: self.column = int(arguments[0]) except TypeError: raise FormattingException, ('extract command was passed with an' + ' illegal column number: ' + str(arguments[0])) try: self.fieldtitle = str(arguments[1]) except TypeError: raise FormattingException, ('extract command was passed with a ' + 'field title argument that could not be converted to a ' + 'string.') try: self.fieldsize = int(arguments[2]) except TypeError: raise FormattingException, ('extract command was passed with an' + ' illegal field size: ' + str(arguments[2])) try: self.justification = str(arguments[3]) except TypeError: raise FormattingException, ('extract command was passed with a ' + 'justification value that could not be converted to a ' + 'string.') # Test the stored arguments for validity. if self.column < 0: raise FormattingException, ('extract command was passed with an' + 'illegal column number: ' + str(self.column)) if not self.fieldtitle: raise FormattingException, ('extract command was passed with an' + ' empty field title.') if self.fieldsize <= 0: raise FormattingException, ('extract command was passed with an' + ' illegal field size: ' + str(self.fieldsize)) if not self.justifications.has_key(self.justification): raise FormattingException, ('extract command was passed with an' + ' illegal justification value: ' + self.justification) # METHOD: # execute # DESCRIPTION: # Executes this instance of ExtractCommand on a given list of # parsed line data and returns the datum that this # instance of ExtractCommand was constructed to extract. # PARAMETERS: # self # A reference to the ExtractCommand (or subclass of # ExtractCommand) instance whose execute method is being # invoked. # lineEntryArray # A list (or other numerically indexed data structure) containing # strings representing individual pieces of data. This # list is supposed to represent a line of data from a PNT file # parsed by whitespace (with the only exception being the first # 11 characters of each noncommented line of the PNT file, which # are treated as the name of the star that the data on that line # describes). For instance, if we use the example PNT # file within the documentation for this module (see the beginning # of this file), then each noncommented line of data is parsed # into a string array suitable for use as the value of # lineEntryArray as follows: # # ["HD 15318", "eq", "2", "2006_052_205350", "7.8408"] # ["HD 21754", "eq", "2", "2006_052_205437", "5.6271"] # ["HD 28305", "eq", "2", "2006_052_205611", "1.3935"] # ["HD 29763", "eq", "2", "2006_052_205712", "-0.5564"] # # RETURN VALUE: # Returns a string containing the extracted datum that this # instance of ExtractCommand was created to extract. For example, # if a particular instance of ExtractCommand is created to extract # the data at column index 3 and left-justify the data in a string # of size 20 and execute is called with lineEntryArray set # to ["HD 29763", "eq", "2", "2006_052_205712", "-0.5564"], then # "2006_052_205712 " is returned. # EXCEPTIONS: # If len(lineEntryArray) is smaller than the column index that this # instance of ExtractCommand uses to extract columnar data, then # a FormatExecutionException is raised. # def execute(self, lineEntryArray): if self.column >= len(lineEntryArray): raise FormatExecutionException, ('Not enough columns in the line'+ ' entry to execute extract command. Column index: ' + str(self.column) + ' Columns in line entry: ' + str(len(lineEntryArray))) return self.justifications[self.justification]( lineEntryArray[self.column], self.fieldsize) # METHOD: # getFieldCaption # DESCRIPTION: # getFieldCaption returns a string containing the caption (the title) # for the data extracted by this instance of ExtractCommand. # PARAMETERS: # self # A reference to the ExtractCommand (or subclass of ExtractCommand) # instance whose getFieldCaption method is being invoked. # RETURN VALUE: # A string representing the caption (title) of the data that this # instance of ExtractCommand extracts. # EXCEPTIONS: # None # def getFieldCaption(self): return self.justifications[self.justification](self.fieldtitle, self.fieldsize) # METHOD: # getNumberOfRequiredArguments # DESCRIPTION: # getNumberOfRequiredArguments returns the number of arguments # required by the constructor of ExtractCommand. In other words, this # method returns the number of string elements that should be in the # arguments parameter for __init__. # PARAMETERS: # self # A reference to the ExtractCommand (or subclass of ExtractCommand) # object whose getNumberOfRequiredArguments method is being # invoked. # RETURN VALUE: # An integer representing the minimum number of string elements for the # arguments parameter to __init__. # EXCEPTIONS: # None # def getNumberOfRequiredArguments(self): return 4 # CLASS: # Smei2daysCommand # SUPERCLASSES: # ExtractCommand # DESCRIPTION: # An instance of Smei2daysCommand extracts a datum from a parsed # line of data from a PNT file and converts the datum from the # standard SMEI date format (YYYY_DOY_HHMMSS) to a floating-point value # (converted to a string) representing the day offset of the SMEI date # from some time origin, or "zero date" (provided as a series of arguments # when the instance of Smei2daysCommand is constructed). # DEFINED METHODS: # __init__ # OVERRIDDEN METHODS: # ExtractCommand.execute # ExtractCommand.getNumberOfRequiredArguments # NONOVERRIDDEN INHERITED METHODS: # ExtractCommand.getFieldCaption # class Smei2daysCommand(ExtractCommand): # Some class constants __min_zero_doy = 1 __max_zero_doy = 366 __max_zero_hour = 23 __max_zero_minute = 59 __max_zero_second = 59 __min_precision = 1 __num_arguments = 10 # METHOD: # __init__ # DESCRIPTION: # __init__ constructs a new instance of Smei2daysCommand. It requires # ten strings values (arguments) in its arguments parameter. The # required arguments are listed under "arguments" in the PARAMETERS # section below. # PARAMETERS: # self # A reference to the Smei2daysCommand instance being constructed. # arguments # A list or tuple of arguments used in constructing the new # instance of Smei2daysCommand. These arguments are used to # specify how the new instance will behave when its execute method # is invoked with a line of data. The required arguments # are as follows: # # arguments[0] # A string containing the integral, zero-based index of # the column whose data is to be extracted and converted. # arguments[1] # A string specifying the caption (title) of the extracted # and converted data (this can differ from the data's # caption in the PNT file; i.e., this is the NEW caption # for the data). # arguments[2] # A string containing a positive integer specifying the # size (in characters) of the string outputted by # the execute method. # arguments[3] # A string determining how the data within the string # returned by the execute method should be justified. # Acceptable values are "l" (left-justified), "r" # (right-justified), and "c" (center-justified), all # case-sensitive. # arguments[4] # A string containing the "zero date" year as an integer. # arguments[5] # A string containing the "zero date" day-of-year as an # integer.. # arguments[6] # A string containing the "zero date" hour as an integer. # arguments[7] # A string containing the "zero date" minute as an integer. # arguments[8] # A string containing the "zero date" second as an integer. # arguments[9] # A string containing a positive integer specifying the # number of digits that will appear after the decimal point # in the floating-point value returned by execute. This # value must be less than (int(arguments[2]) - 2) if the # data retuned by execute is to be correctly formatted. # # For example, if you desire to construct a Smei2daysCommand # instance that extracts data from the sixth column of data # for every line of data in a PNT file, converts the data from # the SMEI date format to days since 2003_148_050505, and output it # in a right-justified field of 8 characters under the caption # "Time (days)" with precision 2, then construct the # Smei2daysCommand object as follows: # # instance = Smei2daysCommand(["5", "Time (days)", "8", "r", # "2003", "148", "5", "5", "5", "2"]) # # Additional arguments are ignored: only the first ten are # taken into account. # RETURN VALUE: # Returns a newly constructed instance of Smei2daysCommand conforming # to the specified arguments. # EXCEPTIONS: # If any of the provided arguments are invalid (for example, providing # a string containing alphabetical characters instead of an integer or # specifying "-100" as the "zero date" hour) or if not enough # arguments are provided, then a FormattingException is raised. # def __init__(self, arguments): # Is the list of arguments large enough? if len(arguments) != self.__num_arguments: raise FormattingException, ('smei2days requires ' + str(__num_arguments) + ' arguments (number provided: ' + str(len(arguments)) + ')') # Initialize the ExtractCommand portion of this command. ExtractCommand.__init__(self, arguments[0: ExtractCommand.getNumberOfRequiredArguments(self)]) # Parse the other arguments (the zero date arguments and precision). try: self.zero_year = int(arguments[4]) except TypeError: raise FormattingException, ('smei2days command passed with an ' + 'illegal zero date year: ' + str(arguments[4])) try: self.zero_doy = int(arguments[5]) except TypeError: raise FormattingException, ('smei2days command passed with an ' + 'illegal zero date day of year: ' + str(arguments[5])) try: self.zero_hour = int(arguments[6]) except TypeError: raise FormattingException, ('smei2days command passed with an ' + 'illegal zero date hour: ' + str(arguments[6])) try: self.zero_minute = int(arguments[7]) except TypeError: raise FormattingException, ('smei2days command passed with an ' + 'illegal zero date minute: ' + str(arguments[7])) try: self.zero_second = int(arguments[8]) except TypeError: raise FormattingException, ('smei2days command passed with an ' + 'illegal zero date second: ' + str(arguments[8])) try: self.precision = int(arguments[9]) except TypeError: raise FormattingException, ('smei2days command passed with an ' + 'illegal precision: ' + str(arguments[9])) # Test some of the arguments for validity. if (self.zero_doy < self.__min_zero_doy or self.zero_doy > self.__max_zero_doy): raise FormattingException, ('smei2days command passed with an ' + 'illegal zero date day of year: ' + str(self.zero_doy)) if self.zero_hour < 0 or self.zero_hour > self.__max_zero_hour: raise FormattingException, ('smei2days command passed with an ' + 'illegal zero date hour: ' + str(self.zero_hour)) if self.zero_minute < 0 or self.zero_minute > self.__max_zero_minute: raise FormattingException, ('smei2days command passed with an ' + 'illegal zero date minute: ' + str(self.zero_minute)) if self.zero_second < 0 or self.zero_second > self.__max_zero_second: raise FormattingException, ('smei2days command passed with an ' + 'illegal zero date second: ' + str(self.zero_second)) if self.precision < self.__min_precision: raise FormattingException, ('smei2days command passed with an ' + 'illegal precision: ' + str(self.precision)) if self.precision >= self.fieldsize - 2: raise FormattingException, ('smei2days command passed with a ' + 'precision greater than or equal to the field size minus ' + 'two.') # METHOD: # execute # DESCRIPTION: # Executes this instance of Smei2daysCommand on a given list of # parsed data. A particular datum (determined by arguments[0] # in the constructor; see __init__) is extracted and converted # from SMEI date format to days since the "zero date" of this # instance of Smei2daysCommand. This converted value is returned # as a formatted string. # PARAMETERS: # self # A reference to the Smei2daysCommand (or subclass of # Smei2daysCommand) instance whose execute method is being # invoked. # lineEntryArray # A list (or other numerically indexed data structure) containing # strings representing individual pieces of data. This # list is supposed to represent a line of data from a PNT file # parsed by whitespace (with the only exception being the first # 11 characters of each noncommented line of the PNT file, which # are treated as the name of the star that the data on that line # corresponds to). For instance, if we use the example PNT # file within the documentation for this module (see the beginning # of this file), then each noncommented line of data is parsed # into a string array suitable for use as the value of # lineEntryArray as follows: # # ["HD 15318", "eq", "2", "2006_052_205350", "7.8408"] # ["HD 21754", "eq", "2", "2006_052_205437", "5.6271"] # ["HD 28305", "eq", "2", "2006_052_205611", "1.3935"] # ["HD 29763", "eq", "2", "2006_052_205712", "-0.5564"] # # RETURN VALUE: # Returns a string containing the extracted and converted # datum that this instance of Smei2daysCommand was created to # extract and convert. For example, if a particular instance of # Smei2daysCommand is created to extract the data at column index # three, convert it to days since 2006_051_205712, and # left-justify the result in a string of size 10 and precision 5, # and if execute is called with lineEntryArray set to # ["HD 29763", "eq", "2", "2006_052_205712", "-0.5564"], then # "1.00000 " is returned. # EXCEPTIONS: # If len(lineEntryArray) is smaller than the column index that this # instance of Smei2daysCommand uses to extract columnar data or the # extracted data is not in standard SMEI date format, then a # FormatExecutionException is raised. # def execute(self, lineEntryArray): smeiDate = ExtractCommand.execute(self, lineEntryArray).strip() # Is the extracted data a standard SMEI date? if not re.match('\d\d\d\d_\d\d\d_\d\d\d\d\d\d', smeiDate): raise FormatExecutionException, ('smei2days executed on an ' + 'entry that is not a standard SMEI date: ' + smeiDate) # Extract the date portions: year, DOY, hour, minute, and second. # No TypeError exceptions should be raised because the date was # matched against the standard SMEI REX form. smeiYear = int(smeiDate[:4]) smeiDOY = int(smeiDate[5:8]) smeiHour = int(smeiDate[9:11]) smeiMinute = int(smeiDate[11:13]) smeiSecond = int(smeiDate[13:]) # Stage 1: Figure out the number of whole years between the zero date # and the given date (that is, the number of years between the dates # without taking the DOY offsets of both dates into account). This # only processes if the given date is later than the zero date. convertedTime = 0.0 middleYears = smeiYear - self.zero_year - 1 if middleYears > 0: # Yes, we do have some middle years. Start with leap years, then # tack on ordinary years. convertedTime += (middleYears + (self.zero_year % 4)) / 4 * 366 convertedTime += (middleYears - (middleYears + (self.zero_year % 4)) / 4) * 365 # Stage 2: Figure out the number of days between the zero date and the # end of that same year (assuming that the zero date and the given date # years are not the same and that the given date is later than the zero # date). if smeiYear > self.zero_year: if self.zero_year % 4 == 0: convertedTime += 366 else: convertedTime += 365 convertedTime -= self.zero_doy + (((self.zero_hour * 3600) + (self.zero_minute * 60) + self.zero_second) / (24.0 * 3600.0)) # Stage 3: Figure out the number of days between the beginning of the # year of the given date and the given date. if smeiYear >= self.zero_year: convertedTime += smeiDOY convertedTime += ((smeiHour * 3600) + (smeiMinute * 60) + smeiSecond) / (24.0 * 3600.0) # Make adjustments if the given date has the same year as the zero # date. if smeiYear == self.zero_year: # Subtract the zero date's days. convertedTime -= self.zero_doy + (((self.zero_hour * 3600) + (self.zero_minute * 60) + self.zero_second) / (24.0 * 3600.0)) # If the given date is earlier than the zero date, then none of the # above three stages executed. The dates must be handled differently. # A negative time must be calculated. else: # Stage 1: Figure out the number of years between the two dates. middleYears = self.zero_year - smeiYear - 1 if middleYears > 0: # Yes, we do have some middle years. Start with leap years, # then tack on regular years. convertedTime -= ((middleYears - (self.zero_year % 4) + 4) / 4 * 366) convertedTime -= (middleYears - (middleYears - (self.zero_year % 4) + 4) / 4) * 365 # Stage 2: Subtract the zero date's days. convertedTime -= self.zero_doy + (((self.zero_hour * 3600) + (self.zero_minute * 60) + self.zero_second) / (24.0 * 3600.0)) # Stage 3: Figure out the number of days between the end of the # year of the given date and the given date. if smeiYear % 4 == 0: convertedTime -= 366 - smeiDOY else: convertedTime -= 365 - smeiDOY convertedTime += ((smeiHour * 3600) + (smeiMinute * 60) + smeiSecond) / (24.0 * 3600.0) # Return the newly formatted date justified the way the user wanted it # to be. return ExtractCommand.justifications[self.justification](('%.' + str(self.precision) + 'f') % (convertedTime), self.fieldsize) # METHOD: # getNumberOfRequiredArguments # DESCRIPTION: # getNumberOfRequiredArguments returns the number of arguments # required by the constructor of Smei2daysCommand. In other words, # this method returns the number of string elements that should be in # the arguments parameter for __init__. # PARAMETERS: # self # A reference to the Smei2daysCommand (or subclass of # Smei2daysCommand) instance whose getNumberOfRequiredArguments # method is being invoked. # RETURN VALUE: # An integer representing the minimum number of string elements for the # arguments parameter to __init__. # EXCEPTIONS: # None # def getNumberOfRequiredArguments(self): return self.__num_arguments # CLASS: # SpaceCommand # SUPERCLASSES: # CaptionedFormattingCommand # DESCRIPTION: # An instance of SpaceCommand does not extract columnar data. Its sole # function it to return strings containing whitespace whenever execute # or getFieldCaption is invoked. The number of spaces within these # returned strings is set when instances of SpaceCommand are constructed. # This command class is useful for producing whitespace for separating # data outputted to text files. # # For example, supposed two command classes (neither of # which is SpaceCommand) are instantiated and their execute # methods are invoked on many lines of data from PNT files. By default, # if the strings returned by the execute methods were to be written to # .TXT files, then the written data would not be separated by spaces. # To solve this problem, we can create an instance of SpaceCommand and # invoke its execute method between invocations of the other two command # classes's execute methods. This places whitespace between the strings # returned by the two classes's execute methods in the resulting .TXT # file, making the data more readable. # DEFINED METHODS: # __init__ # OVERRIDDEN METHODS: # CaptionedFormattingCommand.execute # CaptionedFormattingCommand.getNumberOfRequiredArguments # CaptionedFormattingCommand.getFieldCaption # NONOVERRIDDEN INHERITED METHODS: # None # class SpaceCommand(CaptionedFormattingCommand): # METHOD: # __init__ # DESCRIPTION: # __init__ constructs a new instance of SpaceCommand. It requires # only one string value (argument) in its arguments parameter. The # required argument is explained under "arguments" in the PARAMETERS # section below. # PARAMETERS: # self # A reference to the SpaceCommand instance being constructed. # arguments # A list or tuple of arguments used in constructing the new # instance of SpaceCommand. These arguments are used to # specify how the new instance will behave when its execute and # getFieldCaption methods are invoked. The required argument # is as follows: # # arguments[0] # A string containing an integer specifying the number of # spaces the string values returned by execute and # getFieldCaption will contain. # # For example, if you desire to construct a SpaceCommand that # returns strings containing three spaces when execute and # getFieldCaption are invoked, then construct the SpaceCommand # object as follows: # # instance = SpaceCommand(["3"]) # # Additional arguments are ignored: only the first is taken into # account. # RETURN VALUE: # Returns a newly constructed instance of SpaceCommand conforming # to the specified argument. # EXCEPTIONS: # If the specified argument is invalid (for example, it contains # alphabetical characters) or if the argument is not provided, # then a FormattingException is raised. # def __init__(self, arguments): # Is the list of arguments large enough? if len(arguments) != self.getNumberOfRequiredArguments(): raise FormattingException, ('space requires ' + str(self.getNumberOfRequiredArguments()) + ' arguments ' + '(number provided: ' + str(len(arguments)) + ')') # Parse the arguments and check them for validity. try: self.fieldvalue = ' ' * int(arguments[0]) except TypeError: self.fieldvalue = '' raise FormattingException, ('space command passed with an ' + 'illegal size argument: ' + str(arguments[0])) # METHOD: # execute # DESCRIPTION: # Executes this instance of SpaceCommand on a given list of # parsed data. The parsed data is ignored and a string # containing spaces (the number of which was specified when # this SpaceCommand instance was constructed; see __init__) is # returned. # PARAMETERS: # self # A reference to the SpaceCommand (or subclass of # SpaceCommand) object whose execute method is being invoked. # lineEntryArray # A list (or other numerically indexed data structure) containing # strings representing individual pieces of data. This # list is supposed to represent a line of data from a PNT file # parsed by whitespace (with the only exception being the first # 11 characters of each noncommented line of the PNT file, which # are treated as the name of the star that the data on that line # corresponds to). This argument is ignored by execute but # included so that FormattingCommand.execute is overridden. # RETURN VALUE: # Returns a string containing a particular number of space # characters. # EXCEPTIONS: # None # def execute(self, lineEntryArray): return self.fieldvalue # METHOD: # getNumberOfRequiredArguments # DESCRIPTION: # getNumberOfRequiredArguments returns the number of arguments # required by the constructor of SpaceCommand. In other words, # this method returns the number of string elements that should be in # the arguments parameter for __init__. # PARAMETERS: # self # A reference to the SpaceCommand (or subclass of # SpaceCommand) instance whose getNumberOfRequiredArguments # method is being invoked. # RETURN VALUE: # An integer representing the minimum number of string elements for the # arguments parameter to __init__. # EXCEPTIONS: # None # def getNumberOfRequiredArguments(self): return 1 # METHOD: # getFieldCaption # DESCRIPTION: # getFieldCaption returns the same string that execute returns. # PARAMETERS: # self # A reference to the SpaceCommand (or subclass of SpaceCommand) # instance whose getFieldCaption method is being invoked. # RETURN VALUE: # The same string that execute returns (see execute for details). # EXCEPTIONS: # None # def getFieldCaption(self): return self.fieldvalue # CLASS: # SumFloatExtractCommand # SUPERCLASSES: # CaptionedFormattingCommand # DESCRIPTION: # An instance of SumFloatExtractCommand acts similarly to an instance of # ExtractCommand but differs in a number of ways: # # 1. An instance of SumFloatExtractCommand can extract multiple # pieces of data from a line of data. # 2. Each extracted datum must be a number, either integral or # of type float. # 3. When execute is invoked, data is extracted from a line of # parsed data and summed. Each numerical value in the # sum is multiplied by a constant before the sum is computed. # The sum is returned as a formatted string. # 4. Each datum is associated with a scalar constant (thus if n # pieces of data are extracted and summed by an instance of # SumFloatExtractCommand, then there are n associated scalar # constants). # # DEFINED METHODS: # __init__ # OVERRIDDEN METHODS: # CaptionedFormattingCommand.execute # CaptionedFormattingCommand.getNumberOfRequiredArguments # CaptionedFormattingCommand.getFieldCaption # NONOVERRIDDEN INHERITED METHODS: # None # class SumFloatExtractCommand(CaptionedFormattingCommand): # METHOD: # __init__ # DESCRIPTION: # __init__ constructs a new instance of SumFloatExtractCommand. It # requires six string values (arguments) in its arguments parameter, # but it can take more arguments. The required and optional arguments # are listed under "arguments" in the PARAMETERS section below. # PARAMETERS: # self # A reference to the SumFloatExtractCommand instance being # constructed. # arguments # A list or tuple of arguments used in constructing the new # instance of SumFloatExtractCommand. These arguments are used to # specify how the new instance will behave when its execute method # is invoked. The required arguments are as follows: # # arguments[0] # A string specifying the caption (title) of the extracted # and summed data (this can differ from the captions # in the PNT file; i.e., this is a NEW caption for the # data). # arguments[1] # A string containing a positive integer specifying the # size (in characters) of the string returned by # the execute method. # arguments[2] # A string determining how the data within the string # returned by the execute method should be justified. # Acceptable values are "l" (left-justified), "r" # (right-justified), and "c" (center-justified), all # case-sensitive. # arguments[3] # A string containing a positive integer specifying the # number of digits that will appear after the decimal point # in the floating-point value returned by execute. This # value must be less than (int(arguments[1]) - 2) if the # data retuned by execute is to be correctly formatted. # arguments[4] # A string containing the integral, zero-based index of # the first column of data from which a datum is extracted # by invoking execute. When execute is invoked, a datum is # extracted from a line of parsed columnar data at the # index that this argument represents. # arguments[5] # A string containing a floating point value representing # the scalar constant associated with the index # represented by arguments[4]. When execute is invoked, # the datum extracted from a line of parsed data # at index arguments[4] is converted to a float and scaled # by the numerical value that this argument represents. # # A program can specify additional arguments. The total number # of additional arguments must be a multiple of two. Thus if n # pairs of arguments are provided in addition to the required # ones listed above, then for every m in the inclusive integral # range [0, n-1]: # # arguments[2*m + 6] # A string containing an integral, zero-based index for # a column of data from which a datum is extracted by # invoking execute. This argument is analogous to # arguments[4]. # arguments[2*m + 7] # A string containing a floating point value representing # the scalar constant associated with the index represented # by arguments[2*m + 6]. This argument is analogous to # arguments[5]. # # For example, if you desire to construct a SumFloatExtractCommand # instance that extracts data from the third and sixth columns of # data for every line of data in a PNT file, scales the two values # by 1.0 and 2.0 (respectively), sums the two scaled values, # and returns their sum as a left-justified string of width 10 and # floating point precision 4 under the title "Value + error", then # construct the SumFloatExtractCommand object as follows: # # instance = SumFloatExtractCommand(["Value + error", # "10", "l", "4", "2", "1.0", "5", "2.0"]) # # The following constructs a SumFloatExtractCommand instance # that functions like an ExtractCommand (but is still restricted # to extracting floating point data): # # instance = SumFloatExtractCommand(["Value", "10", "l", # "4", "2", "1.0"]) # # RETURN VALUE: # Returns a newly constructed instance of SumFloatExtractCommand # conforming to the specified arguments. # EXCEPTIONS: # If any of the provided arguments are invalid (for example, providing # a string containing alphabetical characters instead of an integer or # floating point number) or if not enough arguments are provided, then # a FormattingException is raised. # def __init__(self, arguments): # Is the list of arguments large enough? if len(arguments) < self.getNumberOfRequiredArguments(): raise FormattingException, ('sumfloatextract requires at least ' + str(self.getNumberOfRequiredArguments()) + ' arguments ' + '(number provided: ' + str(len(arguments)) + ')') # Parse and store the arguments. try: self.fieldtitle = str(arguments[0]) except TypeError: raise FormattingException, ('sumfloatextract command was passed ' + 'with a field title value that could not be converted to a ' + 'string.') try: self.fieldsize = int(arguments[1]) except TypeError: raise FormattingException, ('sumfloatextract command was passed ' + 'with an illegal field size: ' + str(arguments[1])) try: self.justification = str(arguments[2]) except TypeError: raise FormattingException, ('sumfloatextract command was passed ' + 'with a justification value that could not be converted to a' + ' string.') try: self.precision = int(arguments[3]) except TypeError: raise FormattingException, ('sumfloatextract command was passed ' + 'with a non-integral precision: ' + str(arguments[3])) self.columns = arguments[4::2] self.multipliers = arguments[5::2] # Test the arguments for validity. if not self.fieldtitle: raise FormattingException, ('sumfloatextract command was passed ' + 'with an empty field title.') if self.fieldsize <= 0: raise FormattingException, ('sumfloatextract command was passed ' + 'with an illegal field size: ' + str(self.fieldsize)) if not ExtractCommand.justifications.has_key(self.justification): raise FormattingException, ('sumfloatextract command was passed ' + 'with an illegal justification value: ' + self.justification) if self.precision <= 0: raise FormattingException, ('sumfloatextract command was passed ' + 'with an illegal precision: ' + str(self.precision)) if len(self.columns) != len(self.multipliers): raise FormattingException, ('sumfloatextract command was passed ' + 'with illegal column index-multiplier pairs: one index has a' + ' missing multiplier.') # Ensure that the columnar indicies and associated scalars are # numbers of the appropriate types. for column in self.columns: try: int(column) except TypeError: raise FormattingException, ('sumfloatextract command was ' + 'passed with an illegal column number: ' + str(column)) for index in range(len(self.multipliers)): try: self.multipliers[index] = float(self.multipliers[index]) except TypeError: raise FormattingException, ('sumfloatextract command was ' + 'passed with an illegal multiplier value: ' + str(self.multipliers[index])) # METHOD: # execute # DESCRIPTION: # Executes this instance of SumFloatExtractCommand on a given list of # parsed line data and returns the sum of the scaled data that # this instance of SumFloatExtractCommand was constructed to extract. # PARAMETERS: # self # A reference to the SumFloatExtractCommand (or subclass of # SumFloatExtractCommand) instance whose execute method is being # invoked. # lineEntryArray # A list (or other numerically indexed data structure) containing # strings representing individual pieces of columnar data. This # list is supposed to represent a line of data from a PNT file # parsed by whitespace (with the only exception being the first # 11 characters of each noncommented line of the PNT file, which # are treated as the name of the star that the data on that line # corresponds to). For instance, if we use the example PNT # file within the documentation for this module (see the beginning # of this file), then each noncommented line of data is parsed # into a string array suitable for use as the value of # lineEntryArray as follows: # # ["HD 15318", "eq", "2", "2006_052_205350", "7.8408"] # ["HD 21754", "eq", "2", "2006_052_205437", "5.6271"] # ["HD 28305", "eq", "2", "2006_052_205611", "1.3935"] # ["HD 29763", "eq", "2", "2006_052_205712", "-0.5564"] # # RETURN VALUE: # Returns a string containing the sum of the scaled data that this # instance of SumFloatExtractCommand was created to extract. For # example, if a particular instance of SumFloatExtractCommand is # created to extract the data at column indicies 3 and 4, scale # the extracted values by 1.0 and 2.0 (respectively), sum the # scaled values, and left-justify the sum in a string # of size 10 and precision 4, and if its execute method is called # with lineEntryArray set to ["HD 29763", "eq", "2", "2.0000", # "-0.5564"], then "0.8872 " is returned. # EXCEPTIONS: # If len(lineEntryArray) is smaller than any of the column indicies # that this instance of SumFloatExtractCommand uses to extract # columnar data, then a FormatExecutionException is raised. # def execute(self, lineEntryArray): # Convert the column data into floating point numbers for later # summing. values = [] for index in range(len(self.columns)): value = ExtractCommand([self.columns[index], 't', self.fieldsize, self.justification]).execute(lineEntryArray).strip() try: values.append(self.multipliers[index] * float(value)) except TypeError: raise FormatExecutionException, ('sumfloatextract command ' + 'extracted column data that was not a floating point ' + 'number: ' + value) # Add up the floating point values and return the sum. sum = 0.0 for value in values: sum += value return ExtractCommand.justifications[self.justification](('%.' + str(self.precision) + 'f') % (sum), self.fieldsize) # METHOD: # getNumberOfRequiredArguments # DESCRIPTION: # getNumberOfRequiredArguments returns the number of arguments # required by the constructor of SumFloatExtractCommand. In other # words, this method returns the minimum number of string elements that # should be in the arguments parameter for __init__. # PARAMETERS: # self # A reference to the SumFloatExtractCommand (or subclass of # SumFloatExtractCommand) instance whose # getNumberOfRequiredArguments method is being invoked. # RETURN VALUE: # An integer representing the minimum number of string elements for the # arguments parameter to __init__. # EXCEPTIONS: # None # def getNumberOfRequiredArguments(self): return 6 # METHOD: # getFieldCaption # DESCRIPTION: # getFieldCaption returns a string containing the caption (the title) # for the sums generated by this instance of SumFloatExtractCommand. # PARAMETERS: # self # A reference to the SumFloatExtractCommand (or subclass of # SumFloatExtractCommand) instance whose getFieldCaption method # is being invoked. # RETURN VALUE: # A string representing the caption (title) of the sums that this # instance of SumFloatExtractCommand generates. # EXCEPTIONS: # None # def getFieldCaption(self): return ExtractCommand.justifications[self.justification]( self.fieldtitle, self.fieldsize) # CLASS: # MultiplyFloatExtractCommand # SUPERCLASSES: # CaptionedFormattingCommand # DESCRIPTION: # An instance of MultiplyFloatExtractCommand acts identically to an # instance of SumFloatExtractCommand except that the extracted values are # not scaled and are multiplied instead of summed together. # DEFINED METHODS: # __init__ # OVERRIDDEN METHODS: # CaptionedFormattingCommand.execute # CaptionedFormattingCommand.getNumberOfRequiredArguments # CaptionedFormattingCommand.getFieldCaption # NONOVERRIDDEN INHERITED METHODS: # None # class MultiplyFloatExtractCommand(CaptionedFormattingCommand): # METHOD: # __init__ # DESCRIPTION: # __init__ constructs a new instance of MultiplyFloatExtractCommand. # It requires six string values (arguments) in its arguments parameter, # but it can take more arguments. The required and optional arguments # are listed under "arguments" in the PARAMETERS section below. # PARAMETERS: # self # A reference to the MultiplyFloatExtractCommand instance being # constructed. # arguments # A list or tuple of arguments used in constructing the new # instance of MultiplyFloatExtractCommand. These arguments # specify how the new instance will behave when its execute method # is invoked. The required arguments are as follows: # # arguments[0] # A string specifying the caption (title) of the extracted # and multiplied data (this can differ from the captions # in the PNT file; i.e., this is a NEW caption for the # data). # arguments[1] # A string containing a positive integer specifying the # size (in characters) of the string returned by # the execute method. # arguments[2] # A string determining how the data within the string # returned by the execute method should be justified. # Acceptable values are "l" (left-justified), "r" # (right-justified), and "c" (center-justified), all # case-sensitive. # arguments[3] # A string containing a positive integer specifying the # number of digits that will appear after the decimal point # in the floating-point value returned by execute. This # value must be less than (int(arguments[1]) - 2) if the # data retuned by execute is to be correctly formatted. # arguments[4] # A string containing the integral, zero-based index of # the first column of data from which a datum is extracted # by invoking execute. When execute is invoked, a datum is # extracted from a list of parsed line data at the # index that this argument represents. # # A program can specify additional arguments. If n # arguments are provided in addition to the required ones # listed above, then for every m in the inclusive integral # range [1, n]: # # arguments[m + 4] # A string containing an integral, zero-based index for # a column of data from which a datum is extracted by # invoking execute. This argument is analogous to # arguments[4]. # # For example, if you desire to construct a # MultiplyFloatExtractCommand instance that extracts data from the # third and sixth columns of data for every line of data in a PNT # file, multiplies the two values, and returns their product as a # left-justified string of width 10 and floating point precision 4 # under the title "Value + error", then construct the # MultiplyFloatExtractCommand object as follows: # # instance = MultiplyFloatExtractCommand(["Value + error", # "10", "l", "4", "2", "5"]) # # The following constructs a MultiplyFloatExtractCommand instance # that functions like an ExtractCommand (but is still restricted # to extracting floating point data): # # instance = MultiplyFloatExtractCommand(["Value", "10", "l", # "4", "2"]) # # RETURN VALUE: # Returns a newly constructed instance of MultiplyFloatExtractCommand # conforming to the specified arguments. # EXCEPTIONS: # If any of the provided arguments are invalid (for example, providing # a string containing alphabetical characters instead of an integer) # or if not enough arguments are provided, then a FormattingException # is raised. # def __init__(self, arguments): # Is the list of arguments large enough? if len(arguments) < self.getNumberOfRequiredArguments(): raise FormattingException, ('multiplyfloatextract requires at ' + 'least ' + str(self.getNumberOfRequiredArguments()) + ' arguments (number provided: ' + str(len(arguments)) + ')') # Parse and store the arguments. try: self.fieldtitle = str(arguments[0]) except TypeError: raise FormattingException, ('multiplyfloatextract command was' + ' passed with a field title value that could not be ' + 'converted to a string.') try: self.fieldsize = int(arguments[1]) except TypeError: raise FormattingException, ('multiplyfloatextract command was ' + 'passed with an illegal field size: ' + str(arguments[1])) try: self.justification = str(arguments[2]) except TypeError: raise FormattingException, ('multiplyfloatextract command was ' + 'passed with a justification value that could not be ' + 'converted to a string.') try: self.precision = int(arguments[3]) except TypeError: raise FormattingException, ('multiplyfloatextract command was ' + 'passed with a non-integral precision: ' + str(arguments[3])) self.columns = arguments[4:] # Test the arguments for validity. if not self.fieldtitle: raise FormattingException, ('multiplyfloatextract command was ' + 'passed with an empty field title.') if self.fieldsize <= 0: raise FormattingException, ('multiplyfloatextract command was ' + 'passed with an illegal field size: ' + str(self.fieldsize)) if not ExtractCommand.justifications.has_key(self.justification): raise FormattingException, ('multiplyfloatextract command was ' + 'passed with an illegal justification value: ' + self.justification) if self.precision <= 0: raise FormattingException, ('multiplyfloatextract command was ' + 'passed with an illegal precision: ' + str(self.precision)) for column in self.columns: try: int(column) except TypeError: raise FormattingException, ('multiplyfloatextract command ' + 'was passed with an illegal column number: ' + str(column)) # METHOD: # execute # DESCRIPTION: # Executes this instance of MultiplyFloatExtractCommand on a given # list of parsed line data and returns the product of the extracted # data as a formatted string. # PARAMETERS: # self # A reference to the MultiplyFloatExtractCommand (or subclass of # MultiplyFloatExtractCommand) instance whose execute method is # being invoked. # lineEntryArray # A list (or other numerically indexed data structure) containing # strings representing individual pieces of line data. This # list is supposed to represent a line of data from a PNT file # parsed by whitespace (with the only exception being the first # 11 characters of each noncommented line of the PNT file, which # are treated as the name of the star that the data on that line # corresponds to). For instance, if we use the example PNT # file within the documentation for this module (see the beginning # of this file), then each noncommented line of data is parsed # into a string array suitable for use as the value of # lineEntryArray as follows: # # ["HD 15318", "eq", "2", "2006_052_205350", "7.8408"] # ["HD 21754", "eq", "2", "2006_052_205437", "5.6271"] # ["HD 28305", "eq", "2", "2006_052_205611", "1.3935"] # ["HD 29763", "eq", "2", "2006_052_205712", "-0.5564"] # # RETURN VALUE: # Returns a string containing the product of the extracted data. # For example, if a particular instance of # MultiplyFloatExtractCommand is created to extract the data at # column indicies 3 and 4 and left-justify their product in a # string of size 10 and precision 4, and if its execute method is # called with lineEntryArray set to ["HD 29763", "eq", "2", # "2.0000", "-0.5564"], then "-1.1128 " is returned. # EXCEPTIONS: # If len(lineEntryArray) is smaller than any of the column indicies # that this instance of MultiplyFloatExtractCommand uses to extract # columnar data, then a FormatExecutionException is raised. # def execute(self, lineEntryArray): # Convert the column data into floating point numbers and multiply # them together. product = 1.0 for column in self.columns: value = ExtractCommand([column, 't', self.fieldsize, self.justification]).execute(lineEntryArray).strip() try: product = product * float(value) except TypeError: raise FormatExecutionException, ('multiplyfloatextract ' + 'command extracted column data that was not a floating ' + 'point number: ' + str(value)) # Return the product as a formatted string. return ExtractCommand.justifications[self.justification](('%.' + str(self.precision) + 'f') % (product), self.fieldsize) # METHOD: # getNumberOfRequiredArguments # DESCRIPTION: # getNumberOfRequiredArguments returns the number of arguments # required by the constructor of MultiplyFloatExtractCommand. In other # words, this method returns the minimum number of string elements that # should be in the arguments parameter for __init__. # PARAMETERS: # self # A reference to the MultiplyFloatExtractCommand (or subclass of # MultiplyFloatExtractCommand) instance whose # getNumberOfRequiredArguments method is being invoked. # RETURN VALUE: # An integer representing the minimum number of string elements for the # arguments parameter to __init__. # EXCEPTIONS: # None # def getNumberOfRequiredArguments(self): return 5 # METHOD: # getFieldCaption # DESCRIPTION: # getFieldCaption returns a string containing the caption (the title) # for the products generated by this instance of # MultiplyFloatExtractCommand. # PARAMETERS: # self # A reference to the MultiplyFloatExtractCommand (or subclass of # MultiplyFloatExtractCommand) instance whose getFieldCaption # method is being invoked. # RETURN VALUE: # A string representing the caption (title) of the products generated # by this instance of MultiplyFloatExtractCommand. # EXCEPTIONS: # None # def getFieldCaption(self): return ExtractCommand.justifications[self.justification]( self.fieldtitle, self.fieldsize)