Skip to content
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
42 changes: 9 additions & 33 deletions .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,46 +19,22 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
# Python 3.9 is on macos-13 but not macos-latest (macos-14-arm64)
# https://github.com/actions/setup-python/issues/696#issuecomment-1637587760
exclude:
- { python-version: "3.8", os: "macos-latest" }
- { python-version: "3.9", os: "macos-latest" }
- { python-version: "3.11", os: "macos-latest" }
include:
- { python-version: "3.8", os: "macos-13" }
- { python-version: "3.9", os: "macos-13" }
- { python-version: "3.11", os: "macos-13" }
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v3.5.2
- name: Install and configure Poetry # This could be cached, too...
uses: snok/install-poetry@v1.3.3
with:
version: 1.4.2
virtualenvs-in-project: true
- uses: actions/checkout@v4.1.1
- name: Install Poetry
run: pipx install poetry==1.7.1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5.2.0
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v3
with:
path: .venv
key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('**/poetry.lock') }}
cache: "poetry"
- name: Install dependencies
run: poetry install
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction
- name: Run mypy
run: |
source $VENV
mypy .
run: poetry run mypy .
- name: Test with pytest
run: |
source $VENV
pytest tests -v
run: poetry run pytest tests -v
2 changes: 0 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,3 @@ repos:
rev: 24.1.1
hooks:
- id: black
language_version: python3.8

1,768 changes: 929 additions & 839 deletions poetry.lock

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ classifiers = [
"Operating System :: Microsoft :: Windows :: Windows 11",
"Operating System :: MacOS",
"Operating System :: POSIX :: Linux",
"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.14",
"Typing :: Typed",
]
include = ["src/textual_dev/py.typed", { path = "tests", format = "sdist" }]

[tool.poetry.dependencies]
python = "^3.8.1"
python = "^3.9"
textual = ">=0.86.2"
textual_serve = ">=1.0.3"
aiohttp = ">=3.8.1"
Expand Down
4 changes: 1 addition & 3 deletions src/textual_dev/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from textual.constants import DEVTOOLS_PORT

READY_TIMEOUT = 0.5
WEBSOCKET_CONNECT_TIMEOUT = 3
LOG_QUEUE_MAXSIZE = 512


Expand Down Expand Up @@ -116,8 +115,7 @@ async def connect(self) -> None:
self.log_queue = Queue(maxsize=LOG_QUEUE_MAXSIZE)
try:
self.websocket = await self.session.ws_connect(
f"{self.url}/textual-devtools-websocket",
timeout=WEBSOCKET_CONNECT_TIMEOUT,
f"{self.url}/textual-devtools-websocket"
)
except (ClientConnectorError, ClientResponseError):
raise DevtoolsConnectionError()
Expand Down
7 changes: 6 additions & 1 deletion src/textual_dev/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,17 @@ def _run_devtools(
def noop_print(_: str) -> None:
pass

try:
loop = asyncio.get_event_loop()
except RuntimeError:
loop = asyncio.new_event_loop()

try:
run_app(
app,
port=DEVTOOLS_PORT if port is None else port,
print=noop_print,
loop=asyncio.get_event_loop(),
loop=loop,
)
except OSError:
from rich import print
Expand Down
5 changes: 4 additions & 1 deletion tests/devtools/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing import AsyncGenerator
import pytest

from textual_dev.client import DevtoolsClient
Expand All @@ -6,7 +7,9 @@


@pytest.fixture
async def server(aiohttp_server, unused_tcp_port):
async def server(
aiohttp_server, unused_tcp_port
) -> AsyncGenerator[DevtoolsService, None]:
app = _make_devtools_aiohttp_app(
size_change_poll_delay_secs=0.001,
)
Expand Down
11 changes: 10 additions & 1 deletion tests/devtools/test_devtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
from rich.align import Align
from rich.console import Console
from rich.segment import Segment
from rich.table import Table
from rich.text import Text
from rich.rule import Rule

from textual_dev.renderables import DevConsoleLog, DevConsoleNotice

Expand All @@ -32,7 +35,7 @@ def console():


@time_machine.travel(TIMESTAMP)
def test_log_message_render(console):
def test_log_message_render(console) -> None:
message = DevConsoleLog(
[Segment("content")],
path="abc/hello.py",
Expand All @@ -43,19 +46,24 @@ def test_log_message_render(console):
severity=0,
)
table = next(iter(message.__rich_console__(console, console.options)))
assert isinstance(table, Table)

assert len(table.rows) == 1

columns = list(table.columns)
left_cells = list(columns[0].cells)
left = left_cells[0]
right_cells = list(columns[1].cells)
assert isinstance(right_cells[0], Align)
right: Align = right_cells[0]

# Since we can't guarantee the timezone the tests will run in...
local_time = datetime.fromtimestamp(TIMESTAMP)
string_timestamp = local_time.time()

assert isinstance(left, Text)
assert isinstance(right.renderable, Text)

assert left.plain == f"[{string_timestamp}] UNDEFINED"
assert right.align == "right"
assert "hello.py:123" in right.renderable
Expand All @@ -64,6 +72,7 @@ def test_log_message_render(console):
def test_internal_message_render(console):
message = DevConsoleNotice("hello")
rule = next(iter(message.__rich_console__(console, console.options)))
assert isinstance(rule, Rule)
assert rule.title == "hello"
assert rule.characters == "─"

Expand Down
2 changes: 1 addition & 1 deletion tests/devtools/test_devtools_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ async def test_devtools_log_spillover(devtools):
}


async def test_devtools_client_update_console_dimensions(devtools, server):
async def test_devtools_client_update_console_dimensions(devtools, server) -> None:
"""Sending new server info through websocket from server to client should (eventually)
result in the dimensions of the devtools client console being updated to match.
"""
Expand Down