diff --git a/.python-version b/.python-version index da71773..24ee5b1 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.14.3 +3.13 diff --git a/README.md b/README.md index fca374d..5389e0b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# streamer +# strea.md -Streamer is a personal knowledge management and time-tracking CLI tool. It organizes time-ordered markdown files using `@tag` annotations, letting you manage tasks, track time, and query your notes from the terminal. +Strea.md is a personal knowledge management and time-tracking CLI tool. It organizes time-ordered markdown files using `@tag` annotations, letting you manage tasks, track time, and query your notes from the terminal. ## Core Concepts @@ -12,23 +12,23 @@ Streamer is a personal knowledge management and time-tracking CLI tool. It organ Markdown files are named with a timestamp: `YYYYMMDD-HHMMSS [markers].md` -For example: `20260131-210000 Task Streamer.md` +For example: `20260131-210000 Task Streamd.md` Within files, `@`-prefixed markers at the beginning of paragraphs or headings define how a shard is categorized. ## Commands -- `streamer` / `streamer new` — Create a new timestamped markdown entry, opening your editor -- `streamer todo` — Show all open tasks (shards with `@Task` markers) -- `streamer edit [number]` — Edit a stream file by index (most recent first) -- `streamer timesheet` — Generate time reports from `@Timesheet` markers +- `streamd` / `streamd new` — Create a new timestamped markdown entry, opening your editor +- `streamd todo` — Show all open tasks (shards with `@Task` markers) +- `streamd edit [number]` — Edit a stream file by index (most recent first) +- `streamd timesheet` — Generate time reports from `@Timesheet` markers ## Configuration -Streamer reads its configuration from `~/.config/streamer/config.yaml` (XDG standard). The main setting is `base_folder`, which points to the directory containing your stream files (defaults to the current working directory). +Streamd reads its configuration from `~/.config/streamd/config.yaml` (XDG standard). The main setting is `base_folder`, which points to the directory containing your stream files (defaults to the current working directory). ## Usage -Running `streamer` opens your editor to create a new entry. After saving, the file is renamed based on its timestamp and any markers found in the content. +Running `streamd` opens your editor to create a new entry. After saving, the file is renamed based on its timestamp and any markers found in the content. -Running `streamer todo` finds all shards marked as open tasks and displays them as rich-formatted panels in your terminal. +Running `streamd todo` finds all shards marked as open tasks and displays them as rich-formatted panels in your terminal. diff --git a/pyproject.toml b/pyproject.toml index 7edb03b..4cd209f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,9 +1,9 @@ [project] -name = "streamer" +name = "streamd" version = "0.1.0" description = "Searching for tags in streams" readme = "README.md" -requires-python = ">=3.12" +requires-python = ">=3.13" dependencies = [ "click==8.3.1", "mistletoe==1.5.1", @@ -15,7 +15,7 @@ dependencies = [ ] [project.scripts] -streamer = "streamer:app" +streamd = "streamd:app" [build-system] requires = ["hatchling"] @@ -23,8 +23,8 @@ build-backend = "hatchling.build" [dependency-groups] dev = [ + "basedpyright==1.38.0", "faker==40.4.0", - "pyright==1.1.408", "pytest==9.0.2", "ruff==0.15.1", ] diff --git a/src/streamer/localize/__init__.py b/src/streamd/localize/__init__.py similarity index 100% rename from src/streamer/localize/__init__.py rename to src/streamd/localize/__init__.py diff --git a/src/streamer/localize/extract_datetime.py b/src/streamd/localize/extract_datetime.py similarity index 100% rename from src/streamer/localize/extract_datetime.py rename to src/streamd/localize/extract_datetime.py diff --git a/src/streamer/localize/localized_shard.py b/src/streamd/localize/localized_shard.py similarity index 87% rename from src/streamer/localize/localized_shard.py rename to src/streamd/localize/localized_shard.py index 05cb016..871af20 100644 --- a/src/streamer/localize/localized_shard.py +++ b/src/streamd/localize/localized_shard.py @@ -2,7 +2,7 @@ from __future__ import annotations from datetime import datetime -from streamer.parse.shard import Shard +from streamd.parse.shard import Shard class LocalizedShard(Shard): diff --git a/src/streamer/localize/preconfigured_configurations.py b/src/streamd/localize/preconfigured_configurations.py similarity index 95% rename from src/streamer/localize/preconfigured_configurations.py rename to src/streamd/localize/preconfigured_configurations.py index 0da82d7..a949ddc 100644 --- a/src/streamer/localize/preconfigured_configurations.py +++ b/src/streamd/localize/preconfigured_configurations.py @@ -1,4 +1,4 @@ -from streamer.localize.repository_configuration import ( +from streamd.localize.repository_configuration import ( Dimension, Marker, MarkerPlacement, diff --git a/src/streamer/parse/__init__.py b/src/streamd/parse/__init__.py similarity index 100% rename from src/streamer/parse/__init__.py rename to src/streamd/parse/__init__.py diff --git a/src/streamer/parse/list.py b/src/streamd/parse/list.py similarity index 100% rename from src/streamer/parse/list.py rename to src/streamd/parse/list.py diff --git a/src/streamer/parse/shard.py b/src/streamd/parse/shard.py similarity index 100% rename from src/streamer/parse/shard.py rename to src/streamd/parse/shard.py diff --git a/src/streamer/query/__init__.py b/src/streamd/query/__init__.py similarity index 100% rename from src/streamer/query/__init__.py rename to src/streamd/query/__init__.py diff --git a/src/streamer/timesheet/configuration.py b/src/streamd/timesheet/configuration.py similarity index 96% rename from src/streamer/timesheet/configuration.py rename to src/streamd/timesheet/configuration.py index 6b6c55d..8453dc9 100644 --- a/src/streamer/timesheet/configuration.py +++ b/src/streamd/timesheet/configuration.py @@ -1,7 +1,7 @@ from enum import StrEnum -from streamer.localize import RepositoryConfiguration -from streamer.localize.repository_configuration import ( +from streamd.localize import RepositoryConfiguration +from streamd.localize.repository_configuration import ( Dimension, Marker, MarkerPlacement, diff --git a/src/streamer/timesheet/extract.py b/src/streamd/timesheet/extract.py similarity index 97% rename from src/streamer/timesheet/extract.py rename to src/streamd/timesheet/extract.py index 85547cd..0754f7d 100644 --- a/src/streamer/timesheet/extract.py +++ b/src/streamd/timesheet/extract.py @@ -2,9 +2,8 @@ from datetime import datetime from itertools import groupby from pydantic import BaseModel - -from streamer.localize import LocalizedShard -from streamer.query.find import find_shard_by_set_dimension +from streamd.localize import LocalizedShard +from streamd.query.find import find_shard_by_set_dimension from .configuration import TIMESHEET_DIMENSION_NAME, TimesheetPointType from .timecard import SpecialDayType, Timecard, Timesheet diff --git a/src/streamer/timesheet/timecard.py b/src/streamd/timesheet/timecard.py similarity index 100% rename from src/streamer/timesheet/timecard.py rename to src/streamd/timesheet/timecard.py diff --git a/src/streamer/__init__.py b/src/streamer/__init__.py deleted file mode 100644 index 6109ca8..0000000 --- a/src/streamer/__init__.py +++ /dev/null @@ -1,126 +0,0 @@ -import glob -import os -from datetime import datetime -from shutil import move -from typing import Annotated, Generator - -import click -import typer -from rich import print -from rich.markdown import Markdown -from rich.panel import Panel - -from streamer.localize import ( - LocalizedShard, - RepositoryConfiguration, - localize_stream_file, -) -from streamer.localize.preconfigured_configurations import TaskConfiguration -from streamer.parse import parse_markdown_file -from streamer.query import find_shard_by_position -from streamer.query.find import find_shard_by_set_dimension -from streamer.settings import Settings -from streamer.timesheet.configuration import BasicTimesheetConfiguration -from streamer.timesheet.extract import extract_timesheets - -app = typer.Typer() - - -def all_files(config: RepositoryConfiguration) -> Generator[LocalizedShard]: - for file_name in glob.glob(f"{glob.escape(Settings().base_folder)}/*.md"): - with open(file_name, "r") as file: - file_content = file.read() - if shard := localize_stream_file( - parse_markdown_file(file_name, file_content), config - ): - yield shard - - -@app.command() -def todo() -> None: - all_shards = list(all_files(TaskConfiguration)) - - for task_shard in find_shard_by_position(all_shards, "task", "open"): - with open(task_shard.location["file"], "r") as file: - file_content = file.read().splitlines() - print( - Panel( - Markdown( - "\n".join( - file_content[ - task_shard.start_line - 1 : task_shard.end_line - ] - ) - ), - title=f"{task_shard.location['file']}:{task_shard.start_line}", - ) - ) - - -@app.command() -def edit(number: Annotated[int, typer.Argument()] = 1) -> None: - all_shards = list(all_files(TaskConfiguration)) - sorted_shards = sorted(all_shards, key=lambda s: s.moment) - - if abs(number) >= len(sorted_shards): - raise ValueError("Argument out of range") - - selected_number = number - if selected_number >= 0: - selected_number = len(sorted_shards) - selected_number - else: - selected_number = -selected_number - - click.edit(None, filename=sorted_shards[selected_number].location["file"]) - - -@app.command() -def timesheet() -> None: - all_shards = list(all_files(BasicTimesheetConfiguration)) - sheets = sorted(extract_timesheets(all_shards), key=lambda card: card.date) - for sheet in sheets: - print(sheet.date) - print( - ",".join( - map(lambda card: f"{card.from_time},{card.to_time}", sheet.timecards) - ), - ) - - -@app.command() -def new() -> None: - streamer_directory = Settings().base_folder - - timestamp = datetime.now().strftime("%Y%m%d-%H%M%S") - preliminary_file_name = f"{timestamp}_wip.md" - prelimary_path = os.path.join(streamer_directory, preliminary_file_name) - - content = "# " - with open(prelimary_path, "w") as file: - _ = file.write(content) - - click.edit(None, filename=prelimary_path) - - with open(prelimary_path, "r") as file: - content = file.read() - parsed_content = parse_markdown_file(prelimary_path, content) - - final_file_name = f"{timestamp}.md" - if parsed_content.shard is not None and len( - markers := parsed_content.shard.markers - ): - final_file_name = f"{timestamp} {' '.join(markers)}.md" - - final_path = os.path.join(streamer_directory, final_file_name) - _ = move(prelimary_path, final_path) - print(f"Saved as [yellow]{final_file_name}") - - -@app.callback(invoke_without_command=True) -def main(ctx: typer.Context): - if ctx.invoked_subcommand is None: - new() - - -if __name__ == "__main__": - app() diff --git a/src/streamer/localize/localize.py b/src/streamer/localize/localize.py deleted file mode 100644 index b241fc9..0000000 --- a/src/streamer/localize/localize.py +++ /dev/null @@ -1,70 +0,0 @@ -from datetime import datetime - -from streamer.parse.shard import Shard, StreamFile - -from .extract_datetime import ( - extract_datetime_from_file_name, - extract_datetime_from_marker_list, -) -from .localized_shard import LocalizedShard -from .repository_configuration import RepositoryConfiguration - - -def localize_shard( - shard: Shard, - config: RepositoryConfiguration, - propagated: dict[str, str], - moment: datetime, -) -> LocalizedShard: - position = {**propagated} - private_position: dict[str, str] = {} - - adjusted_moment: datetime = extract_datetime_from_marker_list(shard.markers, moment) - - for marker in shard.markers: - if marker in config.markers: - marker_definition = config.markers[marker] - for placement in marker_definition.placements: - if placement.if_with <= set(shard.markers): - dimension = config.dimensions[placement.dimension] - - value = placement.value or marker - - if placement.overwrites or ( - placement.dimension not in position - and placement.dimension not in private_position - ): - if dimension.propagate: - position[placement.dimension] = value - else: - private_position[placement.dimension] = value - - children = [ - localize_shard(child, config, position, adjusted_moment) - for child in shard.children - ] - - position.update(private_position) - - return LocalizedShard( - **shard.model_dump(exclude={"children"}), - location=position, - children=children, - moment=adjusted_moment, - ) - - -def localize_stream_file( - stream_file: StreamFile, config: RepositoryConfiguration -) -> LocalizedShard | None: - shard_date = extract_datetime_from_file_name(stream_file.file_name) - - if not shard_date or not stream_file.shard: - raise ValueError("Could not extract date") - - return localize_shard( - stream_file.shard, config, {"file": stream_file.file_name}, shard_date - ) - - -__all__ = ["localize_stream_file"] diff --git a/src/streamer/localize/repository_configuration.py b/src/streamer/localize/repository_configuration.py deleted file mode 100644 index f21c556..0000000 --- a/src/streamer/localize/repository_configuration.py +++ /dev/null @@ -1,108 +0,0 @@ -from __future__ import annotations - -from typing import Optional - -from pydantic import BaseModel - - -class Dimension(BaseModel): - display_name: str - comment: Optional[str] = None - propagate: bool = False - - -class MarkerPlacement(BaseModel): - if_with: set[str] = set() - dimension: str - value: str | None = None - overwrites: bool = True - - -class Marker(BaseModel): - display_name: str - placements: list[MarkerPlacement] = [] - - -class RepositoryConfiguration(BaseModel): - dimensions: dict[str, Dimension] - markers: dict[str, Marker] - - -def merge_single_dimension(base: Dimension, second: Dimension) -> Dimension: - second_fields_set = getattr(second, "model_fields_set", set()) - - return Dimension( - display_name=second.display_name or base.display_name, - comment=base.comment if second.comment is None else second.comment, - propagate=second.propagate - if "propagate" in second_fields_set - else base.propagate, - ) - - -def merge_dimensions( - base: dict[str, Dimension], second: dict[str, Dimension] -) -> dict[str, Dimension]: - merged: dict[str, Dimension] = dict(base) - for key, second_dimension in second.items(): - if key in merged: - merged[key] = merge_single_dimension(merged[key], second_dimension) - else: - merged[key] = second_dimension - return merged - - -def _placement_identity(p: MarkerPlacement) -> tuple[frozenset[str], str]: - return (frozenset(p.if_with), p.dimension) - - -def merge_single_marker(base: Marker, second: Marker) -> Marker: - merged_display_name = second.display_name or base.display_name - - merged_placements: list[MarkerPlacement] = [] - seen: dict[tuple[frozenset[str], str], int] = {} - - for placement in base.placements: - ident = _placement_identity(placement) - seen[ident] = len(merged_placements) - merged_placements.append(placement) - - for placement in second.placements: - ident = _placement_identity(placement) - if ident in seen: - merged_placements[seen[ident]] = placement - else: - seen[ident] = len(merged_placements) - merged_placements.append(placement) - - return Marker(display_name=merged_display_name, placements=merged_placements) - - -def merge_markers( - base: dict[str, Marker], second: dict[str, Marker] -) -> dict[str, Marker]: - merged: dict[str, Marker] = dict(base) - for key, second_marker in second.items(): - if key in merged: - merged[key] = merge_single_marker(merged[key], second_marker) - else: - merged[key] = second_marker - return merged - - -def merge_repository_configuration( - base: RepositoryConfiguration, second: RepositoryConfiguration -) -> RepositoryConfiguration: - return RepositoryConfiguration( - dimensions=merge_dimensions(base.dimensions, second.dimensions), - markers=merge_markers(base.markers, second.markers), - ) - - -__all__ = [ - "Dimension", - "Marker", - "MarkerPlacement", - "RepositoryConfiguration", - "merge_repository_configuration", -] diff --git a/src/streamer/parse/extract_tag.py b/src/streamer/parse/extract_tag.py deleted file mode 100644 index ace1258..0000000 --- a/src/streamer/parse/extract_tag.py +++ /dev/null @@ -1,84 +0,0 @@ -import re -from typing import Iterable -from mistletoe.block_token import BlockToken -from mistletoe.span_token import Emphasis, RawText, Strikethrough, Strong, Link -from mistletoe.token import Token - -from .markdown_tag import Tag - - -def extract_markers_and_tags_from_single_token( - token: Token, - marker_boundary_encountered: bool, - return_at_first_marker: bool = False, -) -> tuple[list[str], list[str], bool]: - result_markers, result_tags = [], [] - result_marker_boundary_encountered = marker_boundary_encountered - - if isinstance(token, Tag): - if marker_boundary_encountered: - result_tags.append(token.content) - else: - result_markers.append(token.content) - elif isinstance(token, (Emphasis, Strong, Strikethrough, Link)): - markers, tags, child_marker_boundary_encountered = ( - extract_markers_and_tags_from_tokens( - token.children or [], - marker_boundary_encountered, - return_at_first_marker, - ) - ) - result_markers.extend(markers) - result_tags.extend(tags) - result_marker_boundary_encountered = ( - marker_boundary_encountered or child_marker_boundary_encountered - ) - elif isinstance(token, RawText) and re.match(r"^[\s]*$", token.content): - pass - else: - result_marker_boundary_encountered = True - - return result_markers, result_tags, result_marker_boundary_encountered - - -def extract_markers_and_tags_from_tokens( - tokens: Iterable[Token], - marker_boundary_encountered: bool, - return_at_first_marker: bool = False, -) -> tuple[list[str], list[str], bool]: - result_markers, result_tags = [], [] - result_marker_boundary_encountered = marker_boundary_encountered - - for child in tokens: - markers, tags, child_marker_boundary_encountered = ( - extract_markers_and_tags_from_single_token( - child, result_marker_boundary_encountered, return_at_first_marker - ) - ) - result_markers.extend(markers) - result_tags.extend(tags) - result_marker_boundary_encountered = ( - marker_boundary_encountered or child_marker_boundary_encountered - ) - - if len(result_markers) > 0 and return_at_first_marker: - break - - return result_markers, result_tags, result_marker_boundary_encountered - - -def extract_markers_and_tags(block_token: BlockToken) -> tuple[list[str], list[str]]: - markers, tags, _ = extract_markers_and_tags_from_tokens( - block_token.children or [], False - ) - return markers, tags - - -def has_markers(block_token: BlockToken) -> bool: - markers, _, _ = extract_markers_and_tags_from_tokens( - block_token.children or [], False, return_at_first_marker=True - ) - return len(markers) > 0 - - -__all__ = ["extract_markers_and_tags", "has_markers"] diff --git a/src/streamer/parse/markdown_tag.py b/src/streamer/parse/markdown_tag.py deleted file mode 100644 index 4de6d35..0000000 --- a/src/streamer/parse/markdown_tag.py +++ /dev/null @@ -1,20 +0,0 @@ -import re -from mistletoe.markdown_renderer import Fragment, MarkdownRenderer -from mistletoe.span_token import SpanToken - - -class Tag(SpanToken): - parse_inner = False - pattern = re.compile(r"@([^\s*\x60~\[\]]+)") - - -class TagMarkdownRenderer(MarkdownRenderer): - def __init__(self): - super().__init__(Tag) - - def render_tag(self, token: Tag): - yield Fragment("@") - yield Fragment(token.content) - - -__all__ = ["Tag", "TagMarkdownRenderer"] diff --git a/src/streamer/parse/parse.py b/src/streamer/parse/parse.py deleted file mode 100644 index 058912a..0000000 --- a/src/streamer/parse/parse.py +++ /dev/null @@ -1,242 +0,0 @@ -from collections import Counter - -from mistletoe.block_token import ( - BlockToken, - Document, - Heading, - List, - ListItem, - Paragraph, -) - -from .extract_tag import extract_markers_and_tags, has_markers -from .list import split_at -from .markdown_tag import TagMarkdownRenderer -from .shard import Shard, StreamFile - - -def get_line_number(block_token: BlockToken) -> int: - return block_token.line_number # type: ignore - - -def build_shard( - start_line: int, - end_line: int, - markers: list[str] = [], - tags: list[str] = [], - children: list[Shard] = [], -) -> Shard: - if ( - len(children) == 1 - and len(tags) == 0 - and len(markers) == 0 - and children[0].start_line == start_line - and children[0].end_line == end_line - ): - return children[0] - - return Shard( - markers=markers, - tags=tags, - children=children, - start_line=start_line, - end_line=end_line, - ) - - -def merge_into_first_shard( - shards: list[Shard], start_line: int, end_line: int, additional_tags: list[str] = [] -): - return shards[0].model_copy( - update={ - "start_line": start_line, - "end_line": end_line, - "children": shards[1:], - "tags": shards[0].tags + additional_tags, - } - ) - - -def find_paragraph_shard_positions(block_tokens: list[BlockToken]) -> list[int]: - return [ - index - for index, block_token in enumerate(block_tokens) - if isinstance(block_token, Paragraph) and has_markers(block_token) - ] - - -def find_headings_by_level( - block_tokens: list[BlockToken], header_level: int -) -> list[int]: - return [ - index - for index, block_token in enumerate(block_tokens) - if isinstance(block_token, Heading) and block_token.level == header_level - ] - - -def calculate_heading_level_for_next_split( - block_tokens: list[BlockToken], -) -> int | None: - """ - If there is no marker in any heading, then return None. - If only the first token is a heading with a marker, then return None. - Otherwise: Return the heading level with the lowest level (h1 < h2), of which there are two or which has a marker (and doesn't stem from first) - """ - level_of_headings_without_first_with_marker = [ - token.level - for token in block_tokens[1:] - if isinstance(token, Heading) and has_markers(token) - ] - - if len(level_of_headings_without_first_with_marker) == 0: - return None - - heading_level_counter = Counter( - [token.level for token in block_tokens if isinstance(token, Heading)] - ) - - return min( - [level for level, count in heading_level_counter.items() if count >= 2] - + level_of_headings_without_first_with_marker - ) - - -def parse_single_block_shards( - block_token: BlockToken, start_line: int, end_line: int -) -> tuple[Shard | None, list[str]]: - markers, tags, children = [], [], [] - - if isinstance(block_token, List): - list_items: list[ListItem] = ( # type: ignore - list(block_token.children) if block_token.children is not None else [] - ) - for index, list_item in enumerate(list_items): - list_item_start_line = get_line_number(list_item) - list_item_end_line = ( - get_line_number(list_items[index + 1]) - 1 - if index + 1 < len(list_items) - else end_line - ) - list_item_shard, list_item_tags = parse_multiple_block_shards( - list_item.children, # type: ignore - list_item_start_line, - list_item_end_line, - ) - if list_item_shard is not None: - children.append(list_item_shard) - tags.extend(list_item_tags) - - elif isinstance(block_token, (Paragraph, Heading)): - markers, tags = extract_markers_and_tags(block_token) - - if len(markers) == 0 and len(children) == 0: - return None, tags - - return build_shard( - start_line, end_line, markers=markers, tags=tags, children=children - ), [] - - -def parse_multiple_block_shards( - block_tokens: list[BlockToken], - start_line: int, - end_line: int, - enforce_shard: bool = False, -) -> tuple[Shard | None, list[str]]: - is_first_block_heading = isinstance(block_tokens[0], Heading) and has_markers( - block_tokens[0] - ) - - paragraph_positions = find_paragraph_shard_positions(block_tokens) - children, tags = [], [] - - is_first_block_only_with_marker = False - - for i, token in enumerate(block_tokens): - if i in paragraph_positions: - is_first_block_only_with_marker = i == 0 - - child_start_line = get_line_number(token) - child_end_line = ( - get_line_number(block_tokens[i + 1]) - 1 - if i + 1 < len(block_tokens) - else end_line - ) - - child_shard, child_tags = parse_single_block_shards( - token, child_start_line, child_end_line - ) - - if child_shard is not None: - children.append(child_shard) - if len(child_tags) > 0: - tags.extend(child_tags) - - if len(children) == 0 and not enforce_shard: - return None, tags - if is_first_block_heading or is_first_block_only_with_marker: - return merge_into_first_shard(children, start_line, end_line, tags), [] - else: - return build_shard(start_line, end_line, tags=tags, children=children), [] - - -def parse_header_shards( - block_tokens: list[BlockToken], - start_line: int, - end_line: int, - use_first_child_as_header: bool = False, -) -> Shard | None: - if len(block_tokens) == 0: - return build_shard(start_line, end_line) - - split_at_heading_level = calculate_heading_level_for_next_split(block_tokens) - - if split_at_heading_level is None: - return parse_multiple_block_shards( - block_tokens, start_line, end_line, enforce_shard=True - )[0] - - heading_positions = find_headings_by_level(block_tokens, split_at_heading_level) - - block_tokens_split_by_heading = split_at(block_tokens, heading_positions) - - children = [] - for i, child_blocks in enumerate(block_tokens_split_by_heading): - child_start_line = get_line_number(child_blocks[0]) - child_end_line = ( - get_line_number(block_tokens_split_by_heading[i + 1][0]) - 1 - if i + 1 < len(block_tokens_split_by_heading) - else end_line - ) - if child_shard := parse_header_shards( - child_blocks, - child_start_line, - child_end_line, - use_first_child_as_header=i > 0 or 0 in heading_positions, - ): - children.append(child_shard) - - if use_first_child_as_header and len(children) > 0: - return merge_into_first_shard(children, start_line, end_line) - else: - return build_shard(start_line, end_line, children=children) - - -def parse_markdown_file(file_name: str, file_content: str) -> StreamFile: - shard = build_shard(1, max([len(file_content.splitlines()), 1])) - - with TagMarkdownRenderer(): - ast = Document(file_content) - - block_tokens: list[BlockToken] = ast.children # type: ignore - if len(block_tokens) > 0: - if parsed_shard := parse_header_shards( - block_tokens, shard.start_line, shard.end_line - ): - shard = parsed_shard - - return StreamFile(shard=shard, file_name=file_name) - - -__all__ = ["Shard", "StreamFile", "parse_markdown_file"] diff --git a/src/streamer/query/find.py b/src/streamer/query/find.py deleted file mode 100644 index 49beeca..0000000 --- a/src/streamer/query/find.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Callable - -from streamer.localize import LocalizedShard - - -def find_shard( - shards: list[LocalizedShard], query_function: Callable[[LocalizedShard], bool] -) -> list[LocalizedShard]: - found_shards = [] - - for shard in shards: - if query_function(shard): - found_shards.append(shard) - found_shards.extend(find_shard(shard.children, query_function)) - - return found_shards - - -def find_shard_by_position( - shards: list[LocalizedShard], dimension: str, value: str -) -> list[LocalizedShard]: - return find_shard( - shards, - lambda shard: dimension in shard.location - and shard.location[dimension] == value, - ) - - -def find_shard_by_set_dimension( - shards: list[LocalizedShard], dimension: str -) -> list[LocalizedShard]: - return find_shard(shards, lambda shard: dimension in shard.location) - - -__all__ = ["find_shard_by_position", "find_shard", "find_shard_by_set_dimension"] diff --git a/src/streamer/settings/__init__.py b/src/streamer/settings/__init__.py deleted file mode 100644 index 8099b01..0000000 --- a/src/streamer/settings/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -import os -from pydantic_settings import ( - BaseSettings, - PydanticBaseSettingsSource, - SettingsConfigDict, - YamlConfigSettingsSource, -) -from xdg_base_dirs import xdg_config_home - -SETTINGS_FILE = xdg_config_home() / "streamer" / "config.yaml" - - -class Settings(BaseSettings): - model_config = SettingsConfigDict(env_file_encoding="utf-8") - - base_folder: str = os.getcwd() - - @classmethod - def settings_customise_sources( - cls, - settings_cls: type[BaseSettings], - init_settings: PydanticBaseSettingsSource, - env_settings: PydanticBaseSettingsSource, - dotenv_settings: PydanticBaseSettingsSource, - file_secret_settings: PydanticBaseSettingsSource, - ) -> tuple[PydanticBaseSettingsSource, ...]: - return ( - init_settings, - YamlConfigSettingsSource(settings_cls, yaml_file=SETTINGS_FILE), - dotenv_settings, - env_settings, - file_secret_settings, - ) diff --git a/uv.lock b/uv.lock index 30d9760..f5999a8 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,6 @@ version = 1 revision = 3 -requires-python = ">=3.12" +requires-python = ">=3.13" [[package]] name = "annotated-doc" @@ -20,6 +20,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] +[[package]] +name = "basedpyright" +version = "1.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodejs-wheel-binaries" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/d4/4ac6eeba6cfe2ad8586dcf87fdb9e8b045aa467b559bc2e24e91e84f58b2/basedpyright-1.38.0.tar.gz", hash = "sha256:7a9cf631d7eaf5859022a4352b51ed0e78ce115435a8599402239804000d0cdf", size = 25257385, upload-time = "2026-02-11T16:05:47.834Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/90/1883cec16d667d944b08e8d8909b9b2f46cc1d2b9731e855e3c71f9b0450/basedpyright-1.38.0-py3-none-any.whl", hash = "sha256:a6c11a343fd12a2152a0d721b0e92f54f2e2e3322ee2562197e27dad952f1a61", size = 12303557, upload-time = "2026-02-11T16:05:44.863Z" }, +] + [[package]] name = "click" version = "8.3.1" @@ -93,12 +105,19 @@ wheels = [ ] [[package]] -name = "nodeenv" -version = "1.10.0" +name = "nodejs-wheel-binaries" +version = "24.13.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/d0/81d98b8fddc45332f79d6ad5749b1c7409fb18723545eae75d9b7e0048fb/nodejs_wheel_binaries-24.13.1.tar.gz", hash = "sha256:512659a67449a038231e2e972d49e77049d2cf789ae27db39eff4ab1ca52ac57", size = 8056, upload-time = "2026-02-12T17:31:04.368Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, + { url = "https://files.pythonhosted.org/packages/aa/04/1ffe1838306654fcb50bcf46172567d50c8e27a76f4b9e55a1971fab5c4f/nodejs_wheel_binaries-24.13.1-py2.py3-none-macosx_13_0_arm64.whl", hash = "sha256:360ac9382c651de294c23c4933a02358c4e11331294983f3cf50ca1ac32666b1", size = 54757440, upload-time = "2026-02-12T17:30:35.748Z" }, + { url = "https://files.pythonhosted.org/packages/66/f6/81ad81bc3bd919a20b110130c4fd318c7b6a5abb37eb53daa353ad908012/nodejs_wheel_binaries-24.13.1-py2.py3-none-macosx_13_0_x86_64.whl", hash = "sha256:035b718946793986762cdd50deee7f5f1a8f1b0bad0f0cfd57cad5492f5ea018", size = 54932957, upload-time = "2026-02-12T17:30:40.114Z" }, + { url = "https://files.pythonhosted.org/packages/14/be/8e8a2bd50953c4c5b7e0fca07368d287917b84054dc3c93dd26a2940f0f9/nodejs_wheel_binaries-24.13.1-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:f795e9238438c4225f76fbd01e2b8e1a322116bbd0dc15a7dbd585a3ad97961e", size = 59287257, upload-time = "2026-02-12T17:30:43.781Z" }, + { url = "https://files.pythonhosted.org/packages/58/57/92f6dfa40647702a9fa6d32393ce4595d0fc03c1daa9b245df66cc60e959/nodejs_wheel_binaries-24.13.1-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:978328e3ad522571eb163b042dfbd7518187a13968fe372738f90fdfe8a46afc", size = 59781783, upload-time = "2026-02-12T17:30:47.387Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a5/457b984cf675cf86ace7903204b9c36edf7a2d1b4325ddf71eaf8d1027c7/nodejs_wheel_binaries-24.13.1-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e1dc893df85299420cd2a5feea0c3f8482a719b5f7f82d5977d58718b8b78b5f", size = 61287166, upload-time = "2026-02-12T17:30:50.646Z" }, + { url = "https://files.pythonhosted.org/packages/3c/99/da515f7bc3bce35cfa6005f0e0c4e3c4042a466782b143112eb393b663be/nodejs_wheel_binaries-24.13.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0e581ae219a39073dcadd398a2eb648f0707b0f5d68c565586139f919c91cbe9", size = 61870142, upload-time = "2026-02-12T17:30:54.563Z" }, + { url = "https://files.pythonhosted.org/packages/cc/c0/22001d2c96d8200834af7d1de5e72daa3266c7270330275104c3d9ddd143/nodejs_wheel_binaries-24.13.1-py2.py3-none-win_amd64.whl", hash = "sha256:d4c969ea0bcb8c8b20bc6a7b4ad2796146d820278f17d4dc20229b088c833e22", size = 41185473, upload-time = "2026-02-12T17:30:57.524Z" }, + { url = "https://files.pythonhosted.org/packages/ab/c4/7532325f968ecfc078e8a028e69a52e4c3f95fb800906bf6931ac1e89e2b/nodejs_wheel_binaries-24.13.1-py2.py3-none-win_arm64.whl", hash = "sha256:caec398cb9e94c560bacdcba56b3828df22a355749eb291f47431af88cbf26dc", size = 38881194, upload-time = "2026-02-12T17:31:00.214Z" }, ] [[package]] @@ -143,20 +162,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, - { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, - { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, - { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, - { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, - { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, - { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, - { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, - { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, - { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, - { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, - { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, - { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, - { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, @@ -199,10 +204,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, - { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, - { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, - { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, ] [[package]] @@ -233,19 +234,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] -[[package]] -name = "pyright" -version = "1.1.408" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nodeenv" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/b2/5db700e52554b8f025faa9c3c624c59f1f6c8841ba81ab97641b54322f16/pyright-1.1.408.tar.gz", hash = "sha256:f28f2321f96852fa50b5829ea492f6adb0e6954568d1caa3f3af3a5f555eb684", size = 4400578, upload-time = "2026-01-08T08:07:38.795Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/82/a2c93e32800940d9573fb28c346772a14778b84ba7524e691b324620ab89/pyright-1.1.408-py3-none-any.whl", hash = "sha256:090b32865f4fdb1e0e6cd82bf5618480d48eecd2eb2e70f960982a3d9a4c17c1", size = 6399144, upload-time = "2026-01-08T08:07:37.082Z" }, -] - [[package]] name = "pytest" version = "9.0.2" @@ -277,16 +265,6 @@ version = "6.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, - { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, - { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, - { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, - { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, - { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, - { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, @@ -365,7 +343,7 @@ wheels = [ ] [[package]] -name = "streamer" +name = "streamd" version = "0.1.0" source = { editable = "." } dependencies = [ @@ -380,8 +358,8 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "basedpyright" }, { name = "faker" }, - { name = "pyright" }, { name = "pytest" }, { name = "ruff" }, ] @@ -399,8 +377,8 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ + { name = "basedpyright", specifier = "==1.38.0" }, { name = "faker", specifier = "==40.4.0" }, - { name = "pyright", specifier = "==1.1.408" }, { name = "pytest", specifier = "==9.0.2" }, { name = "ruff", specifier = "==0.15.1" }, ]