title: Restricted generic type hint in Python
body: <p>I want to create a factory method like here.</p>
  <pre><code>class A:
      ...
  
  class B(A):
      def f(self):
          ...
  
  class C:
      ...
  
  def factory(cls):
      return cls()
  </code></pre>
  <p>But I want to add some type hints with two requirements:</p>
  <ul>
  <li>Only subclasses of <code>A</code> are allowed as arguments of <code>factory</code>.</li>
  <li>When <code>B</code> is passed, it is correcly detected that <code>factory(B)</code> is instance of <code>B</code>, ie. <code>factory(B).f()</code> is allowed while <code>factory(A).f()</code> is not.</li>
  </ul>
  <h3>Attempt 1</h3>
  <p>Use <code>Type</code> from <code>typing</code> module.</p>
  <pre><code>from typing import Type
  
  class A:
      ...
  
  class B(A):
      def f(self):
          ...
  
  class C:
      ...
  
  def factory(cls: Type[A]):
      return cls()
  
  factory(A)  # Ok
  factory(B)  # Ok
  factory(C)  # Fail
  factory(A).f()  # Fail
  factory(B).f()  # Fail -- Wrong!
  </code></pre>
  <p>This one correctly detects that <code>C</code> is not suppose to be passed as argument of <code>factory</code>. However, <code>factory(B).f()</code> is not allowed by the type-checker.</p>
  <h3>Attempt 2</h3>
  <p>Use <code>TypeVar</code>.</p>
  <pre><code>from typing import TypeVar, Type
  T = TypeVar('T')
  
  class A:
      ...
  
  class B(A):
      def f(self):
          ...
  
  class C:
      ...
  
  def factory(cls: Type[T]) -&gt; T:
      return cls()
  
  factory(A)  # Ok
  factory(B)  # Ok
  factory(C)  # Ok -- Wrong!
  factory(A).f()  # Fail
  factory(B).f()  # Ok
  </code></pre>
  <p>It is well inferred that <code>factory(B).f()</code> is fine, while <code>factory(A).f()</code> is not. However, the generics is without restriction, ie. factory(C) is Ok as well.</p>
  <h3>Attempt 3</h3>
  <p>Add constraint to <code>T</code>.</p>
  <pre><code>from typing import TypeVar, Type
  
  class A:
      ...
  
  class B(A):
      def f(self):
          ...
  
  class D(A):
      ...
  
  class C:
      ...
  
  T = TypeVar('T', A)
  def factory(cls: Type[T]) -&gt; T:
      return cls()
  
  
  factory(A)  # Ok
  factory(B)  # Ok
  factory(C)  # Fail
  factory(A).f()  # Fail
  factory(B).f()  # Ok
  </code></pre>
  <p>This looks promising and at least PyCharm properly handles all cases. But for practical use is this solution actually the worst - <code>A single constraint is not allowed</code> error arises, though, it is not exactly clear why. In PEP 484, there is only a brief line saying 'There should be at least two constraints, if any; specifying a single constraint is disallowed.'</p>
  <p>Is there any nice solution to this? I have only something like adding a 'dummy' class <code>_A</code>, a blank subclass of <code>A</code>, and putting it as another constraint to have something like this.</p>
  <pre><code>_A = NewType('_A', A)
  T = TypeVar('T', A, _A)
  def factory(cls: Type[T]) -&gt; T:
      return cls()
  </code></pre>
  <p>But I don't really consider it as a nice solution.</p>
  <p>Thank you in advance!</p>