Determining if a string is an Isogram I have two solutions to the task and they are all passing the visible tests but when it is time to submit, I keep getting my failed to pass all tests. There are still some hidden tests my code isn't passing.

The task reads as follow:

Write a program that checks if a word supplied as the argument is an Isogram. An Isogram is a word in which no letter occurs more than once.

Create a method called is_isogram that takes one argument, a word to test if it's an isogram. This method should return a tuple of the word and a boolean indicating whether it is an isogram.

If the argument supplied is an empty string, return the argument and False: (argument, False). If the argument supplied is not a string, raise a TypeError with the message 'Argument should be a string'.

Example:

is_isogram("abolishment")


Expected result:

("abolishment", True)


The visible tests:

from unittest import TestCase

class IsogramTestCases(TestCase):
  def test_checks_for_isograms(self):
    word = 'abolishment'
    self.assertEqual(
      is_isogram(word),
      (word, True),
      msg="Isogram word, '{}' not detected correctly".format(word)
    )

  def test_returns_false_for_nonisograms(self):
    word = 'alphabet'
    self.assertEqual(
      is_isogram(word),
      (word, False),
      msg="Non isogram word, '{}' falsely detected".format(word)
    )

  def test_it_only_accepts_strings(self):
    with self.assertRaises(TypeError) as context:
      is_isogram(2)
      self.assertEqual(
        'Argument should be a string',
        context.exception.message,
        'String inputs allowed only'
      )


I wrote two different solutions to the task and they both passed the tests without errors but when I try submitting I got
 "Test Spec Failed
Your solution failed to pass all the tests".

Please any elegant way of solving this task?

Solution 1:

def is_isogram(word):
    if type(word) != str:
        raise TypeError('Argument should be a string')

    elif word == "":
      return (word, False)
    else:
        word = word.lower()
        for char in word:
            if word.count(char) &gt; 1:
                return (word, False)
            else:
                return (word, True) 


Solution 2:

def is_isogram(string):
    if isinstance(string, str) and len(string) != 0:
        string = string.lower()
        if len(string) == len(set(string)):
            result = True
        else:
            result = False
    elif not string:
      result = False
    else:
        raise TypeError('Argument should be a string')

    return string, result
I would write it as a mix of your two solutions. Checking if the set of the string has the same length as the string is probably the best way to check for an isogram.

On the other hand, the control structures in your first code are nicer, because there is less nesting and it does the same thing.

You should make sure you use a consistent number of spaces for indentation. You seem to be using 2, 4 and 6. PEP8, Python's official style-guide, recommends 4.

def is_isogram(word):
    if not isinstance(word, str):
        raise TypeError('Argument should be a string')
    if not word:
        isogram = False
    else:
        isogram = len(word) == len(set(word.lower()))
    return word, isogram


Does the specification say anything about if A and a should count as the same letter?