emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: python-mode: make sure output is not eaten


From: Slawomir Nowaczyk
Subject: Re: python-mode: make sure output is not eaten
Date: Wed, 30 Aug 2006 23:08:51 +0200

On Mon, 28 Aug 2006 17:43:46 -0400
Stefan Monnier <address@hidden> wrote:

#> > I works better -- no longer hangs my Emacs, but after python-send-buffer
#> > the final prompt still doesn't appear.
#> 
#> I believe my last patch fixes this as well.

Yes, it seems to work.

#> > Agreed. But why is removing "_emacs_out ()" any more selective than
#> > removing ">>> _emacs_out ()"?
#> 
#> We're talking about "^_emacs_out " vs "^\\(>>> \\)?_emacs_out": clearly one
#> of the two regexps describes a superset of the other.  If you can guarantee
#> that it'll always match "^>>> _emacs_out ", then it's a different question.

I do not think it is a problem... The following patch seems to work for me:

************************************************************

--- m:/EmacsCVS/EmacsCVS/lisp/progmodes/python.el       2006-08-30 
17:05:09.399865600 +0200
+++ c:/Emacs/lisp/progmodes/python.el   2006-08-30 21:26:32.132132800 +0200
@@ -1271,7 +1271,7 @@
           (setq python-preoutput-skip-next-prompt nil)
           (setq line (substring line (match-end 0))))
         ;; Recognize special _emacs_out lines.
-        (if (and (string-match "\\`_emacs_out \\(.*\\)\n\\'" line)
+        (if (and (string-match "\\`>>> _emacs_out \\(.*\\)\n\\'" line)
                  (local-variable-p 'python-preoutput-result))
             (progn
               (setq python-preoutput-result (match-string 1 line))
@@ -1351,7 +1351,8 @@
       ;; seems worth putting in a separate file, and it's probably cleaner
       ;; to put it in a module.
       ;; Ensure we're at a prompt before doing anything else.
-      (python-send-receive "import emacs; print '_emacs_out ()'")))
+      (python-send-string "import emacs")
+      (python-send-receive "print '_emacs_out ()'")))
   (if (derived-mode-p 'python-mode)
       (setq python-buffer (default-value 'python-buffer))) ; buffer-local
   ;; Without this, help output goes into the inferior python buffer if
@@ -1601,7 +1602,7 @@
                  (current-word))))
     ;; First try the symbol we're on.
     (or (and symbol
-            (python-send-receive (format "emacs.eargs(%S, %s)"
+            (python-send-receive (format "\nemacs.eargs(%S, %s)"
                                          symbol python-imports)))
        ;; Try moving to symbol before enclosing parens.
        (let ((s (syntax-ppss)))
@@ -1614,9 +1615,9 @@
                  (skip-chars-backward "a-zA-Z._")
                  (if (< (point) point)
                      (python-send-receive
-                      (format "emacs.eargs(%S, %s)"
-                              (buffer-substring-no-properties (point) point)
-                              python-imports)))))))))))
+                      (format "\nemacs.eargs(%S, %s)"
+                               (buffer-substring-no-properties (point) point)
+                               python-imports)))))))))))

;;;; Info-look functionality.

**********************************************************************
#> > I think I understand your reasoning, but I do not think I agree
#> > with it. If we *want* to wait for prompt after both "import ..."
#> > and "print ...", we can always use python-send-receive twice,
#> > instead of python-send-string followed by python-send-receive. But
#> > I still do not see why one is supposed to be more robust than the
#> > other.
#> 
#> python-send-receive doesn't wait for a prompt but for the _emacs_out
#> cookie, which the `import' does not output.

Right, my mistake.

#> > Also, I have finally found a case in which adding "; print ..."
#> > breaks things: assume the string is "if False: print 1". Observe
#> > that "if False: print 1; print '_emacs_out ()'" does *not* print
#> > anything.
#> 
#> > It may not be a *real* problem, but it does -- IMHO -- show that
#> > sending two separate commands *is* more robust.
#> 
#> It's not the only case, and I agree it's not a purely academic
#> question. But: such cases does not occur in python.el (where we only
#> add the "; print ..." at a few special spots where we have control
#> over the text that precedes it).

Yes, I know. My main objection -- although I admit, it is a purely
aesthetic one -- is that if we cannot make the code work right for the
simple case of sending two commands, the underlying code is too fragile.

#> > #> It's not a command, so it can only called from elisp code. Check the
#> > #> callers and you'll see it is never called with a newline. So it's OK
#> > #> to make such an assumption.
#> 
#> > Well, maybe. But still, either python-send-string works for multiline
#> > strings (in which case python-send-command should work as well)
#> 
#> I see no reason why the two should be so linked.

