-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
fix(python): show inefficient apply warning in ipython #10312
Conversation
Super-clean fix; great pick-up! With our current usage the expansion of
Unquestionably :) |
good idea, thanks! yup, can just check if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, looks like something needs a fix-up after adding the IPython check?
oh wow, check this out: running in python repl, py311: the third element is >>> pprint.pprint(list(dis.get_instructions(lambda x: np.sin(x)+1)))
[Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=1, is_jump_target=False, positions=Positions(lineno=1, end_lineno=1, col_offset=0, end_col_offset=0)),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='np', argrepr='np', offset=2, starts_line=None, is_jump_target=False, positions=Positions(lineno=1, end_lineno=1, col_offset=50, end_col_offset=52)),
Instruction(opname='LOAD_METHOD', opcode=160, arg=1, argval='sin', argrepr='sin', offset=14, starts_line=None, is_jump_target=False, positions=Positions(lineno=1, end_lineno=1, col_offset=50, end_col_offset=56)),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='x', argrepr='x', offset=36, starts_line=None, is_jump_target=False, positions=Positions(lineno=1, end_lineno=1, col_offset=57, end_col_offset=58)),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=Positions(lineno=1, end_lineno=1, col_offset=50, end_col_offset=59)),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=Positions(lineno=1, end_lineno=1, col_offset=50, end_col_offset=59)),
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=1, argrepr='1', offset=52, starts_line=None, is_jump_target=False, positions=Positions(lineno=1, end_lineno=1, col_offset=60, end_col_offset=61)),
Instruction(opname='BINARY_OP', opcode=122, arg=0, argval=0, argrepr='+', offset=54, starts_line=None, is_jump_target=False, positions=Positions(lineno=1, end_lineno=1, col_offset=50, end_col_offset=61)),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False, positions=Positions(lineno=1, end_lineno=1, col_offset=0, end_col_offset=0))]
> running from script, note that now, the third element is (.311venv) marcogorelli@DESKTOP-U8OKFP3:~/tmp$ cat t.py
import numpy as np
import dis
import pprint
pprint.pprint(list(dis.get_instructions(lambda x: np.sin(x)+1)))
(.311venv) marcogorelli@DESKTOP-U8OKFP3:~/tmp$ python t.py
[Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=5, is_jump_target=False, positions=Positions(lineno=5, end_lineno=5, col_offset=0, end_col_offset=0)),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='np', argrepr='NULL + np', offset=2, starts_line=None, is_jump_target=False, positions=Positions(lineno=5, end_lineno=5, col_offset=50, end_col_offset=52)),
Instruction(opname='LOAD_ATTR', opcode=106, arg=1, argval='sin', argrepr='sin', offset=14, starts_line=None, is_jump_target=False, positions=Positions(lineno=5, end_lineno=5, col_offset=50, end_col_offset=56)),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='x', argrepr='x', offset=24, starts_line=None, is_jump_target=False, positions=Positions(lineno=5, end_lineno=5, col_offset=57, end_col_offset=58)),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=26, starts_line=None, is_jump_target=False, positions=Positions(lineno=5, end_lineno=5, col_offset=50, end_col_offset=59)),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=30, starts_line=None, is_jump_target=False, positions=Positions(lineno=5, end_lineno=5, col_offset=50, end_col_offset=59)),
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=1, argrepr='1', offset=40, starts_line=None, is_jump_target=False, positions=Positions(lineno=5, end_lineno=5, col_offset=60, end_col_offset=61)),
Instruction(opname='BINARY_OP', opcode=122, arg=0, argval=0, argrepr='+', offset=42, starts_line=None, is_jump_target=False, positions=Positions(lineno=5, end_lineno=5, col_offset=50, end_col_offset=61)),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=Positions(lineno=5, end_lineno=5, col_offset=0, end_col_offset=0))] But before Python3.11, it seems it was consistently I think we should probably match on both ( |
Yup, let's do it - it's definitely safe the way the code is currently put together, and not limiting it to IPython will cover our bases (as this can clearly happen elsewhere 🤔) |
Hi @MarcoGorelli, sorry to be commenting on a closed PR. Not 100% sure this is a problem, but just wanted to draw to your attention. I can see that this PR adds a dependency on From a "clean" environment, the described usage in Steps to reproduce # assumes the starting dir is py-polars
deactivate # if applicable
make clean
make requirements
source .venv/bin/activate
PYTHONPATH=polars/utils pytest tests/test_udfs.py # usage described in file
# 39 failed, 40 passed - the failed tests are the ones ending in `in_ipython` and then when I do the below, all tests pass pip install ipython
PYTHONPATH=polars/utils pytest tests/test_udfs.py Came to my attention as I have (finally) made a start on adding more numpy funcs. |
thanks for noticing this - yeah might be good to add it to the dev requirements |
fixes the bug reported here #9968 (comment)
Essentially, the bytecode is slightly different between python and ipython 😧 I think many, many polars users will be running jupyter notebooks, so it's probably important to get this right
The hardest part was coming up with tests which fail on
main
Gist of the test changes:
test_udfs
which runsipython
in a subprocess and checks the printed outputTEST_CASES
so that the function is a string, rather than a function, so it can be used in the above (and changefunc
toeval(func)
in the existing tests)The only source code change is: