Data Layer¶
Data structures and configuration models.
Configuration Models¶
Configuration models for Svalboard Keymap Image Maker tool.
This module defines the Pydantic configuration models used to customize
the appearance and behavior of generated keymap images. The configuration
is hierarchical, with the root SkimConfig containing nested models
for keyboard settings, keycode mappings, and output styling.
Configuration can be loaded from YAML files or constructed programmatically. All models use Pydantic’s BaseModel for validation and serialization.
Example
Loading configuration from a YAML file:
import yaml
from skim.data.config import SkimConfig
with open("skim-config.yaml") as f:
data = yaml.safe_load(f)
config = SkimConfig(**data)
Creating configuration programmatically:
from skim.data.config import SkimConfig, LayerColor, Palette
config = SkimConfig()
new_layers = config.output.style.palette.layers + (LayerColor(base_color="#FF0000"),)
new_palette = config.output.style.palette.model_copy(update={"layers": new_layers})
new_style = config.output.style.model_copy(update={"palette": new_palette})
new_output = config.output.model_copy(update={"style": new_style})
config = config.model_copy(update={"output": new_output})
- skim.data.config.SplitSidePositionStr¶
Annotated type alias for SplitSidePosition that accepts string values and converts them to enum members.
- class skim.data.config.KeyboardLayer(**data)[source]¶
Bases:
BaseModelConfiguration for a single keyboard layer.
Defines the metadata associated with a layer in the keymap, including its internal name. This is used to customize how layers are named in generated images.
- id¶
Optional unique identifier for the layer. Used for internal reference when processing a keymap from c2json that uses C define-macros instead of layer numbers in with the layer switch functions. It may be None if not specified.
- name¶
Full descriptive name of the layer (e.g., “Base Layer”, “Symbols”, “Navigation”). Used as the “image title” on the generated images.
- variant¶
Optional secondary label shown below the layer name (e.g., “COLEMAK”). Used to display additional layer metadata in the overview image. Defaults to None if not specified.
Example
>>> layer = KeyboardLayer(name="Base Layer") >>> layer.name 'Base Layer' >>> layer.variant is None True
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class skim.data.config.KeyboardFeatures(**data)[source]¶
Bases:
BaseModelConfiguration for optional keyboard hardware features.
Controls which optional hardware features are enabled when generating keymap images. These settings affect which keys are rendered.
- Parameters:
double_south (bool)
- double_south¶
Whether to render the MH (double-south) keys on finger clusters. When False, these positions are hidden. Defaults to False as not all Svalboard configurations have these keys.
Example
>>> features = KeyboardFeatures(double_south=True) >>> features.double_south True
Note
Currently the Svalboard keyboard only have a single feature modifier that can impact a keymap image, but this configuration object is here to future-proof this tool on eventual changes.
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class skim.data.config.Keyboard(**data)[source]¶
Bases:
BaseModelKeyboard-specific configuration settings.
Contains settings that describe the physical keyboard configuration and layer definitions. This is used to customize the rendering based on the specific keyboard setup.
- Parameters:
features (KeyboardFeatures)
layers (Annotated[tuple[KeyboardLayer, ...], BeforeValidator(func=~skim.data.config._coerce_to_tuple, json_schema_input_type=PydanticUndefined)])
- features¶
Hardware feature flags controlling the keymap rendering. Defaults to a KeyboardFeatures instance with all features disabled.
- layers¶
Tuple of layer configurations defining the metadata for each layer in the keymap. The order corresponds to layer indices (0, 1, 2, etc.).
Example
>>> keyboard = Keyboard( ... features=KeyboardFeatures(double_south=True), ... layers=( ... KeyboardLayer(name="Base"), ... KeyboardLayer(name="Symbols"), ... ), ... ) >>> len(keyboard.layers) 2
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
-
features:
KeyboardFeatures¶
-
layers:
Annotated[tuple[KeyboardLayer,...]]¶
- model_post_init(context)[source]¶
Initialize the layer ID lookup map after model construction.
Builds an internal mapping from layer identifiers to their QMK firmware indices for efficient layer lookup. If a layer has an explicit
id, that ID is used as the key. Otherwise, the string representation of the layer’s position index is used.This method is called automatically by Pydantic after the model is constructed.
- Parameters:
context (
object) – Pydantic validation context (unused but required by the Pydantic post-init signature).- Return type:
Example
>>> keyboard = Keyboard( ... layers=[ ... KeyboardLayer(index=0, id="base", name="Base"), ... KeyboardLayer(index=15, name="Symbols"), ... ] ... ) >>> keyboard.layer_index("base") 0 >>> keyboard.layer_index("1") # Second layer has no id, uses QMK index 15
- layer_index(key)[source]¶
Look up a layer’s QMK firmware index by its identifier.
Returns the QMK firmware index of the layer matching the given key. The key can be either a layer’s explicit
id, the string representation of its position index (for layers without an id), or an integer index which is converted to string for lookup.- Parameters:
key (
str|None) – The layer identifier to look up. This can be a layer’sidattribute, a string index like"0","1", or an integer index like0,1. IfNone, returnsNone.- Return type:
- Returns:
The QMK firmware index of the matching layer, or
Noneif no layer matches the given key or if key isNone.
Example
>>> keyboard = Keyboard( ... layers=[ ... KeyboardLayer(index=0, id="nav", name="Navigation"), ... KeyboardLayer(index=15, name="Symbols"), ... ] ... ) >>> keyboard.layer_index("nav") 0 >>> keyboard.layer_index("1") 15 >>> keyboard.layer_index("unknown") is None True
- qmk_index_to_position(qmk_idx)[source]¶
Look up a layer’s position by its QMK firmware index.
Returns the zero-based position of the layer in the layers tuple that has the given QMK firmware index. This is useful when layer indices in the firmware are non-sequential (e.g., 0, 1, 2, 15).
- Parameters:
qmk_idx (
int) – The QMK firmware layer index to look up.- Return type:
- Returns:
The position of the matching layer in the layers tuple, or
Noneif no layer has the given QMK index.
Example
>>> keyboard = Keyboard( ... layers=[ ... KeyboardLayer(index=0, name="Base"), ... KeyboardLayer(index=15, name="Mouse"), ... ] ... ) >>> keyboard.qmk_index_to_position(15) 1 >>> keyboard.qmk_index_to_position(5) is None True
- layer_qmk_index(position)[source]¶
Get the QMK firmware index for a layer at a given position.
Returns the QMK firmware layer index for the layer at the given position in the layers tuple.
- Parameters:
position (
int) – The zero-based position of the layer in the layers tuple.- Return type:
- Returns:
The QMK firmware layer index.
Example
>>> keyboard = Keyboard( ... layers=[ ... KeyboardLayer(index=0, name="Base"), ... KeyboardLayer(index=15, name="Mouse"), ... ] ... ) >>> keyboard.layer_qmk_index(1) 15
- class skim.data.config.Keycode(**data)[source]¶
Bases:
BaseModelA keycode-to-label mapping override.
Defines a custom mapping from a QMK keycode string to a display label. This is used to customize how specific keycodes are rendered, either by preprocessing them before the standard mapping or by overriding the default label entirely.
- keycode¶
The QMK keycode string to match (e.g., “KC_A”, “KC_ESC”). Must match exactly, including case.
- target¶
The replacement label or transformed keycode. For pre-processing, this is typically another keycode. For overrides, this is the display label.
Example
>>> # Override KC_SPC to display as "Space" >>> override = Keycode(keycode="KC_SPC", target="Space") >>> override.keycode 'KC_SPC'
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class skim.data.config.Keycodes(**data)[source]¶
Bases:
BaseModelConfiguration for keycode transformation and display.
Contains tuples of keycode mappings that customize how QMK keycodes are transformed and displayed. The pre-processing transformation happens without any processing by the tool. This mapping should not use the alias and other replacements features from key resolution. Then, the standard label mapping happens with the overrides defined in this configuration having higher priority than the default transformations.
- Parameters:
- pre_process¶
Keycode transformations applied before standard mapping. Useful for normalizing keycodes or representing custom keycodes that act like othes QMK keycodes including functions. Defaults to an empty tuple.
- overrides¶
Keycode-to-label mappings that override the standard mapping results. Applied after all other transformations. Defaults to an empty tuple.
Example
>>> keycodes = Keycodes( ... pre_process=(Keycode(keycode="LCTL_T(KC_A)", target="MT(MOD_LCTL,KC_A)"),), ... overrides=(Keycode(keycode="KC_SPC", target="Space"),), ... ) >>> len(keycodes.overrides) 1
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class skim.data.config.Spacing(**data)[source]¶
Bases:
BaseModelSpacing configuration for layout margins and inset (padding and in-between elements spacing).
Controls the whitespace around and within the generated keymap images. Spacing is specified in SVG units (typically pixels at default scale).
- margin¶
Outer margin around the entire keyboard layout. Space between the keyboard and the image edge. Defaults to 0.
- inset¶
Inner padding within the keyboard border. Space between the border and the key clusters. Defaults to 20.
Example
>>> spacing = Spacing(margin=10, inset=25) >>> spacing.margin 10
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class skim.data.config.Layout(**data)[source]¶
Bases:
BaseModelLayout dimensions and spacing configuration.
Controls the overall dimensions and spacing of generated keymap images. The height is calculated automatically based on the width to maintain the correct aspect ratio for the Svalboard layout.
- width¶
Total width of the generated image in SVG units (typically pixels at default scale). Defaults to 1600.
- spacing¶
Spacing configuration for margins and padding. Defaults to a Spacing instance with default values.
Example
>>> layout = Layout(width=1200, spacing=Spacing(margin=20)) >>> layout.width 1200
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class skim.data.config.Border(**data)[source]¶
Bases:
BaseModelBorder styling configuration.
Controls the appearance of borders drawn around the keyboard layout and optionally around individual key groups.
- width¶
Line width of the border in SVG units. Defaults to 2.
- radius¶
Corner radius for rounded borders in SVG units. Set to 0 for square corners. Defaults to 10.
Example
>>> border = Border(width=3, radius=15) >>> border.radius 15.0
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class skim.data.config.LayerColor(**data)[source]¶
Bases:
BaseModelColor configuration for a keyboard layer.
Defines the color scheme used for keys on a specific layer. Supports both single-color and gradient modes. In gradient mode, different keys within a cluster can have different shades for visual depth.
The gradient tuple contains 6 colors corresponding to the 6 positions in a cluster (e.g., center, north, east, south, west, double-south for finger clusters).
- Parameters:
- base_color¶
The primary color for this layer as a CSS color string (e.g., “#FF0000”, “red”, “rgb(255,0,0)”). Used when gradient is None or as a fallback.
- color_index¶
Index into the gradient for the primary key color. Only used when gradient is set. Defaults to 2.
- gradient¶
Optional tuple of 6 CSS color strings for position-based coloring within clusters. When None, the tool will generate the gradient tuple based on the base_color and the index position it should be in.
Example
>>> # Single color mode >>> layer = LayerColor(base_color="#FF0000") >>> layer[0] '#FF0000'
>>> # Gradient mode >>> layer = LayerColor( ... base_color="#FF0000", ... gradient=("#FF0000", "#CC0000", "#990000", "#660000", "#330000", "#000000"), ... ) >>> layer[1] '#CC0000'
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- __getitem__(index)[source]¶
Get the color for a specific cluster position.
- Parameters:
index (
int) – Position index from 0-5 corresponding to cluster key positions.- Return type:
- Returns:
The CSS color string for the specified position. Returns base_color if gradient is not set.
- Raises:
IndexError – If index is outside the valid range (0-5).
Example
>>> layer = LayerColor(base_color="#FFF") >>> layer[0] '#FFF'
- __str__()[source]¶
Return a string representation of the color configuration.
- Return type:
- Returns:
A JSON-like array string of the colors. For single-color mode, returns a single-element array. For gradient mode, returns all 6 colors.
Example
>>> str(LayerColor(base_color="#FFF")) '["#FFF"]'
- property dark_accent_color: str¶
Get the darker accent color for this layer.
Returns the second color in the gradient (index 1) if a gradient is defined, otherwise returns the base_color. This is typically used for key borders, shadows, or accent elements.
- Returns:
A CSS color string for the accent color.
Example
>>> layer = LayerColor( ... base_color="#FF0000", ... gradient=("#FF0000", "#AA0000", "#880000", "#660000", "#440000", "#220000"), ... ) >>> layer.dark_accent_color '#AA0000'
- class skim.data.config.Palette(**data)[source]¶
Bases:
BaseModelColor palette configuration for the entire keyboard.
Defines the color scheme used throughout the generated keymap images, including background colors, text colors, and per-layer key colors.
- Parameters:
- overrides¶
Dictionary mapping color names to colors values. Used to change the color defined by W3C on the 147 supported named colors on SVG files. Defaults to an empty dictionary so the standard definitions should be used.
- neutral_color¶
Color for keys that don’t have layer-specific coloring (e.g., some thumb cluster keys). Defaults to “#6F768B” (gray).
- text_color¶
Default text color for non key labels. Defaults to “black”.
- key_label_color¶
Text color for key labels. Defaults to “white” for contrast against typically dark key backgrounds.
- background_color¶
Background color for the entire image. Defaults to “white”.
- border_color¶
Color for keyboard and cluster borders. Defaults to “black”.
- layers¶
Tuple of LayerColor configurations, one per layer. Layer indices correspond to positions in this tuple. Defaults to an empty tuple.
Example
>>> palette = Palette( ... background_color="#F0F0F0", ... layers=( ... LayerColor(base_color="#3366CC"), ... LayerColor(base_color="#CC6633"), ... ), ... ) >>> palette.background_color '#F0F0F0'
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
-
layers:
Annotated[tuple[LayerColor,...]]¶
- class skim.data.config.SplitSidePosition(value)[source]¶
-
Position options for hold-tap key symbol placement.
Controls where the “hold” portion of a hold-tap key is displayed relative to the “tap” portion. This affects keys like LT(1, KC_A) where tapping produces “A” but holding activates layer 1.
- QMK_DEFINED¶
Use the position defined in QMK firmware settings. This respects the argument order of the macro-functions defined by QMK, which is always the hold part as the first argument, and the tap part as the second.
- INWARD¶
Place the hold symbol toward the center of the keyboard cluster (right on left side, left on right side).
- OUTWARD¶
Place the hold symbol toward the outside of the keyboard cluster (left on left side, right on right side). This is the default.
- QMK_DEFINED = 'qmk'¶
- INWARD = 'inward'¶
- OUTWARD = 'outward'¶
- __format__(format_spec)¶
Returns format using actual value type unless __str__ has been overridden.
- skim.data.config.SplitSidePositionStr¶
Annotated type for SplitSidePosition that accepts string inputs.
This type alias allows configuration files to specify hold symbol positions as plain strings (e.g., “inward”, “outward”) which are automatically converted to SplitSidePosition enum members during validation.
Example
In a YAML configuration file:
style: hold_symbol_position: outward
When parsed, “outward” is converted to SplitSidePosition.OUTWARD.
alias of
Annotated[SplitSidePosition,BeforeValidator(func=~skim.data.config., json_schema_input_type=PydanticUndefined)]
- class skim.data.config.Style(**data)[source]¶
Bases:
BaseModelVisual styling configuration for keymap images.
Controls the overall visual appearance of generated images, including colors, borders, and key labeling options.
- Parameters:
use_layer_colors_on_keys (bool)
hold_symbol_position (Annotated[SplitSidePosition, BeforeValidator(func=~skim.data.config.<lambda>, json_schema_input_type=PydanticUndefined)])
border (Border | None)
palette (Palette)
use_system_fonts (bool)
show_layer_indicators (bool)
show_layer_connectors (bool)
show_transparent_fallthrough (bool)
- use_layer_colors_on_keys¶
Whether to color keys backgrounds based on the layer it activates. When True, keys use colors from the palette’s layer list. When False, all keys use their standard colors. Defaults to True.
- hold_symbol_position¶
Where to place the “hold” portion of hold-tap keys relative to the “tap” portion. See
SplitSidePositionfor options. Defaults to OUTWARD.
- border¶
Border styling configuration, or None to disable borders. Defaults to a Border instance with default values.
- palette¶
Color palette configuration for the entire keyboard. Defaults to a Palette instance with default values.
- show_transparent_fallthrough¶
When True (default), transparent keycodes (KC_TRNS / _______) on layers above 0 render the same label as layer 0 in a faded “ghost” color. Set False to leave transparent keys blank.
Example
>>> style = Style( ... use_layer_colors_on_keys=True, ... hold_symbol_position=SplitSidePosition.INWARD, ... ) >>> style.hold_symbol_position <SplitSidePosition.INWARD: 'inward'>
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
-
hold_symbol_position:
Annotated[SplitSidePosition]¶
- class skim.data.config.Output(**data)[source]¶
Bases:
BaseModelOutput configuration for generated images.
Groups together layout dimensions and visual styling settings that control the final appearance of generated keymap images.
- layout¶
Layout dimensions and spacing configuration. Defaults to a Layout instance with default values.
- style¶
Visual styling configuration. Defaults to a Style instance with default values.
- keymap_title¶
Optional title for the overview keymap image. When set, overrides the auto-generated title. Defaults to None.
- copyright¶
Optional copyright notice displayed in the overview image. Defaults to None.
Example
>>> output = Output( ... layout=Layout(width=1000), ... style=Style(use_layer_colors_on_keys=False), ... ) >>> output.layout.width 1000
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class skim.data.config.SkimConfig(**data)[source]¶
Bases:
BaseModelRoot configuration model for skim keymap image generation.
This is the top-level configuration class that contains all settings for generating Svalboard keymap images. It can be loaded from YAML files or constructed programmatically.
The configuration is organized into three main sections: - keyboard: Hardware and layer settings - keycodes: Keycode transformation and display rules - output: Layout dimensions and visual styling
- keyboard¶
Keyboard-specific configuration including hardware features and layer definitions. Defaults to a Keyboard instance with default values.
- keycodes¶
Keycode transformation rules including pre-processing and overrides. Defaults to a Keycodes instance with empty rule tuples.
- output¶
Output configuration including layout dimensions and visual styling. Defaults to an Output instance with default values.
Example
Creating a basic configuration:
config = SkimConfig() new_layout = config.output.layout.model_copy(update={"width": 1200}) new_output = config.output.model_copy(update={"layout": new_layout}) config = config.model_copy(update={"output": new_output})
Loading from a dictionary (e.g., parsed YAML):
data = { "keyboard": { "features": {"double_south": True}, "layers": [{"label": "1", "name": "Base"}], }, "output": {"layout": {"width": 1000}}, } config = SkimConfig(**data)
- model_config: ClassVar[ConfigDict] = {'frozen': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
Keyboard Structures¶
Keyboard cluster data structures for Svalboard key layouts.
This module provides generic container classes for representing key clusters on the Svalboard keyboard. The Svalboard has a unique 3D layout with two types of clusters:
Finger clusters: 5-directional keys (center, north, east, south, west) plus an optional double-south key. Each hand has 4 finger clusters (pinky, ring, middle, index).
Thumb clusters: 6 keys (down, pad, up, nail, knuckle, double-down). Each hand has 1 thumb cluster.
Both cluster types are generic containers that can hold any type of value, making them suitable for storing keycodes, labels, colors, or any other per-key data.
Example
Creating clusters with a default value and overrides:
from skim.data.keyboard import FingerCluster, ThumbCluster
# All keys set to empty string, except south_key
finger = FingerCluster("", south_key="A")
# Clusters are iterable and unpackable
center, north, east, south, west, dsouth = finger
Zipping multiple clusters together:
from skim.data.keyboard import FingerCluster, zip_clusters
keycodes = FingerCluster("KC_NO", center_key="KC_A")
labels = FingerCluster("", center_key="A")
# Create a cluster where each position contains both values
combined = zip_clusters(FingerCluster, "KeyData", codes=keycodes, labels=labels)
# combined.center_key.codes == "KC_A"
# combined.center_key.labels == "A"
- class skim.data.keyboard.ClusterT¶
TypeVar bound to cluster types for writing generic cluster functions.
This TypeVar is constrained to FingerCluster or ThumbCluster (or any subclass of _ClusterBase), enabling type-safe generic functions that work with any cluster type.
Example
Writing a generic function that works with any cluster:
from skim.data.keyboard import ClusterT, FingerCluster, ThumbCluster def count_non_empty(cluster: ClusterT) -> int: return sum(1 for value in cluster if value) finger = FingerCluster("", center_key="A") thumb = ThumbCluster("X") count_non_empty(finger) # Works with FingerCluster count_non_empty(thumb) # Works with ThumbCluster
alias of TypeVar(‘ClusterT’, bound=
_ClusterBase[Any])
- class skim.data.keyboard.FingerCluster(*, center_key: T, north_key: T, east_key: T, south_key: T, west_key: T, double_south_key: T)[source]¶
- class skim.data.keyboard.FingerCluster(default: T, *, center_key: T = ..., north_key: T = ..., east_key: T = ..., south_key: T = ..., west_key: T = ..., double_south_key: T = ...)
Bases:
_ClusterBase[T]A container for values associated with a Svalboard finger cluster.
Each finger on the Svalboard has a 5-directional key cluster arranged in a cross pattern, plus an optional double-south key for chording. The physical layout corresponds to pushing the finger in different directions:
center_key: The home/rest position (pressing straight down)
north_key: Pushing the finger forward (away from palm)
east_key: Pushing the finger toward the thumb
south_key: Pulling the finger backward (toward palm)
west_key: Pushing the finger away from the thumb
double_south_key: A secondary south key on certain Svalboard boards
This class is generic and can store any type of value at each position, making it suitable for keycodes, labels, styling information, or any other per-key data.
The class supports two initialization modes: 1. Explicit: All six fields must be provided as keyword arguments 2. Default with overrides: A default value fills all positions, with
optional keyword arguments to override specific positions
- Parameters:
default (T | _Unset)
kwargs (Any)
- center_key¶
Value for the center (home) position.
- north_key¶
Value for the north (forward) position.
- east_key¶
Value for the east (thumb-ward) position.
- south_key¶
Value for the south (backward) position.
- west_key¶
Value for the west (away from thumb) position.
- double_south_key¶
Value for the double-south position.
Example
Creating with all explicit values:
cluster = FingerCluster( center_key="A", north_key="B", east_key="C", south_key="D", west_key="E", double_south_key="F", )
Creating with a default and overrides:
cluster = FingerCluster("", south_key="Space") # center="", north="", east="", south="Space", west="", dsouth=""
Unpacking values:
center, north, east, south, west, dsouth = cluster
- __init__(default=<UNSET>, **kwargs)[source]¶
Initialize the finger cluster.
- Parameters:
default (
Union[TypeVar(T),_Unset]) – Optional default value for all positions. If provided, any position not explicitly set via kwargs will use this value. If not provided, all positions must be set via kwargs.**kwargs (
Any) – Key position values. Valid keys are: center_key, north_key, east_key, south_key, west_key, double_south_key.
- Raises:
TypeError – If default is not provided and any required key position is missing from kwargs.
- Return type:
None
- classmethod from_sequence(values)[source]¶
Create a FingerCluster from a sequence of 6 values.
See
_ClusterBase.from_sequence()for full documentation.- Return type:
FingerCluster[TypeVar(T)]- Parameters:
values (Sequence[T])
- map(fn)[source]¶
Create a new FingerCluster by applying a function to each value.
See
_ClusterBase.map()for full documentation.- Return type:
FingerCluster[TypeVar(U)]- Parameters:
fn (Callable[[T], U])
- class skim.data.keyboard.ThumbCluster(*, down_key: T, pad_key: T, up_key: T, nail_key: T, knuckle_key: T, double_down_key: T)[source]¶
- class skim.data.keyboard.ThumbCluster(default: T, *, down_key: T = ..., pad_key: T = ..., up_key: T = ..., nail_key: T = ..., knuckle_key: T = ..., double_down_key: T = ...)
Bases:
_ClusterBase[T]A container for values associated with a Svalboard thumb cluster.
Each thumb on the Svalboard has a cluster of keys operated by different parts of the thumb and in different directions. The physical layout corresponds to:
down_key: Pressing the thumb straight down
pad_key: Using the thumb pad (fleshy part)
up_key: Pressing upward with the thumb
nail_key: Using the thumbnail area
knuckle_key: Using the thumb knuckle
- double_down_key: A secondary down position activated by exercing
extra force to the down key
This class is generic and can store any type of value at each position, making it suitable for keycodes, labels, styling information, or any other per-key data.
The class supports two initialization modes: 1. Explicit: All six fields must be provided as keyword arguments 2. Default with overrides: A default value fills all positions, with
optional keyword arguments to override specific positions
- Parameters:
default (T | _Unset)
kwargs (Any)
- down_key¶
Value for the down (pressing) position.
- pad_key¶
Value for the thumb pad position.
- up_key¶
Value for the up position.
- nail_key¶
Value for the thumbnail position.
- knuckle_key¶
Value for the thumb knuckle position.
- double_down_key¶
Value for the double-down position.
Example
Creating with all explicit values:
cluster = ThumbCluster( down_key="Space", pad_key="Enter", up_key="Tab", nail_key="Esc", knuckle_key="Ctrl", double_down_key="", )
Creating with a default and overrides:
cluster = ThumbCluster("", down_key="Space") # down="Space", pad="", up="", nail="", knuckle="", ddown=""
Unpacking values:
down, pad, up, nail, knuckle, ddown = cluster
- __init__(default=<UNSET>, **kwargs)[source]¶
Initialize the thumb cluster.
- Parameters:
default (
Union[TypeVar(T),_Unset]) – Optional default value for all positions. If provided, any position not explicitly set via kwargs will use this value. If not provided, all positions must be set via kwargs.**kwargs (
Any) – Key position values. Valid keys are: down_key, pad_key, up_key, nail_key, knuckle_key, double_down_key.
- Raises:
TypeError – If default is not provided and any required key position is missing from kwargs.
- Return type:
None
- classmethod from_sequence(values)[source]¶
Create a ThumbCluster from a sequence of 6 values.
See
_ClusterBase.from_sequence()for full documentation.- Return type:
ThumbCluster[TypeVar(T)]- Parameters:
values (Sequence[T])
- map(fn)[source]¶
Create a new ThumbCluster by applying a function to each value.
See
_ClusterBase.map()for full documentation.- Return type:
ThumbCluster[TypeVar(U)]- Parameters:
fn (Callable[[T], U])
- class skim.data.keyboard.SplitSide(index, middle, ring, pinky, thumb)[source]¶
Bases:
Generic[T]A container representing one side (left or right) of a Svalboard keyboard.
Each side of the Svalboard consists of four finger clusters (index, middle, ring, pinky) and one thumb cluster. This class provides a generic container that can hold any type of per-key data for an entire side of the keyboard.
The class is generic over type T, which represents the type of value stored at each key position, allowing it to be used for keycodes, labels, colors, or any other per-key data.
- Parameters:
index (FingerCluster[T])
middle (FingerCluster[T])
ring (FingerCluster[T])
pinky (FingerCluster[T])
thumb (ThumbCluster[T])
- index¶
The index finger cluster (6 keys).
- middle¶
The middle finger cluster (6 keys).
- ring¶
The ring finger cluster (6 keys).
- pinky¶
The pinky finger cluster (6 keys).
- thumb¶
The thumb cluster (6 keys).
Example
Creating a side with string values:
from skim.data.keyboard import SplitSide, FingerCluster, ThumbCluster side = SplitSide( index=FingerCluster(""), middle=FingerCluster(""), ring=FingerCluster(""), pinky=FingerCluster(""), thumb=ThumbCluster(""), )
Accessing keys by linear index:
key = side[0] # First key of index finger (center) key = side[24] # First key of thumb (down)
Iterating over all clusters:
for cluster in side: print(cluster)
-
index:
FingerCluster[TypeVar(T)]¶
-
middle:
FingerCluster[TypeVar(T)]¶
-
ring:
FingerCluster[TypeVar(T)]¶
-
pinky:
FingerCluster[TypeVar(T)]¶
-
thumb:
ThumbCluster[TypeVar(T)]¶
- __iter__()[source]¶
Iterate over all clusters in the side.
Yields clusters in order: index, middle, ring, pinky, thumb.
- Yields:
Each cluster on this side of the keyboard, starting with finger clusters and ending with the thumb cluster.
- Return type:
Iterator[Union[FingerCluster[TypeVar(T)],ThumbCluster[TypeVar(T)]]]
- __getitem__(idx)[source]¶
Access a key value by linear index.
Provides flat indexing across all 30 keys on this side. Keys 0-23 are the finger clusters (6 keys each × 4 fingers), and keys 24-29 are the thumb cluster.
- Parameters:
idx (
int) – Linear index from 0-29. Indices 0-5 are index finger, 6-11 are middle finger, 12-17 are ring finger, 18-23 are pinky finger, and 24-29 are thumb.- Return type:
TypeVar(T)- Returns:
The value stored at the specified key position.
- Raises:
IndexError – If idx is outside the valid range (0-29).
Example
Accessing individual keys:
side[0] # Index finger center key side[6] # Middle finger center key side[24] # Thumb down key
- property fingers: tuple[FingerCluster[T], ...]¶
Return all finger clusters as a tuple.
- Returns:
(index, middle, ring, pinky).
- Return type:
A tuple of the four finger clusters in order
- __init__(index, middle, ring, pinky, thumb)¶
- Parameters:
index (FingerCluster[T])
middle (FingerCluster[T])
ring (FingerCluster[T])
pinky (FingerCluster[T])
thumb (ThumbCluster[T])
- Return type:
None
- class skim.data.keyboard.SvalboardLayout(left, right)[source]¶
Bases:
Generic[T]A container representing the complete Svalboard keyboard layout.
The Svalboard is a split ergonomic keyboard with a unique 3D key arrangement. This class provides a container for storing per-key data across the entire keyboard, with support for both hierarchical access (side → cluster → key) and flat linear indexing.
The keyboard has 60 total keys: - Left side: 24 finger keys (4 clusters × 6 keys) + 6 thumb keys = 30 keys - Right side: 24 finger keys (4 clusters × 6 keys) + 6 thumb keys = 30 keys
The class is generic over type T, which represents the type of value stored at each key position.
- left¶
The left side of the keyboard (30 keys).
- right¶
The right side of the keyboard (30 keys).
Example
Creating a layout with string values:
from skim.data.keyboard import ( SvalboardLayout, SplitSide, FingerCluster, ThumbCluster, ) def make_side(): return SplitSide( index=FingerCluster(""), middle=FingerCluster(""), ring=FingerCluster(""), pinky=FingerCluster(""), thumb=ThumbCluster(""), ) layout = SvalboardLayout(left=make_side(), right=make_side())
Accessing keys by linear index:
key = layout[0] # Right index finger center key = layout[24] # Left index finger center key = layout[48] # Right thumb down key = layout[54] # Left thumb down
Iterating over all keys:
for key in layout: print(key) # Prints all 60 keys
- __iter__()[source]¶
Iterate over all key values in the layout.
Yields keys in the standard Svalboard order: 1. Right hand finger clusters (index → pinky, 24 keys) 2. Left hand finger clusters (index → pinky, 24 keys) 3. Right thumb cluster (6 keys) 4. Left thumb cluster (6 keys)
This order matches the typical QMK keymap array layout for the Svalboard.
- __getitem__(idx)[source]¶
Access a key value by linear index.
Provides flat indexing across all 60 keys in the layout using the standard Svalboard key ordering: - 0-23: Right hand finger keys - 24-47: Left hand finger keys - 48-53: Right thumb keys - 54-59: Left thumb keys
- Parameters:
idx (
int) – Linear index from 0-59.- Return type:
TypeVar(T)- Returns:
The value stored at the specified key position.
- Raises:
IndexError – If idx is outside the valid range (0-59).
Example
Accessing individual keys:
layout[0] # Right index finger center layout[24] # Left index finger center layout[48] # Right thumb down layout[54] # Left thumb down
- classmethod from_sequence(values)[source]¶
Create a SvalboardLayout from a flat sequence of 60 values.
Constructs a complete keyboard layout from a linear sequence of values, mapping each index to its corresponding key position using the standard Svalboard ordering (same as
__getitem__and__iter__).The mapping is: - 0-23: Right hand finger keys (index, middle, ring, pinky clusters) - 24-47: Left hand finger keys (index, middle, ring, pinky clusters) - 48-53: Right thumb keys - 54-59: Left thumb keys
Within each finger cluster, the 6 keys are ordered: center, north, east, south, west, double_south.
Within each thumb cluster, the 6 keys are ordered: down, pad, up, nail, knuckle, double_down.
- Parameters:
values (
Sequence[TypeVar(T)]) – A sequence of exactly 60 values to populate the layout. Can be a list, tuple, or any object supportinglen()and index access.- Return type:
- Returns:
A new SvalboardLayout with values distributed across all key positions.
- Raises:
ValueError – If the sequence does not contain exactly 60 values.
Example
Creating a layout from a list:
keys = ["KC_A"] * 60 # 60 identical values layout = SvalboardLayout.from_sequence(keys) # Or with distinct values keys = [f"KEY_{i}" for i in range(60)] layout = SvalboardLayout.from_sequence(keys) layout[0] # "KEY_0" (right index center) layout[59] # "KEY_59" (left thumb double_down)
- classmethod from_zipped(*, bundle='KeyValues', **layouts)[source]¶
Create a new layout by zipping values from multiple source layouts.
This class method combines multiple SvalboardLayout instances into a single layout where each key position contains a bundle of values from all source layouts. The bundle can be either a dynamically created frozen dataclass or a user-provided dataclass type.
This is useful when you need to associate multiple pieces of data with each key position, such as pairing keycodes with their display labels, or combining styling information from multiple sources.
- Parameters:
bundle (
str|type) – Either a string name for a dynamically created bundle dataclass, or an existing dataclass type to use. Defaults to “KeyValues”.**layouts (
SvalboardLayout[Any]) – Keyword arguments mapping names to source layouts. Each name becomes an attribute on the bundle objects.
- Return type:
- Returns:
A new SvalboardLayout where each key position contains a frozen dataclass instance with attributes from each source layout.
- Raises:
ValueError – If no layouts are provided.
TypeError – If a provided bundle class is missing required attributes.
Example
Using a dynamic bundle class:
codes = SvalboardLayout.from_sequence(["KC_A"] * 60) labels = SvalboardLayout.from_sequence(["A"] * 60) combined = SvalboardLayout.from_zipped( bundle="KeyData", code=codes, label=labels, ) combined[0].code # "KC_A" combined[0].label # "A"
Using a custom dataclass:
@dataclass(frozen=True) class KeyData: code: str label: str combined = SvalboardLayout.from_zipped(bundle=KeyData, code=codes, label=labels)
- map(fn)[source]¶
Create a new layout by applying a function to each key value.
This method transforms each of the 60 key values in the layout using the provided function, returning a new SvalboardLayout with the transformed values.
- Parameters:
fn (
Callable[[TypeVar(T)],TypeVar(U)]) – A callable that takes a value of type T and returns a value of type U. Applied to each key position in the layout.- Return type:
- Returns:
A new SvalboardLayout with transformed values.
Example
Transforming layout values:
codes = SvalboardLayout.from_sequence(["KC_A"] * 60) labels = codes.map(keycode_to_label) # Chain multiple transformations result = layout.map(fn1).map(fn2) # Use with lambdas upper = labels.map(str.upper)
- class skim.data.keyboard.SvalboardKeymap(layers)[source]¶
Bases:
Generic[T]A complete Svalboard keymap containing multiple layers.
A keymap represents the full key configuration for a Svalboard keyboard, organized into multiple layers. Each layer is a complete SvalboardLayout containing all 60 keys. Users typically switch between layers to access different key bindings (e.g., base layer, symbols layer, navigation layer).
The class is generic over type T, which represents the type of value stored at each key position, allowing it to be used for keycodes, labels, colors, or any other per-key data.
- Parameters:
layers (dict[int, SvalboardLayout[T]])
- layers¶
A dict mapping layer indices to SvalboardLayout objects. Keys are QMK layer indices (which may be non-sequential, e.g. 0, 1, 2, 15). Layer 0 is typically the base/default layer.
Example
Creating a keymap with multiple layers:
from skim.data.keyboard import SvalboardKeymap, SvalboardLayout # Create layouts for each layer base_layer = SvalboardLayout.from_sequence(["KC_A"] * 60) symbol_layer = SvalboardLayout.from_sequence(["KC_1"] * 60) nav_layer = SvalboardLayout.from_sequence(["KC_LEFT"] * 60) keymap = SvalboardKeymap(layers={0: base_layer, 1: symbol_layer, 2: nav_layer})
Accessing layers:
keymap.layers[0] # Base layer keymap.layers[1][0] # First key of symbol layer len(keymap.layers) # Number of layers
- __init__(layers)¶
- Parameters:
layers (dict[int, SvalboardLayout[T]])
- Return type:
None
-
layers:
dict[int,SvalboardLayout[TypeVar(T)]]¶
- skim.data.keyboard.zip_clusters(cluster_type, bundle='KeyValues', /, **clusters)[source]¶
Zip multiple clusters into a single cluster of bundled values.
This function combines multiple clusters of the same category (all FingerCluster or all ThumbCluster) into a new cluster where each position contains a bundle object holding values from all source clusters.
This is useful when you need to associate multiple pieces of data with each key position, such as pairing keycodes with their display labels, or combining styling information from multiple sources.
- Parameters:
cluster_type (
type[TypeVar(ClusterT, bound=_ClusterBase[Any])]) – The type of cluster to create (FingerCluster or ThumbCluster). This also determines the expected field structure for all source clusters.bundle (
str|type) – Either a string name for a dynamically created bundle dataclass, or an existing dataclass type to use. Defaults to “KeyValues”.**clusters (
_ClusterBase[Any]) – Keyword arguments mapping names to source clusters. Each name becomes an attribute on the bundle objects. All clusters must have the same field structure as cluster_type.
- Return type:
- Returns:
A new cluster of the specified type where each field contains a frozen dataclass instance with attributes from each source cluster.
- Raises:
ValueError – If no clusters are provided.
TypeError – If any source cluster has fields that don’t match the target cluster type, or if a provided bundle class is missing required attributes.
Example
Using a dynamic bundle class:
from skim.data.keyboard import FingerCluster, zip_clusters keycodes = FingerCluster("KC_NO", center_key="KC_A", south_key="KC_SPC") labels = FingerCluster("", center_key="A", south_key="Space") colors = FingerCluster("#888", center_key="#F00", south_key="#0F0") combined = zip_clusters( FingerCluster, "KeyData", code=keycodes, label=labels, color=colors ) # Access bundled values combined.center_key.code # "KC_A" combined.center_key.label # "A" combined.center_key.color # "#F00"
Using a custom dataclass:
@dataclass(frozen=True) class KeyData: code: str label: str color: str combined = zip_clusters( FingerCluster, KeyData, code=keycodes, label=labels, color=colors )
- skim.data.keyboard.zip_layouts(bundle='KeyValues', /, **layouts)[source]¶
Zip multiple layouts into a single layout of bundled values.
This function combines multiple SvalboardLayout instances into a new layout where each key position contains a bundle object holding values from all source layouts.
This is useful when you need to associate multiple pieces of data with each key position, such as pairing keycodes with their display labels, or combining styling information from multiple sources.
- Parameters:
bundle (
str|type) – Either a string name for a dynamically created bundle dataclass, or an existing dataclass type to use. Defaults to “KeyValues”.**layouts (
SvalboardLayout[Any]) – Keyword arguments mapping names to source layouts. Each name becomes an attribute on the bundle objects.
- Return type:
- Returns:
A new SvalboardLayout where each key position contains a frozen dataclass instance with attributes from each source layout.
- Raises:
ValueError – If no layouts are provided.
TypeError – If a provided bundle class is missing required attributes.
Example
Using a dynamic bundle class:
from skim.data.keyboard import SvalboardLayout, zip_layouts codes = SvalboardLayout.from_sequence(["KC_A"] * 60) labels = SvalboardLayout.from_sequence(["A"] * 60) colors = SvalboardLayout.from_sequence(["#F00"] * 60) combined = zip_layouts("KeyData", code=codes, label=labels, color=colors) # Access bundled values combined[0].code # "KC_A" combined[0].label # "A" combined[0].color # "#F00"
Using a custom dataclass:
@dataclass(frozen=True) class KeyData: code: str label: str color: str combined = zip_layouts(KeyData, code=codes, label=labels, color=colors)
CLI Data Transfer Objects¶
Data transfer objects for CLI argument handling.
This module defines frozen dataclasses used to pass parsed CLI arguments between the command-line interface and the application layer. These DTOs provide type-safe, immutable containers for input/output file specifications and layer selection options.
Example
>>> from skim.data import InputFiles, OutputFiles, KeymapGeneratorTargets
>>> from pathlib import Path
>>> inputs = InputFiles(config=Path("config.yaml"), keymap=Path("keymap.kbi"))
>>> outputs = OutputFiles(output_dir=Path("./images"), output_format="png")
>>> targets = KeymapGeneratorTargets.from_args(("1", "3-5", "overview"))
- class skim.data.cli.RenderEngine(value)[source]¶
Bases:
EnumAvailable render engines for non-vector image generation.
- CHROMIUM¶
Use Playwright with Chromium browser for rendering.
- CAIRO¶
Use Cairo graphics library for rendering.
- CHROMIUM = 'chromium'¶
- CAIRO = 'cairo'¶
- class skim.data.cli.OutputFiles(output_dir=<factory>, output_format='svg', force_overwrite=False, use_system_fonts=False, render_engine=None)[source]¶
Bases:
objectConfiguration for output file generation.
Specifies where and how to write generated keymap images. This is a frozen dataclass, meaning instances are immutable after creation.
- Parameters:
output_dir (Path)
output_format (str)
force_overwrite (bool)
use_system_fonts (bool)
render_engine (RenderEngine | None)
- output_dir¶
Directory path where generated images will be written. The directory will be created if it doesn’t exist. Defaults to the current working directory.
- output_format¶
Image format for output files. Supported values are “svg”, “png”, “jpeg”, “webp”, and “avif”. Defaults to “svg”.
- force_overwrite¶
Whether to overwrite existing files without prompting for confirmation. Defaults to False.
- use_system_fonts¶
Whether to use system fonts instead of embedding fonts in SVG. Defaults to False.
- render_engine¶
Which render engine to use for non-vector formats. Options are CHROMIUM (Playwright) or CAIRO. If None, uses the first available engine. Defaults to None.
Example
>>> output = OutputFiles( ... output_dir=Path("./images"), ... output_format="png", ... force_overwrite=True, ... ) >>> output.output_format 'png'
-
render_engine:
RenderEngine|None¶
- class skim.data.cli.InputFiles(config=None, keymap=None, force_stdin_keymap=False)[source]¶
Bases:
objectConfiguration for input file sources.
Specifies the source files for keymap data and optional configuration. This is a frozen dataclass, meaning instances are immutable after creation.
- config¶
Optional path to a YAML configuration file. When provided, settings from this file override the default configuration. Defaults to None (use default configuration).
- keymap¶
Optional path to the keymap file (.kbi, .vil, or .json). When None, keymap data is read from stdin. Defaults to None.
- force_stdin_keymap¶
Whether to read keymap data from stdin instead of a file. When True, the keymap is ignored and stdin is used. Defaults to False.
Example
>>> # Read keymap from file with custom config >>> inputs = InputFiles( ... config=Path("my-config.yaml"), ... keymap=Path("my-keymap.kbi"), ... )
>>> # Read keymap from stdin >>> inputs = InputFiles(force_stdin_keymap=True)
- class skim.data.cli.KeymapGeneratorTargets(all_layers=False, overview=False, selected_layers=<factory>)[source]¶
Bases:
objectSpecification of which layers and views to generate.
Defines the target outputs for keymap generation, including which individual layers to render and whether to generate an overview image. This is a frozen dataclass, meaning instances are immutable after creation.
- all_layers¶
Whether to generate images for all layers in the keymap. When True, selected_layers is ignored. Defaults to False.
- overview¶
Whether to generate an overview image showing all layers in a grid layout. Defaults to False.
- selected_layers¶
List of specific layer indices to generate. Only used when all_layers is False. Layer indices are 1-based in CLI input but stored as 0-based internally. Defaults to an empty list.
Example
>>> # Generate specific layers and overview >>> targets = KeymapGeneratorTargets( ... overview=True, ... selected_layers=[0, 2, 4], ... ) >>> targets.overview True
>>> # Generate all layers >>> targets = KeymapGeneratorTargets(all_layers=True, overview=True)
- classmethod from_args(layer, logger=<built-in function print>)[source]¶
Parse CLI layer arguments into a KeymapGeneratorTargets instance.
Interprets various layer selection formats from command-line arguments and constructs the appropriate targets configuration. Supports ranges, comma-separated values, and special keywords.
- Parameters:
Tuple of layer specification strings from the CLI. Each string can be:
A single number: “1”, “3” (generates that layer)
A range: “1-3” (generates layers 1, 2, and 3)
Comma-separated: “1,3,5” (generates layers 1, 3, and 5)
”overview”: Generates only the overview image
”all-layers”: Generates all individual layers
”all”: Generates all layers plus overview (default behavior)
logger (
Callable[[str],None]) – Callable for warning messages about invalid input. Defaults to print. Called with a string message when invalid layer specifications are encountered.
- Return type:
- Returns:
A KeymapGeneratorTargets instance configured according to the parsed arguments.
Example
>>> # No arguments = all layers + overview >>> targets = KeymapGeneratorTargets.from_args(()) >>> targets.all_layers True >>> targets.overview True
>>> # Specific layers >>> targets = KeymapGeneratorTargets.from_args(("1", "3-5")) >>> targets.selected_layers [1, 3, 4, 5]
>>> # Keywords >>> targets = KeymapGeneratorTargets.from_args(("overview",)) >>> targets.overview True >>> targets.all_layers False
Trie¶
Trie (prefix tree) data structure for efficient prefix matching.
This module provides a Trie implementation optimized for checking whether a string starts with any of a predefined set of prefixes. It is used internally by the keycode label adapter to efficiently match QMK macro function names like “LT”, “MO”, “TG”, etc.
Example
>>> from skim.data.trie import Trie
>>> trie = Trie(["LT", "MO", "TG", "OSL"])
>>> trie.get_matching_prefix("LT0")
'LT'
>>> trie.get_matching_prefix("MO(1)")
'MO'
>>> trie.get_matching_prefix("KC_A") is None
True
- class skim.data.trie.Trie(words)[source]¶
Bases:
objectA trie (prefix tree) for efficient prefix matching.
This data structure allows O(m) lookup time to check if a string starts with any word from a predefined set, where m is the length of the search string (or more precisely, the length of the matching prefix).
The trie is built once during initialization and then supports fast prefix queries. It is particularly useful for parsing QMK macro functions where we need to identify function names at the start of strings like “LT(1, KC_A)” or “MO(2)”.
- root¶
The root node of the trie, represented as a nested dictionary. Each key is a character leading to a child node (another dict), except for None which marks the end of a word and stores the complete word string.
Example
>>> trie = Trie(["cat", "car", "card"]) >>> trie.get_matching_prefix("catalog") 'cat' >>> trie.get_matching_prefix("car") 'car' >>> trie.get_matching_prefix("dog") is None True
- __init__(words)[source]¶
Initialize the trie with a collection of words.
Builds the trie structure by inserting all provided words. Each word creates a path through the trie, with the complete word stored at the terminal node.
- Parameters:
words (
Iterable[str]) – An iterable of strings to index in the trie. Can be a list, tuple, set, generator, or any other iterable of strings.- Return type:
None
Example
>>> trie = Trie(["LT", "MO", "TG"]) >>> trie.get_matching_prefix("LT0") 'LT'
>>> # Can also use generators >>> trie = Trie(w.upper() for w in ["lt", "mo", "tg"]) >>> trie.get_matching_prefix("MO(1)") 'MO'
- get_matching_prefix(search_string)[source]¶
Find the longest indexed word that is a prefix of the search string.
Traverses the trie following characters from the search string. If a complete indexed word is found (marked by a None key), that word is returned. The search continues to find the longest possible match.
- Parameters:
search_string (
str) – The string to check for a matching prefix.- Return type:
- Returns:
The matching prefix word if found, or None if the search string doesn’t start with any indexed word.
Example
>>> trie = Trie(["LT", "LM", "OSL"]) >>> trie.get_matching_prefix("LT(1, KC_A)") 'LT' >>> trie.get_matching_prefix("OSL(2)") 'OSL' >>> trie.get_matching_prefix("KC_SPACE") is None True >>> trie.get_matching_prefix("LT") 'LT'