python-send-command does very little beyond calling python-send-string.
Definitely nothing that would make reasonable for only one of them to
work with multiline strings.

#> > or python-send-string doesn't work for multiline strings, in which case
#> > the assert in python-send-command doesn't help at all (as you wrote,
#> > nothing can call it with multiline command anyway).
#> 
#> In python-send-string, multiline strings work.  In python-send-command
#> multiline strings were very likely to fail because we added "; print ...".
#> Hence the presence of an `assert' (assertions are of no use to the user,
#> their only meaning is for the programmer as a form of documentation that's
#> slightly better sync'd with the code than mere comments).

In other words, the only reason for the assert is that we have chosen to
add "; print" instead of sending two commands?

#> > #> > It should work just fine with multiple lines, the only thing which
#> > #> > might cause problems is indentation, and even that only if there is
#> > #> > an indented block at the very end.
#> > #> 
#> > #> Sending a multiline thingy via python-send-string will look like
#> > #> absolute crap in the resulting output,
#> 
#> > I disagree...
#> 
#> Actually, you seem to be right: the prompt-elimination heuristic
#> seems to work well for this in practice.
#> 
#> Although it points top another problem: the result of the evaluation
#> is printed on the line of the prompt. I.e. if I start with
#> 
#>    >>> 
#> 
#> after python-send-string "print 1" I get
#> 
#>    >>> 1
#>    >>> 
#> 
#> rather than
#> 
#>    >>> 
#>    1
#>    >>> 
#> 
#> or
#> 
#>    >>> print 1
#>    1
#>    >>> 

Yes, I know... that is on the list of bugs I want to fix. I was just
waiting for the current code to stabilise. I believe that the right
thing to do would be to print, in the above case, something like:

>>> # evaluating buffer <test.py>
1
>>> 

or

>>> # evaluating region in buffer <test.py>
1
>>> 

The other mode, python-mode.el, uses something like this, and I remember
it was really helpful, especially when I worked with multiple files. It
really allowed me to see what was happening.

I am not sure what should be printed by python-send-string, but maybe
simple "print 1" would work best.

#> > #> because all the intermediate prompts will get concatenated rather
#> > #> than interleaved with the input.
#> 
#> > Right, but what's wrong with that? If I send a string like "a = 1\n
#> > print 'Test'\n b = 2", what's wrong with getting output like
#> > ">>> Test\n>>> \n >>>"?
#> 
#> In a session log, the prompt is expected to be followed by user
#> input, not program output.

Sure... some day we might want to do that. But it's pretty far down on
my list of priorities.

#> > #> So I see no point in trying to support this in a case such as
#> > #> `python-send-command' where we don't use this flexibility anyway (and
#> > #> where we need to analyze the output, so the more control over it the
#> > #> better).
#> 
#> > You may be right... but if you think it makes sense, the assert should
#> > be in python-send-string, not in python-send-command.
#> 
#> I see no point in restricting the use of python-send-string where the only
#> potential problem is ugly output, but not incorrect execution.

I agree.

#> Whereas in python-send-command, the result could have been incorrect
#> execution.

Yes, but -- IMHO -- this is only due to the bad design decision of
adding "; print"

#> Also adding the assert to python-send-command did not restrict the
#> user in any way, only the python.el hacker.

Right. Fine, this is probably not important enough to warrant further
discussion.

#> > I have hard time imagining how the current code could work at all
#> > if it send anything to Python interpreter while it was busy, but I
#> > will take a closer look at this.
#> 
#> Indeed, if the python process is busy when we send the command, the
#> result may be wrong. But I expect that in most cases it'll be right.

It seems to work to some degree in my very limited testing... but there
are a lot of ways to break it. There is some kind of queueing
implemented in python-mode.el, which detects busy interpreter and waits
with sending commands... but I haven't checked how is it implemented.

#> Still, I think checking busy/idle-ness is a good idea in itself and
#> your above suggestion as well.

I agree.

#> Note that checking idle/busy-ness can be tricky. Even assuming the
#> program's output does not look like a prompt, you may have to count
#> the number of newlines sent to the python's process to know how many
#> prompts to expect in return. Or alternatively, you'd have to send
#> each input line one at a time, waiting for the prompt before sending
#> the next one.

I was only thinking about checking busyness of things like
python-send-region -- when we can wait for _emacs_out. I believe it is
not worth the trouble to worry about python-send-string.

-- 
 Best wishes,
   Slawomir Nowaczyk
     ( address@hidden )

Hardware: The parts of a computer system that can be kicked.





reply via email to

[Prev in Thread] Current Thread [Next in Thread]