Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Don't transform function calls on IPyAutocall objects #1121

Merged
merged 4 commits into from

4 participants

Thomas Kluyver Bradley M. Froehle Min RK Fernando Perez
Thomas Kluyver
Owner

Closes #1117.

Bradley M. Froehle

The lstrip isn't necessary.... or at least we don't use it later on in the_rest.startswith('[')

Owner

Good point.

Bradley M. Froehle
Collaborator

Anyway, looks fine to me. The logic in this section is terribly convoluted, the best I could do to disentangle it was something like

            if force_auto:
                # Don't rewrite if it is already a call.
                do_rewrite = not the_rest.startswith('(')
            else:
                if not the_rest:
                    # We only apply it to argument-less calls if the autocall
                    # parameter is set to 2.
                    do_rewrite = self.shell.autocall == 2
                elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
                    # Don't autocall in this case: item access for an object
                    # which is BOTH callable and implements __getitem__.
                    do_rewrite = False
                else:
                    do_rewrite = True

            # Figure out the rewritten command
            if do_rewrite:
                if the_rest.endswith(';'):
                    newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
                else:
                    newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
            else:
                newcmd = '%s %s' % (ifun,the_rest)

Thomas Kluyver
Owner

Thanks, Brad. I've tested that, and committed it here.

Bradley M. Froehle

Oops, not sure what happened here.

Bradley M. Froehle

Need to revert this change as well, as the tests expect 'autocallable ()'. My bad.

Owner

It's alright, it's a change I made (I should really have done a separate commit for it, but I wanted to go to bed).

The difference is that previously, if it decided not to rewrite the line, it simply used string formatting: newcmd = '%s %s' % (ifun,the_rest), which forced a single space in there. I've told it to use the default prefilter handler (normal_handler) instead. I think the new behaviour is better - when we're not rewriting it, I'd rather not change the input at all.

Min RK
Owner

I don't pretend to understand the slightly weird previous logic, but the replacement certainly looks clean and sensible, nice work!

Thomas Kluyver takluyver merged commit 7ea3e2f into from
Thomas Kluyver
Owner

Merged, to keep the queue moving. Tests are passing - if you spot any issues with this, I'll do my best to respond to them quickly.

@fperez - tagged so you're aware of this.

Fernando Perez
Owner

Thanks, @takluyver. Good call on keeping the queue moving, otherwise we'll drown. I had a look and don't see any problems, and with the tests added we should be in good shape.

Brian E. Granger ellisonbg referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 27 additions and 21 deletions.
  1. +24 −20 IPython/core/prefilter.py
  2. +3 −1 IPython/core/tests/test_handlers.py
44 IPython/core/prefilter.py
View
@@ -826,29 +826,33 @@ def handle(self, line_info):
elif esc == ESC_PAREN:
newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
else:
- # Auto-paren.
- # We only apply it to argument-less calls if the autocall
- # parameter is set to 2. We only need to check that autocall is <
- # 2, since this function isn't called unless it's at least 1.
- if not the_rest and (self.shell.autocall < 2) and not force_auto:
- newcmd = '%s %s' % (ifun,the_rest)
- auto_rewrite = False
+ # Auto-paren.
+ if force_auto:
+ # Don't rewrite if it is already a call.
+ do_rewrite = not the_rest.startswith('(')
else:
- if not force_auto and the_rest.startswith('['):
- if hasattr(obj,'__getitem__'):
- # Don't autocall in this case: item access for an object
- # which is BOTH callable and implements __getitem__.
- newcmd = '%s %s' % (ifun,the_rest)
- auto_rewrite = False
- else:
- # if the object doesn't support [] access, go ahead and
- # autocall
- newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
- elif the_rest.endswith(';'):
- newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
+ if not the_rest:
+ # We only apply it to argument-less calls if the autocall
+ # parameter is set to 2.
+ do_rewrite = (self.shell.autocall >= 2)
+ elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
+ # Don't autocall in this case: item access for an object
+ # which is BOTH callable and implements __getitem__.
+ do_rewrite = False
else:
- newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
+ do_rewrite = True
+ # Figure out the rewritten command
+ if do_rewrite:
+ if the_rest.endswith(';'):
+ newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
+ else:
+ newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
+ else:
+ normal_handler = self.prefilter_manager.get_handler_by_name('normal')
+ return normal_handler.handle(line_info)
+
+ # Display the rewritten call
if auto_rewrite:
self.shell.auto_rewrite_input(newcmd)
4 IPython/core/tests/test_handlers.py
View
@@ -132,6 +132,8 @@ def test_handlers():
run([
('len "abc"', 'len "abc"'),
('autocallable', 'autocallable()'),
+ # Don't add extra brackets (gh-1117)
+ ('autocallable()', 'autocallable()'),
(",list 1 2 3", 'list("1", "2", "3")'),
(";list 1 2 3", 'list("1 2 3")'),
("/len range(1,4)", 'len(range(1,4))'),
@@ -148,7 +150,7 @@ def test_handlers():
('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
('call_idx 1', 'call_idx(1)'),
- ('len', 'len '), # only at 2 does it auto-call on single args
+ ('len', 'len'), # only at 2 does it auto-call on single args
])
ip.magic('autocall 2')
run([
Something went wrong with that request. Please try again.