Skip to content

Allow using modules as subtypes of protocols #5018

Description

@ilevkivskyi

There is an idea to allow modules be accepted where a protocol is expected. This pattern is sometimes used for configs and option management, for example:

# file default_config.py
timeout = 100
one_flag = True
other_flag = False

# file __main__.py
import default_config
from typing import Protocol

class Options(Protocol):
    timeout: int
    one_flag: bool
    other_flag: bool

def setup(options: Options) -> None:
    ...

setup(default_config)  # OK

This will allow better typing than just types.ModuleType and should be straightforward to implement. Are there any objections against this?

Activity

  1. gvanrossum commented on May 10, 2018

    @gvanrossum
    Member
  2. gvanrossum commented on May 10, 2018

    @gvanrossum
    Member
  3. JukkaL commented on May 10, 2018

    @JukkaL
    Collaborator

    Sounds good. We should perhaps explicitly specify how module-level functions would work, since they don't take a self argument. Example:

    # m.py
    def f(x: int) -> None: pass
    
    # main.py
    import m
    from typing import Protocol
    
    class P(Protocol):
        def f(self, x: int) -> None: ...
    
    p: P = m  # Should be ok?
  4. ilevkivskyi commented on May 10, 2018

    @ilevkivskyi
    MemberAuthor

    @JukkaL Yes, I think just dropping the self is what everyone would expect.

  5. shoyer commented on Jun 21, 2018

    @shoyer

    Another use case would be interchanging the random module and random.Random objects. (Or numpy.random and numpy.random.RandomState.)

    This is a nice way to make functions that either use the global RNG state or support overloading with explicit objects, e.g.,

    import random
    from typing import Protocol
    
    class Random(Protocol):
        ...  # all methods from random.Random
    
    def random_add(rng: Random = random):
        return rng.rand() + rng.rand()
  6. ilevkivskyi commented on Jun 21, 2018

    @ilevkivskyi
    MemberAuthor

    This is a nice way to make functions that either use the global RNG state or support overloading with explicit objects, e.g.,

    Yes, I think everyone is sold on this (there is already a PR to add this to the PEP 544), but we just didn't have time to implement this (even though it is pretty straightforward).

  7. jbcpollak commented on Jul 29, 2020

    @jbcpollak

    looks like the PEP was merged two years ago, but this is still an open issue. Is there any progress on this?

  8. hjwp commented on Jul 30, 2020

    @hjwp

    Is there any progress on this?

    Please don't do this. You can see there's been no progress. Nagging only makes the (unpaid, volunteer) maintainers feel stressed and underappreciated. If you really need a feature, the best thing you can do is to dig into the codebase and open a PR.

  9. jbcpollak commented on Jul 30, 2020

    @jbcpollak

    I understand the etiquette, but from looking at the messages its unclear what the current state is - conversation seems to have just stalled. Its also labeled 'needs discussion'. @ilevkivskyi mentioned its straight forward work, what needs to be done? is it something a newbie can do?

  10. ilevkivskyi commented on Jul 30, 2020

    @ilevkivskyi
    MemberAuthor

    is it something a newbie can do?

    Hm, I think this is not the best first issue.

  11. hjwp commented on Jul 30, 2020

    @hjwp

    sorry for lecturing 😅

  12. JukkaL commented on Jul 31, 2020

    @JukkaL
    Collaborator

    Removed the "needs discussion" label since we would definitely want to have this. However, the design of the implementation will still need some discussion :-)

  13. seiyab commented on Jan 26, 2021

    @seiyab
  14. added a commit that references this issue on Jan 7, 2022
  15. theCapypara commented on Jun 24, 2022

    @theCapypara

    Is there at least a workaround for this? It seems even classes (the classes itself not the instances!) can't be tested against protocols:

    from typing import Protocol
    
    class AProtocol(Protocol):
        a: str
    
    class A:
        a = "a"
    
    a_ex: AProtocol = A

    results in

    Incompatible types in assignment (expression has type "Type[A]", variable has type "AProtocol")
    

    Or is there no way at the moment with mypy to check protocols for "non-instantiated" objects? I need this functionality to check some static generated code.

  16. hauntsaninja commented on Aug 7, 2022

    @hauntsaninja
    Collaborator

    @theCapypara your issue is unrelated. Do

    if TYPE_CHECKING:
        a_concrete: A
        a_proto: AProtocol = a_concrete
    
  17. added a commit that references this issue on Aug 27, 2022
    3efbc5c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions