Adding upstream version 3.0.30.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
b6d29f411e
commit
635a85607c
35 changed files with 212 additions and 195 deletions
33
.github/workflows/test.yaml
vendored
33
.github/workflows/test.yaml
vendored
|
@ -10,29 +10,32 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]
|
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Setup Python ${{ matrix.python-version }}
|
- uses: astral-sh/setup-uv@v5
|
||||||
uses: actions/setup-python@v1
|
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
- name: Install Dependencies
|
- name: Type Checking
|
||||||
run: |
|
run: |
|
||||||
sudo apt remove python3-pip
|
uvx --with . mypy src/ptpython/
|
||||||
python -m pip install --upgrade pip
|
uvx --with . mypy examples/
|
||||||
python -m pip install . ruff mypy pytest readme_renderer
|
- name: Code formatting
|
||||||
pip list
|
if: ${{ matrix.python-version == '3.13' }}
|
||||||
- name: Type Checker
|
|
||||||
run: |
|
run: |
|
||||||
mypy ptpython
|
uvx ruff check .
|
||||||
ruff check .
|
uvx ruff format --check .
|
||||||
ruff format --check .
|
- name: Typos
|
||||||
- name: Run Tests
|
if: ${{ matrix.python-version == '3.13' }}
|
||||||
run: |
|
run: |
|
||||||
./tests/run_tests.py
|
uvx typos .
|
||||||
|
- name: Unit test
|
||||||
|
run: |
|
||||||
|
uvx --with . pytest tests/
|
||||||
- name: Validate README.md
|
- name: Validate README.md
|
||||||
|
if: ${{ matrix.python-version == '3.13' }}
|
||||||
# Ensure that the README renders correctly (required for uploading to PyPI).
|
# Ensure that the README renders correctly (required for uploading to PyPI).
|
||||||
run: |
|
run: |
|
||||||
|
uv pip install readme_renderer
|
||||||
python -m readme_renderer README.rst > /dev/null
|
python -m readme_renderer README.rst > /dev/null
|
||||||
|
|
11
CHANGELOG
11
CHANGELOG
|
@ -1,6 +1,17 @@
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
3.0.30: 2025-04-15
|
||||||
|
------------------
|
||||||
|
|
||||||
|
New features:
|
||||||
|
- Show exception cause/context when printing chained exceptions.
|
||||||
|
- Reworked project layout and use pyproject.toml instead of setup.py.
|
||||||
|
|
||||||
|
Breaking changes:
|
||||||
|
- Drop Python 3.7 support.
|
||||||
|
|
||||||
|
|
||||||
3.0.29: 2024-07-22
|
3.0.29: 2024-07-22
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ async def print_counter() -> None:
|
||||||
Coroutine that prints counters and saves it in a global variable.
|
Coroutine that prints counters and saves it in a global variable.
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
print("Counter: %i" % counter[0])
|
print(f"Counter: {counter[0]}")
|
||||||
counter[0] += 1
|
counter[0] += 1
|
||||||
await asyncio.sleep(3)
|
await asyncio.sleep(3)
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,8 @@ async def main(port: int = 8222) -> None:
|
||||||
def create_server() -> MySSHServer:
|
def create_server() -> MySSHServer:
|
||||||
return MySSHServer(lambda: environ)
|
return MySSHServer(lambda: environ)
|
||||||
|
|
||||||
print("Listening on :%i" % port)
|
print(f"Listening on: {port}")
|
||||||
print('To connect, do "ssh localhost -p %i"' % port)
|
print(f'To connect, do "ssh localhost -p {port}"')
|
||||||
|
|
||||||
await asyncssh.create_server(
|
await asyncssh.create_server(
|
||||||
create_server, "", port, server_host_keys=["/etc/ssh/ssh_host_dsa_key"]
|
create_server, "", port, server_host_keys=["/etc/ssh/ssh_host_dsa_key"]
|
||||||
|
|
|
@ -6,6 +6,8 @@ Thanks to Vincent Michel for this!
|
||||||
https://gist.github.com/vxgmichel/7685685b3e5ead04ada4a3ba75a48eef
|
https://gist.github.com/vxgmichel/7685685b3e5ead04ada4a3ba75a48eef
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
|
@ -15,7 +17,7 @@ from prompt_toolkit.contrib.ssh.server import (
|
||||||
PromptToolkitSSHServer,
|
PromptToolkitSSHServer,
|
||||||
PromptToolkitSSHSession,
|
PromptToolkitSSHSession,
|
||||||
)
|
)
|
||||||
from prompt_toolkit.contrib.telnet.server import TelnetServer
|
from prompt_toolkit.contrib.telnet.server import TelnetConnection, TelnetServer
|
||||||
|
|
||||||
from ptpython.repl import embed
|
from ptpython.repl import embed
|
||||||
|
|
||||||
|
@ -28,7 +30,7 @@ def ensure_key(filename: str = "ssh_host_key") -> str:
|
||||||
return str(path)
|
return str(path)
|
||||||
|
|
||||||
|
|
||||||
async def interact(connection: PromptToolkitSSHSession) -> None:
|
async def interact(connection: PromptToolkitSSHSession | TelnetConnection) -> None:
|
||||||
global_dict = {**globals(), "print": print_formatted_text}
|
global_dict = {**globals(), "print": print_formatted_text}
|
||||||
await embed(return_asyncio_coroutine=True, globals=global_dict)
|
await embed(return_asyncio_coroutine=True, globals=global_dict)
|
||||||
|
|
||||||
|
|
6
mypy.ini
6
mypy.ini
|
@ -1,6 +0,0 @@
|
||||||
[mypy]
|
|
||||||
ignore_missing_imports = True
|
|
||||||
no_implicit_optional = True
|
|
||||||
platform = win32
|
|
||||||
strict_equality = True
|
|
||||||
strict_optional = True
|
|
|
@ -1,3 +1,55 @@
|
||||||
|
[project]
|
||||||
|
name = "ptpython"
|
||||||
|
version = "3.0.30"
|
||||||
|
description = "Python REPL build on top of prompt_toolkit"
|
||||||
|
readme = "README.rst"
|
||||||
|
authors = [{ name = "Jonathan Slenders" }]
|
||||||
|
classifiers = [
|
||||||
|
"License :: OSI Approved :: BSD License",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
|
"Programming Language :: Python",
|
||||||
|
]
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
dependencies = [
|
||||||
|
"appdirs",
|
||||||
|
"jedi>=0.16.0",
|
||||||
|
# Use prompt_toolkit 3.0.43, because of `OneStyleAndTextTuple` import.
|
||||||
|
"prompt_toolkit>=3.0.43,<3.1.0",
|
||||||
|
"pygments",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://github.com/prompt-toolkit/ptpython"
|
||||||
|
Changelog = "https://github.com/prompt-toolkit/ptpython/blob/master/CHANGELOG"
|
||||||
|
"Bug Tracker" = "https://github.com/prompt-toolkit/ptpython/issues"
|
||||||
|
"Source Code" = "https://github.com/prompt-toolkit/ptpython"
|
||||||
|
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
ptpython = "ptpython.entry_points.run_ptpython:run"
|
||||||
|
ptipython = "ptpython.entry_points.run_ptipython:run"
|
||||||
|
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
ptipython = ["ipython"] # For ptipython, we need to have IPython
|
||||||
|
|
||||||
|
|
||||||
|
[tool.mypy]
|
||||||
|
ignore_missing_imports = true
|
||||||
|
no_implicit_optional = true
|
||||||
|
platform = "win32"
|
||||||
|
strict_equality = true
|
||||||
|
strict_optional = true
|
||||||
|
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py37"
|
target-version = "py37"
|
||||||
lint.select = [
|
lint.select = [
|
||||||
|
@ -22,14 +74,22 @@ lint.ignore = [
|
||||||
[tool.ruff.lint.per-file-ignores]
|
[tool.ruff.lint.per-file-ignores]
|
||||||
"examples/*" = ["T201"] # Print allowed in examples.
|
"examples/*" = ["T201"] # Print allowed in examples.
|
||||||
"examples/ptpython_config/config.py" = ["F401"] # Unused imports in config.
|
"examples/ptpython_config/config.py" = ["F401"] # Unused imports in config.
|
||||||
"ptpython/entry_points/run_ptipython.py" = ["T201", "F401"] # Print, import usage.
|
"src/ptpython/entry_points/run_ptipython.py" = ["T201", "F401"] # Print, import usage.
|
||||||
"ptpython/entry_points/run_ptpython.py" = ["T201"] # Print usage.
|
"src/ptpython/entry_points/run_ptpython.py" = ["T201"] # Print usage.
|
||||||
"ptpython/ipython.py" = ["T100"] # Import usage.
|
"src/ptpython/ipython.py" = ["T100"] # Import usage.
|
||||||
"ptpython/repl.py" = ["T201"] # Print usage.
|
"src/ptpython/repl.py" = ["T201"] # Print usage.
|
||||||
"ptpython/printer.py" = ["T201"] # Print usage.
|
"src/ptpython/printer.py" = ["T201"] # Print usage.
|
||||||
"tests/run_tests.py" = ["F401"] # Unused imports.
|
|
||||||
|
|
||||||
|
|
||||||
[tool.ruff.lint.isort]
|
[tool.ruff.lint.isort]
|
||||||
known-first-party = ["ptpython"]
|
known-first-party = ["ptpython"]
|
||||||
known-third-party = ["prompt_toolkit", "pygments", "asyncssh"]
|
known-third-party = ["prompt_toolkit", "pygments", "asyncssh"]
|
||||||
|
|
||||||
|
[tool.typos.default]
|
||||||
|
extend-ignore-re = [
|
||||||
|
"impotr" # Intentional typo in: ./examples/ptpython_config/config.py
|
||||||
|
]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=68"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
41
setup.cfg
41
setup.cfg
|
@ -1,41 +0,0 @@
|
||||||
[bdist_wheel]
|
|
||||||
universal=1
|
|
||||||
|
|
||||||
[flake8]
|
|
||||||
exclude=__init__.py
|
|
||||||
max_line_length=150
|
|
||||||
ignore=
|
|
||||||
E114,
|
|
||||||
E116,
|
|
||||||
E117,
|
|
||||||
E121,
|
|
||||||
E122,
|
|
||||||
E123,
|
|
||||||
E125,
|
|
||||||
E126,
|
|
||||||
E127,
|
|
||||||
E128,
|
|
||||||
E131,
|
|
||||||
E171,
|
|
||||||
E203,
|
|
||||||
E211,
|
|
||||||
E221,
|
|
||||||
E227,
|
|
||||||
E231,
|
|
||||||
E241,
|
|
||||||
E251,
|
|
||||||
E301,
|
|
||||||
E402,
|
|
||||||
E501,
|
|
||||||
E701,
|
|
||||||
E702,
|
|
||||||
E704,
|
|
||||||
E731,
|
|
||||||
E741,
|
|
||||||
F401,
|
|
||||||
F403,
|
|
||||||
F405,
|
|
||||||
F811,
|
|
||||||
W503,
|
|
||||||
W504,
|
|
||||||
E722
|
|
67
setup.py
67
setup.py
|
@ -1,67 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from setuptools import find_packages, setup
|
|
||||||
|
|
||||||
with open(os.path.join(os.path.dirname(__file__), "README.rst")) as f:
|
|
||||||
long_description = f.read()
|
|
||||||
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name="ptpython",
|
|
||||||
author="Jonathan Slenders",
|
|
||||||
version="3.0.29",
|
|
||||||
url="https://github.com/prompt-toolkit/ptpython",
|
|
||||||
description="Python REPL build on top of prompt_toolkit",
|
|
||||||
long_description=long_description,
|
|
||||||
package_urls={
|
|
||||||
"Changelog": "https://github.com/prompt-toolkit/ptpython/blob/master/CHANGELOG",
|
|
||||||
},
|
|
||||||
project_urls={
|
|
||||||
"Bug Tracker": "https://github.com/prompt-toolkit/ptpython/issues",
|
|
||||||
"Source Code": "https://github.com/prompt-toolkit/ptpython",
|
|
||||||
"Changelog": "https://github.com/prompt-toolkit/ptpython/blob/master/CHANGELOG",
|
|
||||||
},
|
|
||||||
packages=find_packages("."),
|
|
||||||
package_data={"ptpython": ["py.typed"]},
|
|
||||||
install_requires=[
|
|
||||||
"appdirs",
|
|
||||||
"importlib_metadata;python_version<'3.8'",
|
|
||||||
"jedi>=0.16.0",
|
|
||||||
# Use prompt_toolkit 3.0.43, because of `OneStyleAndTextTuple` import.
|
|
||||||
"prompt_toolkit>=3.0.43,<3.1.0",
|
|
||||||
"pygments",
|
|
||||||
],
|
|
||||||
python_requires=">=3.7",
|
|
||||||
classifiers=[
|
|
||||||
"License :: OSI Approved :: BSD License",
|
|
||||||
"Programming Language :: Python :: 3",
|
|
||||||
"Programming Language :: Python :: 3.7",
|
|
||||||
"Programming Language :: Python :: 3.8",
|
|
||||||
"Programming Language :: Python :: 3.9",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
|
||||||
"Programming Language :: Python :: 3.11",
|
|
||||||
"Programming Language :: Python :: 3.12",
|
|
||||||
"Programming Language :: Python :: 3 :: Only",
|
|
||||||
"Programming Language :: Python",
|
|
||||||
],
|
|
||||||
entry_points={
|
|
||||||
"console_scripts": [
|
|
||||||
"ptpython = ptpython.entry_points.run_ptpython:run",
|
|
||||||
"ptipython = ptpython.entry_points.run_ptipython:run",
|
|
||||||
f"ptpython{sys.version_info[0]} = ptpython.entry_points.run_ptpython:run",
|
|
||||||
"ptpython{}.{} = ptpython.entry_points.run_ptpython:run".format(
|
|
||||||
*sys.version_info[:2]
|
|
||||||
),
|
|
||||||
f"ptipython{sys.version_info[0]} = ptpython.entry_points.run_ptipython:run",
|
|
||||||
"ptipython{}.{} = ptpython.entry_points.run_ptipython:run".format(
|
|
||||||
*sys.version_info[:2]
|
|
||||||
),
|
|
||||||
]
|
|
||||||
},
|
|
||||||
extras_require={
|
|
||||||
"ptipython": ["ipython"], # For ptipython, we need to have IPython
|
|
||||||
"all": ["black"], # Black not always possible on PyPy
|
|
||||||
},
|
|
||||||
)
|
|
|
@ -30,8 +30,9 @@ import asyncio
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import sys
|
import sys
|
||||||
|
from importlib import metadata
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from typing import IO
|
from typing import Protocol
|
||||||
|
|
||||||
import appdirs
|
import appdirs
|
||||||
from prompt_toolkit.formatted_text import HTML
|
from prompt_toolkit.formatted_text import HTML
|
||||||
|
@ -39,17 +40,15 @@ from prompt_toolkit.shortcuts import print_formatted_text
|
||||||
|
|
||||||
from ptpython.repl import PythonRepl, embed, enable_deprecation_warnings, run_config
|
from ptpython.repl import PythonRepl, embed, enable_deprecation_warnings, run_config
|
||||||
|
|
||||||
try:
|
|
||||||
from importlib import metadata # type: ignore
|
|
||||||
except ImportError:
|
|
||||||
import importlib_metadata as metadata # type: ignore
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["create_parser", "get_config_and_history_file", "run"]
|
__all__ = ["create_parser", "get_config_and_history_file", "run"]
|
||||||
|
|
||||||
|
|
||||||
|
class _SupportsWrite(Protocol):
|
||||||
|
def write(self, s: str, /) -> object: ...
|
||||||
|
|
||||||
|
|
||||||
class _Parser(argparse.ArgumentParser):
|
class _Parser(argparse.ArgumentParser):
|
||||||
def print_help(self, file: IO[str] | None = None) -> None:
|
def print_help(self, file: _SupportsWrite | None = None) -> None:
|
||||||
super().print_help()
|
super().print_help()
|
||||||
print(
|
print(
|
||||||
dedent(
|
dedent(
|
|
@ -58,13 +58,15 @@ from ptpython.layout import get_inputmode_fragments
|
||||||
from .utils import if_mousedown
|
from .utils import if_mousedown
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from typing_extensions import TypeAlias
|
||||||
|
|
||||||
from .python_input import PythonInput
|
from .python_input import PythonInput
|
||||||
|
|
||||||
HISTORY_COUNT = 2000
|
HISTORY_COUNT = 2000
|
||||||
|
|
||||||
__all__ = ["HistoryLayout", "PythonHistory"]
|
__all__ = ["HistoryLayout", "PythonHistory"]
|
||||||
|
|
||||||
E = KeyPressEvent
|
E: TypeAlias = KeyPressEvent
|
||||||
|
|
||||||
HELP_TEXT = """
|
HELP_TEXT = """
|
||||||
This interface is meant to select multiple lines from the
|
This interface is meant to select multiple lines from the
|
|
@ -22,6 +22,8 @@ from prompt_toolkit.keys import Keys
|
||||||
from .utils import document_is_multiline_python
|
from .utils import document_is_multiline_python
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from typing_extensions import TypeAlias
|
||||||
|
|
||||||
from .python_input import PythonInput
|
from .python_input import PythonInput
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -30,7 +32,7 @@ __all__ = [
|
||||||
"load_confirm_exit_bindings",
|
"load_confirm_exit_bindings",
|
||||||
]
|
]
|
||||||
|
|
||||||
E = KeyPressEvent
|
E: TypeAlias = KeyPressEvent
|
||||||
|
|
||||||
|
|
||||||
@Condition
|
@Condition
|
|
@ -108,7 +108,7 @@ def python_sidebar(python_input: PythonInput) -> Window:
|
||||||
tokens.extend(
|
tokens.extend(
|
||||||
[
|
[
|
||||||
("class:sidebar", " "),
|
("class:sidebar", " "),
|
||||||
("class:sidebar.title", " %-36s" % category.title),
|
("class:sidebar.title", f" {category.title:36}"),
|
||||||
("class:sidebar", "\n"),
|
("class:sidebar", "\n"),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -130,7 +130,7 @@ def python_sidebar(python_input: PythonInput) -> Window:
|
||||||
sel = ",selected" if selected else ""
|
sel = ",selected" if selected else ""
|
||||||
|
|
||||||
tokens.append(("class:sidebar" + sel, " >" if selected else " "))
|
tokens.append(("class:sidebar" + sel, " >" if selected else " "))
|
||||||
tokens.append(("class:sidebar.label" + sel, "%-24s" % label, select_item))
|
tokens.append(("class:sidebar.label" + sel, f"{label:24}", select_item))
|
||||||
tokens.append(("class:sidebar.status" + sel, " ", select_item))
|
tokens.append(("class:sidebar.status" + sel, " ", select_item))
|
||||||
tokens.append(("class:sidebar.status" + sel, f"{status}", goto_next))
|
tokens.append(("class:sidebar.status" + sel, f"{status}", goto_next))
|
||||||
|
|
||||||
|
@ -332,7 +332,7 @@ class PythonPromptMargin(PromptMargin):
|
||||||
width: int, line_number: int, is_soft_wrap: bool
|
width: int, line_number: int, is_soft_wrap: bool
|
||||||
) -> StyleAndTextTuples:
|
) -> StyleAndTextTuples:
|
||||||
if python_input.show_line_numbers and not is_soft_wrap:
|
if python_input.show_line_numbers and not is_soft_wrap:
|
||||||
text = ("%i " % (line_number + 1)).rjust(width)
|
text = f"{line_number + 1} ".rjust(width)
|
||||||
return [("class:line-number", text)]
|
return [("class:line-number", text)]
|
||||||
else:
|
else:
|
||||||
return to_formatted_text(get_prompt_style().in2_prompt(width))
|
return to_formatted_text(get_prompt_style().in2_prompt(width))
|
||||||
|
@ -368,8 +368,7 @@ def status_bar(python_input: PythonInput) -> Container:
|
||||||
append(
|
append(
|
||||||
(
|
(
|
||||||
TB,
|
TB,
|
||||||
"%i/%i "
|
f"{python_buffer.working_index + 1}/{len(python_buffer._working_lines)} ",
|
||||||
% (python_buffer.working_index + 1, len(python_buffer._working_lines)),
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -492,8 +491,7 @@ def show_sidebar_button_info(python_input: PythonInput) -> Container:
|
||||||
("class:status-toolbar", " - "),
|
("class:status-toolbar", " - "),
|
||||||
(
|
(
|
||||||
"class:status-toolbar.python-version",
|
"class:status-toolbar.python-version",
|
||||||
"%s %i.%i.%i"
|
f"{platform.python_implementation()} {version[0]}.{version[1]}.{version[2]}",
|
||||||
% (platform.python_implementation(), version[0], version[1], version[2]),
|
|
||||||
),
|
),
|
||||||
("class:status-toolbar", " "),
|
("class:status-toolbar", " "),
|
||||||
]
|
]
|
|
@ -1,6 +1,5 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
|
||||||
import traceback
|
import traceback
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
@ -254,7 +253,6 @@ class OutputPrinter:
|
||||||
columns_in_buffer += width
|
columns_in_buffer += width
|
||||||
current_line.append((style, c))
|
current_line.append((style, c))
|
||||||
|
|
||||||
if len(current_line) > 0:
|
|
||||||
yield current_line
|
yield current_line
|
||||||
|
|
||||||
def _print_paginated_formatted_text(
|
def _print_paginated_formatted_text(
|
||||||
|
@ -323,14 +321,20 @@ class OutputPrinter:
|
||||||
def _format_exception_output(
|
def _format_exception_output(
|
||||||
self, e: BaseException, highlight: bool
|
self, e: BaseException, highlight: bool
|
||||||
) -> Generator[OneStyleAndTextTuple, None, None]:
|
) -> Generator[OneStyleAndTextTuple, None, None]:
|
||||||
# Instead of just calling ``traceback.format_exc``, we take the
|
if e.__cause__:
|
||||||
# traceback and skip the bottom calls of this framework.
|
yield from self._format_exception_output(e.__cause__, highlight=highlight)
|
||||||
t, v, tb = sys.exc_info()
|
yield (
|
||||||
|
"",
|
||||||
|
"\nThe above exception was the direct cause of the following exception:\n\n",
|
||||||
|
)
|
||||||
|
elif e.__context__:
|
||||||
|
yield from self._format_exception_output(e.__context__, highlight=highlight)
|
||||||
|
yield (
|
||||||
|
"",
|
||||||
|
"\nDuring handling of the above exception, another exception occurred:\n\n",
|
||||||
|
)
|
||||||
|
|
||||||
# Required for pdb.post_mortem() to work.
|
tblist = list(traceback.extract_tb(e.__traceback__))
|
||||||
sys.last_type, sys.last_value, sys.last_traceback = t, v, tb
|
|
||||||
|
|
||||||
tblist = list(traceback.extract_tb(tb))
|
|
||||||
|
|
||||||
for line_nr, tb_tuple in enumerate(tblist):
|
for line_nr, tb_tuple in enumerate(tblist):
|
||||||
if tb_tuple[0] == "<stdin>":
|
if tb_tuple[0] == "<stdin>":
|
||||||
|
@ -340,7 +344,7 @@ class OutputPrinter:
|
||||||
tb_list = traceback.format_list(tblist)
|
tb_list = traceback.format_list(tblist)
|
||||||
if tb_list:
|
if tb_list:
|
||||||
tb_list.insert(0, "Traceback (most recent call last):\n")
|
tb_list.insert(0, "Traceback (most recent call last):\n")
|
||||||
tb_list.extend(traceback.format_exception_only(t, v))
|
tb_list.extend(traceback.format_exception_only(type(e), e))
|
||||||
|
|
||||||
tb_str = "".join(tb_list)
|
tb_str = "".join(tb_list)
|
||||||
|
|
|
@ -20,7 +20,17 @@ import types
|
||||||
import warnings
|
import warnings
|
||||||
from dis import COMPILER_FLAG_NAMES
|
from dis import COMPILER_FLAG_NAMES
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Callable, ContextManager, Iterable, NoReturn, Sequence
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
ContextManager,
|
||||||
|
Coroutine,
|
||||||
|
Iterable,
|
||||||
|
Literal,
|
||||||
|
NoReturn,
|
||||||
|
Sequence,
|
||||||
|
overload,
|
||||||
|
)
|
||||||
|
|
||||||
from prompt_toolkit.formatted_text import OneStyleAndTextTuple
|
from prompt_toolkit.formatted_text import OneStyleAndTextTuple
|
||||||
from prompt_toolkit.patch_stdout import patch_stdout as patch_stdout_context
|
from prompt_toolkit.patch_stdout import patch_stdout as patch_stdout_context
|
||||||
|
@ -362,7 +372,7 @@ class PythonRepl(PythonInput):
|
||||||
|
|
||||||
def _store_eval_result(self, result: object) -> 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
|
locals["_"] = locals[f"_{self.current_statement_index}"] = result
|
||||||
|
|
||||||
def get_compiler_flags(self) -> int:
|
def get_compiler_flags(self) -> int:
|
||||||
return super().get_compiler_flags() | PyCF_ALLOW_TOP_LEVEL_AWAIT
|
return super().get_compiler_flags() | PyCF_ALLOW_TOP_LEVEL_AWAIT
|
||||||
|
@ -378,6 +388,10 @@ class PythonRepl(PythonInput):
|
||||||
)
|
)
|
||||||
|
|
||||||
def _handle_exception(self, e: BaseException) -> None:
|
def _handle_exception(self, e: BaseException) -> None:
|
||||||
|
# Required for pdb.post_mortem() to work.
|
||||||
|
t, v, tb = sys.exc_info()
|
||||||
|
sys.last_type, sys.last_value, sys.last_traceback = t, v, tb
|
||||||
|
|
||||||
self._get_output_printer().display_exception(
|
self._get_output_printer().display_exception(
|
||||||
e,
|
e,
|
||||||
highlight=self.enable_syntax_highlighting,
|
highlight=self.enable_syntax_highlighting,
|
||||||
|
@ -501,6 +515,34 @@ class ReplExit(Exception):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def embed(
|
||||||
|
globals: dict[str, Any] | None = ...,
|
||||||
|
locals: dict[str, Any] | None = ...,
|
||||||
|
configure: Callable[[PythonRepl], None] | None = ...,
|
||||||
|
vi_mode: bool = ...,
|
||||||
|
history_filename: str | None = ...,
|
||||||
|
title: str | None = ...,
|
||||||
|
startup_paths: Sequence[str | Path] | None = ...,
|
||||||
|
patch_stdout: bool = ...,
|
||||||
|
return_asyncio_coroutine: Literal[False] = ...,
|
||||||
|
) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def embed(
|
||||||
|
globals: dict[str, Any] | None = ...,
|
||||||
|
locals: dict[str, Any] | None = ...,
|
||||||
|
configure: Callable[[PythonRepl], None] | None = ...,
|
||||||
|
vi_mode: bool = ...,
|
||||||
|
history_filename: str | None = ...,
|
||||||
|
title: str | None = ...,
|
||||||
|
startup_paths: Sequence[str | Path] | None = ...,
|
||||||
|
patch_stdout: bool = ...,
|
||||||
|
return_asyncio_coroutine: Literal[True] = ...,
|
||||||
|
) -> Coroutine[Any, Any, None]: ...
|
||||||
|
|
||||||
|
|
||||||
def embed(
|
def embed(
|
||||||
globals: dict[str, Any] | None = None,
|
globals: dict[str, Any] | None = None,
|
||||||
locals: dict[str, Any] | None = None,
|
locals: dict[str, Any] | None = None,
|
||||||
|
@ -511,7 +553,7 @@ def embed(
|
||||||
startup_paths: Sequence[str | Path] | None = None,
|
startup_paths: Sequence[str | Path] | None = None,
|
||||||
patch_stdout: bool = False,
|
patch_stdout: bool = False,
|
||||||
return_asyncio_coroutine: bool = False,
|
return_asyncio_coroutine: bool = False,
|
||||||
) -> None:
|
) -> None | Coroutine[Any, Any, None]:
|
||||||
"""
|
"""
|
||||||
Call this to embed Python shell at the current point in your program.
|
Call this to embed Python shell at the current point in your program.
|
||||||
It's similar to `IPython.embed` and `bpython.embed`. ::
|
It's similar to `IPython.embed` and `bpython.embed`. ::
|
||||||
|
@ -573,3 +615,4 @@ def embed(
|
||||||
else:
|
else:
|
||||||
with patch_context:
|
with patch_context:
|
||||||
repl.run()
|
repl.run()
|
||||||
|
return None
|
|
@ -1,24 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
import ptpython.completer
|
|
||||||
import ptpython.eventloop
|
|
||||||
import ptpython.filters
|
|
||||||
import ptpython.history_browser
|
|
||||||
import ptpython.key_bindings
|
|
||||||
import ptpython.layout
|
|
||||||
import ptpython.python_input
|
|
||||||
import ptpython.repl
|
|
||||||
import ptpython.style
|
|
||||||
import ptpython.utils
|
|
||||||
import ptpython.validator
|
|
||||||
|
|
||||||
# For now there are no tests here.
|
|
||||||
# However this is sufficient for Travis to do at least a syntax check.
|
|
||||||
# That way we are at least sure to restrict to the Python 2.6 syntax.
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
31
tests/test_dummy.py
Executable file
31
tests/test_dummy.py
Executable file
|
@ -0,0 +1,31 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import ptpython.completer
|
||||||
|
import ptpython.eventloop
|
||||||
|
import ptpython.filters
|
||||||
|
import ptpython.history_browser
|
||||||
|
import ptpython.key_bindings
|
||||||
|
import ptpython.layout
|
||||||
|
import ptpython.python_input
|
||||||
|
import ptpython.repl
|
||||||
|
import ptpython.style
|
||||||
|
import ptpython.utils
|
||||||
|
import ptpython.validator
|
||||||
|
|
||||||
|
# For now there are no tests here.
|
||||||
|
# However this is sufficient to do at least a syntax check.
|
||||||
|
|
||||||
|
|
||||||
|
def test_dummy() -> None:
|
||||||
|
assert ptpython.completer
|
||||||
|
assert ptpython.eventloop
|
||||||
|
assert ptpython.filters
|
||||||
|
assert ptpython.history_browser
|
||||||
|
assert ptpython.key_bindings
|
||||||
|
assert ptpython.layout
|
||||||
|
assert ptpython.python_input
|
||||||
|
assert ptpython.repl
|
||||||
|
assert ptpython.style
|
||||||
|
assert ptpython.utils
|
||||||
|
assert ptpython.validator
|
Loading…
Add table
Add a link
Reference in a new issue