Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deduced actual type of variable not used in lambda context #1016

Closed
oldium opened this issue Mar 5, 2021 · 5 comments
Closed

Deduced actual type of variable not used in lambda context #1016

oldium opened this issue Mar 5, 2021 · 5 comments
Labels
fixed in next version (main) A fix has been implemented and will appear in an upcoming version

Comments

@oldium
Copy link

oldium commented Mar 5, 2021

Environment data

  • Language Server version: 2021.2.4 (pyright a18e6fb4)
  • OS and version: Windows 10
  • Python version (& distribution if applicable, e.g. Anaconda): Python 3.4.1, typing 3.6.2 (from PyPi)

Expected behaviour

Deduced actual type (reduced by isinstance's) is recognised in lambda context.

Actual behaviour

When typed argument is used inside lambda, the original argument type is used instead of the one reduced by isinstance's.

Warning:

(parameter) value: int | (*args: Unknown, **kwargs: Unknown) -> Any
Object of type "int" is not callablePylancereportGeneralTypeIssues)

Logs

This is reported from a company notebook, so I cannot provide logs (data collection restrictions).

Code Snippet / Additional information

This fails, see the last line and a value() call.:

from typing import Callable
def int_to_value(value: 'int | Callable') -> 'dict':
  if isinstance(value, int):
    return dict(hex="0x{:X}".format(value))
  else:
    return dict(hex=lambda: "0x{:X}".format(value()))

Please note that the following works correctly:

from typing import Callable
def int_to_value(value: 'int | Callable') -> 'dict':
  if isinstance(value, int):
    return dict(hex="0x{:X}".format(value))
  else:
    return dict(hex="0x{:X}".format(value()))
@github-actions github-actions bot added the triage label Mar 5, 2021
@erictraut
Copy link
Contributor

Type narrowing is not applied to variables captured within a lambda context because captured symbols can be reassigned a new value (with a different type) by the time the lambda is executed. In this particular case, it is safe, but in general a type checker cannot make this assumption.

The workaround is to assign the narrowed value to a local variable that has a non-union callable type.

from typing import Callable
def int_to_value(value: 'int | Callable') -> 'dict':
  if isinstance(value, int):
    return dict(hex="0x{:X}".format(value))
  else:
    callable_value = value
    return dict(hex=lambda: "0x{:X}".format(callable_value()))

@oldium oldium changed the title Callable not recognised correctly Deduced acutal type of variable not used in lambda context Mar 5, 2021
@oldium
Copy link
Author

oldium commented Mar 5, 2021

Perfect, thanks for really fast response, it works fine with this workround.

@oldium oldium changed the title Deduced acutal type of variable not used in lambda context Deduced actual type of variable not used in lambda context Mar 5, 2021
@erictraut erictraut reopened this Sep 27, 2021
@erictraut
Copy link
Contributor

I found a way to handle type narrowing of local variables and parameters captured by inner-scoped functions and lambdas, so the above workaround will no longer be necessary in this case.

@erictraut erictraut added fixed in next version (main) A fix has been implemented and will appear in an upcoming version and removed triage labels Sep 27, 2021
@jakebailey
Copy link
Member

This issue has been fixed in version 2021.9.4, which we've just released. You can find the changelog here: https://github.com/microsoft/pylance-release/blob/main/CHANGELOG.md#202194-29-september-2021

@oldium
Copy link
Author

oldium commented Sep 30, 2021

Works great. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fixed in next version (main) A fix has been implemented and will appear in an upcoming version
Projects
None yet
Development

No branches or pull requests

3 participants