From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: kobarity Newsgroups: gmane.emacs.bugs Subject: bug#60142: 28.1; python.el Incorrect region when python-shell-send-region from indented code Date: Fri, 23 Dec 2022 00:01:15 +0900 Message-ID: References: <83mt7lf12y.fsf@gnu.org> <87zgbjheqt.fsf@gmail.com> Mime-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Content-Type: multipart/mixed; boundary="Multipart_Fri_Dec_23_00:01:13_2022-1" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="14057"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Wanderlust/2.15.9 (Almost Unreal) SEMI-EPG/1.14.7 (Harue) FLIM-LB/1.14.9 (=?UTF-8?Q?Goj=C5=8D?=) APEL-LB/10.8 EasyPG/1.0.0 Emacs/30.0.50 (x86_64-pc-linux-gnu) MULE/6.0 (HANACHIRUSATO) To: Augusto Stoffel , Eli Zaretskii , pmercatoris , 60142@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Thu Dec 22 17:39:15 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1p8ObD-0003TA-Bc for geb-bug-gnu-emacs@m.gmane-mx.org; Thu, 22 Dec 2022 17:39:15 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p8Ob2-0007Do-0X; Thu, 22 Dec 2022 11:39:04 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p8Ob0-0007Dg-N5 for bug-gnu-emacs@gnu.org; Thu, 22 Dec 2022 11:39:02 -0500 Original-Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p8Ob0-0005Di-Dx for bug-gnu-emacs@gnu.org; Thu, 22 Dec 2022 11:39:02 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1p8Ob0-0000Yw-6d for bug-gnu-emacs@gnu.org; Thu, 22 Dec 2022 11:39:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: kobarity Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 22 Dec 2022 16:39:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 60142 X-GNU-PR-Package: emacs Original-Received: via spool by 60142-submit@debbugs.gnu.org id=B60142.16717270972137 (code B ref 60142); Thu, 22 Dec 2022 16:39:02 +0000 Original-Received: (at 60142) by debbugs.gnu.org; 22 Dec 2022 16:38:17 +0000 Original-Received: from localhost ([127.0.0.1]:36026 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p8OaG-0000YP-PG for submit@debbugs.gnu.org; Thu, 22 Dec 2022 11:38:17 -0500 Original-Received: from mail-yw1-f175.google.com ([209.85.128.175]:35684) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1p8OaE-0000YG-SY for 60142@debbugs.gnu.org; Thu, 22 Dec 2022 11:38:15 -0500 Original-Received: by mail-yw1-f175.google.com with SMTP id 00721157ae682-45ef306bd74so34021397b3.2 for <60142@debbugs.gnu.org>; Thu, 22 Dec 2022 08:38:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:user-agent:references:in-reply-to:subject:to:from :message-id:date:from:to:cc:subject:date:message-id:reply-to; bh=/e+OhHpyXoOLafGPKR9IzTLsa942PI28R6nHcB2gl7w=; b=Rm3VxzlPSeB6l3CH7fohos8dLdJKnwYIDTC8nGbk6qG5gfeYvrQIoZ5rQunlKoaQWd Bf310BibjN84VeTmUfsJwuO7QA9XaKLZm8Dwd4C557I75C4jA/yfPFOTJPH5/WvMln9P bxuvWXCuIvsYorNGsQEz7JybfPh06ExcidlIInF0bte73JyoGSC9OmKnJUp8G1BX95MJ oI0YLxXjj9roAhYVY7yRZQY5ODRrnBLvDDACxaeaiNAQuiPP+1AjvtvY3Jv6HJj25CCE SdkEQjtv+aduPOWyyKhMhgPbnJukqwYdxCjZIPmGUcykww5nz8qc79RhJmT0JVDzO2FN oEmw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:user-agent:references:in-reply-to:subject:to:from :message-id:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=/e+OhHpyXoOLafGPKR9IzTLsa942PI28R6nHcB2gl7w=; b=c6s1N0hHQ6yqYPNfzgJhJ7nM3QO5AsGzWYJDvp/o0FptspQEuJCBcTgr9vyFu2Slvb WKKfLpq2Ddj96jNooQOfhyHPkQtiqn3u4KzRTX/+29fEAnTD/SCrtPagJtbn7RrdkG3G wz0pXYPvFSjmS80uTiWm8tcM8h9WEcO+mhO/z8/K5AS0dBNz8xZ4m30KfJcyDm6meA9d xIebgrSy29J43H6udO/HL3Jtpv1yFfAtIlAkqin6uWAj3ncV7m5c6uUnS1GLwncjToJx K9uEVWkNPrPOgf5T/ICDggz9+dgmwTIuJp8Gh/ndKKqS4WS5NXR6nlNysauc2MGFXya5 0qrw== X-Gm-Message-State: AFqh2kpCEiIMvg/Ra9SsloxgO8mU/7quFA8jfu4lbq3IWGuxtkklHPMW XrWMTEZ/nUj2eVaUJrT5MGmxbM44gQg= X-Google-Smtp-Source: AMrXdXvRidE0n+fx5UihMHs6JXVaQ1NOD9OAT2M97EQQIDqkvZc+8lrQqXBtiSQKoPUyLuYe040+sQ== X-Received: by 2002:a17:903:40c8:b0:189:65e7:e16b with SMTP id t8-20020a17090340c800b0018965e7e16bmr6676545pld.66.1671721296375; Thu, 22 Dec 2022 07:01:36 -0800 (PST) Original-Received: from localhost (58x12x133x161.ap58.ftth.ucom.ne.jp. [58.12.133.161]) by smtp.gmail.com with ESMTPSA id d4-20020a170903230400b001896af10ca7sm642632plh.134.2022.12.22.07.01.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 22 Dec 2022 07:01:35 -0800 (PST) In-Reply-To: <87zgbjheqt.fsf@gmail.com> X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:251673 Archived-At: --Multipart_Fri_Dec_23_00:01:13_2022-1 Content-Type: text/plain; charset=US-ASCII Augusto Stoffel wrote: > On Sun, 18 Dec 2022 at 12:39, Eli Zaretskii wrote: > >> If I select the `a` or `a = "test"` it will correctly send it to the > >> console, however it won't echo the evaluation of the statement. > > I can at least explain why this happens and is expected. > > An evaluation result is printed only if you send a bunch of statements, > the last of which is an expression. OTOH, since whitespace is > significant in Python, if you evaluate anything that's not a "toplevel > form" it gets wrapper in a `if True:` statement, so the actually > evaluated code is not a simple expression anymore. > > It seems hard to work around this limitation. Sorry for the late reply. As Augusto explained, `if True:` is added to the indented region. This behavior is documented in `python-shell-buffer-substring'. Maybe it's better to add a reference to `python-shell-buffer-substring' in the docstring of `python-shell-send-region'. What I'm trying to do is to improve the behavior in some use cases. Specifically, there is no need to add `if True:` if the region consists of a single statement such as `a` or `a = "test"`. Removing leading spaces should be enough to avoid an indentation error even if the single statement spans multiple lines. The corner case is the following use case. #+begin_src python if True: s = """ a = 1 b = 2 """ #+end_src Let's assume we want to send the lines "a = 1" and "b = 1" only. Although they are part of a single statement (multiline string), `if True:` should be added to avoid an indentation error. In other words, they should not be considered as a single statement. To address such situation, the single statement check should be done after calling `narrow-to-region'. Attached is a patch to achieve this. I appreciate your comments. Thanks, --Multipart_Fri_Dec_23_00:01:13_2022-1 Content-Type: application/octet-stream; type=patch; name="0001-Fix-python-shell-buffer-substring-when-retrieving-a-.patch" Content-Disposition: attachment; filename="0001-Fix-python-shell-buffer-substring-when-retrieving-a-.patch" Content-Transfer-Encoding: 7bit >From 5512a76bf696e33003cf3c2be7de6fe7c0464b98 Mon Sep 17 00:00:00 2001 From: kobarity Date: Thu, 22 Dec 2022 23:08:40 +0900 Subject: [PATCH] Fix python-shell-buffer-substring when retrieving a single statement * lisp/progmodes/python.el (python-shell-buffer-substring): Do not add "if True:" line when retrieving a single statement. (python-shell-send-region): Add a reference to `python-shell-buffer-substring' in docstring. * test/lisp/progmodes/python-tests.el (python-shell-buffer-substring-13) (python-shell-buffer-substring-14, python-shell-buffer-substring-15) (python-shell-buffer-substring-16, python-shell-buffer-substring-17): New tests. (Bug#60142) --- lisp/progmodes/python.el | 45 +++++++++++++------- test/lisp/progmodes/python-tests.el | 64 +++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 14 deletions(-) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index bdc9e6fa78..c808f57171 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -3717,19 +3717,35 @@ python-shell-buffer-substring appending extra empty lines so tracebacks are correct. 3. When the region sent is a substring of the current buffer, a coding cookie is added. - 4. Wraps indented regions under an \"if True:\" block so the - interpreter evaluates them correctly." - (let* ((start (save-excursion - ;; If we're at the start of the expression, and - ;; there's just blank space ahead of it, then expand - ;; the region to include the start of the line. - ;; This makes things work better with the rest of - ;; the data we're sending over. + 4. When the region consists of a single statement, leading + whitespaces will be removed. Otherwise, wraps indented + regions under an \"if True:\" block so the interpreter + evaluates them correctly." + (let* ((single-p (save-restriction + (narrow-to-region start end) + (= (progn + (goto-char start) + (python-nav-beginning-of-statement)) + (progn + (goto-char end) + (python-nav-beginning-of-statement))))) + (start (save-excursion + ;; If we're at the start of the expression, and if + ;; the region consists of a single statement, then + ;; remove leading whitespaces, else if there's just + ;; blank space ahead of it, then expand the region + ;; to include the start of the line. This makes + ;; things work better with the rest of the data + ;; we're sending over. (goto-char start) - (if (string-blank-p - (buffer-substring (line-beginning-position) start)) - (line-beginning-position) - start))) + (if single-p + (progn + (skip-chars-forward "[:space:]" end) + (point)) + (if (string-blank-p + (buffer-substring (line-beginning-position) start)) + (line-beginning-position) + start)))) (substring (buffer-substring-no-properties start end)) (starts-at-point-min-p (save-restriction (widen) @@ -3753,7 +3769,7 @@ python-shell-buffer-substring (python-mode) (when fillstr (insert fillstr)) - (when (not toplevel-p) + (when (and (not single-p) (not toplevel-p)) (forward-line -1) (insert "if True:\n") (delete-region (point) (line-end-position))) @@ -3797,7 +3813,8 @@ python-shell-send-region When called interactively SEND-MAIN defaults to nil, unless it's called with prefix argument. When optional argument MSG is non-nil, forces display of a user-friendly message if there's no -process running; defaults to t when called interactively." +process running; defaults to t when called interactively. The +substring to be sent is retrieved using `python-shell-buffer-substring'." (interactive (list (region-beginning) (region-end) current-prefix-arg t)) (let* ((string (python-shell-buffer-substring start end (not send-main) diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index 17d6d8aa70..930234a12f 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -4456,6 +4456,70 @@ python-shell-buffer-substring-12 (point-max)) "# -*- coding: utf-8 -*-\n\nif True:\n # Whitespace\n\n print ('a')\n\n")))) +(ert-deftest python-shell-buffer-substring-13 () + "Check substring from indented single statement." + (python-tests-with-temp-buffer + " +def foo(): + a = 1 +" + (should (string= (python-shell-buffer-substring + (python-tests-look-at "a = 1") + (pos-eol)) + "# -*- coding: utf-8 -*-\n\na = 1")))) + +(ert-deftest python-shell-buffer-substring-14 () + "Check substring from indented single statement spanning multiple lines." + (python-tests-with-temp-buffer + " +def foo(): + a = \"\"\"Some + string\"\"\" +" + (should (string= (python-shell-buffer-substring + (python-tests-look-at "a = \"\"\"Some") + (pos-eol 2)) + "# -*- coding: utf-8 -*-\n\na = \"\"\"Some\n string\"\"\"")))) + +(ert-deftest python-shell-buffer-substring-15 () + "Check substring from partial statement." + (python-tests-with-temp-buffer + " +def foo(): + a = 1 +" + (should (string= (python-shell-buffer-substring + (python-tests-look-at " a = 1") + (python-tests-look-at " = 1")) + "# -*- coding: utf-8 -*-\n\na")))) + +(ert-deftest python-shell-buffer-substring-16 () + "Check substring from partial statement." + (python-tests-with-temp-buffer + " +def foo(): + a = 1 +" + (should (string= (python-shell-buffer-substring + (python-tests-look-at "1") + (1+ (point))) + "# -*- coding: utf-8 -*-\n\n1")))) + +(ert-deftest python-shell-buffer-substring-17 () + "Check substring from multiline string." + (python-tests-with-temp-buffer + " +def foo(): + s = \"\"\" + a = 1 + b = 2 +\"\"\" +" + (should (string= (python-shell-buffer-substring + (python-tests-look-at "a = 1") + (python-tests-look-at "\"\"\"")) + "# -*- coding: utf-8 -*-\n\nif True:\n a = 1\n b = 2\n\n")))) + ;;; Shell completion -- 2.34.1 --Multipart_Fri_Dec_23_00:01:13_2022-1--