I have a config.py file which has a list of constants, such as:
# config.py
NAME = 'John'
AGE = 23
In another file, I import this file as a module and then pass it as a parameter to other functions. I used ModuleType as the type for this parameter.
import config
from types import ModuleType
def f1(config: ModuleType) -> None:
print(config.NAME)
The problem is when I run pyright linter, it reports an error:
79:30 - error: Cannot access member "NAME" for type "ModuleType"
Member "NAME" is unknown (reportGeneralTypeIssues)
What's the correct way to type hint the config to avoid these errors?
By far the easiest and most convenient way to handle this is to just not annotate the
configargument, or annotate it asAny. You can provide a more specific annotation, but it gets extremely awkward.The problem with your existing annotation is that your
f1is annotated as taking arbitrary modules as arguments, and arbitrary modules may not have aNAMEattribute. (AlsoModuleTypeis intypes, nottyping.) A correct, specific annotation forf1would specify that it takes something with aNAMEattribute, which you can specify with a custom protocol class:but you'll have to do this for everything you want to define in
config, and it'll get even more awkward if you want to allow optional config definitions inconfig.Also, if you try to pass
configas an argument tof1now, it still won't work, because when you pass a module as an argument, mypy treats it as just a generic module, and doesn't consider its contents. (I don't know what pyright does, but that's how mypy handles it.) You would have to explicitly castconfig:which is extremely awkward. Plus, once you have this cast in place, mypy won't report an error even if
configdoesn't have aNAMEattribute, so you've gained no safety at all from all this awkward work.