Skip to content

Commit

Permalink
Use ruff for linting and formatting.
Browse files Browse the repository at this point in the history
- Several fixes because of Ruff.
- Updated GitHub workflow to use ruff instead of isort and black.
- Added Python 3.10 to GitHub workflow.
- Ruff formatting.
- Removed unnecessary trailing comma.
  • Loading branch information
jonathanslenders committed Nov 3, 2023
1 parent e66b1f2 commit b8a3ee5
Show file tree
Hide file tree
Showing 35 changed files with 203 additions and 232 deletions.
15 changes: 8 additions & 7 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8, 3.9, "3.10"]
python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]

steps:
- uses: actions/checkout@v2
Expand All @@ -22,21 +22,22 @@ jobs:
run: |
sudo apt remove python3-pip
python -m pip install --upgrade pip
python -m pip install . black coverage codecov flake8 isort==5.6.4 mypy pytest readme_renderer types-contextvars asyncssh
python -m pip install . ruff coverage codecov mypy pytest readme_renderer types-contextvars asyncssh
pip list
- name: Run Tests
- name: Ruff
run: |
ruff .
ruff format --check .
- name: Tests
run: |
flake8 .
coverage run -m pytest
- name: Type Checker
- name: Mypy
# Check wheather the imports were sorted correctly.
# When this fails, please run ./tools/sort-imports.sh
run: |
mypy --strict src/prompt_toolkit --platform win32
mypy --strict src/prompt_toolkit --platform linux
mypy --strict src/prompt_toolkit --platform darwin
isort -c --profile black src examples tests setup.py
black --check src examples tests setup.py
- name: Validate README.md
# Ensure that the README renders correctly (required for uploading to PyPI).
run: |
Expand Down
35 changes: 0 additions & 35 deletions .travis.yml

This file was deleted.

1 change: 0 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
# serve to show the default.

import os
import sys


