Merging upstream version 3.0.23.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
4c4da9307f
commit
568aae77cf
27 changed files with 230 additions and 152 deletions
2
.github/workflows/test.yaml
vendored
2
.github/workflows/test.yaml
vendored
|
@ -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
|
||||
|
|
11
CHANGELOG
11
CHANGELOG
|
@ -1,6 +1,17 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
3.0.23: 2023-02-22
|
||||
------------------
|
||||
|
||||
Fixes:
|
||||
- Don't print exception messages twice for unhandled exceptions.
|
||||
- Added cursor shape support.
|
||||
|
||||
Breaking changes:
|
||||
- Drop Python 3.6 support.
|
||||
|
||||
|
||||
3.0.22: 2022-12-06
|
||||
------------------
|
||||
|
||||
|
|
|
@ -213,7 +213,7 @@ This is also available for embedding:
|
|||
|
||||
.. code:: python
|
||||
|
||||
from ptpython.ipython.repl import embed
|
||||
from ptpython.ipython import embed
|
||||
embed(globals(), locals())
|
||||
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ When a normal blocking embed is used:
|
|||
When an awaitable embed is used, for embedding in a coroutine, but having the
|
||||
event loop continue:
|
||||
* We run the input method from the blocking embed in an asyncio executor
|
||||
and do an `await loop.run_in_excecutor(...)`.
|
||||
and do an `await loop.run_in_executor(...)`.
|
||||
* The "eval" happens again in the main thread.
|
||||
* "print" is also similar, except that the pager code (if used) runs in an
|
||||
executor too.
|
||||
|
|
|
@ -3,6 +3,7 @@ Configuration example for ``ptpython``.
|
|||
|
||||
Copy this file to $XDG_CONFIG_HOME/ptpython/config.py
|
||||
On Linux, this is: ~/.config/ptpython/config.py
|
||||
On macOS, this is: ~/Library/Application Support/ptpython/config.py
|
||||
"""
|
||||
from prompt_toolkit.filters import ViInsertMode
|
||||
from prompt_toolkit.key_binding.key_processor import KeyPress
|
||||
|
@ -49,7 +50,7 @@ def configure(repl):
|
|||
# Swap light/dark colors on or off
|
||||
repl.swap_light_and_dark = False
|
||||
|
||||
# Highlight matching parethesis.
|
||||
# Highlight matching parentheses.
|
||||
repl.highlight_matching_parenthesis = True
|
||||
|
||||
# Line wrapping. (Instead of horizontal scrolling.)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .repl import embed
|
||||
|
||||
__all__ = ["embed"]
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
"""
|
||||
Make `python -m ptpython` an alias for running `./ptpython`.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from .entry_points.run_ptpython import run
|
||||
|
||||
run()
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import collections.abc as collections_abc
|
||||
import inspect
|
||||
|
@ -44,8 +46,8 @@ class PythonCompleter(Completer):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
get_globals: Callable[[], Dict[str, Any]],
|
||||
get_locals: Callable[[], Dict[str, Any]],
|
||||
get_globals: Callable[[], dict[str, Any]],
|
||||
get_locals: Callable[[], dict[str, Any]],
|
||||
enable_dictionary_completion: Callable[[], bool],
|
||||
) -> None:
|
||||
super().__init__()
|
||||
|
@ -58,8 +60,8 @@ class PythonCompleter(Completer):
|
|||
self._jedi_completer = JediCompleter(get_globals, get_locals)
|
||||
self._dictionary_completer = DictionaryCompleter(get_globals, get_locals)
|
||||
|
||||
self._path_completer_cache: Optional[GrammarCompleter] = None
|
||||
self._path_completer_grammar_cache: Optional["_CompiledGrammar"] = None
|
||||
self._path_completer_cache: GrammarCompleter | None = None
|
||||
self._path_completer_grammar_cache: _CompiledGrammar | None = None
|
||||
|
||||
@property
|
||||
def _path_completer(self) -> GrammarCompleter:
|
||||
|
@ -74,7 +76,7 @@ class PythonCompleter(Completer):
|
|||
return self._path_completer_cache
|
||||
|
||||
@property
|
||||
def _path_completer_grammar(self) -> "_CompiledGrammar":
|
||||
def _path_completer_grammar(self) -> _CompiledGrammar:
|
||||
"""
|
||||
Return the grammar for matching paths inside strings inside Python
|
||||
code.
|
||||
|
@ -85,7 +87,7 @@ class PythonCompleter(Completer):
|
|||
self._path_completer_grammar_cache = self._create_path_completer_grammar()
|
||||
return self._path_completer_grammar_cache
|
||||
|
||||
def _create_path_completer_grammar(self) -> "_CompiledGrammar":
|
||||
def _create_path_completer_grammar(self) -> _CompiledGrammar:
|
||||
def unwrapper(text: str) -> str:
|
||||
return re.sub(r"\\(.)", r"\1", text)
|
||||
|
||||
|
@ -189,7 +191,6 @@ class PythonCompleter(Completer):
|
|||
):
|
||||
# If we are inside a string, Don't do Jedi completion.
|
||||
if not self._path_completer_grammar.match(document.text_before_cursor):
|
||||
|
||||
# Do Jedi Python completions.
|
||||
yield from self._jedi_completer.get_completions(
|
||||
document, complete_event
|
||||
|
@ -203,8 +204,8 @@ class JediCompleter(Completer):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
get_globals: Callable[[], Dict[str, Any]],
|
||||
get_locals: Callable[[], Dict[str, Any]],
|
||||
get_globals: Callable[[], dict[str, Any]],
|
||||
get_locals: Callable[[], dict[str, Any]],
|
||||
) -> None:
|
||||
super().__init__()
|
||||
|
||||
|
@ -242,7 +243,7 @@ class JediCompleter(Completer):
|
|||
# Jedi issue: "KeyError: u'a_lambda'."
|
||||
# https://github.com/jonathanslenders/ptpython/issues/89
|
||||
pass
|
||||
except IOError:
|
||||
except OSError:
|
||||
# Jedi issue: "IOError: No such file or directory."
|
||||
# https://github.com/jonathanslenders/ptpython/issues/71
|
||||
pass
|
||||
|
@ -303,8 +304,8 @@ class DictionaryCompleter(Completer):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
get_globals: Callable[[], Dict[str, Any]],
|
||||
get_locals: Callable[[], Dict[str, Any]],
|
||||
get_globals: Callable[[], dict[str, Any]],
|
||||
get_locals: Callable[[], dict[str, Any]],
|
||||
) -> None:
|
||||
super().__init__()
|
||||
|
||||
|
@ -386,7 +387,7 @@ class DictionaryCompleter(Completer):
|
|||
re.VERBOSE,
|
||||
)
|
||||
|
||||
def _lookup(self, expression: str, temp_locals: Dict[str, Any]) -> object:
|
||||
def _lookup(self, expression: str, temp_locals: dict[str, Any]) -> object:
|
||||
"""
|
||||
Do lookup of `object_var` in the context.
|
||||
`temp_locals` is a dictionary, used for the locals.
|
||||
|
@ -399,7 +400,6 @@ class DictionaryCompleter(Completer):
|
|||
def get_completions(
|
||||
self, document: Document, complete_event: CompleteEvent
|
||||
) -> Iterable[Completion]:
|
||||
|
||||
# First, find all for-loops, and assign the first item of the
|
||||
# collections they're iterating to the iterator variable, so that we
|
||||
# can provide code completion on the iterators.
|
||||
|
@ -431,7 +431,7 @@ class DictionaryCompleter(Completer):
|
|||
except BaseException:
|
||||
raise ReprFailedError
|
||||
|
||||
def eval_expression(self, document: Document, locals: Dict[str, Any]) -> object:
|
||||
def eval_expression(self, document: Document, locals: dict[str, Any]) -> object:
|
||||
"""
|
||||
Evaluate
|
||||
"""
|
||||
|
@ -446,7 +446,7 @@ class DictionaryCompleter(Completer):
|
|||
self,
|
||||
document: Document,
|
||||
complete_event: CompleteEvent,
|
||||
temp_locals: Dict[str, Any],
|
||||
temp_locals: dict[str, Any],
|
||||
) -> Iterable[Completion]:
|
||||
"""
|
||||
Complete the [ or . operator after an object.
|
||||
|
@ -454,7 +454,6 @@ class DictionaryCompleter(Completer):
|
|||
result = self.eval_expression(document, temp_locals)
|
||||
|
||||
if result is not None:
|
||||
|
||||
if isinstance(
|
||||
result,
|
||||
(list, tuple, dict, collections_abc.Mapping, collections_abc.Sequence),
|
||||
|
@ -470,7 +469,7 @@ class DictionaryCompleter(Completer):
|
|||
self,
|
||||
document: Document,
|
||||
complete_event: CompleteEvent,
|
||||
temp_locals: Dict[str, Any],
|
||||
temp_locals: dict[str, Any],
|
||||
) -> Iterable[Completion]:
|
||||
"""
|
||||
Complete dictionary keys.
|
||||
|
@ -478,6 +477,7 @@ class DictionaryCompleter(Completer):
|
|||
|
||||
def meta_repr(value: object) -> Callable[[], str]:
|
||||
"Abbreviate meta text, make sure it fits on one line."
|
||||
|
||||
# We return a function, so that it gets computed when it's needed.
|
||||
# When there are many completions, that improves the performance
|
||||
# quite a bit (for the multi-column completion menu, we only need
|
||||
|
@ -549,7 +549,7 @@ class DictionaryCompleter(Completer):
|
|||
self,
|
||||
document: Document,
|
||||
complete_event: CompleteEvent,
|
||||
temp_locals: Dict[str, Any],
|
||||
temp_locals: dict[str, Any],
|
||||
) -> Iterable[Completion]:
|
||||
"""
|
||||
Complete attribute names.
|
||||
|
@ -568,9 +568,9 @@ class DictionaryCompleter(Completer):
|
|||
obj = getattr(result, name, None)
|
||||
if inspect.isfunction(obj) or inspect.ismethod(obj):
|
||||
return "()"
|
||||
if isinstance(obj, dict):
|
||||
if isinstance(obj, collections_abc.Mapping):
|
||||
return "{}"
|
||||
if isinstance(obj, (list, tuple)):
|
||||
if isinstance(obj, collections_abc.Sequence):
|
||||
return "[]"
|
||||
except:
|
||||
pass
|
||||
|
@ -581,13 +581,13 @@ class DictionaryCompleter(Completer):
|
|||
suffix = get_suffix(name)
|
||||
yield Completion(name, -len(attr_name), display=name + suffix)
|
||||
|
||||
def _sort_attribute_names(self, names: List[str]) -> List[str]:
|
||||
def _sort_attribute_names(self, names: list[str]) -> list[str]:
|
||||
"""
|
||||
Sort attribute names alphabetically, but move the double underscore and
|
||||
underscore names to the end.
|
||||
"""
|
||||
|
||||
def sort_key(name: str) -> Tuple[int, str]:
|
||||
def sort_key(name: str) -> tuple[int, str]:
|
||||
if name.startswith("__"):
|
||||
return (2, name) # Double underscore comes latest.
|
||||
if name.startswith("_"):
|
||||
|
@ -599,7 +599,7 @@ class DictionaryCompleter(Completer):
|
|||
|
||||
class HidePrivateCompleter(Completer):
|
||||
"""
|
||||
Wrapper around completer that hides private fields, deponding on whether or
|
||||
Wrapper around completer that hides private fields, depending on whether or
|
||||
not public fields are shown.
|
||||
|
||||
(The reason this is implemented as a `Completer` wrapper is because this
|
||||
|
@ -617,7 +617,6 @@ class HidePrivateCompleter(Completer):
|
|||
def get_completions(
|
||||
self, document: Document, complete_event: CompleteEvent
|
||||
) -> Iterable[Completion]:
|
||||
|
||||
completions = list(self.completer.get_completions(document, complete_event))
|
||||
complete_private_attributes = self.complete_private_attributes()
|
||||
hide_private = False
|
||||
|
@ -653,7 +652,7 @@ except ImportError: # Python 2.
|
|||
|
||||
|
||||
def _get_style_for_jedi_completion(
|
||||
jedi_completion: "jedi.api.classes.Completion",
|
||||
jedi_completion: jedi.api.classes.Completion,
|
||||
) -> str:
|
||||
"""
|
||||
Return completion style to use for this name.
|
||||
|
|
|
@ -6,6 +6,8 @@ Note that the code in this file is Python 3 only. However, we
|
|||
should make sure not to use Python 3-only syntax, because this
|
||||
package should be installable in Python 2 as well!
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from typing import Any, Optional, TextIO, cast
|
||||
|
||||
|
@ -29,7 +31,7 @@ class ReplSSHServerSession(asyncssh.SSHServerSession):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self, get_globals: _GetNamespace, get_locals: Optional[_GetNamespace] = None
|
||||
self, get_globals: _GetNamespace, get_locals: _GetNamespace | None = None
|
||||
) -> None:
|
||||
self._chan: Any = None
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
@ -58,7 +60,7 @@ def run(user_ns=None):
|
|||
code = compile(f.read(), path, "exec")
|
||||
exec(code, user_ns, user_ns)
|
||||
else:
|
||||
print("File not found: {}\n\n".format(path))
|
||||
print(f"File not found: {path}\n\n")
|
||||
sys.exit(1)
|
||||
|
||||
# Apply config file
|
||||
|
|
|
@ -21,6 +21,8 @@ environment variables:
|
|||
PTPYTHON_CONFIG_HOME: a configuration directory to use
|
||||
PYTHONSTARTUP: file executed on interactive startup (no default)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
|
@ -44,7 +46,7 @@ __all__ = ["create_parser", "get_config_and_history_file", "run"]
|
|||
|
||||
|
||||
class _Parser(argparse.ArgumentParser):
|
||||
def print_help(self, file: Optional[IO[str]] = None) -> None:
|
||||
def print_help(self, file: IO[str] | None = None) -> None:
|
||||
super().print_help()
|
||||
print(
|
||||
dedent(
|
||||
|
@ -90,7 +92,7 @@ def create_parser() -> _Parser:
|
|||
return parser
|
||||
|
||||
|
||||
def get_config_and_history_file(namespace: argparse.Namespace) -> Tuple[str, str]:
|
||||
def get_config_and_history_file(namespace: argparse.Namespace) -> tuple[str, str]:
|
||||
"""
|
||||
Check which config/history files to use, ensure that the directories for
|
||||
these files exist, and return the config and history path.
|
||||
|
|
|
@ -7,6 +7,8 @@ way we don't block the UI of for instance ``turtle`` and other Tk libraries.
|
|||
in readline. ``prompt-toolkit`` doesn't understand that input hook, but this
|
||||
will fix it for Tk.)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from prompt_toolkit.filters import Filter
|
||||
|
@ -9,7 +11,7 @@ __all__ = ["HasSignature", "ShowSidebar", "ShowSignature", "ShowDocstring"]
|
|||
|
||||
|
||||
class PythonInputFilter(Filter):
|
||||
def __init__(self, python_input: "PythonInput") -> None:
|
||||
def __init__(self, python_input: PythonInput) -> None:
|
||||
super().__init__()
|
||||
self.python_input = python_input
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ Utility to easily select lines from the history and execute them again.
|
|||
`create_history_application` creates an `Application` instance that runs will
|
||||
run as a sub application of the Repl/PythonInput.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING, Callable, List, Optional, Set
|
||||
|
||||
|
@ -128,7 +130,7 @@ class HistoryLayout:
|
|||
application.
|
||||
"""
|
||||
|
||||
def __init__(self, history: "PythonHistory") -> None:
|
||||
def __init__(self, history: PythonHistory) -> None:
|
||||
search_toolbar = SearchToolbar()
|
||||
|
||||
self.help_buffer_control = BufferControl(
|
||||
|
@ -224,7 +226,7 @@ def _get_top_toolbar_fragments() -> StyleAndTextTuples:
|
|||
return [("class:status-bar.title", "History browser - Insert from history")]
|
||||
|
||||
|
||||
def _get_bottom_toolbar_fragments(history: "PythonHistory") -> StyleAndTextTuples:
|
||||
def _get_bottom_toolbar_fragments(history: PythonHistory) -> StyleAndTextTuples:
|
||||
python_input = history.python_input
|
||||
|
||||
@if_mousedown
|
||||
|
@ -258,7 +260,7 @@ class HistoryMargin(Margin):
|
|||
This displays a green bar for the selected entries.
|
||||
"""
|
||||
|
||||
def __init__(self, history: "PythonHistory") -> None:
|
||||
def __init__(self, history: PythonHistory) -> None:
|
||||
self.history_buffer = history.history_buffer
|
||||
self.history_mapping = history.history_mapping
|
||||
|
||||
|
@ -307,7 +309,7 @@ class ResultMargin(Margin):
|
|||
The margin to be shown in the result pane.
|
||||
"""
|
||||
|
||||
def __init__(self, history: "PythonHistory") -> None:
|
||||
def __init__(self, history: PythonHistory) -> None:
|
||||
self.history_mapping = history.history_mapping
|
||||
self.history_buffer = history.history_buffer
|
||||
|
||||
|
@ -356,7 +358,7 @@ class GrayExistingText(Processor):
|
|||
Turn the existing input, before and after the inserted code gray.
|
||||
"""
|
||||
|
||||
def __init__(self, history_mapping: "HistoryMapping") -> None:
|
||||
def __init__(self, history_mapping: HistoryMapping) -> None:
|
||||
self.history_mapping = history_mapping
|
||||
self._lines_before = len(
|
||||
history_mapping.original_document.text_before_cursor.splitlines()
|
||||
|
@ -384,7 +386,7 @@ class HistoryMapping:
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
history: "PythonHistory",
|
||||
history: PythonHistory,
|
||||
python_history: History,
|
||||
original_document: Document,
|
||||
) -> None:
|
||||
|
@ -393,11 +395,11 @@ class HistoryMapping:
|
|||
self.original_document = original_document
|
||||
|
||||
self.lines_starting_new_entries = set()
|
||||
self.selected_lines: Set[int] = set()
|
||||
self.selected_lines: set[int] = set()
|
||||
|
||||
# Process history.
|
||||
history_strings = python_history.get_strings()
|
||||
history_lines: List[str] = []
|
||||
history_lines: list[str] = []
|
||||
|
||||
for entry_nr, entry in list(enumerate(history_strings))[-HISTORY_COUNT:]:
|
||||
self.lines_starting_new_entries.add(len(history_lines))
|
||||
|
@ -419,7 +421,7 @@ class HistoryMapping:
|
|||
else:
|
||||
self.result_line_offset = 0
|
||||
|
||||
def get_new_document(self, cursor_pos: Optional[int] = None) -> Document:
|
||||
def get_new_document(self, cursor_pos: int | None = None) -> Document:
|
||||
"""
|
||||
Create a `Document` instance that contains the resulting text.
|
||||
"""
|
||||
|
@ -449,7 +451,7 @@ class HistoryMapping:
|
|||
b.set_document(self.get_new_document(b.cursor_position), bypass_readonly=True)
|
||||
|
||||
|
||||
def _toggle_help(history: "PythonHistory") -> None:
|
||||
def _toggle_help(history: PythonHistory) -> None:
|
||||
"Display/hide help."
|
||||
help_buffer_control = history.history_layout.help_buffer_control
|
||||
|
||||
|
@ -459,7 +461,7 @@ def _toggle_help(history: "PythonHistory") -> None:
|
|||
history.app.layout.current_control = help_buffer_control
|
||||
|
||||
|
||||
def _select_other_window(history: "PythonHistory") -> None:
|
||||
def _select_other_window(history: PythonHistory) -> None:
|
||||
"Toggle focus between left/right window."
|
||||
current_buffer = history.app.current_buffer
|
||||
layout = history.history_layout.layout
|
||||
|
@ -472,8 +474,8 @@ def _select_other_window(history: "PythonHistory") -> None:
|
|||
|
||||
|
||||
def create_key_bindings(
|
||||
history: "PythonHistory",
|
||||
python_input: "PythonInput",
|
||||
history: PythonHistory,
|
||||
python_input: PythonInput,
|
||||
history_mapping: HistoryMapping,
|
||||
) -> KeyBindings:
|
||||
"""
|
||||
|
@ -592,14 +594,12 @@ def create_key_bindings(
|
|||
|
||||
|
||||
class PythonHistory:
|
||||
def __init__(
|
||||
self, python_input: "PythonInput", original_document: Document
|
||||
) -> None:
|
||||
def __init__(self, python_input: PythonInput, original_document: Document) -> None:
|
||||
"""
|
||||
Create an `Application` for the history screen.
|
||||
This has to be run as a sub application of `python_input`.
|
||||
|
||||
When this application runs and returns, it retuns the selected lines.
|
||||
When this application runs and returns, it returns the selected lines.
|
||||
"""
|
||||
self.python_input = python_input
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ also the power of for instance all the %-magic functions that IPython has to
|
|||
offer.
|
||||
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterable
|
||||
from warnings import warn
|
||||
|
||||
|
@ -62,12 +64,12 @@ class IPythonPrompt(PromptStyle):
|
|||
|
||||
class IPythonValidator(PythonValidator):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(IPythonValidator, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.isp = IPythonInputSplitter()
|
||||
|
||||
def validate(self, document: Document) -> None:
|
||||
document = Document(text=self.isp.transform_cell(document.text))
|
||||
super(IPythonValidator, self).validate(document)
|
||||
super().validate(document)
|
||||
|
||||
|
||||
def create_ipython_grammar():
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from prompt_toolkit.application import get_app
|
||||
|
@ -47,7 +49,7 @@ def tab_should_insert_whitespace() -> bool:
|
|||
return bool(b.text and (not before_cursor or before_cursor.isspace()))
|
||||
|
||||
|
||||
def load_python_bindings(python_input: "PythonInput") -> KeyBindings:
|
||||
def load_python_bindings(python_input: PythonInput) -> KeyBindings:
|
||||
"""
|
||||
Custom key bindings.
|
||||
"""
|
||||
|
@ -157,7 +159,7 @@ def load_python_bindings(python_input: "PythonInput") -> KeyBindings:
|
|||
Behaviour of the Enter key.
|
||||
|
||||
Auto indent after newline/Enter.
|
||||
(When not in Vi navigaton mode, and when multiline is enabled.)
|
||||
(When not in Vi navigation mode, and when multiline is enabled.)
|
||||
"""
|
||||
b = event.current_buffer
|
||||
empty_lines_required = python_input.accept_input_on_enter or 10000
|
||||
|
@ -218,7 +220,7 @@ def load_python_bindings(python_input: "PythonInput") -> KeyBindings:
|
|||
return bindings
|
||||
|
||||
|
||||
def load_sidebar_bindings(python_input: "PythonInput") -> KeyBindings:
|
||||
def load_sidebar_bindings(python_input: PythonInput) -> KeyBindings:
|
||||
"""
|
||||
Load bindings for the navigation in the sidebar.
|
||||
"""
|
||||
|
@ -273,7 +275,7 @@ def load_sidebar_bindings(python_input: "PythonInput") -> KeyBindings:
|
|||
return bindings
|
||||
|
||||
|
||||
def load_confirm_exit_bindings(python_input: "PythonInput") -> KeyBindings:
|
||||
def load_confirm_exit_bindings(python_input: PythonInput) -> KeyBindings:
|
||||
"""
|
||||
Handle yes/no key presses when the exit confirmation is shown.
|
||||
"""
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
"""
|
||||
Creation of the `Layout` instance for the Python input/REPL.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import platform
|
||||
import sys
|
||||
from enum import Enum
|
||||
|
@ -78,26 +80,26 @@ class CompletionVisualisation(Enum):
|
|||
TOOLBAR = "toolbar"
|
||||
|
||||
|
||||
def show_completions_toolbar(python_input: "PythonInput") -> Condition:
|
||||
def show_completions_toolbar(python_input: PythonInput) -> Condition:
|
||||
return Condition(
|
||||
lambda: python_input.completion_visualisation == CompletionVisualisation.TOOLBAR
|
||||
)
|
||||
|
||||
|
||||
def show_completions_menu(python_input: "PythonInput") -> Condition:
|
||||
def show_completions_menu(python_input: PythonInput) -> Condition:
|
||||
return Condition(
|
||||
lambda: python_input.completion_visualisation == CompletionVisualisation.POP_UP
|
||||
)
|
||||
|
||||
|
||||
def show_multi_column_completions_menu(python_input: "PythonInput") -> Condition:
|
||||
def show_multi_column_completions_menu(python_input: PythonInput) -> Condition:
|
||||
return Condition(
|
||||
lambda: python_input.completion_visualisation
|
||||
== CompletionVisualisation.MULTI_COLUMN
|
||||
)
|
||||
|
||||
|
||||
def python_sidebar(python_input: "PythonInput") -> Window:
|
||||
def python_sidebar(python_input: PythonInput) -> Window:
|
||||
"""
|
||||
Create the `Layout` for the sidebar with the configurable options.
|
||||
"""
|
||||
|
@ -105,7 +107,7 @@ def python_sidebar(python_input: "PythonInput") -> Window:
|
|||
def get_text_fragments() -> StyleAndTextTuples:
|
||||
tokens: StyleAndTextTuples = []
|
||||
|
||||
def append_category(category: "OptionCategory[Any]") -> None:
|
||||
def append_category(category: OptionCategory[Any]) -> None:
|
||||
tokens.extend(
|
||||
[
|
||||
("class:sidebar", " "),
|
||||
|
@ -149,7 +151,7 @@ def python_sidebar(python_input: "PythonInput") -> Window:
|
|||
append_category(category)
|
||||
|
||||
for option in category.options:
|
||||
append(i, option.title, "%s" % option.get_current_value())
|
||||
append(i, option.title, "%s" % (option.get_current_value(),))
|
||||
i += 1
|
||||
|
||||
tokens.pop() # Remove last newline.
|
||||
|
@ -172,7 +174,7 @@ def python_sidebar(python_input: "PythonInput") -> Window:
|
|||
)
|
||||
|
||||
|
||||
def python_sidebar_navigation(python_input: "PythonInput") -> Window:
|
||||
def python_sidebar_navigation(python_input: PythonInput) -> Window:
|
||||
"""
|
||||
Create the `Layout` showing the navigation information for the sidebar.
|
||||
"""
|
||||
|
@ -198,7 +200,7 @@ def python_sidebar_navigation(python_input: "PythonInput") -> Window:
|
|||
)
|
||||
|
||||
|
||||
def python_sidebar_help(python_input: "PythonInput") -> Container:
|
||||
def python_sidebar_help(python_input: PythonInput) -> Container:
|
||||
"""
|
||||
Create the `Layout` for the help text for the current item in the sidebar.
|
||||
"""
|
||||
|
@ -232,7 +234,7 @@ def python_sidebar_help(python_input: "PythonInput") -> Container:
|
|||
)
|
||||
|
||||
|
||||
def signature_toolbar(python_input: "PythonInput") -> Container:
|
||||
def signature_toolbar(python_input: PythonInput) -> Container:
|
||||
"""
|
||||
Return the `Layout` for the signature.
|
||||
"""
|
||||
|
@ -318,7 +320,7 @@ class PythonPromptMargin(PromptMargin):
|
|||
It shows something like "In [1]:".
|
||||
"""
|
||||
|
||||
def __init__(self, python_input: "PythonInput") -> None:
|
||||
def __init__(self, python_input: PythonInput) -> None:
|
||||
self.python_input = python_input
|
||||
|
||||
def get_prompt_style() -> PromptStyle:
|
||||
|
@ -339,7 +341,7 @@ class PythonPromptMargin(PromptMargin):
|
|||
super().__init__(get_prompt, get_continuation)
|
||||
|
||||
|
||||
def status_bar(python_input: "PythonInput") -> Container:
|
||||
def status_bar(python_input: PythonInput) -> Container:
|
||||
"""
|
||||
Create the `Layout` for the status bar.
|
||||
"""
|
||||
|
@ -412,7 +414,7 @@ def status_bar(python_input: "PythonInput") -> Container:
|
|||
)
|
||||
|
||||
|
||||
def get_inputmode_fragments(python_input: "PythonInput") -> StyleAndTextTuples:
|
||||
def get_inputmode_fragments(python_input: PythonInput) -> StyleAndTextTuples:
|
||||
"""
|
||||
Return current input mode as a list of (token, text) tuples for use in a
|
||||
toolbar.
|
||||
|
@ -440,7 +442,7 @@ def get_inputmode_fragments(python_input: "PythonInput") -> StyleAndTextTuples:
|
|||
recording_register = app.vi_state.recording_register
|
||||
if recording_register:
|
||||
append((token, " "))
|
||||
append((token + " class:record", "RECORD({})".format(recording_register)))
|
||||
append((token + " class:record", f"RECORD({recording_register})"))
|
||||
append((token, " - "))
|
||||
|
||||
if app.current_buffer.selection_state is not None:
|
||||
|
@ -473,7 +475,7 @@ def get_inputmode_fragments(python_input: "PythonInput") -> StyleAndTextTuples:
|
|||
return result
|
||||
|
||||
|
||||
def show_sidebar_button_info(python_input: "PythonInput") -> Container:
|
||||
def show_sidebar_button_info(python_input: PythonInput) -> Container:
|
||||
"""
|
||||
Create `Layout` for the information in the right-bottom corner.
|
||||
(The right part of the status bar.)
|
||||
|
@ -519,7 +521,7 @@ def show_sidebar_button_info(python_input: "PythonInput") -> Container:
|
|||
|
||||
|
||||
def create_exit_confirmation(
|
||||
python_input: "PythonInput", style: str = "class:exit-confirmation"
|
||||
python_input: PythonInput, style: str = "class:exit-confirmation"
|
||||
) -> Container:
|
||||
"""
|
||||
Create `Layout` for the exit message.
|
||||
|
@ -543,7 +545,7 @@ def create_exit_confirmation(
|
|||
)
|
||||
|
||||
|
||||
def meta_enter_message(python_input: "PythonInput") -> Container:
|
||||
def meta_enter_message(python_input: PythonInput) -> Container:
|
||||
"""
|
||||
Create the `Layout` for the 'Meta+Enter` message.
|
||||
"""
|
||||
|
@ -575,15 +577,15 @@ def meta_enter_message(python_input: "PythonInput") -> Container:
|
|||
class PtPythonLayout:
|
||||
def __init__(
|
||||
self,
|
||||
python_input: "PythonInput",
|
||||
python_input: PythonInput,
|
||||
lexer: Lexer,
|
||||
extra_body: Optional[AnyContainer] = None,
|
||||
extra_toolbars: Optional[List[AnyContainer]] = None,
|
||||
extra_buffer_processors: Optional[List[Processor]] = None,
|
||||
input_buffer_height: Optional[AnyDimension] = None,
|
||||
extra_body: AnyContainer | None = None,
|
||||
extra_toolbars: list[AnyContainer] | None = None,
|
||||
extra_buffer_processors: list[Processor] | None = None,
|
||||
input_buffer_height: AnyDimension | None = None,
|
||||
) -> None:
|
||||
D = Dimension
|
||||
extra_body_list: List[AnyContainer] = [extra_body] if extra_body else []
|
||||
extra_body_list: list[AnyContainer] = [extra_body] if extra_body else []
|
||||
extra_toolbars = extra_toolbars or []
|
||||
|
||||
input_buffer_height = input_buffer_height or D(min=6)
|
||||
|
@ -591,7 +593,7 @@ class PtPythonLayout:
|
|||
search_toolbar = SearchToolbar(python_input.search_buffer)
|
||||
|
||||
def create_python_input_window() -> Window:
|
||||
def menu_position() -> Optional[int]:
|
||||
def menu_position() -> int | None:
|
||||
"""
|
||||
When there is no autocompletion menu to be shown, and we have a
|
||||
signature, set the pop-up position at `bracket_start`.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Callable, Optional
|
||||
|
||||
from prompt_toolkit.document import Document
|
||||
|
@ -17,7 +19,7 @@ class PtpythonLexer(Lexer):
|
|||
use a Python 3 lexer.
|
||||
"""
|
||||
|
||||
def __init__(self, python_lexer: Optional[Lexer] = None) -> None:
|
||||
def __init__(self, python_lexer: Lexer | None = None) -> None:
|
||||
self.python_lexer = python_lexer or PygmentsLexer(PythonLexer)
|
||||
self.system_lexer = PygmentsLexer(BashLexer)
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
@ -40,7 +42,7 @@ class IPythonPrompt(PromptStyle):
|
|||
A prompt resembling the IPython prompt.
|
||||
"""
|
||||
|
||||
def __init__(self, python_input: "PythonInput") -> None:
|
||||
def __init__(self, python_input: PythonInput) -> None:
|
||||
self.python_input = python_input
|
||||
|
||||
def in_prompt(self) -> AnyFormattedText:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Application for reading Python input.
|
||||
This can be used for creation of Python REPLs.
|
||||
"""
|
||||
import __future__
|
||||
from __future__ import annotations
|
||||
|
||||
from asyncio import get_event_loop
|
||||
from functools import partial
|
||||
|
@ -34,6 +34,12 @@ from prompt_toolkit.completion import (
|
|||
ThreadedCompleter,
|
||||
merge_completers,
|
||||
)
|
||||
from prompt_toolkit.cursor_shapes import (
|
||||
AnyCursorShapeConfig,
|
||||
CursorShape,
|
||||
DynamicCursorShapeConfig,
|
||||
ModalCursorShapeConfig,
|
||||
)
|
||||
from prompt_toolkit.document import Document
|
||||
from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
|
||||
from prompt_toolkit.filters import Condition
|
||||
|
@ -84,6 +90,11 @@ from .style import generate_style, get_all_code_styles, get_all_ui_styles
|
|||
from .utils import unindent_code
|
||||
from .validator import PythonValidator
|
||||
|
||||
# Isort introduces a SyntaxError, if we'd write `import __future__`.
|
||||
# https://github.com/PyCQA/isort/issues/2100
|
||||
__future__ = __import__("__future__")
|
||||
|
||||
|
||||
__all__ = ["PythonInput"]
|
||||
|
||||
|
||||
|
@ -101,7 +112,7 @@ _T = TypeVar("_T", bound="_SupportsLessThan")
|
|||
|
||||
|
||||
class OptionCategory(Generic[_T]):
|
||||
def __init__(self, title: str, options: List["Option[_T]"]) -> None:
|
||||
def __init__(self, title: str, options: list[Option[_T]]) -> None:
|
||||
self.title = title
|
||||
self.options = options
|
||||
|
||||
|
@ -194,26 +205,25 @@ class PythonInput:
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
get_globals: Optional[_GetNamespace] = None,
|
||||
get_locals: Optional[_GetNamespace] = None,
|
||||
history_filename: Optional[str] = None,
|
||||
get_globals: _GetNamespace | None = None,
|
||||
get_locals: _GetNamespace | None = None,
|
||||
history_filename: str | None = None,
|
||||
vi_mode: bool = False,
|
||||
color_depth: Optional[ColorDepth] = None,
|
||||
color_depth: ColorDepth | None = None,
|
||||
# Input/output.
|
||||
input: Optional[Input] = None,
|
||||
output: Optional[Output] = None,
|
||||
input: Input | None = None,
|
||||
output: Output | None = None,
|
||||
# For internal use.
|
||||
extra_key_bindings: Optional[KeyBindings] = None,
|
||||
extra_key_bindings: KeyBindings | None = None,
|
||||
create_app: bool = True,
|
||||
_completer: Optional[Completer] = None,
|
||||
_validator: Optional[Validator] = None,
|
||||
_lexer: Optional[Lexer] = None,
|
||||
_completer: Completer | None = None,
|
||||
_validator: Validator | None = None,
|
||||
_lexer: Lexer | None = None,
|
||||
_extra_buffer_processors=None,
|
||||
_extra_layout_body: Optional[AnyContainer] = None,
|
||||
_extra_layout_body: AnyContainer | None = None,
|
||||
_extra_toolbars=None,
|
||||
_input_buffer_height=None,
|
||||
) -> None:
|
||||
|
||||
self.get_globals: _GetNamespace = get_globals or (lambda: {})
|
||||
self.get_locals: _GetNamespace = get_locals or self.get_globals
|
||||
|
||||
|
@ -310,7 +320,7 @@ class PythonInput:
|
|||
self.show_exit_confirmation: bool = False
|
||||
|
||||
# The title to be displayed in the terminal. (None or string.)
|
||||
self.terminal_title: Optional[str] = None
|
||||
self.terminal_title: str | None = None
|
||||
|
||||
self.exit_message: str = "Do you really want to exit?"
|
||||
self.insert_blank_line_after_output: bool = True # (For the REPL.)
|
||||
|
@ -321,11 +331,23 @@ class PythonInput:
|
|||
self.search_buffer: Buffer = Buffer()
|
||||
self.docstring_buffer: Buffer = Buffer(read_only=True)
|
||||
|
||||
# Cursor shapes.
|
||||
self.cursor_shape_config = "Block"
|
||||
self.all_cursor_shape_configs: Dict[str, AnyCursorShapeConfig] = {
|
||||
"Block": CursorShape.BLOCK,
|
||||
"Underline": CursorShape.UNDERLINE,
|
||||
"Beam": CursorShape.BEAM,
|
||||
"Modal (vi)": ModalCursorShapeConfig(),
|
||||
"Blink block": CursorShape.BLINKING_BLOCK,
|
||||
"Blink under": CursorShape.BLINKING_UNDERLINE,
|
||||
"Blink beam": CursorShape.BLINKING_BEAM,
|
||||
}
|
||||
|
||||
# Tokens to be shown at the prompt.
|
||||
self.prompt_style: str = "classic" # The currently active style.
|
||||
|
||||
# Styles selectable from the menu.
|
||||
self.all_prompt_styles: Dict[str, PromptStyle] = {
|
||||
self.all_prompt_styles: dict[str, PromptStyle] = {
|
||||
"ipython": IPythonPrompt(self),
|
||||
"classic": ClassicPrompt(),
|
||||
}
|
||||
|
@ -339,7 +361,7 @@ class PythonInput:
|
|||
].out_prompt()
|
||||
|
||||
#: Load styles.
|
||||
self.code_styles: Dict[str, BaseStyle] = get_all_code_styles()
|
||||
self.code_styles: dict[str, BaseStyle] = get_all_code_styles()
|
||||
self.ui_styles = get_all_ui_styles()
|
||||
self._current_code_style_name: str = "default"
|
||||
self._current_ui_style_name: str = "default"
|
||||
|
@ -361,7 +383,7 @@ class PythonInput:
|
|||
self.current_statement_index: int = 1
|
||||
|
||||
# Code signatures. (This is set asynchronously after a timeout.)
|
||||
self.signatures: List[Signature] = []
|
||||
self.signatures: list[Signature] = []
|
||||
|
||||
# Boolean indicating whether we have a signatures thread running.
|
||||
# (Never run more than one at the same time.)
|
||||
|
@ -400,9 +422,7 @@ class PythonInput:
|
|||
# Create an app if requested. If not, the global get_app() is returned
|
||||
# for self.app via property getter.
|
||||
if create_app:
|
||||
self._app: Optional[Application[str]] = self._create_application(
|
||||
input, output
|
||||
)
|
||||
self._app: Application[str] | None = self._create_application(input, output)
|
||||
# Setting vi_mode will not work unless the prompt_toolkit
|
||||
# application has been created.
|
||||
if vi_mode:
|
||||
|
@ -528,7 +548,7 @@ class PythonInput:
|
|||
self.ui_styles[self._current_ui_style_name],
|
||||
)
|
||||
|
||||
def _create_options(self) -> List[OptionCategory[Any]]:
|
||||
def _create_options(self) -> list[OptionCategory[Any]]:
|
||||
"""
|
||||
Create a list of `Option` instances for the options sidebar.
|
||||
"""
|
||||
|
@ -547,14 +567,14 @@ class PythonInput:
|
|||
title: str,
|
||||
description: str,
|
||||
field_name: str,
|
||||
values: Tuple[str, str] = ("off", "on"),
|
||||
values: tuple[str, str] = ("off", "on"),
|
||||
) -> Option[str]:
|
||||
"Create Simple on/of option."
|
||||
|
||||
def get_current_value() -> str:
|
||||
return values[bool(getattr(self, field_name))]
|
||||
|
||||
def get_values() -> Dict[str, Callable[[], bool]]:
|
||||
def get_values() -> dict[str, Callable[[], bool]]:
|
||||
return {
|
||||
values[1]: lambda: enable(field_name),
|
||||
values[0]: lambda: disable(field_name),
|
||||
|
@ -582,6 +602,16 @@ class PythonInput:
|
|||
"Vi": lambda: enable("vi_mode"),
|
||||
},
|
||||
),
|
||||
Option(
|
||||
title="Cursor shape",
|
||||
description="Change the cursor style, possibly according "
|
||||
"to the Vi input mode.",
|
||||
get_current_value=lambda: self.cursor_shape_config,
|
||||
get_values=lambda: dict(
|
||||
(s, partial(enable, "cursor_shape_config", s))
|
||||
for s in self.all_cursor_shape_configs
|
||||
),
|
||||
),
|
||||
simple_option(
|
||||
title="Paste mode",
|
||||
description="When enabled, don't indent automatically.",
|
||||
|
@ -731,10 +761,10 @@ class PythonInput:
|
|||
title="Prompt",
|
||||
description="Visualisation of the prompt. ('>>>' or 'In [1]:')",
|
||||
get_current_value=lambda: self.prompt_style,
|
||||
get_values=lambda: dict(
|
||||
(s, partial(enable, "prompt_style", s))
|
||||
get_values=lambda: {
|
||||
s: partial(enable, "prompt_style", s)
|
||||
for s in self.all_prompt_styles
|
||||
),
|
||||
},
|
||||
),
|
||||
simple_option(
|
||||
title="Blank line after input",
|
||||
|
@ -826,10 +856,10 @@ class PythonInput:
|
|||
title="User interface",
|
||||
description="Color scheme to use for the user interface.",
|
||||
get_current_value=lambda: self._current_ui_style_name,
|
||||
get_values=lambda: dict(
|
||||
(name, partial(self.use_ui_colorscheme, name))
|
||||
get_values=lambda: {
|
||||
name: partial(self.use_ui_colorscheme, name)
|
||||
for name in self.ui_styles
|
||||
),
|
||||
},
|
||||
),
|
||||
Option(
|
||||
title="Color depth",
|
||||
|
@ -863,7 +893,7 @@ class PythonInput:
|
|||
]
|
||||
|
||||
def _create_application(
|
||||
self, input: Optional[Input], output: Optional[Output]
|
||||
self, input: Input | None, output: Output | None
|
||||
) -> Application[str]:
|
||||
"""
|
||||
Create an `Application` instance.
|
||||
|
@ -894,6 +924,9 @@ class PythonInput:
|
|||
style_transformation=self.style_transformation,
|
||||
include_default_pygments_style=False,
|
||||
reverse_vi_search_direction=True,
|
||||
cursor=DynamicCursorShapeConfig(
|
||||
lambda: self.all_cursor_shape_configs[self.cursor_shape_config]
|
||||
),
|
||||
input=input,
|
||||
output=output,
|
||||
)
|
||||
|
@ -953,7 +986,7 @@ class PythonInput:
|
|||
in another thread, get the signature of the current code.
|
||||
"""
|
||||
|
||||
def get_signatures_in_executor(document: Document) -> List[Signature]:
|
||||
def get_signatures_in_executor(document: Document) -> list[Signature]:
|
||||
# First, get signatures from Jedi. If we didn't found any and if
|
||||
# "dictionary completion" (eval-based completion) is enabled, then
|
||||
# get signatures using eval.
|
||||
|
@ -1043,6 +1076,7 @@ class PythonInput:
|
|||
|
||||
This can raise EOFError, when Control-D is pressed.
|
||||
"""
|
||||
|
||||
# Capture the current input_mode in order to restore it after reset,
|
||||
# for ViState.reset() sets it to InputMode.INSERT unconditionally and
|
||||
# doesn't accept any arguments.
|
||||
|
|
|
@ -7,6 +7,8 @@ Utility for creating a Python repl.
|
|||
embed(globals(), locals(), vi_mode=False)
|
||||
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import builtins
|
||||
import os
|
||||
|
@ -53,7 +55,7 @@ except ImportError:
|
|||
__all__ = ["PythonRepl", "enable_deprecation_warnings", "run_config", "embed"]
|
||||
|
||||
|
||||
def _get_coroutine_flag() -> Optional[int]:
|
||||
def _get_coroutine_flag() -> int | None:
|
||||
for k, v in COMPILER_FLAG_NAMES.items():
|
||||
if v == "COROUTINE":
|
||||
return k
|
||||
|
@ -62,7 +64,7 @@ def _get_coroutine_flag() -> Optional[int]:
|
|||
return None
|
||||
|
||||
|
||||
COROUTINE_FLAG: Optional[int] = _get_coroutine_flag()
|
||||
COROUTINE_FLAG: int | None = _get_coroutine_flag()
|
||||
|
||||
|
||||
def _has_coroutine_flag(code: types.CodeType) -> bool:
|
||||
|
@ -89,14 +91,15 @@ class PythonRepl(PythonInput):
|
|||
exec(code, self.get_globals(), self.get_locals())
|
||||
else:
|
||||
output = self.app.output
|
||||
output.write("WARNING | File not found: {}\n\n".format(path))
|
||||
output.write(f"WARNING | File not found: {path}\n\n")
|
||||
|
||||
def run_and_show_expression(self, expression: str) -> None:
|
||||
try:
|
||||
# Eval.
|
||||
try:
|
||||
result = self.eval(expression)
|
||||
except KeyboardInterrupt: # KeyboardInterrupt doesn't inherit from Exception.
|
||||
except KeyboardInterrupt:
|
||||
# KeyboardInterrupt doesn't inherit from Exception.
|
||||
raise
|
||||
except SystemExit:
|
||||
raise
|
||||
|
@ -299,7 +302,7 @@ class PythonRepl(PythonInput):
|
|||
return None
|
||||
|
||||
def _store_eval_result(self, result: object) -> None:
|
||||
locals: Dict[str, Any] = self.get_locals()
|
||||
locals: dict[str, Any] = self.get_locals()
|
||||
locals["_"] = locals["_%i" % self.current_statement_index] = result
|
||||
|
||||
def get_compiler_flags(self) -> int:
|
||||
|
@ -402,7 +405,7 @@ class PythonRepl(PythonInput):
|
|||
|
||||
def show_result(self, result: object) -> None:
|
||||
"""
|
||||
Show __repr__ for an `eval` result and print to ouptut.
|
||||
Show __repr__ for an `eval` result and print to output.
|
||||
"""
|
||||
formatted_text_output = self._format_result_output(result)
|
||||
|
||||
|
@ -523,7 +526,7 @@ class PythonRepl(PythonInput):
|
|||
|
||||
flush_page()
|
||||
|
||||
def create_pager_prompt(self) -> PromptSession["PagerResult"]:
|
||||
def create_pager_prompt(self) -> PromptSession[PagerResult]:
|
||||
"""
|
||||
Create pager --MORE-- prompt.
|
||||
"""
|
||||
|
@ -572,8 +575,6 @@ class PythonRepl(PythonInput):
|
|||
include_default_pygments_style=False,
|
||||
output=output,
|
||||
)
|
||||
|
||||
output.write("%s\n" % e)
|
||||
output.flush()
|
||||
|
||||
def _handle_keyboard_interrupt(self, e: KeyboardInterrupt) -> None:
|
||||
|
@ -652,7 +653,7 @@ def run_config(
|
|||
|
||||
# Run the config file in an empty namespace.
|
||||
try:
|
||||
namespace: Dict[str, Any] = {}
|
||||
namespace: dict[str, Any] = {}
|
||||
|
||||
with open(config_file, "rb") as f:
|
||||
code = compile(f.read(), config_file, "exec")
|
||||
|
@ -671,10 +672,10 @@ def run_config(
|
|||
def embed(
|
||||
globals=None,
|
||||
locals=None,
|
||||
configure: Optional[Callable[[PythonRepl], None]] = None,
|
||||
configure: Callable[[PythonRepl], None] | None = None,
|
||||
vi_mode: bool = False,
|
||||
history_filename: Optional[str] = None,
|
||||
title: Optional[str] = None,
|
||||
history_filename: str | None = None,
|
||||
title: str | None = None,
|
||||
startup_paths=None,
|
||||
patch_stdout: bool = False,
|
||||
return_asyncio_coroutine: bool = False,
|
||||
|
|
|
@ -5,6 +5,8 @@ editing.
|
|||
Either with the Jedi library, or using `inspect.signature` if Jedi fails and we
|
||||
can use `eval()` to evaluate the function object.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
from inspect import Signature as InspectSignature
|
||||
from inspect import _ParameterKind as ParameterKind
|
||||
|
@ -25,8 +27,8 @@ class Parameter:
|
|||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
annotation: Optional[str],
|
||||
default: Optional[str],
|
||||
annotation: str | None,
|
||||
default: str | None,
|
||||
kind: ParameterKind,
|
||||
) -> None:
|
||||
self.name = name
|
||||
|
@ -66,9 +68,9 @@ class Signature:
|
|||
name: str,
|
||||
docstring: str,
|
||||
parameters: Sequence[Parameter],
|
||||
index: Optional[int] = None,
|
||||
index: int | None = None,
|
||||
returns: str = "",
|
||||
bracket_start: Tuple[int, int] = (0, 0),
|
||||
bracket_start: tuple[int, int] = (0, 0),
|
||||
) -> None:
|
||||
self.name = name
|
||||
self.docstring = docstring
|
||||
|
@ -84,7 +86,7 @@ class Signature:
|
|||
docstring: str,
|
||||
signature: InspectSignature,
|
||||
index: int,
|
||||
) -> "Signature":
|
||||
) -> Signature:
|
||||
parameters = []
|
||||
|
||||
def get_annotation_name(annotation: object) -> str:
|
||||
|
@ -123,9 +125,7 @@ class Signature:
|
|||
)
|
||||
|
||||
@classmethod
|
||||
def from_jedi_signature(
|
||||
cls, signature: "jedi.api.classes.Signature"
|
||||
) -> "Signature":
|
||||
def from_jedi_signature(cls, signature: jedi.api.classes.Signature) -> Signature:
|
||||
parameters = []
|
||||
|
||||
for p in signature.params:
|
||||
|
@ -160,8 +160,8 @@ class Signature:
|
|||
|
||||
|
||||
def get_signatures_using_jedi(
|
||||
document: Document, locals: Dict[str, Any], globals: Dict[str, Any]
|
||||
) -> List[Signature]:
|
||||
document: Document, locals: dict[str, Any], globals: dict[str, Any]
|
||||
) -> list[Signature]:
|
||||
script = get_jedi_script_from_document(document, locals, globals)
|
||||
|
||||
# Show signatures in help text.
|
||||
|
@ -195,8 +195,8 @@ def get_signatures_using_jedi(
|
|||
|
||||
|
||||
def get_signatures_using_eval(
|
||||
document: Document, locals: Dict[str, Any], globals: Dict[str, Any]
|
||||
) -> List[Signature]:
|
||||
document: Document, locals: dict[str, Any], globals: dict[str, Any]
|
||||
) -> list[Signature]:
|
||||
"""
|
||||
Look for the signature of the function before the cursor position without
|
||||
use of Jedi. This uses a similar approach as the `DictionaryCompleter` of
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Dict
|
||||
|
||||
from prompt_toolkit.styles import BaseStyle, Style, merge_styles
|
||||
|
@ -8,11 +10,11 @@ from pygments.styles import get_all_styles, get_style_by_name
|
|||
__all__ = ["get_all_code_styles", "get_all_ui_styles", "generate_style"]
|
||||
|
||||
|
||||
def get_all_code_styles() -> Dict[str, BaseStyle]:
|
||||
def get_all_code_styles() -> dict[str, BaseStyle]:
|
||||
"""
|
||||
Return a mapping from style names to their classes.
|
||||
"""
|
||||
result: Dict[str, BaseStyle] = {
|
||||
result: dict[str, BaseStyle] = {
|
||||
name: style_from_pygments_cls(get_style_by_name(name))
|
||||
for name in get_all_styles()
|
||||
}
|
||||
|
@ -20,7 +22,7 @@ def get_all_code_styles() -> Dict[str, BaseStyle]:
|
|||
return result
|
||||
|
||||
|
||||
def get_all_ui_styles() -> Dict[str, BaseStyle]:
|
||||
def get_all_ui_styles() -> dict[str, BaseStyle]:
|
||||
"""
|
||||
Return a dict mapping {ui_style_name -> style_dict}.
|
||||
"""
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
"""
|
||||
For internal use only.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
|
@ -65,8 +67,8 @@ def has_unclosed_brackets(text: str) -> bool:
|
|||
|
||||
|
||||
def get_jedi_script_from_document(
|
||||
document: Document, locals: Dict[str, Any], globals: Dict[str, Any]
|
||||
) -> "Interpreter":
|
||||
document: Document, locals: dict[str, Any], globals: dict[str, Any]
|
||||
) -> Interpreter:
|
||||
import jedi # We keep this import in-line, to improve start-up time.
|
||||
|
||||
# Importing Jedi is 'slow'.
|
||||
|
@ -154,7 +156,7 @@ def if_mousedown(handler: _T) -> _T:
|
|||
by the Window.)
|
||||
"""
|
||||
|
||||
def handle_if_mouse_down(mouse_event: MouseEvent) -> "NotImplementedOrNone":
|
||||
def handle_if_mouse_down(mouse_event: MouseEvent) -> NotImplementedOrNone:
|
||||
if mouse_event.event_type == MouseEventType.MOUSE_DOWN:
|
||||
return handler(mouse_event)
|
||||
else:
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Callable, Optional
|
||||
|
||||
from prompt_toolkit.document import Document
|
||||
|
@ -16,7 +18,7 @@ class PythonValidator(Validator):
|
|||
active compiler flags.
|
||||
"""
|
||||
|
||||
def __init__(self, get_compiler_flags: Optional[Callable[[], int]] = None) -> None:
|
||||
def __init__(self, get_compiler_flags: Callable[[], int] | None = None) -> None:
|
||||
self.get_compiler_flags = get_compiler_flags
|
||||
|
||||
def validate(self, document: Document) -> None:
|
||||
|
|
10
setup.py
10
setup.py
|
@ -11,7 +11,7 @@ with open(os.path.join(os.path.dirname(__file__), "README.rst")) as f:
|
|||
setup(
|
||||
name="ptpython",
|
||||
author="Jonathan Slenders",
|
||||
version="3.0.22",
|
||||
version="3.0.23",
|
||||
url="https://github.com/prompt-toolkit/ptpython",
|
||||
description="Python REPL build on top of prompt_toolkit",
|
||||
long_description=long_description,
|
||||
|
@ -21,14 +21,14 @@ setup(
|
|||
"appdirs",
|
||||
"importlib_metadata;python_version<'3.8'",
|
||||
"jedi>=0.16.0",
|
||||
# Use prompt_toolkit 3.0.18, because of the `in_thread` option.
|
||||
"prompt_toolkit>=3.0.18,<3.1.0",
|
||||
# Use prompt_toolkit 3.0.28, because of cursor shape support.
|
||||
"prompt_toolkit>=3.0.28,<3.1.0",
|
||||
"pygments",
|
||||
],
|
||||
python_requires=">=3.6",
|
||||
python_requires=">=3.7",
|
||||
classifiers=[
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
import ptpython.completer
|
||||
|
|
Loading…
Add table
Reference in a new issue