0

I'd like to construct a type hint for a sequence of string literals which could accept each of the literals but any literal couldn't occur more than once in the sequence.

I've tried to look for existing solutions and in the standard docs but so far without luck.

This is what I'm trying to accomplish:

from typing import Literal, Sequence

MyValues = Literal["a", "b", "c"]

def my_function(values: Sequence[MyValues]):
    pass

my_function(values=[]) 
my_function(values=["a", "b"])  
my_function(values=["a", "b", "a"])  # should fail type checking

In the above example all function calls pass type checking, which is expected. However during a third case I'd like to see an error which tells me that the literal "a" occurs more than once in the sequence.

I'm not sure if it's even possible but I'm curious if anyone has an idea how to workaround this issue.

Obviously I can filter out duplicates in the function body, but in this case the main idea is to catch such mistakes during development time.

Szabolcs
  • 3,990
  • 18
  • 38
  • 2
    Would it make sense to make `values` a `Set` rather than a `Sequence`? – Samwise Feb 28 '22 at 20:54
  • 2
    The *contents* of a list are not a type-level feature. You would have to define your own type which carries a guaranteed of element uniqueness, then make it that type's responsibility to enforce that guarantee. – chepner Feb 28 '22 at 20:58
  • Also note that typehinting in python does nothing at runtime. It won't throw an error if you pass it an argument which doesn't fit. – Mous Feb 28 '22 at 21:01
  • @Mous Syntactic sugar is something that could be expressed in terms of other, more primitive, syntax. (Decorator syntax, for example, which is just a shorthand for function application.) Type hints simply don't have any run-time effect. – chepner Feb 28 '22 at 21:03
  • I'll edit my comment appropriately. – Mous Feb 28 '22 at 21:04
  • 1
    Python's type system has no support for this, and only pretty exotic type systems would support it. – juanpa.arrivillaga Mar 01 '22 at 00:21
  • I don't want to guarantee anything using type hints, I think that is obvious. I just want to aid developers during dev time, so auto-completion would only display those literals which haven't been passed to the sequence already. – Szabolcs Mar 02 '22 at 09:59
  • @juanpa.arrivillaga seems like TypeScript somehow supports this https://stackoverflow.com/questions/57016728/is-there-a-way-to-define-type-for-array-with-unique-items-in-typescript – Szabolcs Mar 02 '22 at 10:04

1 Answers1

0

If you actually want your code to throw an error, you'll need to check it at runtime. Contrary to popular belief, typehints don't actually raise an Exception at runtime if they are passed the wrong argument. For example, no error will be thrown in the following code:

from typing import Sequence

def foo(bar: Sequence):
    pass

foo(0) #this is an integer, and yet doesn't error

For your code to throw an error, you need something going on inside your function, such as:

def my_function(values):
    if len(set(values))!=len(values):
        raise Exception("Duplicate value in argument")
Mous
  • 953
  • 3
  • 14