Skip to content

module references aren't followed correctly #1741

Closed

Description

@jdelic

It seems that given an imported module and a reference to that module, mypy doesn't follow the reference.

Example:

# main.py
from test import mod

mod.blah()
for m in [mod]:
    m.blah()

# test/mod.py
def blah() -> None:
    print("blah")

MYPYPATH=. bin/mypy main.py will result in

main.py:5: error: "module" has no attribute "blah"

Note that mypy does not complain about mod.blah(), which is resolved correctly.

I apologize if this is a known bug, I read a lot of issues before writing this up, but wasn't able to find anything relating to this.

Activity

  1. gvanrossum commented on Jun 23, 2016

    @gvanrossum
    Member

    IIUC the 'mod' object in main's global namespace is special, it knows exactly which module it references. But when you put a module in a list like your example (or do anything else with it other than plain assignment or an attribute reference), the resulting type becomes just the generic module and has no attributes except __name__ and such.

    What was your real-world use case?

  2. jdelic commented on Jun 23, 2016

    @jdelic
    Author

    What was your real-world use case?

    I have a command-line application that, when started, calls init_subsystem() on multiple modules, each of which then does things like validate command-line parameters and loading plugins using pkg_resources. So my real code looks like this:

    from gopythongo import initializers, builders, versioners, assemblers, packers, stores
    
    for s in [initializers, versioners, builders, assemblers, packers, stores]:
        s.init_subsystem()

    I could just unroll the loop as a work-around... but is there a better solution?

    for s in [initializers.init_subsystem, builders.init_subsystem, ...]:
        s()

    ...will probably work, but strikes me as unwieldy.

  3. gvanrossum commented on Jun 23, 2016

    @gvanrossum
    Member

    I see. Your special case defines an "interface" for each module to follow. Honestly I think the for-loop is a little clever here, so I would just unroll the loop. Or just add a # type: ignore to the call.

    I know what mypy could do, in theory, but I don't think it's worth the effort of actually implementing it.

  4. added this to the milestone on Jun 23, 2016
  5. fabianhjr commented on Jul 20, 2016

    @fabianhjr
    Contributor

    Just found a case form an existing codebase,

    The module threading has a function/attribute enumerate which is is used to check if there are other threads alive before exiting/restarting.

    https://github.com/fabianhjr/home-assistant/blob/improvement-typing/homeassistant/__main__.py#L276,L281

  6. gvanrossum commented on Jul 20, 2016

    @gvanrossum
    Member

    @fabianhjr What error do you get? I don't see how that code snippet relates to this issue yet -- the issue is about the type of [mod] being represented poorly (losing the fact that its values are all the mod module). I assume your problem is merely that the Python 3 stub for threading in typeshed doesn't have a definition for enumerate(). That's a typeshed bug which you can report here: https://github.com/python/typeshed (or better, submit a PR!).

  7. fabianhjr commented on Jul 20, 2016

    @fabianhjr
    Contributor

    The error is:

    homeassistant/__main__.py: note: In function "try_to_restart":
    homeassistant/__main__.py:278: error: "module" has no attribute "enumerate"
    

    EDIT: Ok, upon reading on typeshed I think I should open a PR over there. Thanks.

  8. gvanrossum commented on Jul 20, 2016

    @gvanrossum
    Member

    Yup, that has nothing to do with the issue here: even though the error message is superficially the same, the cause is unrelated.

  9. JukkaL commented on Jan 16, 2017

    @JukkaL
    Collaborator

    More generally, module aliases aren't supported:

    import module
    alias = module
    alias.foo  # not supported, even if module.foo exists
    
  10. removed this from the milestone on Mar 29, 2017
  11. ilevkivskyi commented on May 17, 2018

    @ilevkivskyi
    Member

    The module aliasing now works, but iterating over list of modules seems like a very low priority. Also this is superseded by python/typeshed#2147

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