Skip to content

[3.10] bpo-45447: Add syntax highlighting for .pyi files in IDLE (GH-28950) #31303

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

Merged
merged 1 commit into from
Feb 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Lib/idlelib/NEWS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Released on 2022-05-16
=========================


bpo-28950: Apply IDLE syntax highlighting to `.pyi` files. Add util.py
for common components. Patch by Alex Waygood and Terry Jan Reedy.

bpo-46630: Make query dialogs on Windows start with a cursor in the
entry box.

Expand Down
1 change: 1 addition & 0 deletions Lib/idlelib/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ tabbedpages.py # Define tabbed pages widget (nim).
textview.py # Define read-only text widget (nim).
tree.py # Define tree widget, used in browsers (nim).
undo.py # Manage undo stack.
util.py # Define objects imported elsewhere with no dependencies (nim)
windows.py # Manage window list and define listed top level.
zoomheight.py # Zoom window to full height of screen.

Expand Down
3 changes: 2 additions & 1 deletion Lib/idlelib/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from idlelib import replace
from idlelib import search
from idlelib.tree import wheel_event
from idlelib.util import py_extensions
from idlelib import window

# The default tab setting for a Text widget, in average-width characters.
Expand Down Expand Up @@ -757,7 +758,7 @@ def ispythonsource(self, filename):
if not filename or os.path.isdir(filename):
return True
base, ext = os.path.splitext(os.path.basename(filename))
if os.path.normcase(ext) in (".py", ".pyw"):
if os.path.normcase(ext) in py_extensions:
return True
line = self.text.get('1.0', '1.0 lineend')
return line.startswith('#!') and 'python' in line
Expand Down
4 changes: 4 additions & 0 deletions Lib/idlelib/idle_test/example_noext
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!usr/bin/env python

def example_function(some_argument):
pass
2 changes: 2 additions & 0 deletions Lib/idlelib/idle_test/example_stub.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class Example:
def method(self, argument1: str, argument2: list[int]) -> None: ...
24 changes: 23 additions & 1 deletion Lib/idlelib/idle_test/test_iomenu.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"Test , coverage 17%."

from idlelib import iomenu
from idlelib import iomenu, util
import unittest
from test.support import requires
from tkinter import Tk
Expand Down Expand Up @@ -45,5 +45,27 @@ def test_fixnewlines_end(self):
eq(fix(), 'a'+io.eol_convention)


def _extension_in_filetypes(extension):
return any(
f'*{extension}' in filetype_tuple[1]
for filetype_tuple in iomenu.IOBinding.filetypes
)


class FiletypesTest(unittest.TestCase):
def test_python_source_files(self):
for extension in util.py_extensions:
with self.subTest(extension=extension):
self.assertTrue(
_extension_in_filetypes(extension)
)

def test_text_files(self):
self.assertTrue(_extension_in_filetypes('.txt'))

def test_all_files(self):
self.assertTrue(_extension_in_filetypes(''))


if __name__ == '__main__':
unittest.main(verbosity=2)
14 changes: 14 additions & 0 deletions Lib/idlelib/idle_test/test_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Test util, coverage 100%"""

import unittest
from idlelib import util


class UtilTest(unittest.TestCase):
def test_extensions(self):
for extension in {'.pyi', '.py', '.pyw'}:
self.assertIn(extension, util.py_extensions)


if __name__ == '__main__':
unittest.main(verbosity=2)
5 changes: 4 additions & 1 deletion Lib/idlelib/iomenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

import idlelib
from idlelib.config import idleConf
from idlelib.util import py_extensions

py_extensions = ' '.join("*"+ext for ext in py_extensions)

encoding = 'utf-8'
if sys.platform == 'win32':
Expand Down Expand Up @@ -348,7 +351,7 @@ def print_window(self, event):
savedialog = None

filetypes = (
("Python files", "*.py *.pyw", "TEXT"),
("Python files", py_extensions, "TEXT"),
("Text files", "*.txt", "TEXT"),
("All files", "*"),
)
Expand Down
22 changes: 22 additions & 0 deletions Lib/idlelib/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""
Idlelib objects with no external idlelib dependencies
which are needed in more than one idlelib module.

They are included here because
a) they don't particularly belong elsewhere; or
b) because inclusion here simplifies the idlelib dependency graph.

TODO:
* Python versions (editor and help_about),
* tk version and patchlevel (pyshell, help_about, maxos?, editor?),
* std streams (pyshell, run),
* warning stuff (pyshell, run).
"""
from os import path

# .pyw is for Windows; .pyi is for stub files.
py_extensions = ('.py', '.pyw', '.pyi') # Order needed for open/save dialogs.

if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_util', verbosity=2)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Apply IDLE syntax highlighting to `.pyi` files. Patch by Alex Waygood
and Terry Jan Reedy.