Open Source Stenography Software providing real-time stenographic typing, machine support, and plugin architecture.
npx @tessl/cli install tessl/pypi-plover@4.0.0Plover is a cross-platform stenography application that enables high-speed typing through machine shorthand. It provides real-time stenographic translation, supports multiple stenotype machines, offers customizable dictionaries, and includes a comprehensive plugin architecture for extensibility.
pip install plover# Core engine and configuration
from plover.engine import StenoEngine
from plover.config import Config
# Registry system for plugins
from plover.registry import registry
# Stenographic data models
from plover.steno import Stroke
from plover.translation import Translation, Translator
from plover.formatting import Formatter
# Dictionary system
from plover.steno_dictionary import StenoDictionary, StenoDictionaryCollection
# Exception classes
from plover.exception import InvalidConfigurationError, DictionaryLoaderExceptionimport plover
from plover.engine import StenoEngine
from plover.config import Config
from plover.oslayer.config import CONFIG_FILE
# Initialize configuration
config = Config(CONFIG_FILE)
# Create and start stenography engine
# Parameters: config, controller=None, keyboard_emulation=None
from plover.oslayer.keyboardcontrol import KeyboardEmulation
engine = StenoEngine(config, controller=None, keyboard_emulation=KeyboardEmulation())
engine.start()
# Connect to engine events
def on_stroke_received(stroke):
print(f"Stroke received: {stroke}")
engine.hook_connect('stroked', on_stroke_received)
# Control output
engine.set_output(True) # Enable stenographic output
engine.toggle_output() # Toggle output state
# Access dictionaries
dictionaries = engine.dictionaries
translation = dictionaries.lookup(('STENO',)) # Tuple of stroke strings
# Add custom translation
engine.add_translation(('KUFT/TOM',), 'custom') # Tuple of stroke strings to translation
# Shutdown
engine.quit()Plover is built around several key components:
Core stenographic processing engine providing machine control, dictionary management, translation processing, and output generation with comprehensive event hooks.
class StenoEngine:
def __init__(self, config, controller=None, keyboard_emulation=None): ...
def start(self) -> None: ...
def quit(self, code: int = 0) -> None: ...
def restart(self) -> None: ...
def toggle_output(self) -> None: ...
def set_output(self, enabled: bool) -> None: ...
@property
def output(self) -> bool: ...
@property
def config(self) -> dict: ...
def hook_connect(self, hook: str, callback) -> None: ...
def hook_disconnect(self, hook: str, callback) -> None: ...Centralized plugin management system supporting dynamic registration and discovery of extensions, machines, dictionaries, GUI components, and other plugin types.
class Registry:
PLUGIN_TYPES = (
'command', 'dictionary', 'extension', 'gui',
'gui.qt.machine_option', 'gui.qt.tool', 'machine',
'macro', 'meta', 'system'
)
def register_plugin(self, plugin_type: str, name: str, obj) -> None: ...
def get_plugin(self, plugin_type: str, plugin_name: str) -> Plugin: ...
def list_plugins(self, plugin_type: str) -> list: ...
def update(self) -> None: ...
registry: RegistryComprehensive configuration management with file persistence, validation, and runtime updates supporting all aspects of stenographic operation.
class Config:
def __init__(self, path: str = None): ...
def load(self) -> None: ...
def save(self) -> None: ...
def __getitem__(self, key: str): ...
def __setitem__(self, key: str, value): ...
def update(self, **kwargs) -> None: ...
class DictionaryConfig:
def __new__(cls, path: str, enabled: bool = True): ...
@property
def short_path(self) -> str: ...Powerful dictionary management system supporting multiple formats, hierarchical precedence, filtering, and real-time updates with comprehensive lookup capabilities.
class StenoDictionary:
readonly: bool
@classmethod
def create(cls, resource: str) -> 'StenoDictionary': ...
@classmethod
def load(cls, resource: str) -> 'StenoDictionary': ...
def save(self) -> None: ...
def lookup(self, strokes: tuple) -> str: ...
def reverse_lookup(self, translation: str) -> list: ...
class StenoDictionaryCollection:
def lookup(self, strokes: tuple) -> str: ...
def set(self, strokes: tuple, translation: str, path: str = None) -> None: ...
def add_filter(self, filter_func) -> None: ...Abstracted machine interface supporting various stenotype hardware with unified API for stroke capture, state management, and device-specific configuration.
class StenotypeBase:
KEYS_LAYOUT: str
ACTIONS: tuple
def start_capture(self) -> None: ...
def stop_capture(self) -> None: ...
def add_stroke_callback(self, callback) -> None: ...
def add_state_callback(self, callback) -> None: ...
def set_keymap(self, keymap: dict) -> None: ...
@classmethod
def get_option_info(cls) -> dict: ...Core data structures for representing stenographic strokes, translations, and formatting with support for normalization, validation, and conversion between formats.
class Stroke:
@classmethod
def from_steno(cls, steno: str) -> 'Stroke': ...
@classmethod
def from_keys(cls, keys: set) -> 'Stroke': ...
@property
def steno_keys(self) -> tuple: ...
@property
def rtfcre(self) -> str: ...
@property
def is_correction(self) -> bool: ...
def normalize_stroke(steno: str, strict: bool = True) -> str: ...
def normalize_steno(steno: str, strict: bool = True) -> str: ...Comprehensive extension system enabling custom functionality through hooks, plugins, and direct engine API access with support for background processing and GUI integration.
class Extension:
def __init__(self, engine: StenoEngine): ...
def start(self) -> None: ...
def stop(self) -> None: ...from typing import Dict, List, Tuple, Optional, Callable, Union
from collections import namedtuple
# Core data types
StartingStrokeState = namedtuple('StartingStrokeState',
'attach capitalize space_char', defaults=(False, False, ' '))
MachineParams = namedtuple('MachineParams', 'type options keymap')
Suggestion = namedtuple('Suggestion', 'text steno_list')
# Machine states
STATE_STOPPED: str
STATE_INITIALIZING: str
STATE_RUNNING: str
STATE_ERROR: str
# Hook types
HookCallback = Callable[..., None]
StrokeCallback = Callable[[List[str]], None]
StateCallback = Callable[[str], None]
# Configuration types
ConfigValue = Union[str, int, bool, List, Dict]
DictionaryPath = str
# Exception classes
class InvalidConfigurationError(Exception):
"""Raised when configuration contains errors or invalid values."""
pass
class DictionaryLoaderException(Exception):
"""Raised when dictionary file cannot be loaded or parsed."""
path: str # Path to failed dictionary file
exception: Exception # Underlying exception that caused failure
def __init__(self, path: str, exception: Exception): ...