# If extensions (or modules to document with autodoc) are in another directory,
Expand Down
4 changes: 2 additions & 2 deletions examples/full-screen/calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ def main():
def accept(buff):
# Evaluate "calculator" expression.
try:
output = "\n\nIn: {}\nOut: {}".format(
input_field.text, eval(input_field.text)
output = (
f"\n\nIn: {input_field.text}\nOut: {eval(input_field.text)}"
) # Don't do 'eval' in real code!
except BaseException as e:
output = f"\n\n{e}"
Expand Down
7 changes: 1 addition & 6 deletions examples/prompts/asyncio-prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,4 @@ async def main():


if __name__ == "__main__":
try:
from asyncio import run
except ImportError:
asyncio.run_until_complete(main())
else:
asyncio.run(main())
asyncio.run(main())
2 changes: 1 addition & 1 deletion examples/prompts/custom-lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class RainbowLexer(Lexer):
def lex_document(self, document):
colors = list(sorted(NAMED_COLORS, key=NAMED_COLORS.get))
colors = sorted(NAMED_COLORS, key=NAMED_COLORS.get)

def get_line(lineno):
return [
Expand Down
1 change: 0 additions & 1 deletion examples/ssh/asyncssh-server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"""
import asyncio
import logging
from asyncio import run

import asyncssh
from pygments.lexers.html import HtmlLexer
Expand Down
2 changes: 1 addition & 1 deletion examples/telnet/hello-world.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
That is probably the preferred way if you only need Python 3 support.
"""
import logging
from asyncio import Future, run
from asyncio import run

from prompt_toolkit.contrib.telnet.server import TelnetServer
from prompt_toolkit.shortcuts import PromptSession, clear
Expand Down
2 changes: 1 addition & 1 deletion examples/telnet/toolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
in the prompt.
"""
import logging
from asyncio import Future, run
from asyncio import run

from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.contrib.telnet.server import TelnetServer
Expand Down
51 changes: 38 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,38 @@
[tool.black]
target-version = ['py36']


[tool.isort]
# isort configuration that is compatible with Black.
multi_line_output = 3
include_trailing_comma = true
known_first_party = "prompt_toolkit"
known_third_party = "asyncssh,pygments"
force_grid_wrap = 0
use_parentheses = true
line_length = 88
[tool.ruff]
target-version = "py37"
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"C", # flake8-comprehensions
"T", # Print.
"I", # isort
# "B", # flake8-bugbear
"UP", # pyupgrade
"RUF100", # unused-noqa
"Q", # quotes
]
ignore = [
"E501", # Line too long, handled by black
"C901", # Too complex
"E731", # Assign lambda.
"E402", # Module level import not at the top.
"E741", # Ambiguous variable name.
]


[tool.ruff.per-file-ignores]
"examples/*" = ["T201"] # Print allowed in examples.
"src/prompt_toolkit/application/application.py" = ["T100", "T201", "F821"] # pdb and print allowed.
"src/prompt_toolkit/contrib/telnet/server.py" = ["T201"] # Print allowed.
"src/prompt_toolkit/key_binding/bindings/named_commands.py" = ["T201"] # Print allowed.
"src/prompt_toolkit/shortcuts/progress_bar/base.py" = ["T201"] # Print allowed.
"tools/*" = ["T201"] # Print allowed.
"src/prompt_toolkit/filters/__init__.py" = ["F403", "F405"] # Possibly undefined due to star import.
"src/prompt_toolkit/filters/cli.py" = ["F403", "F405"] # Possibly undefined due to star import.
"src/prompt_toolkit/shortcuts/progress_bar/formatters.py" = ["UP031"] # %-style formatting.


[tool.ruff.isort]
known-first-party = ["prompt_toolkit"]
known-third-party = ["pygments", "asyncssh"]
2 changes: 1 addition & 1 deletion src/prompt_toolkit/application/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ async def run_async(
# See: https://github.com/prompt-toolkit/python-prompt-toolkit/issues/1553
handle_sigint = False

async def _run_async(f: "asyncio.Future[_AppResult]") -> _AppResult:
async def _run_async(f: asyncio.Future[_AppResult]) -> _AppResult:
context = contextvars.copy_context()
self.context = context

Expand Down
3 changes: 0 additions & 3 deletions src/prompt_toolkit/application/current.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import sys
from contextlib import contextmanager
from contextvars import ContextVar
from typing import TYPE_CHECKING, Any, Generator
Expand Down Expand Up @@ -148,8 +147,6 @@ def create_app_session(
Like in the case of an Telnet/SSH server. This functionality uses
contextvars and requires at least Python 3.7.
"""
if sys.version_info <= (3, 6):
raise RuntimeError("Application sessions require Python 3.7.")

# If no input/output is specified, fall back to the current input/output,
# whatever that is.
Expand Down
6 changes: 3 additions & 3 deletions src/prompt_toolkit/auto_suggest.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def get_suggestion(self, buffer: Buffer, document: Document) -> Suggestion | Non
"""

async def get_suggestion_async(
self, buff: "Buffer", document: Document
self, buff: Buffer, document: Document
) -> Suggestion | None:
"""
Return a :class:`.Future` which is set when the suggestions are ready.
Expand All @@ -96,7 +96,7 @@ def get_suggestion(self, buff: Buffer, document: Document) -> Suggestion | None:
return self.auto_suggest.get_suggestion(buff, document)

async def get_suggestion_async(
self, buff: "Buffer", document: Document
self, buff: Buffer, document: Document
) -> Suggestion | None:
"""
Run the `get_suggestion` function in a thread.
Expand Down Expand Up @@ -170,7 +170,7 @@ def get_suggestion(self, buff: Buffer, document: Document) -> Suggestion | None:
return auto_suggest.get_suggestion(buff, document)

async def get_suggestion_async(
self, buff: "Buffer", document: Document
self, buff: Buffer, document: Document
) -> Suggestion | None:
auto_suggest = self.get_auto_suggest() or DummyAutoSuggest()
return await auto_suggest.get_suggestion_async(buff, document)
5 changes: 3 additions & 2 deletions src/prompt_toolkit/buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from collections import deque
from enum import Enum
from functools import wraps
from typing import Any, Awaitable, Callable, Coroutine, Deque, Iterable, TypeVar, cast
from typing import Any, Awaitable, Callable, Coroutine, Iterable, TypeVar, cast

from .application.current import get_app
from .application.run_in_terminal import run_in_terminal
Expand Down Expand Up @@ -56,6 +56,7 @@ class EditReadOnlyBuffer(Exception):

class ValidationState(Enum):
"The validation state of a buffer. This is set after the validation."

VALID = "VALID"
INVALID = "INVALID"
UNKNOWN = "UNKNOWN"
Expand Down Expand Up @@ -366,7 +367,7 @@ def reset(
#: Ctrl-C should reset this, and copy the whole history back in here.
#: Enter should process the current command and append to the real
#: history.
self._working_lines: Deque[str] = deque([document.text])
self._working_lines: deque[str] = deque([document.text])
self.__working_index = 0

def load_history_if_not_yet_loaded(self) -> None:
Expand Down
6 changes: 3 additions & 3 deletions src/prompt_toolkit/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from collections import deque
from functools import wraps
from typing import Any, Callable, Deque, Dict, Generic, Hashable, Tuple, TypeVar, cast
from typing import Any, Callable, Dict, Generic, Hashable, Tuple, TypeVar, cast

__all__ = [
"SimpleCache",
Expand All @@ -26,7 +26,7 @@ def __init__(self, maxsize: int = 8) -> None:
assert maxsize > 0

self._data: dict[_T, _U] = {}
self._keys: Deque[_T] = deque()
self._keys: deque[_T] = deque()
self.maxsize: int = maxsize

def get(self, key: _T, getter_func: Callable[[], _U]) -> _U:
Expand Down Expand Up @@ -86,7 +86,7 @@ class FastDictCache(Dict[_K, _V]):
def __init__(self, get_value: Callable[..., _V], size: int = 1000000) -> None:
assert size > 0

self._keys: Deque[_K] = deque()
self._keys: deque[_K] = deque()
self.get_value = get_value
self.size = size

Expand Down
3 changes: 1 addition & 2 deletions src/prompt_toolkit/clipboard/in_memory.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

from collections import deque
from typing import Deque

from .base import Clipboard, ClipboardData

Expand All @@ -22,7 +21,7 @@ def __init__(self, data: ClipboardData | None = None, max_size: int = 60) -> Non
assert max_size >= 1

self.max_size = max_size
self._ring: Deque[ClipboardData] = deque()
self._ring: deque[ClipboardData] = deque()

if data is not None:
self.set_data(data)
Expand Down
2 changes: 1 addition & 1 deletion src/prompt_toolkit/completion/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,4 @@ def __init__(self) -> None:
get_paths=lambda: os.environ.get("PATH", "").split(os.pathsep),
file_filter=lambda name: os.access(name, os.X_OK),
expanduser=True,
),
)
8 changes: 2 additions & 6 deletions src/prompt_toolkit/contrib/regular_languages/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@
from __future__ import annotations

import re
from typing import Callable, Dict, Iterable, Iterator
from typing import Callable, Dict, Iterable, Iterator, Pattern
from typing import Match as RegexMatch
from typing import Pattern

from .regex_parser import (
AnyNode,
Expand Down Expand Up @@ -170,10 +169,7 @@ def transform(node: Node) -> str:

# A `Variable` wraps the children into a named group.
elif isinstance(node, Variable):
return "(?P<{}>{})".format(
create_group_func(node),
transform(node.childnode),
)
return f"(?P<{create_group_func(node)}>{transform(node.childnode)})"

# `Repeat`.
elif isinstance(node, Repeat):
Expand Down
2 changes: 1 addition & 1 deletion src/prompt_toolkit/contrib/telnet/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def handle_incoming_data() -> None:
self.feed(data)
else:
# Connection closed by client.
logger.info("Connection closed by client. %r %r" % self.addr)
logger.info("Connection closed by client. {!r} {!r}".format(*self.addr))
self.close()

# Add reader.
Expand Down
2 changes: 1 addition & 1 deletion src/prompt_toolkit/formatted_text/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def to_formatted_text(
else:
raise ValueError(
"No formatted text. Expecting a unicode object, "
"HTML, ANSI or a FormattedText instance. Got %r" % (value,)
f"HTML, ANSI or a FormattedText instance. Got {value!r}"
)

# Apply extra style.
Expand Down
Loading

0 comments on commit b8a3ee5

Please sign in to comment.