python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.21k stars 2.78k forks source link

Tracking variable whereabouts in a plugin #9010

Open kornicameister opened 4 years ago

kornicameister commented 4 years ago

Please provide more information to help us understand the issue:

from luguru import logger

LOG_A = logger.opt(lazy=False)
LOG_B = logger.opt(lazy=True)

LOG_A.info('Test {}', lambda x: x)    # should work
LOG_B.info('Test {}', lambda x: x)    # error

logger.opt(lazy=False).info('Test {c}', c=lambda x: x)  # should work
logger.opt(lazy=True).info('Test {d}', d=lambda x: x)   # error

In short: with loguru you can use Callable[[], Any] for lazy loggers to avoid costly computations. But those have to be non-argument callables. Above you can find non-lazy loggers that will work just fine by doing str(callable). In other words, to rephrase question from above, how can we:

track a variable/object on which behalf a method was called?

This is quite vital because type checking cannot be done solely on a method call level because we need something from another call. There is opt method being called but having call details from it without anything to tie them to will not help too much.

kornicameister commented 4 years ago

@Delgan I am linking you to this issue. If it comes to it, you will be able to explain runtime details much better :+1:

Delgan commented 4 years ago

Basically, what we need is a way to customize the returned type of a method based on introspection of the arguments.

foo = logger.opt(lazy=True)   # => foo is of type "LazyLogger"
bar = logger.opt(lazy=False)  # => bar is of type "Logger"

These types needs to be defined by the plugin, and later we need to be able to use them to decide whether foo.info(...) is valid or not.

JukkaL commented 4 years ago

I don't think that you need a plugin for this. Why not use literal types and and overloaded function to vary the return type of logger.opt based on the value of lazy?

Delgan commented 4 years ago

@JukkaL Sounds like a promising idea. I was not aware of literal types, thanks!

What do you think @kornicameister? Would that solve the problem if we add this to the loguru type hints file?

kornicameister commented 4 years ago

@JukkaL this might work. I guess loguru already exports typings so we can of course check it out.

kornicameister commented 4 years ago

@JukkaL I have checked typing in loguru and indeed we can add LazyLogger if lazy=True but then again I am not sure how we can describe a signature of method like info, debug and so on. Indeed a signatures like:

    @overload
    def info(__self, __message: str, *args: Any, **kwargs: Any) -> None: ...
    @overload
    def info(__self, __message: Any) -> None: ...

are quite accurate given dynamic nature of loguru. For one, lazy=True and how it affects callables is just one example. Another one can be opt(record=True). With that set we can use special record dictionary in message template. Can we in fact use just typing to do describe all that? I mean perhaps lazy can be done somehow , but we need to know how to differentiate all Callable (that can be passed both as *arg or **kwarg) from other arguments passed to methods of loggers where each of those arguments can also be passed as *arg or **kwarg.

This sounds as some high level problem but if there's way to deal with that, I'd happy to know :D.

kornicameister commented 4 years ago

@JukkaL Care to check this one out? https://github.com/kornicameister/loguru-mypy/pull/7 ? I assume that if that's correct it can be an answer to this issue.

kornicameister commented 4 years ago

FYI: It seems like it is sufficient to keep a state of what we want to track over in an instance of the plugin and pass it to specific handlers via functools.partial or equivalent.

That approach is being used in loguru-mypy already. Wonder if that's correct one as well as if that's an intended usage.

JukkaL commented 4 years ago

Wonder if that's correct one as well as if that's an intended usage.

Can you explain this in more detail? Based on the description it's hard to say.

kornicameister commented 4 years ago

@JukkaL it is actually not just description. I have just forgotten to link appropriate part of the plugin :crying_cat_face: Here it is for reference:

I just realized, that apart from a question if that is "the" way to implement that, there is just one question related to caching, but let's maybe stick to the original one for the time being.

AlexWaygood commented 2 years ago

Hi! Is this still a problem for loguru-mypy, or can this issue now be closed? :)