Open whitphx opened 2 months ago
Converting lines inside functions (precisely, "code blocks") is difficult because they are undeterministic.
Here is an example where what sleep
in foo
refers to is dynamically determined at runtime.
def foo():
sleep(1)
from time import sleep
foo()
sleep = lambda x: None # no-op
foo()
On the other hand, the scope of the sleep
can be determined by parsing the AST by the nearest-enclosing-scope policy.
The point is, the nearest-enclosing-scope is determined at build time (so the scope is deterministic), the name resolution is done by the scope at runtime.
Let's see what some existing static analyzers do:
Pylance, for example, parses the example above and infers the sleep
as sleep: ((secs: float) -> None) | ((x: Any) -> None)
, a union type.
So, for this issue, it would be a solution to deal with only the case where the inferred name resolution can be determined as a single result. If so, the example above becomes not a target of this auto-conversion.
time.sleep()
-> await asyncio.sleep()
, and converting the normal functions is still todo.time.sleep()
to await asyncio.sleep()
can be replaced with patching time.sleep
with asyncio.sleep
and AST transformation from time.sleep()
to await time.sleep()
. This makes the AST processing simpler and looks better.
time.sleep()
->await asyncio.sleep()
Such auto-conversion is already implemented in #965 for
st.write_stream()
that convertsst.write_stream()
toawait st.write_stream()
, so we can simply extend it.