def parse_line(text_line):
    words = split_line(text_line.upper())
    # empty line or comment line
    if len(words) == 0 or text_line[0] == '*':
        return None
    # line without a label
    if text_line[0].isspace():
        words.insert(0, None)
    if len(words) < 2:
        raise MissingOperationError
    # line without an operand
    if len(words) < 3:
        words.append(None)
    label, operation, argument = words[0:3]
    # check label
    if label is not None:
        if not SymbolTable.is_label(label):
            raise InvalidLabelError(label)
        if len(label) > 10:
            raise TooLongLabelError(label)
     # check operation
    if not operations.is_valid_operation(operation):
        raise UnknownOperationError(operation)
     # check arg for directives
    if operations.is_arg_required(operation) and argument is None:
        raise ArgumentRequiredError(operation)
    return Line(label, operation, argument)
  def test_is_label(self):
    for l in 'blah a z 123y321 1a1 a1 1a 123456789a 9H labellabel 40F 40B F B'.split():
      self.assertEqual(SymbolTable.is_label(l), True)

    for l in '4F 4B 0F 0B 9F 9B 123 1 2 label* # % label,'.split():
      self.assertEqual(SymbolTable.is_label(l), False)