Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(type): add type hints to trame/app #542

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
7 changes: 3 additions & 4 deletions trame/app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from __future__ import annotations

import logging
from typing import Literal

from trame_client.widgets.core import VirtualNode
from trame_server import Client, Server
from trame_server.core import set_default_client_type
from trame_server.core import set_default_client_type, ClientType

# Ensure this is imported so that mimetypes.init() is decorated
import trame.app.mimetypes # noqa: F401
Expand All @@ -19,7 +18,7 @@
set_default_client_type("vue3")


def apply_client_type(server: Server, client_type: str | None = None) -> Server:
def apply_client_type(server: Server, client_type: ClientType | None = None) -> Server:
if client_type is not None:
server.client_type = client_type
return server
Expand All @@ -28,7 +27,7 @@ def apply_client_type(server: Server, client_type: str | None = None) -> Server:
def get_server(
name: str | Server | None = None,
create_if_missing: bool = True,
client_type: Literal["vue2", "vue3"] | None = None,
client_type: ClientType | None = None,
**kwargs,
) -> Server | None:
"""Return a server for serving trame applications.
Expand Down
15 changes: 11 additions & 4 deletions trame/app/dev.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
def clear_triggers(server):
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from types import ModuleType
from trame_server import Server


def clear_triggers(server: Server) -> None:
"""
Helper function to remove all triggers.

Expand All @@ -12,7 +19,7 @@ def clear_triggers(server):
print(f"unregister trigger {name}")


def clear_change_listeners(server):
def clear_change_listeners(server: Server) -> None:
"""
Helper function to remove all state.change listeners.

Expand All @@ -22,7 +29,7 @@ def clear_change_listeners(server):
server.state._change_callbacks.clear()


def remove_change_listeners(server, *names):
def remove_change_listeners(server: Server, *names: str) -> None:
"""
Helper function to remove any listeners for a given set
of state variable names.
Expand All @@ -38,7 +45,7 @@ def remove_change_listeners(server, *names):
server.state._change_callbacks.pop(name)


def reload(*reload_list):
def reload(*reload_list: ModuleType) -> None:
"""
Helper function use to reload python modules that were passed as
arguments.
Expand Down
19 changes: 11 additions & 8 deletions trame/app/file_upload.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from __future__ import annotations


class ClientFile:
"""
Helper class that make it easier to handle file from the trame state

This class behave like a decorator to the state variable so you can easily access its various properties and content.
"""

def __init__(self, file_state_variable=None):
def __init__(self: ClientFile, file_state_variable: dict | None = None) -> None:
"""Pass the state variable you want to decorate as arg"""
self._name = None
self._size = None
Expand All @@ -22,36 +25,36 @@ def __init__(self, file_state_variable=None):
self._content = b"".join(self._content)

@property
def is_empty(self):
def is_empty(self: ClientFile) -> bool:
"""Return true if the file is empty"""
return self._content is None

@property
def name(self):
def name(self: ClientFile) -> str | None:
"""File name"""
return self._name

@property
def size(self):
def size(self: ClientFile) -> int | None:
"""File size in Bytes"""
return self._size

@property
def modified_time(self):
def modified_time(self: ClientFile) -> int | None:
"""Modified time"""
return self._time

@property
def mime_type(self):
def mime_type(self: ClientFile) -> str | None:
"""Mime type of the file"""
return self._mime_type

@property
def content(self):
def content(self: ClientFile) -> bytes | None:
"""Bytes content of the file"""
return self._content

@property
def info(self):
def info(self: ClientFile) -> str:
"""Return a string summarizing the file information"""
return f"File: {self.name} of size {self.size} and type {self.mime_type}"
13 changes: 10 additions & 3 deletions trame/app/jupyter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
from __future__ import annotations

from typing import TYPE_CHECKING

import asyncio
from IPython import display

if TYPE_CHECKING:
from trame_server import Server

from . import get_server

__all__ = [
Expand All @@ -10,7 +17,7 @@
]


def show(_server, ui=None, **kwargs):
def show(_server: Server, ui: str | None = None, **kwargs) -> None:
"""
Helper function to show a server ui element into the cell.

Expand Down Expand Up @@ -48,7 +55,7 @@ def on_ready(**_):
on_ready()


def display_iframe(src, **kwargs):
def display_iframe(src: str, **kwargs) -> display.DisplayHandle:
"""
Convenience method to display an iframe for the given url source

Expand All @@ -69,7 +76,7 @@ def display_iframe(src, **kwargs):
return display.display(iframe)


def run(name, **kwargs):
def run(name: str, **kwargs) -> display.DisplayHandle:
"""Run and display a Jupyter server proxy process with the given name

Note that the proxy process must be registered with Jupyter by setting
Expand Down
13 changes: 10 additions & 3 deletions trame/app/mimetypes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
from __future__ import annotations

import mimetypes

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from os import PathLike


MIMETYPE_OVERRIDES = {
# On Windows, mimetypes pulls this from the registry, which is
Expand All @@ -8,7 +15,7 @@
}


def decorate_mimetypes_init():
def decorate_mimetypes_init() -> None:
"""
Decorate the mimetypes.init() method with our function that
afterwards adds any mimetype overrides that were saved.
Expand All @@ -24,7 +31,7 @@ def new_init(*args, **kwargs):
mimetypes.init = new_init


def add_mimetype_override(type, ext):
def add_mimetype_override(type: str, ext: str) -> None:
"""
Add a mimetype both now and when mimetypes.init() is called.

Expand All @@ -40,7 +47,7 @@ def add_mimetype_override(type, ext):
mimetypes.add_type(type, ext)


def to_mime(file_path):
def to_mime(file_path: str | PathLike[str]) -> str | None:
"""
Return the mime type from a given path

Expand Down
21 changes: 14 additions & 7 deletions trame/app/testing.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
from __future__ import annotations

import os
import json

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from trame_server import Server


class TrameServerMonitor:
"""Helper class capture sever state from log"""

def __init__(self, log_path):
def __init__(self: TrameServerMonitor, log_path: str | os.PathLike) -> None:
self._log_path = log_path
self._last_state = {}
self.port = 0
self.update()

def update(self):
def update(self: TrameServerMonitor) -> None:
last_state_line = "STATE: {}"
with open(self._log_path, "r") as f:
for line in f.readlines():
for line in f:
print(line)
if "SERVER_PORT:" in line:
self.port = int(line[13:])
Expand All @@ -23,16 +30,16 @@ def update(self):

self._last_state = json.loads(last_state_line[7:])

def get_state(self):
def get_state(self: TrameServerMonitor) -> dict:
self.update()
return self._last_state

def get(self, name):
def get(self: TrameServerMonitor, name: str):
self.update()
return self._last_state.get(name)


def remove_page_urls(base_path):
def remove_page_urls(base_path: str | os.PathLike) -> None:
"""Selenium capture page_url.txt which will change through
tests and therefore we need to remove them."""
for root, dirs, files in os.walk(base_path):
Expand All @@ -47,7 +54,7 @@ def print_state(**kwargs):
print("STATE:", json.dumps(kwargs), flush=True)


def enable_testing(server, *state_monitor):
def enable_testing(server: Server, *state_monitor):
"""Register state monitoring for TrameServerMonitor and port extractor"""
server.state.change(*state_monitor)(print_state)

Expand Down
Loading