From 34ba9869d1aaed66f6c0431d53e90509128636a0 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 12 Feb 2026 00:06:12 +0000 Subject: [PATCH 01/28] fix(deps): update dependency typer to v0.23.0 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a58de8c..7c117be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ dependencies = [ "pydantic==2.12.5", "pydantic-settings[yaml]==2.12.0", "rich==14.3.2", - "typer==0.21.2", + "typer==0.23.0", "xdg-base-dirs==6.0.2", ] diff --git a/uv.lock b/uv.lock index 4be435e..6b0c03b 100644 --- a/uv.lock +++ b/uv.lock @@ -393,7 +393,7 @@ requires-dist = [ { name = "pydantic", specifier = "==2.12.5" }, { name = "pydantic-settings", extras = ["yaml"], specifier = "==2.12.0" }, { name = "rich", specifier = "==14.3.2" }, - { name = "typer", specifier = "==0.21.2" }, + { name = "typer", specifier = "==0.23.0" }, { name = "xdg-base-dirs", specifier = "==6.0.2" }, ] @@ -407,7 +407,7 @@ dev = [ [[package]] name = "typer" -version = "0.21.2" +version = "0.23.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -415,9 +415,9 @@ dependencies = [ { name = "rich" }, { name = "shellingham" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f2/1e/a27cc02a0cd715118c71fa2aef2c687fdefc3c28d90fd0dd789c5118154c/typer-0.21.2.tar.gz", hash = "sha256:1abd95a3b675e17ff61b0838ac637fe9478d446d62ad17fa4bb81ea57cc54028", size = 120426, upload-time = "2026-02-10T19:33:46.182Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/e6/44e073787aa57cd71c151f44855232feb0f748428fd5242d7366e3c4ae8b/typer-0.23.0.tar.gz", hash = "sha256:d8378833e47ada5d3d093fa20c4c63427cc4e27127f6b349a6c359463087d8cc", size = 120181, upload-time = "2026-02-11T15:22:18.637Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/cc/d59f893fbdfb5f58770c05febfc4086a46875f1084453621c35605cec946/typer-0.21.2-py3-none-any.whl", hash = "sha256:c3d8de54d00347ef90b82131ca946274f017cffb46683ae3883c360fa958f55c", size = 56728, upload-time = "2026-02-10T19:33:48.01Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ed/d6fca788b51d0d4640c4bc82d0e85bad4b49809bca36bf4af01b4dcb66a7/typer-0.23.0-py3-none-any.whl", hash = "sha256:79f4bc262b6c37872091072a3cb7cb6d7d79ee98c0c658b4364bdcde3c42c913", size = 56668, upload-time = "2026-02-11T15:22:21.075Z" }, ] [[package]] From c0911307fdddd4571238eae5de533321b4072106 Mon Sep 17 00:00:00 2001 From: Konstantin Fickel Date: Sat, 7 Feb 2026 22:03:45 +0100 Subject: [PATCH 02/28] docs: expand README with project overview, concepts, and usage --- README.md | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2fcf603..fca374d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,34 @@ # streamer -Searching for `@tags` in time-based [streams](https://www.cs.yale.edu/homes/freeman/lifestreams.html). +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. -# Usage +## Core Concepts -Running `streamer` finds all lines with @Task \ No newline at end of file +- **Shards** — Sections of markdown files, organized hierarchically by headings. Each shard can contain markers, tags, and nested child shards. +- **Markers** — Special `@tags` like `@Task`, `@Done`, `@Waiting`, or `@Timesheet` that give shards semantic meaning and place them into dimensions. +- **Dimensions** — Classification axes (e.g. task state, project, timesheet) that categorize shards. Some dimensions propagate to child shards. + +## File Format + +Markdown files are named with a timestamp: `YYYYMMDD-HHMMSS [markers].md` + +For example: `20260131-210000 Task Streamer.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 + +## 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). + +## 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 `streamer todo` finds all shards marked as open tasks and displays them as rich-formatted panels in your terminal. From 646241f355a1587eecf26649cbe3aefa3889e169 Mon Sep 17 00:00:00 2001 From: Konstantin Fickel Date: Sat, 14 Feb 2026 17:59:43 +0100 Subject: [PATCH 03/28] feat: add home-manager module output --- flake.lock | 12 ++++++------ flake.nix | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 0f2727f..4fa0a20 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1769789167, - "narHash": "sha256-kKB3bqYJU5nzYeIROI82Ef9VtTbu4uA3YydSk/Bioa8=", + "lastModified": 1770197578, + "narHash": "sha256-AYqlWrX09+HvGs8zM6ebZ1pwUqjkfpnv8mewYwAo+iM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "62c8382960464ceb98ea593cb8321a2cf8f9e3e5", + "rev": "00c21e4c93d963c50d4c0c89bfa84ed6e0694df2", "type": "github" }, "original": { @@ -80,11 +80,11 @@ ] }, "locked": { - "lastModified": 1769957392, - "narHash": "sha256-6PkqwwYf5K2CHi2V+faI/9pqjfz/HxUkI/MVid6hlOY=", + "lastModified": 1770331927, + "narHash": "sha256-jlOvO++uvne/lTgWqdI4VhTV5OpVWi70ZDVBlT6vGSs=", "owner": "pyproject-nix", "repo": "uv2nix", - "rev": "d18bc50ae1c3d4be9c41c2d94ea765524400af75", + "rev": "5b43a934e15b23bfba6c408cba1c570eccf80080", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 669701a..d112b66 100644 --- a/flake.nix +++ b/flake.nix @@ -85,6 +85,50 @@ in { + homeManagerModules.default = + { + lib, + config, + pkgs, + ... + }: + let + cfg = config.programs.streamer; + in + { + options.programs.streamer = { + enable = lib.mkEnableOption "streamer"; + + base-folder = lib.mkOption { + type = lib.types.str; + description = "Base Folder of Streamer"; + }; + + package = lib.mkOption { + type = lib.types.package; + default = self.packages.${pkgs.system}.streamer; + defaultText = lib.literalExpression "inputs.streamer.packages.\${pkgs.system}.streamer"; + description = "The package to use for the streamer binary."; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "programs.streamer" pkgs lib.platforms.linux) + ]; + + home.packages = [ cfg.package ]; + + xdg.configFile."streamer/config.yaml".source = + (pkgs.formats.yaml { }).generate "streamer-configuration" + { + base_folder = cfg.base-folder; + }; + + home.shellAliases.s = "streamer"; + }; + }; + # Package a virtual environment as our main application. # # Enable no optional dependencies for production build. From 2298bdaa8f28d5b0e5fb2a8b4bb4a055b4c00503 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 15 Feb 2026 00:06:41 +0000 Subject: [PATCH 04/28] chore(deps): update dependency ruff to v0.15.1 --- pyproject.toml | 2 +- uv.lock | 40 ++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7c117be..f526dda 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,5 +26,5 @@ dev = [ "faker==40.4.0", "pyright==1.1.408", "pytest==9.0.2", - "ruff==0.15.0", + "ruff==0.15.1", ] diff --git a/uv.lock b/uv.lock index 6b0c03b..bdacd98 100644 --- a/uv.lock +++ b/uv.lock @@ -332,27 +332,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.0" +version = "0.15.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c8/39/5cee96809fbca590abea6b46c6d1c586b49663d1d2830a751cc8fc42c666/ruff-0.15.0.tar.gz", hash = "sha256:6bdea47cdbea30d40f8f8d7d69c0854ba7c15420ec75a26f463290949d7f7e9a", size = 4524893, upload-time = "2026-02-03T17:53:35.357Z" } +sdist = { url = "https://files.pythonhosted.org/packages/04/dc/4e6ac71b511b141cf626357a3946679abeba4cf67bc7cc5a17920f31e10d/ruff-0.15.1.tar.gz", hash = "sha256:c590fe13fb57c97141ae975c03a1aedb3d3156030cabd740d6ff0b0d601e203f", size = 4540855, upload-time = "2026-02-12T23:09:09.998Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/88/3fd1b0aa4b6330d6aaa63a285bc96c9f71970351579152d231ed90914586/ruff-0.15.0-py3-none-linux_armv6l.whl", hash = "sha256:aac4ebaa612a82b23d45964586f24ae9bc23ca101919f5590bdb368d74ad5455", size = 10354332, upload-time = "2026-02-03T17:52:54.892Z" }, - { url = "https://files.pythonhosted.org/packages/72/f6/62e173fbb7eb75cc29fe2576a1e20f0a46f671a2587b5f604bfb0eaf5f6f/ruff-0.15.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dcd4be7cc75cfbbca24a98d04d0b9b36a270d0833241f776b788d59f4142b14d", size = 10767189, upload-time = "2026-02-03T17:53:19.778Z" }, - { url = "https://files.pythonhosted.org/packages/99/e4/968ae17b676d1d2ff101d56dc69cf333e3a4c985e1ec23803df84fc7bf9e/ruff-0.15.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d747e3319b2bce179c7c1eaad3d884dc0a199b5f4d5187620530adf9105268ce", size = 10075384, upload-time = "2026-02-03T17:53:29.241Z" }, - { url = "https://files.pythonhosted.org/packages/a2/bf/9843c6044ab9e20af879c751487e61333ca79a2c8c3058b15722386b8cae/ruff-0.15.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:650bd9c56ae03102c51a5e4b554d74d825ff3abe4db22b90fd32d816c2e90621", size = 10481363, upload-time = "2026-02-03T17:52:43.332Z" }, - { url = "https://files.pythonhosted.org/packages/55/d9/4ada5ccf4cd1f532db1c8d44b6f664f2208d3d93acbeec18f82315e15193/ruff-0.15.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6664b7eac559e3048223a2da77769c2f92b43a6dfd4720cef42654299a599c9", size = 10187736, upload-time = "2026-02-03T17:53:00.522Z" }, - { url = "https://files.pythonhosted.org/packages/86/e2/f25eaecd446af7bb132af0a1d5b135a62971a41f5366ff41d06d25e77a91/ruff-0.15.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f811f97b0f092b35320d1556f3353bf238763420ade5d9e62ebd2b73f2ff179", size = 10968415, upload-time = "2026-02-03T17:53:15.705Z" }, - { url = "https://files.pythonhosted.org/packages/e7/dc/f06a8558d06333bf79b497d29a50c3a673d9251214e0d7ec78f90b30aa79/ruff-0.15.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:761ec0a66680fab6454236635a39abaf14198818c8cdf691e036f4bc0f406b2d", size = 11809643, upload-time = "2026-02-03T17:53:23.031Z" }, - { url = "https://files.pythonhosted.org/packages/dd/45/0ece8db2c474ad7df13af3a6d50f76e22a09d078af63078f005057ca59eb/ruff-0.15.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:940f11c2604d317e797b289f4f9f3fa5555ffe4fb574b55ed006c3d9b6f0eb78", size = 11234787, upload-time = "2026-02-03T17:52:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/8a/d9/0e3a81467a120fd265658d127db648e4d3acfe3e4f6f5d4ea79fac47e587/ruff-0.15.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcbca3d40558789126da91d7ef9a7c87772ee107033db7191edefa34e2c7f1b4", size = 11112797, upload-time = "2026-02-03T17:52:49.274Z" }, - { url = "https://files.pythonhosted.org/packages/b2/cb/8c0b3b0c692683f8ff31351dfb6241047fa873a4481a76df4335a8bff716/ruff-0.15.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9a121a96db1d75fa3eb39c4539e607f628920dd72ff1f7c5ee4f1b768ac62d6e", size = 11033133, upload-time = "2026-02-03T17:53:33.105Z" }, - { url = "https://files.pythonhosted.org/packages/f8/5e/23b87370cf0f9081a8c89a753e69a4e8778805b8802ccfe175cc410e50b9/ruff-0.15.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5298d518e493061f2eabd4abd067c7e4fb89e2f63291c94332e35631c07c3662", size = 10442646, upload-time = "2026-02-03T17:53:06.278Z" }, - { url = "https://files.pythonhosted.org/packages/e1/9a/3c94de5ce642830167e6d00b5c75aacd73e6347b4c7fc6828699b150a5ee/ruff-0.15.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:afb6e603d6375ff0d6b0cee563fa21ab570fd15e65c852cb24922cef25050cf1", size = 10195750, upload-time = "2026-02-03T17:53:26.084Z" }, - { url = "https://files.pythonhosted.org/packages/30/15/e396325080d600b436acc970848d69df9c13977942fb62bb8722d729bee8/ruff-0.15.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:77e515f6b15f828b94dc17d2b4ace334c9ddb7d9468c54b2f9ed2b9c1593ef16", size = 10676120, upload-time = "2026-02-03T17:53:09.363Z" }, - { url = "https://files.pythonhosted.org/packages/8d/c9/229a23d52a2983de1ad0fb0ee37d36e0257e6f28bfd6b498ee2c76361874/ruff-0.15.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6f6e80850a01eb13b3e42ee0ebdf6e4497151b48c35051aab51c101266d187a3", size = 11201636, upload-time = "2026-02-03T17:52:57.281Z" }, - { url = "https://files.pythonhosted.org/packages/6f/b0/69adf22f4e24f3677208adb715c578266842e6e6a3cc77483f48dd999ede/ruff-0.15.0-py3-none-win32.whl", hash = "sha256:238a717ef803e501b6d51e0bdd0d2c6e8513fe9eec14002445134d3907cd46c3", size = 10465945, upload-time = "2026-02-03T17:53:12.591Z" }, - { url = "https://files.pythonhosted.org/packages/51/ad/f813b6e2c97e9b4598be25e94a9147b9af7e60523b0cb5d94d307c15229d/ruff-0.15.0-py3-none-win_amd64.whl", hash = "sha256:dd5e4d3301dc01de614da3cdffc33d4b1b96fb89e45721f1598e5532ccf78b18", size = 11564657, upload-time = "2026-02-03T17:52:51.893Z" }, - { url = "https://files.pythonhosted.org/packages/f6/b0/2d823f6e77ebe560f4e397d078487e8d52c1516b331e3521bc75db4272ca/ruff-0.15.0-py3-none-win_arm64.whl", hash = "sha256:c480d632cc0ca3f0727acac8b7d053542d9e114a462a145d0b00e7cd658c515a", size = 10865753, upload-time = "2026-02-03T17:53:03.014Z" }, + { url = "https://files.pythonhosted.org/packages/23/bf/e6e4324238c17f9d9120a9d60aa99a7daaa21204c07fcd84e2ef03bb5fd1/ruff-0.15.1-py3-none-linux_armv6l.whl", hash = "sha256:b101ed7cf4615bda6ffe65bdb59f964e9f4a0d3f85cbf0e54f0ab76d7b90228a", size = 10367819, upload-time = "2026-02-12T23:09:03.598Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ea/c8f89d32e7912269d38c58f3649e453ac32c528f93bb7f4219258be2e7ed/ruff-0.15.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:939c995e9277e63ea632cc8d3fae17aa758526f49a9a850d2e7e758bfef46602", size = 10798618, upload-time = "2026-02-12T23:09:22.928Z" }, + { url = "https://files.pythonhosted.org/packages/5e/0f/1d0d88bc862624247d82c20c10d4c0f6bb2f346559d8af281674cf327f15/ruff-0.15.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d83466455fdefe60b8d9c8df81d3c1bbb2115cede53549d3b522ce2bc703899", size = 10148518, upload-time = "2026-02-12T23:08:58.339Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c8/291c49cefaa4a9248e986256df2ade7add79388fe179e0691be06fae6f37/ruff-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9457e3c3291024866222b96108ab2d8265b477e5b1534c7ddb1810904858d16", size = 10518811, upload-time = "2026-02-12T23:09:31.865Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1a/f5707440e5ae43ffa5365cac8bbb91e9665f4a883f560893829cf16a606b/ruff-0.15.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92c92b003e9d4f7fbd33b1867bb15a1b785b1735069108dfc23821ba045b29bc", size = 10196169, upload-time = "2026-02-12T23:09:17.306Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ff/26ddc8c4da04c8fd3ee65a89c9fb99eaa5c30394269d424461467be2271f/ruff-0.15.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fe5c41ab43e3a06778844c586251eb5a510f67125427625f9eb2b9526535779", size = 10990491, upload-time = "2026-02-12T23:09:25.503Z" }, + { url = "https://files.pythonhosted.org/packages/fc/00/50920cb385b89413f7cdb4bb9bc8fc59c1b0f30028d8bccc294189a54955/ruff-0.15.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66a6dd6df4d80dc382c6484f8ce1bcceb55c32e9f27a8b94c32f6c7331bf14fb", size = 11843280, upload-time = "2026-02-12T23:09:19.88Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6d/2f5cad8380caf5632a15460c323ae326f1e1a2b5b90a6ee7519017a017ca/ruff-0.15.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a4a42cbb8af0bda9bcd7606b064d7c0bc311a88d141d02f78920be6acb5aa83", size = 11274336, upload-time = "2026-02-12T23:09:14.907Z" }, + { url = "https://files.pythonhosted.org/packages/a3/1d/5f56cae1d6c40b8a318513599b35ea4b075d7dc1cd1d04449578c29d1d75/ruff-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ab064052c31dddada35079901592dfba2e05f5b1e43af3954aafcbc1096a5b2", size = 11137288, upload-time = "2026-02-12T23:09:07.475Z" }, + { url = "https://files.pythonhosted.org/packages/cd/20/6f8d7d8f768c93b0382b33b9306b3b999918816da46537d5a61635514635/ruff-0.15.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5631c940fe9fe91f817a4c2ea4e81f47bee3ca4aa646134a24374f3c19ad9454", size = 11070681, upload-time = "2026-02-12T23:08:55.43Z" }, + { url = "https://files.pythonhosted.org/packages/9a/67/d640ac76069f64cdea59dba02af2e00b1fa30e2103c7f8d049c0cff4cafd/ruff-0.15.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:68138a4ba184b4691ccdc39f7795c66b3c68160c586519e7e8444cf5a53e1b4c", size = 10486401, upload-time = "2026-02-12T23:09:27.927Z" }, + { url = "https://files.pythonhosted.org/packages/65/3d/e1429f64a3ff89297497916b88c32a5cc88eeca7e9c787072d0e7f1d3e1e/ruff-0.15.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:518f9af03bfc33c03bdb4cb63fabc935341bb7f54af500f92ac309ecfbba6330", size = 10197452, upload-time = "2026-02-12T23:09:12.147Z" }, + { url = "https://files.pythonhosted.org/packages/78/83/e2c3bade17dad63bf1e1c2ffaf11490603b760be149e1419b07049b36ef2/ruff-0.15.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:da79f4d6a826caaea95de0237a67e33b81e6ec2e25fc7e1993a4015dffca7c61", size = 10693900, upload-time = "2026-02-12T23:09:34.418Z" }, + { url = "https://files.pythonhosted.org/packages/a1/27/fdc0e11a813e6338e0706e8b39bb7a1d61ea5b36873b351acee7e524a72a/ruff-0.15.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3dd86dccb83cd7d4dcfac303ffc277e6048600dfc22e38158afa208e8bf94a1f", size = 11227302, upload-time = "2026-02-12T23:09:36.536Z" }, + { url = "https://files.pythonhosted.org/packages/f6/58/ac864a75067dcbd3b95be5ab4eb2b601d7fbc3d3d736a27e391a4f92a5c1/ruff-0.15.1-py3-none-win32.whl", hash = "sha256:660975d9cb49b5d5278b12b03bb9951d554543a90b74ed5d366b20e2c57c2098", size = 10462555, upload-time = "2026-02-12T23:09:29.899Z" }, + { url = "https://files.pythonhosted.org/packages/e0/5e/d4ccc8a27ecdb78116feac4935dfc39d1304536f4296168f91ed3ec00cd2/ruff-0.15.1-py3-none-win_amd64.whl", hash = "sha256:c820fef9dd5d4172a6570e5721704a96c6679b80cf7be41659ed439653f62336", size = 11599956, upload-time = "2026-02-12T23:09:01.157Z" }, + { url = "https://files.pythonhosted.org/packages/2a/07/5bda6a85b220c64c65686bc85bd0bbb23b29c62b3a9f9433fa55f17cda93/ruff-0.15.1-py3-none-win_arm64.whl", hash = "sha256:5ff7d5f0f88567850f45081fac8f4ec212be8d0b963e385c3f7d0d2eb4899416", size = 10874604, upload-time = "2026-02-12T23:09:05.515Z" }, ] [[package]] @@ -402,7 +402,7 @@ dev = [ { name = "faker", specifier = "==40.4.0" }, { name = "pyright", specifier = "==1.1.408" }, { name = "pytest", specifier = "==9.0.2" }, - { name = "ruff", specifier = "==0.15.0" }, + { name = "ruff", specifier = "==0.15.1" }, ] [[package]] From 1e203d9db3d5e438bd3b646a63c99bdef627d010 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 15 Feb 2026 00:06:52 +0000 Subject: [PATCH 05/28] fix(deps): update dependency typer to v0.23.1 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f526dda..7edb03b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ dependencies = [ "pydantic==2.12.5", "pydantic-settings[yaml]==2.12.0", "rich==14.3.2", - "typer==0.23.0", + "typer==0.23.1", "xdg-base-dirs==6.0.2", ] diff --git a/uv.lock b/uv.lock index bdacd98..30d9760 100644 --- a/uv.lock +++ b/uv.lock @@ -393,7 +393,7 @@ requires-dist = [ { name = "pydantic", specifier = "==2.12.5" }, { name = "pydantic-settings", extras = ["yaml"], specifier = "==2.12.0" }, { name = "rich", specifier = "==14.3.2" }, - { name = "typer", specifier = "==0.23.0" }, + { name = "typer", specifier = "==0.23.1" }, { name = "xdg-base-dirs", specifier = "==6.0.2" }, ] @@ -407,7 +407,7 @@ dev = [ [[package]] name = "typer" -version = "0.23.0" +version = "0.23.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -415,9 +415,9 @@ dependencies = [ { name = "rich" }, { name = "shellingham" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7e/e6/44e073787aa57cd71c151f44855232feb0f748428fd5242d7366e3c4ae8b/typer-0.23.0.tar.gz", hash = "sha256:d8378833e47ada5d3d093fa20c4c63427cc4e27127f6b349a6c359463087d8cc", size = 120181, upload-time = "2026-02-11T15:22:18.637Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/07/b822e1b307d40e263e8253d2384cf98c51aa2368cc7ba9a07e523a1d964b/typer-0.23.1.tar.gz", hash = "sha256:2070374e4d31c83e7b61362fd859aa683576432fd5b026b060ad6b4cd3b86134", size = 120047, upload-time = "2026-02-13T10:04:30.984Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/ed/d6fca788b51d0d4640c4bc82d0e85bad4b49809bca36bf4af01b4dcb66a7/typer-0.23.0-py3-none-any.whl", hash = "sha256:79f4bc262b6c37872091072a3cb7cb6d7d79ee98c0c658b4364bdcde3c42c913", size = 56668, upload-time = "2026-02-11T15:22:21.075Z" }, + { url = "https://files.pythonhosted.org/packages/d5/91/9b286ab899c008c2cb05e8be99814807e7fbbd33f0c0c960470826e5ac82/typer-0.23.1-py3-none-any.whl", hash = "sha256:3291ad0d3c701cbf522012faccfbb29352ff16ad262db2139e6b01f15781f14e", size = 56813, upload-time = "2026-02-13T10:04:32.008Z" }, ] [[package]] From 49cd9bcfa055608dfadfe9d7a0c3a9c9bf9a8376 Mon Sep 17 00:00:00 2001 From: Konstantin Fickel Date: Sun, 15 Feb 2026 17:10:09 +0100 Subject: [PATCH 06/28] fix: resolve all basedpyright warnings - Use collections.abc.Generator/Iterable instead of deprecated typing imports - Replace Optional with union syntax (X | None) - Add explicit type annotations to eliminate reportUnknownVariableType - Use typing.cast for untyped mistletoe attributes (content, level, line_number) - Replace mutable default arguments with None defaults (reportCallInDefaultInitializer) - Add ClassVar annotation for model_config (reportIncompatibleVariableOverride) - Add @override decorator for settings_customise_sources (reportImplicitOverride) - Annotate class attributes in Tag (reportUnannotatedClassAttribute) - Add parameter type annotations in test (reportMissingParameterType) - Assign unused call result to _ (reportUnusedCallResult) --- src/streamd/__init__.py | 126 +++++++++ src/streamd/localize/localize.py | 73 +++++ .../localize/repository_configuration.py | 106 +++++++ src/streamd/parse/extract_tag.py | 92 +++++++ src/streamd/parse/markdown_tag.py | 23 ++ src/streamd/parse/parse.py | 258 ++++++++++++++++++ src/streamd/query/find.py | 36 +++ src/streamd/settings/__init__.py | 38 +++ .../test_repository_configuration_merge.py | 20 +- test/timesheet/test_extract_timesheets.py | 14 +- 10 files changed, 770 insertions(+), 16 deletions(-) create mode 100644 src/streamd/__init__.py create mode 100644 src/streamd/localize/localize.py create mode 100644 src/streamd/localize/repository_configuration.py create mode 100644 src/streamd/parse/extract_tag.py create mode 100644 src/streamd/parse/markdown_tag.py create mode 100644 src/streamd/parse/parse.py create mode 100644 src/streamd/query/find.py create mode 100644 src/streamd/settings/__init__.py diff --git a/src/streamd/__init__.py b/src/streamd/__init__.py new file mode 100644 index 0000000..c72d098 --- /dev/null +++ b/src/streamd/__init__.py @@ -0,0 +1,126 @@ +import glob +import os +from collections.abc import Generator +from datetime import datetime +from shutil import move +from typing import Annotated + +import click +import typer +from rich import print +from rich.markdown import Markdown +from rich.panel import Panel + +from streamd.localize import ( + LocalizedShard, + RepositoryConfiguration, + localize_stream_file, +) +from streamd.localize.preconfigured_configurations import TaskConfiguration +from streamd.parse import parse_markdown_file +from streamd.query import find_shard_by_position +from streamd.settings import Settings +from streamd.timesheet.configuration import BasicTimesheetConfiguration +from streamd.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: + streamd_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(streamd_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(streamd_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/streamd/localize/localize.py b/src/streamd/localize/localize.py new file mode 100644 index 0000000..bc084f4 --- /dev/null +++ b/src/streamd/localize/localize.py @@ -0,0 +1,73 @@ +from datetime import datetime + +from streamd.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( + markers=shard.markers, + tags=shard.tags, + start_line=shard.start_line, + end_line=shard.end_line, + 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/streamd/localize/repository_configuration.py b/src/streamd/localize/repository_configuration.py new file mode 100644 index 0000000..4b83a03 --- /dev/null +++ b/src/streamd/localize/repository_configuration.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +from pydantic import BaseModel + + +class Dimension(BaseModel): + display_name: str + comment: str | None = 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: set[str] = 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/streamd/parse/extract_tag.py b/src/streamd/parse/extract_tag.py new file mode 100644 index 0000000..b7bfd45 --- /dev/null +++ b/src/streamd/parse/extract_tag.py @@ -0,0 +1,92 @@ +import re +from collections.abc import Iterable +from typing import cast + +from mistletoe.block_token import BlockToken +from mistletoe.span_token import Emphasis, Link, RawText, Strikethrough, Strong +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: list[str] = [] + result_tags: list[str] = [] + result_marker_boundary_encountered = marker_boundary_encountered + + if isinstance(token, Tag): + content = cast(str, token.content) + if marker_boundary_encountered: + result_tags.append(content) + else: + result_markers.append(content) + elif isinstance(token, (Emphasis, Strong, Strikethrough, Link)): + children = list(token.children or []) + markers, tags, child_marker_boundary_encountered = ( + extract_markers_and_tags_from_tokens( + children, + 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): + content_raw = cast(str, token.content) + if not re.match(r"^[\s]*$", content_raw): + result_marker_boundary_encountered = True + 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: list[str] = [] + result_tags: list[str] = [] + 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]]: + children = list(block_token.children or []) + markers, tags, _ = extract_markers_and_tags_from_tokens(children, False) + return markers, tags + + +def has_markers(block_token: BlockToken) -> bool: + children = list(block_token.children or []) + markers, _, _ = extract_markers_and_tags_from_tokens( + children, False, return_at_first_marker=True + ) + return len(markers) > 0 + + +__all__ = ["extract_markers_and_tags", "has_markers"] diff --git a/src/streamd/parse/markdown_tag.py b/src/streamd/parse/markdown_tag.py new file mode 100644 index 0000000..798f10e --- /dev/null +++ b/src/streamd/parse/markdown_tag.py @@ -0,0 +1,23 @@ +import re +from typing import cast + +from mistletoe.markdown_renderer import Fragment, MarkdownRenderer +from mistletoe.span_token import SpanToken + + +class Tag(SpanToken): + parse_inner: bool = False + pattern: re.Pattern[str] = re.compile(r"@([^\s*\x60~\[\]]+)") + + +class TagMarkdownRenderer(MarkdownRenderer): + def __init__(self) -> None: + super().__init__(Tag) # pyright: ignore[reportUnknownMemberType] + + def render_tag(self, token: Tag): + content = cast(str, token.content) + yield Fragment("@") + yield Fragment(content) + + +__all__ = ["Tag", "TagMarkdownRenderer"] diff --git a/src/streamd/parse/parse.py b/src/streamd/parse/parse.py new file mode 100644 index 0000000..4d14fa3 --- /dev/null +++ b/src/streamd/parse/parse.py @@ -0,0 +1,258 @@ +from collections import Counter +from typing import cast + +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 cast(int, block_token.line_number) # pyright: ignore[reportAttributeAccessIssue] + + +def build_shard( + start_line: int, + end_line: int, + markers: list[str] | None = None, + tags: list[str] | None = None, + children: list[Shard] | None = None, +) -> Shard: + markers = markers or [] + tags = tags or [] + children = children or [] + + 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] | None = None, +) -> Shard: + return shards[0].model_copy( + update={ + "start_line": start_line, + "end_line": end_line, + "children": shards[1:], + "tags": shards[0].tags + (additional_tags or []), + } + ) + + +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 _heading_level(heading: Heading) -> int: + return cast(int, heading.level) + + +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 _heading_level(block_token) == 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: list[int] = [ + _heading_level(token) + 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[int] = Counter( + [_heading_level(token) 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: list[str] = [] + tags: list[str] = [] + children: list[Shard] = [] + + if isinstance(block_token, List): + list_items: list[ListItem] = ( # pyright: ignore[reportAssignmentType] + 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, # pyright: ignore[reportArgumentType] + 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: list[Shard] = [] + tags: list[str] = [] + + 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: list[Shard] = [] + 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 # pyright: ignore[reportAssignmentType] + 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/streamd/query/find.py b/src/streamd/query/find.py new file mode 100644 index 0000000..428e05a --- /dev/null +++ b/src/streamd/query/find.py @@ -0,0 +1,36 @@ +from typing import Callable + +from streamd.localize import LocalizedShard + + +def find_shard( + shards: list[LocalizedShard], query_function: Callable[[LocalizedShard], bool] +) -> list[LocalizedShard]: + found_shards: list[LocalizedShard] = [] + + 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/streamd/settings/__init__.py b/src/streamd/settings/__init__.py new file mode 100644 index 0000000..bdf28b4 --- /dev/null +++ b/src/streamd/settings/__init__.py @@ -0,0 +1,38 @@ +import os +from typing import ClassVar, override + +from pydantic_settings import ( + BaseSettings, + PydanticBaseSettingsSource, + SettingsConfigDict, + YamlConfigSettingsSource, +) +from xdg_base_dirs import xdg_config_home + +SETTINGS_FILE = xdg_config_home() / "streamd" / "config.yaml" + + +class Settings(BaseSettings): + model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict( + env_file_encoding="utf-8" + ) + + base_folder: str = os.getcwd() + + @classmethod + @override + 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/test/localize/test_repository_configuration_merge.py b/test/localize/test_repository_configuration_merge.py index f5d345d..ba74c76 100644 --- a/test/localize/test_repository_configuration_merge.py +++ b/test/localize/test_repository_configuration_merge.py @@ -1,6 +1,6 @@ import pytest -from streamer.localize.repository_configuration import ( +from streamd.localize.repository_configuration import ( Dimension, Marker, MarkerPlacement, @@ -252,8 +252,8 @@ class TestMergeRepositoryConfiguration: ), }, markers={ - "Streamer": Marker( - display_name="Streamer", + "Streamd": Marker( + display_name="Streamd", placements=[MarkerPlacement(dimension="project")], ) }, @@ -267,8 +267,8 @@ class TestMergeRepositoryConfiguration: ), }, markers={ - "Streamer": Marker( - display_name="Streamer2", + "Streamd": Marker( + display_name="Streamd2", placements=[ MarkerPlacement( if_with={"Timesheet"}, dimension="timesheet", value="coding" @@ -291,9 +291,9 @@ class TestMergeRepositoryConfiguration: assert merged.dimensions["moment"].display_name == "Moment" assert merged.dimensions["timesheet"].display_name == "Timesheet" - assert set(merged.markers.keys()) == {"Streamer", "JobHunting"} - assert merged.markers["Streamer"].display_name == "Streamer2" - assert merged.markers["Streamer"].placements == [ + assert set(merged.markers.keys()) == {"Streamd", "JobHunting"} + assert merged.markers["Streamd"].display_name == "Streamd2" + assert merged.markers["Streamd"].placements == [ MarkerPlacement(dimension="project", value=None, if_with=set()), MarkerPlacement( if_with={"Timesheet"}, dimension="timesheet", value="coding" @@ -359,7 +359,9 @@ class TestMergeRepositoryConfiguration: ], ) def test_merge_repository_configuration_propagate_preserves_base_when_omitted( - base, second, expected_propagate + base: RepositoryConfiguration, + second: RepositoryConfiguration, + expected_propagate: bool, ): merged = merge_repository_configuration(base, second) assert merged.dimensions["d"].propagate is expected_propagate diff --git a/test/timesheet/test_extract_timesheets.py b/test/timesheet/test_extract_timesheets.py index c5a0bbe..b54befc 100644 --- a/test/timesheet/test_extract_timesheets.py +++ b/test/timesheet/test_extract_timesheets.py @@ -4,13 +4,13 @@ from datetime import datetime, time import pytest -from streamer.localize.localized_shard import LocalizedShard -from streamer.timesheet.configuration import ( +from streamd.localize.localized_shard import LocalizedShard +from streamd.timesheet.configuration import ( TIMESHEET_DIMENSION_NAME, TimesheetPointType, ) -from streamer.timesheet.extract import extract_timesheets -from streamer.timesheet.timecard import SpecialDayType, Timecard, Timesheet +from streamd.timesheet.extract import extract_timesheets +from streamd.timesheet.timecard import SpecialDayType, Timecard, Timesheet def point(at: datetime, type: TimesheetPointType) -> LocalizedShard: @@ -243,7 +243,7 @@ class TestExtractTimesheets: ] with pytest.raises(ValueError, match=r"Last Timecard of .* is not a break"): - extract_timesheets(shards) + _ = extract_timesheets(shards) def test_two_special_day_types_same_day_is_invalid(self): """ @@ -257,7 +257,7 @@ class TestExtractTimesheets: ] with pytest.raises(ValueError, match=r"is both .* and .*"): - extract_timesheets(shards) + _ = extract_timesheets(shards) def test_points_with_mixed_dates_inside_one_group_raises(self): """ @@ -273,7 +273,7 @@ class TestExtractTimesheets: ] with pytest.raises(ValueError, match=r"Last Timecard of .* is not a break"): - extract_timesheets(shards) + _ = extract_timesheets(shards) def test_day_with_only_breaks_is_ignored(self): """ From af2debc19b03c515dde7057c73bf2389a167870b Mon Sep 17 00:00:00 2001 From: Konstantin Fickel Date: Sun, 15 Feb 2026 17:30:31 +0100 Subject: [PATCH 07/28] refactor!: rename package from streamer to streamd - Rename src/streamer/ to src/streamd/ - Update all internal imports - Update pyproject.toml project name and entry point - Update README branding (Streamer -> Strea.md) - Switch from pyright to basedpyright - Bump requires-python to >=3.13 --- .python-version | 2 +- README.md | 20 +- pyproject.toml | 8 +- .../localize/__init__.py | 0 .../localize/extract_datetime.py | 0 .../localize/localized_shard.py | 2 +- .../localize/preconfigured_configurations.py | 2 +- src/{streamer => streamd}/parse/__init__.py | 0 src/{streamer => streamd}/parse/list.py | 0 src/{streamer => streamd}/parse/shard.py | 0 src/{streamer => streamd}/query/__init__.py | 0 .../timesheet/configuration.py | 4 +- .../timesheet/extract.py | 5 +- .../timesheet/timecard.py | 0 src/streamer/__init__.py | 126 --------- src/streamer/localize/localize.py | 70 ----- .../localize/repository_configuration.py | 108 -------- src/streamer/parse/extract_tag.py | 84 ------ src/streamer/parse/markdown_tag.py | 20 -- src/streamer/parse/parse.py | 242 ------------------ src/streamer/query/find.py | 35 --- src/streamer/settings/__init__.py | 33 --- uv.lock | 76 ++---- 23 files changed, 48 insertions(+), 789 deletions(-) rename src/{streamer => streamd}/localize/__init__.py (100%) rename src/{streamer => streamd}/localize/extract_datetime.py (100%) rename src/{streamer => streamd}/localize/localized_shard.py (87%) rename src/{streamer => streamd}/localize/preconfigured_configurations.py (95%) rename src/{streamer => streamd}/parse/__init__.py (100%) rename src/{streamer => streamd}/parse/list.py (100%) rename src/{streamer => streamd}/parse/shard.py (100%) rename src/{streamer => streamd}/query/__init__.py (100%) rename src/{streamer => streamd}/timesheet/configuration.py (96%) rename src/{streamer => streamd}/timesheet/extract.py (97%) rename src/{streamer => streamd}/timesheet/timecard.py (100%) delete mode 100644 src/streamer/__init__.py delete mode 100644 src/streamer/localize/localize.py delete mode 100644 src/streamer/localize/repository_configuration.py delete mode 100644 src/streamer/parse/extract_tag.py delete mode 100644 src/streamer/parse/markdown_tag.py delete mode 100644 src/streamer/parse/parse.py delete mode 100644 src/streamer/query/find.py delete mode 100644 src/streamer/settings/__init__.py 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" }, ] From f9ed0463f7670ecbe7972daf03e66d3ce9a1fac2 Mon Sep 17 00:00:00 2001 From: Konstantin Fickel Date: Sun, 15 Feb 2026 17:30:44 +0100 Subject: [PATCH 08/28] refactor: rename test/ to tests/ --- .../localize/test_extract_datetime.py | 2 +- .../test_repository_configuration_merge.py | 0 {test => tests}/parse/test_parse.py | 3 +-- {test => tests}/query/test_find.py | 4 ++-- {test => tests}/test_localize.py | 24 +++++++++---------- .../timesheet/test_extract_timesheets.py | 0 6 files changed, 16 insertions(+), 17 deletions(-) rename {test => tests}/localize/test_extract_datetime.py (99%) rename {test => tests}/localize/test_repository_configuration_merge.py (100%) rename {test => tests}/parse/test_parse.py (99%) rename {test => tests}/query/test_find.py (96%) rename {test => tests}/test_localize.py (93%) rename {test => tests}/timesheet/test_extract_timesheets.py (100%) diff --git a/test/localize/test_extract_datetime.py b/tests/localize/test_extract_datetime.py similarity index 99% rename from test/localize/test_extract_datetime.py rename to tests/localize/test_extract_datetime.py index 279f194..8758ebf 100644 --- a/test/localize/test_extract_datetime.py +++ b/tests/localize/test_extract_datetime.py @@ -1,6 +1,6 @@ from datetime import date, datetime, time -from streamer.localize.extract_datetime import ( +from streamd.localize.extract_datetime import ( extract_date_from_marker, extract_datetime_from_file_name, extract_datetime_from_marker, diff --git a/test/localize/test_repository_configuration_merge.py b/tests/localize/test_repository_configuration_merge.py similarity index 100% rename from test/localize/test_repository_configuration_merge.py rename to tests/localize/test_repository_configuration_merge.py diff --git a/test/parse/test_parse.py b/tests/parse/test_parse.py similarity index 99% rename from test/parse/test_parse.py rename to tests/parse/test_parse.py index b692120..ef72e5a 100644 --- a/test/parse/test_parse.py +++ b/tests/parse/test_parse.py @@ -1,6 +1,5 @@ from faker import Faker - -from streamer.parse import Shard, StreamFile, parse_markdown_file +from streamd.parse import Shard, StreamFile, parse_markdown_file fake = Faker() diff --git a/test/query/test_find.py b/tests/query/test_find.py similarity index 96% rename from test/query/test_find.py rename to tests/query/test_find.py index 725d3b2..6b72e87 100644 --- a/test/query/test_find.py +++ b/tests/query/test_find.py @@ -2,8 +2,8 @@ from __future__ import annotations from datetime import datetime -from streamer.localize import LocalizedShard -from streamer.query.find import find_shard, find_shard_by_position +from streamd.localize import LocalizedShard +from streamd.query.find import find_shard, find_shard_by_position def generate_localized_shard( diff --git a/test/test_localize.py b/tests/test_localize.py similarity index 93% rename from test/test_localize.py rename to tests/test_localize.py index 678604b..ecdb864 100644 --- a/test/test_localize.py +++ b/tests/test_localize.py @@ -1,14 +1,14 @@ from datetime import datetime -from streamer.localize.localize import localize_stream_file -from streamer.localize.localized_shard import LocalizedShard -from streamer.localize.repository_configuration import ( +from streamd.localize.localize import localize_stream_file +from streamd.localize.localized_shard import LocalizedShard +from streamd.localize.repository_configuration import ( Dimension, Marker, MarkerPlacement, RepositoryConfiguration, ) -from streamer.parse.shard import Shard, StreamFile +from streamd.parse.shard import Shard, StreamFile repository_configuration = RepositoryConfiguration( dimensions={ @@ -29,8 +29,8 @@ repository_configuration = RepositoryConfiguration( ), }, markers={ - "Streamer": Marker( - display_name="Streamer", + "Streamd": Marker( + display_name="Streamd", placements=[ MarkerPlacement(dimension="project"), MarkerPlacement( @@ -49,39 +49,39 @@ class TestLocalize: def test_project_simple_stream_file(self): stream_file = StreamFile( file_name="20250622-121000 Test File.md", - shard=Shard(start_line=1, end_line=1, markers=["Streamer"]), + shard=Shard(start_line=1, end_line=1, markers=["Streamd"]), ) assert localize_stream_file( stream_file, repository_configuration ) == LocalizedShard( moment=datetime(2025, 6, 22, 12, 10, 0, 0), - markers=["Streamer"], + markers=["Streamd"], tags=[], start_line=1, end_line=1, children=[], - location={"project": "Streamer", "file": stream_file.file_name}, + location={"project": "Streamd", "file": stream_file.file_name}, ) def test_timesheet_use_case(self): stream_file = StreamFile( file_name="20260131-210000 Test File.md", - shard=Shard(start_line=1, end_line=1, markers=["Timesheet", "Streamer"]), + shard=Shard(start_line=1, end_line=1, markers=["Timesheet", "Streamd"]), ) assert localize_stream_file( stream_file, repository_configuration ) == LocalizedShard( moment=datetime(2026, 1, 31, 21, 0, 0, 0), - markers=["Timesheet", "Streamer"], + markers=["Timesheet", "Streamd"], tags=[], start_line=1, end_line=1, children=[], location={ "file": stream_file.file_name, - "project": "Streamer", + "project": "Streamd", "timesheet": "coding", }, ) diff --git a/test/timesheet/test_extract_timesheets.py b/tests/timesheet/test_extract_timesheets.py similarity index 100% rename from test/timesheet/test_extract_timesheets.py rename to tests/timesheet/test_extract_timesheets.py From b4848bb6610fe016f608a303e75c6d3924af0dda Mon Sep 17 00:00:00 2001 From: Konstantin Fickel Date: Sun, 15 Feb 2026 17:31:02 +0100 Subject: [PATCH 09/28] build: migrate to devenv - Add devenv.nix with Python/uv setup and git-hooks - Add devenv.yaml and devenv.lock - Refactor flake.nix to use devenv integration - Update .envrc from flake to devenv - Add devenv artifacts to .gitignore --- .envrc | 4 +- .gitignore | 3 + devenv.lock | 123 +++++++++++++++++++++ devenv.nix | 28 +++++ devenv.yaml | 6 + flake.lock | 82 ++++++++++++-- flake.nix | 311 +++++++++++++++++++++++----------------------------- 7 files changed, 373 insertions(+), 184 deletions(-) create mode 100644 devenv.lock create mode 100644 devenv.nix create mode 100644 devenv.yaml diff --git a/.envrc b/.envrc index 99764ea..163bbd9 100644 --- a/.envrc +++ b/.envrc @@ -1 +1,3 @@ -use flake .#impure +#!/usr/bin/env bash +eval "$(devenv direnvrc)" +use devenv diff --git a/.gitignore b/.gitignore index 2b9abaa..ff4088b 100644 --- a/.gitignore +++ b/.gitignore @@ -177,3 +177,6 @@ pyrightconfig.json .direnv test-report.xml +.devenv +.devenv.flake.nix +.pre-commit-config.yaml diff --git a/devenv.lock b/devenv.lock new file mode 100644 index 0000000..9996189 --- /dev/null +++ b/devenv.lock @@ -0,0 +1,123 @@ +{ + "nodes": { + "devenv": { + "locked": { + "dir": "src/modules", + "lastModified": 1771157881, + "owner": "cachix", + "repo": "devenv", + "rev": "b0b3dfa70ec90fa49f672e579f186faf4f61bd4b", + "type": "github" + }, + "original": { + "dir": "src/modules", + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770726378, + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "5eaaedde414f6eb1aea8b8525c466dc37bba95ae", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762808025, + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "inputs": { + "nixpkgs-src": "nixpkgs-src" + }, + "locked": { + "lastModified": 1770434727, + "owner": "cachix", + "repo": "devenv-nixpkgs", + "rev": "8430f16a39c27bdeef236f1eeb56f0b51b33d348", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "rolling", + "repo": "devenv-nixpkgs", + "type": "github" + } + }, + "nixpkgs-src": { + "flake": false, + "locked": { + "lastModified": 1769922788, + "narHash": "sha256-H3AfG4ObMDTkTJYkd8cz1/RbY9LatN5Mk4UF48VuSXc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "207d15f1a6603226e1e223dc79ac29c7846da32e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "git-hooks": "git-hooks", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": [ + "git-hooks" + ] + } + } + }, + "root": "root", + "version": 7 +} diff --git a/devenv.nix b/devenv.nix new file mode 100644 index 0000000..ce1097e --- /dev/null +++ b/devenv.nix @@ -0,0 +1,28 @@ +{ + pkgs, + ... +}: +{ + languages = { + python = { + enable = true; + uv.enable = true; + }; + }; + + packages = [ + pkgs.basedpyright + ]; + + git-hooks.hooks = { + basedpyright = { + enable = true; + entry = "${pkgs.basedpyright}/bin/basedpyright"; + files = "\\.py$"; + types = [ "file" ]; + }; + ruff.enable = true; + ruff-format.enable = true; + commitizen.enable = true; + }; +} diff --git a/devenv.yaml b/devenv.yaml new file mode 100644 index 0000000..28877ba --- /dev/null +++ b/devenv.yaml @@ -0,0 +1,6 @@ +inputs: + git-hooks: + url: github:cachix/git-hooks.nix + inputs: + nixpkgs: + follows: nixpkgs diff --git a/flake.lock b/flake.lock index 4fa0a20..b04d8e3 100644 --- a/flake.lock +++ b/flake.lock @@ -1,16 +1,75 @@ { "nodes": { - "nixpkgs": { + "flake-compat": { + "flake": false, "locked": { - "lastModified": 1770197578, - "narHash": "sha256-AYqlWrX09+HvGs8zM6ebZ1pwUqjkfpnv8mewYwAo+iM=", + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", "owner": "NixOS", - "repo": "nixpkgs", - "rev": "00c21e4c93d963c50d4c0c89bfa84ed6e0694df2", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", "type": "github" }, "original": { "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770726378, + "narHash": "sha256-kck+vIbGOaM/dHea7aTBxdFYpeUl/jHOy5W3eyRvVx8=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "5eaaedde414f6eb1aea8b8525c466dc37bba95ae", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1771008912, + "narHash": "sha256-gf2AmWVTs8lEq7z/3ZAsgnZDhWIckkb+ZnAo5RzSxJg=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "a82ccc39b39b621151d6732718e3e250109076fa", + "type": "github" + }, + "original": { + "owner": "nixos", "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" @@ -29,11 +88,11 @@ ] }, "locked": { - "lastModified": 1763662255, - "narHash": "sha256-4bocaOyLa3AfiS8KrWjZQYu+IAta05u3gYZzZ6zXbT0=", + "lastModified": 1771039651, + "narHash": "sha256-WZOfX4APbc6vmL14ZWJXgBeRfEER8H+OIX0D0nSmv0M=", "owner": "pyproject-nix", "repo": "build-system-pkgs", - "rev": "042904167604c681a090c07eb6967b4dd4dae88c", + "rev": "69bc2b53b79cbd6ce9f66f506fc962b45b5e68b9", "type": "github" }, "original": { @@ -64,6 +123,7 @@ }, "root": { "inputs": { + "git-hooks": "git-hooks", "nixpkgs": "nixpkgs", "pyproject-build-systems": "pyproject-build-systems", "pyproject-nix": "pyproject-nix", @@ -80,11 +140,11 @@ ] }, "locked": { - "lastModified": 1770331927, - "narHash": "sha256-jlOvO++uvne/lTgWqdI4VhTV5OpVWi70ZDVBlT6vGSs=", + "lastModified": 1770770348, + "narHash": "sha256-A2GzkmzdYvdgmMEu5yxW+xhossP+txrYb7RuzRaqhlg=", "owner": "pyproject-nix", "repo": "uv2nix", - "rev": "5b43a934e15b23bfba6c408cba1c570eccf80080", + "rev": "5d1b2cb4fe3158043fbafbbe2e46238abbc954b0", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index d112b66..02359db 100644 --- a/flake.nix +++ b/flake.nix @@ -1,8 +1,8 @@ { - description = "Hello world flake using uv2nix"; + description = "Using Markdown Files to organize your life as a @Tag-Stream"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; pyproject-nix = { url = "github:pyproject-nix/pyproject.nix"; @@ -21,70 +21,135 @@ inputs.uv2nix.follows = "uv2nix"; inputs.nixpkgs.follows = "nixpkgs"; }; + + git-hooks = { + url = "github:cachix/git-hooks.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = { self, nixpkgs, - uv2nix, pyproject-nix, + uv2nix, pyproject-build-systems, + git-hooks, ... }: let inherit (nixpkgs) lib; + forAllSystems = lib.genAttrs lib.systems.flakeExposed; - # Load a uv workspace from a workspace root. - # Uv2nix treats all uv projects as workspace projects. workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; - # Create package overlay from workspace. overlay = workspace.mkPyprojectOverlay { - # Prefer prebuilt binary wheels as a package source. - # Sdists are less likely to "just work" because of the metadata missing from uv.lock. - # Binary wheels are more likely to, but may still require overrides for library dependencies. - sourcePreference = "wheel"; # or sourcePreference = "sdist"; - # Optionally customise PEP 508 environment - # environ = { - # platform_release = "5.10.65"; - # }; + sourcePreference = "wheel"; }; - # Extend generated overlay with build fixups - # - # Uv2nix can only work with what it has, and uv.lock is missing essential metadata to perform some builds. - # This is an additional overlay implementing build fixups. - # See: - # - https://pyproject-nix.github.io/uv2nix/FAQ.html - pyprojectOverrides = _final: _prev: { - # Implement build fixups here. - # Note that uv2nix is _not_ using Nixpkgs buildPythonPackage. - # It's using https://pyproject-nix.github.io/pyproject.nix/build.html + editableOverlay = workspace.mkEditablePyprojectOverlay { + root = "$REPO_ROOT"; }; - # This example is only using x86_64-linux - pkgs = nixpkgs.legacyPackages.x86_64-linux; + pythonSets = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + inherit (pkgs) stdenv; - # Use Python 3.14 from nixpkgs - python = pkgs.python314; + baseSet = pkgs.callPackage pyproject-nix.build.packages { + python = pkgs.python313; + }; - # Construct package set - pythonSet = - # Use base package set from pyproject.nix builders - (pkgs.callPackage pyproject-nix.build.packages { - inherit python; - }).overrideScope - ( - lib.composeManyExtensions [ - pyproject-build-systems.overlays.default - overlay - pyprojectOverrides - ] - ); + pyprojectOverrides = _final: prev: { + streamd = prev.streamd.overrideAttrs (old: { + passthru = old.passthru // { + tests = (old.passthru.tests or { }) // { + pytest = stdenv.mkDerivation { + name = "${_final.streamd.name}-pytest"; + inherit (_final.streamd) src; + nativeBuildInputs = [ + (_final.mkVirtualEnv "streamd-pytest-env" { + streamd = [ "dev" ]; + }) + ]; + dontConfigure = true; + buildPhase = '' + runHook preBuild + # Exit code 5 means no tests collected — allow it so the + # check succeeds on an empty test suite. + pytest || [ $? -eq 5 ] + runHook postBuild + ''; + installPhase = '' + runHook preInstall + touch $out + runHook postInstall + ''; + }; + }; + }; + }); + }; + + in + baseSet.overrideScope ( + lib.composeManyExtensions [ + pyproject-build-systems.overlays.default + overlay + pyprojectOverrides + ] + ) + ); + + mkGitHooksCheck = + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + pythonSet = pythonSets.${system}; + venv = pythonSet.mkVirtualEnv "streamd-check-env" workspace.deps.default; + in + git-hooks.lib.${system}.run { + src = ./.; + hooks = { + basedpyright = { + enable = true; + entry = "${pkgs.basedpyright}/bin/basedpyright --pythonpath ${venv}/bin/python --project ${ + pkgs.writeText "pyrightconfig.json" ( + builtins.toJSON { + reportMissingTypeStubs = false; + reportUnnecessaryTypeIgnoreComment = false; + } + ) + }"; + files = "\\.py$"; + types = [ "file" ]; + }; + ruff.enable = true; + ruff-format.enable = true; + commitizen.enable = true; + }; + }; in { + packages = forAllSystems ( + system: + let + pythonSet = pythonSets.${system}; + pkgs = nixpkgs.legacyPackages.${system}; + inherit (pkgs.callPackages pyproject-nix.build.util { }) mkApplication; + in + rec { + streamd = mkApplication { + venv = pythonSet.mkVirtualEnv "streamd-env" workspace.deps.default; + package = pythonSet.streamd; + }; + default = streamd; + } + ); + homeManagerModules.default = { lib, @@ -93,176 +158,78 @@ ... }: let - cfg = config.programs.streamer; + cfg = config.programs.streamd; in { - options.programs.streamer = { - enable = lib.mkEnableOption "streamer"; + options.programs.streamd = { + enable = lib.mkEnableOption "streamd"; base-folder = lib.mkOption { type = lib.types.str; - description = "Base Folder of Streamer"; + description = "Base Folder of streamd"; }; package = lib.mkOption { type = lib.types.package; - default = self.packages.${pkgs.system}.streamer; - defaultText = lib.literalExpression "inputs.streamer.packages.\${pkgs.system}.streamer"; - description = "The package to use for the streamer binary."; + default = self.packages.${pkgs.system}.streamd; + defaultText = lib.literalExpression "inputs.streamd.packages.\${pkgs.system}.streamd"; + description = "The package to use for the streamd binary."; }; }; config = lib.mkIf cfg.enable { assertions = [ - (lib.hm.assertions.assertPlatform "programs.streamer" pkgs lib.platforms.linux) + (lib.hm.assertions.assertPlatform "programs.streamd" pkgs lib.platforms.linux) ]; home.packages = [ cfg.package ]; - xdg.configFile."streamer/config.yaml".source = - (pkgs.formats.yaml { }).generate "streamer-configuration" + xdg.configFile."streamd/config.yaml".source = + (pkgs.formats.yaml { }).generate "streamd-configuration" { base_folder = cfg.base-folder; }; - home.shellAliases.s = "streamer"; + home.shellAliases.s = "streamd"; }; }; - # Package a virtual environment as our main application. - # - # Enable no optional dependencies for production build. - packages.x86_64-linux = + checks = forAllSystems ( + system: let - streamer = pythonSet.mkVirtualEnv "streamer-env" workspace.deps.default; + pythonSet = pythonSets.${system}; in { - inherit streamer; - default = streamer; - }; + inherit (pythonSet.streamd.passthru.tests) pytest; + pre-commit = mkGitHooksCheck system; + } + ); - # Make streamer runnable with `nix run` - apps.x86_64-linux = { - default = { - type = "app"; - program = "${self.packages.x86_64-linux.default}/bin/streamer"; - }; - }; - - # This example provides two different modes of development: - # - Impurely using uv to manage virtual environments - # - Pure development using uv2nix to manage virtual environments - devShells.x86_64-linux = { - # It is of course perfectly OK to keep using an impure virtualenv workflow and only use uv2nix to build packages. - # This devShell simply adds Python and undoes the dependency leakage done by Nixpkgs Python infrastructure. - impure = pkgs.mkShell { - packages = with pkgs; [ - python - uv - pre-commit - bashInteractive - ]; - env = { - # Prevent uv from managing Python downloads - UV_PYTHON_DOWNLOADS = "never"; - # Force uv to use nixpkgs Python interpreter - UV_PYTHON = python.interpreter; - } - // lib.optionalAttrs pkgs.stdenv.isLinux { - # Python libraries often load native shared objects using dlopen(3). - # Setting LD_LIBRARY_PATH makes the dynamic library loader aware of libraries without using RPATH for lookup. - LD_LIBRARY_PATH = lib.makeLibraryPath pkgs.pythonManylinuxPackages.manylinux1; - }; - shellHook = '' - unset PYTHONPATH - ''; - }; - - # This devShell uses uv2nix to construct a virtual environment purely from Nix, using the same dependency specification as the application. - # The notable difference is that we also apply another overlay here enabling editable mode ( https://setuptools.pypa.io/en/latest/userguide/development_mode.html ). - # - # This means that any changes done to your local files do not require a rebuild. - # - # Note: Editable package support is still unstable and subject to change. - uv2nix = - let - # Create an overlay enabling editable mode for all local dependencies. - editableOverlay = workspace.mkEditablePyprojectOverlay { - # Use environment variable - root = "$REPO_ROOT"; - # Optional: Only enable editable for these packages - # members = [ "streamer" ]; - }; - - # Override previous set with our overrideable overlay. - editablePythonSet = pythonSet.overrideScope ( - lib.composeManyExtensions [ - editableOverlay - - # Apply fixups for building an editable package of your workspace packages - (final: prev: { - streamer = prev.streamer.overrideAttrs (old: { - # It's a good idea to filter the sources going into an editable build - # so the editable package doesn't have to be rebuilt on every change. - src = lib.fileset.toSource { - root = old.src; - fileset = lib.fileset.unions [ - (old.src + "/pyproject.toml") - (old.src + "/README.md") - (old.src + "/src/streamer/__init__.py") - ]; - }; - - # Hatchling (our build system) has a dependency on the `editables` package when building editables. - # - # In normal Python flows this dependency is dynamically handled, and doesn't need to be explicitly declared. - # This behaviour is documented in PEP-660. - # - # With Nix the dependency needs to be explicitly declared. - nativeBuildInputs = - old.nativeBuildInputs - ++ final.resolveBuildSystem { - editables = [ ]; - }; - }); - - }) - ] - ); - - # Build virtual environment, with local packages being editable. - # - # Enable all optional dependencies for development. - virtualenv = editablePythonSet.mkVirtualEnv "streamer-dev-env" workspace.deps.all; - - in - pkgs.mkShell { - packages = with pkgs; [ + devShells = forAllSystems ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + pythonSet = pythonSets.${system}.overrideScope editableOverlay; + virtualenv = pythonSet.mkVirtualEnv "streamd-dev-env" workspace.deps.all; + in + { + default = pkgs.mkShell { + packages = [ virtualenv - uv - pre-commit - bashInteractive + pkgs.uv ]; - env = { - # Don't create venv using uv UV_NO_SYNC = "1"; - - # Force uv to use Python interpreter from venv - UV_PYTHON = "${virtualenv}/bin/python"; - - # Prevent uv from downloading managed Python's + UV_PYTHON = pythonSet.python.interpreter; UV_PYTHON_DOWNLOADS = "never"; }; - shellHook = '' - # Undo dependency propagation by nixpkgs. unset PYTHONPATH - - # Get repository root using git. This is expanded at runtime by the editable `.pth` machinery. export REPO_ROOT=$(git rev-parse --show-toplevel) + ${(mkGitHooksCheck system).shellHook} ''; }; - }; + } + ); }; } From ce5e476b2326643f5d963aa11b058df48ca1e2c8 Mon Sep 17 00:00:00 2001 From: Konstantin Fickel Date: Sun, 15 Feb 2026 17:31:18 +0100 Subject: [PATCH 10/28] ci: split workflow into check and build jobs --- .forgejo/workflows/ci.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 7fcb54b..6ce781f 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -5,7 +5,7 @@ on: workflow_dispatch: jobs: - build-and-lint: + check: name: Lint, Check & Test runs-on: nix @@ -16,8 +16,12 @@ jobs: - run: nix --version - run: nix flake check - - name: Install the project - run: 'nix develop .#impure --command bash -c "uv sync --locked --all-extras --dev"' + build: + name: Build Package + runs-on: nix - - name: Test with PyTest - run: nix develop .#impure --command bash -c "uv run pytest --junit-xml test-report.xml" + steps: + - name: Check out Repository + uses: https://git.konstantinfickel.de/actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - run: nix build From ca6b5bbd4d872257d3ed53be1e68e0fe3385b256 Mon Sep 17 00:00:00 2001 From: Konstantin Fickel Date: Sun, 15 Feb 2026 17:32:39 +0100 Subject: [PATCH 11/28] fix: include dev deps in basedpyright check environment Use workspace.deps.all instead of workspace.deps.default so that basedpyright can resolve test dependencies like faker. --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 02359db..32093d0 100644 --- a/flake.nix +++ b/flake.nix @@ -108,7 +108,7 @@ let pkgs = nixpkgs.legacyPackages.${system}; pythonSet = pythonSets.${system}; - venv = pythonSet.mkVirtualEnv "streamd-check-env" workspace.deps.default; + venv = pythonSet.mkVirtualEnv "streamd-check-env" workspace.deps.all; in git-hooks.lib.${system}.run { src = ./.; From d89ad8b131a6d89049f871e3297e84ca7d4050a6 Mon Sep 17 00:00:00 2001 From: Konstantin Fickel Date: Sun, 15 Feb 2026 17:33:12 +0100 Subject: [PATCH 12/28] build: add /result to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index ff4088b..5976f3d 100644 --- a/.gitignore +++ b/.gitignore @@ -180,3 +180,5 @@ test-report.xml .devenv .devenv.flake.nix .pre-commit-config.yaml + +result From 20a3e8b43709547c24b17c9da4342fb448a6c3c9 Mon Sep 17 00:00:00 2001 From: Konstantin Fickel Date: Sun, 15 Feb 2026 17:40:17 +0100 Subject: [PATCH 13/28] feat: add streamd logo --- README.md | 2 + streamd.svg | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 285 insertions(+) create mode 100644 streamd.svg diff --git a/README.md b/README.md index 5389e0b..9e5fa28 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # strea.md +![The Strea.md-Logo: A tag on an endless paper roll](./streamd.svg) + 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 diff --git a/streamd.svg b/streamd.svg new file mode 100644 index 0000000..11973db --- /dev/null +++ b/streamd.svg @@ -0,0 +1,283 @@ + + + + + Streamd + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Streamd + + + Konstantin Fickel + + + + + + From 1dc41ecb3ef7fe9d12ef850abea31c87baa3ed1f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 18 Feb 2026 00:07:10 +0000 Subject: [PATCH 14/28] fix(deps): update dependency pydantic-settings to v2.13.0 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4cd209f..21c889e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ dependencies = [ "click==8.3.1", "mistletoe==1.5.1", "pydantic==2.12.5", - "pydantic-settings[yaml]==2.12.0", + "pydantic-settings[yaml]==2.13.0", "rich==14.3.2", "typer==0.23.1", "xdg-base-dirs==6.0.2", diff --git a/uv.lock b/uv.lock index f5999a8..7c49749 100644 --- a/uv.lock +++ b/uv.lock @@ -208,16 +208,16 @@ wheels = [ [[package]] name = "pydantic-settings" -version = "2.12.0" +version = "2.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/a1/ae859ffac5a3338a66b74c5e29e244fd3a3cc483c89feaf9f56c39898d75/pydantic_settings-2.13.0.tar.gz", hash = "sha256:95d875514610e8595672800a5c40b073e99e4aae467fa7c8f9c263061ea2e1fe", size = 222450, upload-time = "2026-02-15T12:11:23.476Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1a/dd1b9d7e627486cf8e7523d09b70010e05a4bc41414f4ae6ce184cf0afb6/pydantic_settings-2.13.0-py3-none-any.whl", hash = "sha256:d67b576fff39cd086b595441bf9c75d4193ca9c0ed643b90360694d0f1240246", size = 58429, upload-time = "2026-02-15T12:11:22.133Z" }, ] [package.optional-dependencies] @@ -369,7 +369,7 @@ requires-dist = [ { name = "click", specifier = "==8.3.1" }, { name = "mistletoe", specifier = "==1.5.1" }, { name = "pydantic", specifier = "==2.12.5" }, - { name = "pydantic-settings", extras = ["yaml"], specifier = "==2.12.0" }, + { name = "pydantic-settings", extras = ["yaml"], specifier = "==2.13.0" }, { name = "rich", specifier = "==14.3.2" }, { name = "typer", specifier = "==0.23.1" }, { name = "xdg-base-dirs", specifier = "==6.0.2" }, From 47a972719836a5d1d99a42f32b17897c9a514a79 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 18 Feb 2026 00:06:40 +0000 Subject: [PATCH 15/28] chore(deps): update python docker tag to v3.14 --- .python-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.python-version b/.python-version index 24ee5b1..6324d40 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.13 +3.14 From ad751696cb8bde0f9b6f0e3d7642a07d6c5bf702 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 18 Feb 2026 00:07:18 +0000 Subject: [PATCH 16/28] fix(deps): update dependency typer to v0.24.0 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 21c889e..7ce2d40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ dependencies = [ "pydantic==2.12.5", "pydantic-settings[yaml]==2.13.0", "rich==14.3.2", - "typer==0.23.1", + "typer==0.24.0", "xdg-base-dirs==6.0.2", ] diff --git a/uv.lock b/uv.lock index 7c49749..6ceb3e8 100644 --- a/uv.lock +++ b/uv.lock @@ -371,7 +371,7 @@ requires-dist = [ { name = "pydantic", specifier = "==2.12.5" }, { name = "pydantic-settings", extras = ["yaml"], specifier = "==2.13.0" }, { name = "rich", specifier = "==14.3.2" }, - { name = "typer", specifier = "==0.23.1" }, + { name = "typer", specifier = "==0.24.0" }, { name = "xdg-base-dirs", specifier = "==6.0.2" }, ] @@ -385,7 +385,7 @@ dev = [ [[package]] name = "typer" -version = "0.23.1" +version = "0.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -393,9 +393,9 @@ dependencies = [ { name = "rich" }, { name = "shellingham" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fd/07/b822e1b307d40e263e8253d2384cf98c51aa2368cc7ba9a07e523a1d964b/typer-0.23.1.tar.gz", hash = "sha256:2070374e4d31c83e7b61362fd859aa683576432fd5b026b060ad6b4cd3b86134", size = 120047, upload-time = "2026-02-13T10:04:30.984Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b6/3e681d3b6bb22647509bdbfdd18055d5adc0dce5c5585359fa46ff805fdc/typer-0.24.0.tar.gz", hash = "sha256:f9373dc4eff901350694f519f783c29b6d7a110fc0dcc11b1d7e353b85ca6504", size = 118380, upload-time = "2026-02-16T22:08:48.496Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/91/9b286ab899c008c2cb05e8be99814807e7fbbd33f0c0c960470826e5ac82/typer-0.23.1-py3-none-any.whl", hash = "sha256:3291ad0d3c701cbf522012faccfbb29352ff16ad262db2139e6b01f15781f14e", size = 56813, upload-time = "2026-02-13T10:04:32.008Z" }, + { url = "https://files.pythonhosted.org/packages/85/d0/4da85c2a45054bb661993c93524138ace4956cb075a7ae0c9d1deadc331b/typer-0.24.0-py3-none-any.whl", hash = "sha256:5fc435a9c8356f6160ed6e85a6301fdd6e3d8b2851da502050d1f92c5e9eddc8", size = 56441, upload-time = "2026-02-16T22:08:47.535Z" }, ] [[package]] From bfb9b78ef5c25ef970cab4d12c851209f670ce06 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 19 Feb 2026 00:05:21 +0000 Subject: [PATCH 17/28] chore(deps): update dependency basedpyright to v1.38.1 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7ce2d40..e1580bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ build-backend = "hatchling.build" [dependency-groups] dev = [ - "basedpyright==1.38.0", + "basedpyright==1.38.1", "faker==40.4.0", "pytest==9.0.2", "ruff==0.15.1", diff --git a/uv.lock b/uv.lock index 6ceb3e8..3d66b36 100644 --- a/uv.lock +++ b/uv.lock @@ -22,14 +22,14 @@ wheels = [ [[package]] name = "basedpyright" -version = "1.38.0" +version = "1.38.1" 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" } +sdist = { url = "https://files.pythonhosted.org/packages/17/ea/4d45e3c66c609496f3069a7c9e5fbd1f9ba54097c41b89048af0d8021ea6/basedpyright-1.38.1.tar.gz", hash = "sha256:e4876aa3ef7c76569ffdcd908d4e260b8d1a1deaa8838f2486f91a10b60d68d6", size = 25267403, upload-time = "2026-02-18T09:20:45.563Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/28/92/42f4dc30a28c052a70c939d8dbb34102674b48c89369010442038d3c888b/basedpyright-1.38.1-py3-none-any.whl", hash = "sha256:24f21661d2754687b64f3bc35efcc78781e11b08c8b2310312ed92bf178ea627", size = 12311610, upload-time = "2026-02-18T09:20:50.09Z" }, ] [[package]] @@ -377,7 +377,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "basedpyright", specifier = "==1.38.0" }, + { name = "basedpyright", specifier = "==1.38.1" }, { name = "faker", specifier = "==40.4.0" }, { name = "pytest", specifier = "==9.0.2" }, { name = "ruff", specifier = "==0.15.1" }, From ea42b31a1e3cb449c715ba3c677b66d343570319 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 20 Feb 2026 00:07:01 +0000 Subject: [PATCH 18/28] fix(deps): update dependency pydantic-settings to v2.13.1 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e1580bb..338af55 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ dependencies = [ "click==8.3.1", "mistletoe==1.5.1", "pydantic==2.12.5", - "pydantic-settings[yaml]==2.13.0", + "pydantic-settings[yaml]==2.13.1", "rich==14.3.2", "typer==0.24.0", "xdg-base-dirs==6.0.2", diff --git a/uv.lock b/uv.lock index 3d66b36..48d68b0 100644 --- a/uv.lock +++ b/uv.lock @@ -208,16 +208,16 @@ wheels = [ [[package]] name = "pydantic-settings" -version = "2.13.0" +version = "2.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/a1/ae859ffac5a3338a66b74c5e29e244fd3a3cc483c89feaf9f56c39898d75/pydantic_settings-2.13.0.tar.gz", hash = "sha256:95d875514610e8595672800a5c40b073e99e4aae467fa7c8f9c263061ea2e1fe", size = 222450, upload-time = "2026-02-15T12:11:23.476Z" } +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/fffca34caecc4a3f97bda81b2098da5e8ab7efc9a66e819074a11955d87e/pydantic_settings-2.13.1.tar.gz", hash = "sha256:b4c11847b15237fb0171e1462bf540e294affb9b86db4d9aa5c01730bdbe4025", size = 223826, upload-time = "2026-02-19T13:45:08.055Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/1a/dd1b9d7e627486cf8e7523d09b70010e05a4bc41414f4ae6ce184cf0afb6/pydantic_settings-2.13.0-py3-none-any.whl", hash = "sha256:d67b576fff39cd086b595441bf9c75d4193ca9c0ed643b90360694d0f1240246", size = 58429, upload-time = "2026-02-15T12:11:22.133Z" }, + { url = "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl", hash = "sha256:d56fd801823dbeae7f0975e1f8c8e25c258eb75d278ea7abb5d9cebb01b56237", size = 58929, upload-time = "2026-02-19T13:45:06.034Z" }, ] [package.optional-dependencies] @@ -369,7 +369,7 @@ requires-dist = [ { name = "click", specifier = "==8.3.1" }, { name = "mistletoe", specifier = "==1.5.1" }, { name = "pydantic", specifier = "==2.12.5" }, - { name = "pydantic-settings", extras = ["yaml"], specifier = "==2.13.0" }, + { name = "pydantic-settings", extras = ["yaml"], specifier = "==2.13.1" }, { name = "rich", specifier = "==14.3.2" }, { name = "typer", specifier = "==0.24.0" }, { name = "xdg-base-dirs", specifier = "==6.0.2" }, From 49fb18d34206fc47a6d856e46f2977e667c8cf7f Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 20 Feb 2026 00:06:49 +0000 Subject: [PATCH 19/28] chore(deps): update dependency ruff to v0.15.2 --- pyproject.toml | 2 +- uv.lock | 40 ++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 338af55..495c3bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,5 +26,5 @@ dev = [ "basedpyright==1.38.1", "faker==40.4.0", "pytest==9.0.2", - "ruff==0.15.1", + "ruff==0.15.2", ] diff --git a/uv.lock b/uv.lock index 48d68b0..3cc4d7b 100644 --- a/uv.lock +++ b/uv.lock @@ -310,27 +310,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.1" +version = "0.15.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/dc/4e6ac71b511b141cf626357a3946679abeba4cf67bc7cc5a17920f31e10d/ruff-0.15.1.tar.gz", hash = "sha256:c590fe13fb57c97141ae975c03a1aedb3d3156030cabd740d6ff0b0d601e203f", size = 4540855, upload-time = "2026-02-12T23:09:09.998Z" } +sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/bf/e6e4324238c17f9d9120a9d60aa99a7daaa21204c07fcd84e2ef03bb5fd1/ruff-0.15.1-py3-none-linux_armv6l.whl", hash = "sha256:b101ed7cf4615bda6ffe65bdb59f964e9f4a0d3f85cbf0e54f0ab76d7b90228a", size = 10367819, upload-time = "2026-02-12T23:09:03.598Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ea/c8f89d32e7912269d38c58f3649e453ac32c528f93bb7f4219258be2e7ed/ruff-0.15.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:939c995e9277e63ea632cc8d3fae17aa758526f49a9a850d2e7e758bfef46602", size = 10798618, upload-time = "2026-02-12T23:09:22.928Z" }, - { url = "https://files.pythonhosted.org/packages/5e/0f/1d0d88bc862624247d82c20c10d4c0f6bb2f346559d8af281674cf327f15/ruff-0.15.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d83466455fdefe60b8d9c8df81d3c1bbb2115cede53549d3b522ce2bc703899", size = 10148518, upload-time = "2026-02-12T23:08:58.339Z" }, - { url = "https://files.pythonhosted.org/packages/f5/c8/291c49cefaa4a9248e986256df2ade7add79388fe179e0691be06fae6f37/ruff-0.15.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9457e3c3291024866222b96108ab2d8265b477e5b1534c7ddb1810904858d16", size = 10518811, upload-time = "2026-02-12T23:09:31.865Z" }, - { url = "https://files.pythonhosted.org/packages/c3/1a/f5707440e5ae43ffa5365cac8bbb91e9665f4a883f560893829cf16a606b/ruff-0.15.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92c92b003e9d4f7fbd33b1867bb15a1b785b1735069108dfc23821ba045b29bc", size = 10196169, upload-time = "2026-02-12T23:09:17.306Z" }, - { url = "https://files.pythonhosted.org/packages/2a/ff/26ddc8c4da04c8fd3ee65a89c9fb99eaa5c30394269d424461467be2271f/ruff-0.15.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fe5c41ab43e3a06778844c586251eb5a510f67125427625f9eb2b9526535779", size = 10990491, upload-time = "2026-02-12T23:09:25.503Z" }, - { url = "https://files.pythonhosted.org/packages/fc/00/50920cb385b89413f7cdb4bb9bc8fc59c1b0f30028d8bccc294189a54955/ruff-0.15.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66a6dd6df4d80dc382c6484f8ce1bcceb55c32e9f27a8b94c32f6c7331bf14fb", size = 11843280, upload-time = "2026-02-12T23:09:19.88Z" }, - { url = "https://files.pythonhosted.org/packages/5d/6d/2f5cad8380caf5632a15460c323ae326f1e1a2b5b90a6ee7519017a017ca/ruff-0.15.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a4a42cbb8af0bda9bcd7606b064d7c0bc311a88d141d02f78920be6acb5aa83", size = 11274336, upload-time = "2026-02-12T23:09:14.907Z" }, - { url = "https://files.pythonhosted.org/packages/a3/1d/5f56cae1d6c40b8a318513599b35ea4b075d7dc1cd1d04449578c29d1d75/ruff-0.15.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ab064052c31dddada35079901592dfba2e05f5b1e43af3954aafcbc1096a5b2", size = 11137288, upload-time = "2026-02-12T23:09:07.475Z" }, - { url = "https://files.pythonhosted.org/packages/cd/20/6f8d7d8f768c93b0382b33b9306b3b999918816da46537d5a61635514635/ruff-0.15.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:5631c940fe9fe91f817a4c2ea4e81f47bee3ca4aa646134a24374f3c19ad9454", size = 11070681, upload-time = "2026-02-12T23:08:55.43Z" }, - { url = "https://files.pythonhosted.org/packages/9a/67/d640ac76069f64cdea59dba02af2e00b1fa30e2103c7f8d049c0cff4cafd/ruff-0.15.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:68138a4ba184b4691ccdc39f7795c66b3c68160c586519e7e8444cf5a53e1b4c", size = 10486401, upload-time = "2026-02-12T23:09:27.927Z" }, - { url = "https://files.pythonhosted.org/packages/65/3d/e1429f64a3ff89297497916b88c32a5cc88eeca7e9c787072d0e7f1d3e1e/ruff-0.15.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:518f9af03bfc33c03bdb4cb63fabc935341bb7f54af500f92ac309ecfbba6330", size = 10197452, upload-time = "2026-02-12T23:09:12.147Z" }, - { url = "https://files.pythonhosted.org/packages/78/83/e2c3bade17dad63bf1e1c2ffaf11490603b760be149e1419b07049b36ef2/ruff-0.15.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:da79f4d6a826caaea95de0237a67e33b81e6ec2e25fc7e1993a4015dffca7c61", size = 10693900, upload-time = "2026-02-12T23:09:34.418Z" }, - { url = "https://files.pythonhosted.org/packages/a1/27/fdc0e11a813e6338e0706e8b39bb7a1d61ea5b36873b351acee7e524a72a/ruff-0.15.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3dd86dccb83cd7d4dcfac303ffc277e6048600dfc22e38158afa208e8bf94a1f", size = 11227302, upload-time = "2026-02-12T23:09:36.536Z" }, - { url = "https://files.pythonhosted.org/packages/f6/58/ac864a75067dcbd3b95be5ab4eb2b601d7fbc3d3d736a27e391a4f92a5c1/ruff-0.15.1-py3-none-win32.whl", hash = "sha256:660975d9cb49b5d5278b12b03bb9951d554543a90b74ed5d366b20e2c57c2098", size = 10462555, upload-time = "2026-02-12T23:09:29.899Z" }, - { url = "https://files.pythonhosted.org/packages/e0/5e/d4ccc8a27ecdb78116feac4935dfc39d1304536f4296168f91ed3ec00cd2/ruff-0.15.1-py3-none-win_amd64.whl", hash = "sha256:c820fef9dd5d4172a6570e5721704a96c6679b80cf7be41659ed439653f62336", size = 11599956, upload-time = "2026-02-12T23:09:01.157Z" }, - { url = "https://files.pythonhosted.org/packages/2a/07/5bda6a85b220c64c65686bc85bd0bbb23b29c62b3a9f9433fa55f17cda93/ruff-0.15.1-py3-none-win_arm64.whl", hash = "sha256:5ff7d5f0f88567850f45081fac8f4ec212be8d0b963e385c3f7d0d2eb4899416", size = 10874604, upload-time = "2026-02-12T23:09:05.515Z" }, + { url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" }, + { url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" }, + { url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" }, + { url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" }, + { url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" }, + { url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" }, + { url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" }, + { url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" }, + { url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" }, + { url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" }, + { url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" }, + { url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" }, + { url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" }, + { url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" }, ] [[package]] @@ -380,7 +380,7 @@ dev = [ { name = "basedpyright", specifier = "==1.38.1" }, { name = "faker", specifier = "==40.4.0" }, { name = "pytest", specifier = "==9.0.2" }, - { name = "ruff", specifier = "==0.15.1" }, + { name = "ruff", specifier = "==0.15.2" }, ] [[package]] From 0ed680f0b1dacc8ba2508965aa0d0ead847e690e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 20 Feb 2026 15:53:52 +0000 Subject: [PATCH 20/28] fix(deps): update dependency rich to v14.3.3 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 495c3bd..e7cee9f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ dependencies = [ "mistletoe==1.5.1", "pydantic==2.12.5", "pydantic-settings[yaml]==2.13.1", - "rich==14.3.2", + "rich==14.3.3", "typer==0.24.0", "xdg-base-dirs==6.0.2", ] diff --git a/uv.lock b/uv.lock index 3cc4d7b..1aa1a8d 100644 --- a/uv.lock +++ b/uv.lock @@ -297,15 +297,15 @@ wheels = [ [[package]] name = "rich" -version = "14.3.2" +version = "14.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/74/99/a4cab2acbb884f80e558b0771e97e21e939c5dfb460f488d19df485e8298/rich-14.3.2.tar.gz", hash = "sha256:e712f11c1a562a11843306f5ed999475f09ac31ffb64281f73ab29ffdda8b3b8", size = 230143, upload-time = "2026-02-01T16:20:47.908Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl", hash = "sha256:08e67c3e90884651da3239ea668222d19bea7b589149d8014a21c633420dbb69", size = 309963, upload-time = "2026-02-01T16:20:46.078Z" }, + { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" }, ] [[package]] @@ -370,7 +370,7 @@ requires-dist = [ { name = "mistletoe", specifier = "==1.5.1" }, { name = "pydantic", specifier = "==2.12.5" }, { name = "pydantic-settings", extras = ["yaml"], specifier = "==2.13.1" }, - { name = "rich", specifier = "==14.3.2" }, + { name = "rich", specifier = "==14.3.3" }, { name = "typer", specifier = "==0.24.0" }, { name = "xdg-base-dirs", specifier = "==6.0.2" }, ] From 51ee07dbbe03bcd5dcd1bb059eb690b39d901b50 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 22 Feb 2026 00:05:21 +0000 Subject: [PATCH 21/28] fix(deps): update dependency typer to v0.24.1 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e7cee9f..508c2e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ dependencies = [ "pydantic==2.12.5", "pydantic-settings[yaml]==2.13.1", "rich==14.3.3", - "typer==0.24.0", + "typer==0.24.1", "xdg-base-dirs==6.0.2", ] diff --git a/uv.lock b/uv.lock index 1aa1a8d..0d04148 100644 --- a/uv.lock +++ b/uv.lock @@ -371,7 +371,7 @@ requires-dist = [ { name = "pydantic", specifier = "==2.12.5" }, { name = "pydantic-settings", extras = ["yaml"], specifier = "==2.13.1" }, { name = "rich", specifier = "==14.3.3" }, - { name = "typer", specifier = "==0.24.0" }, + { name = "typer", specifier = "==0.24.1" }, { name = "xdg-base-dirs", specifier = "==6.0.2" }, ] @@ -385,7 +385,7 @@ dev = [ [[package]] name = "typer" -version = "0.24.0" +version = "0.24.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -393,9 +393,9 @@ dependencies = [ { name = "rich" }, { name = "shellingham" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5a/b6/3e681d3b6bb22647509bdbfdd18055d5adc0dce5c5585359fa46ff805fdc/typer-0.24.0.tar.gz", hash = "sha256:f9373dc4eff901350694f519f783c29b6d7a110fc0dcc11b1d7e353b85ca6504", size = 118380, upload-time = "2026-02-16T22:08:48.496Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/24/cb09efec5cc954f7f9b930bf8279447d24618bb6758d4f6adf2574c41780/typer-0.24.1.tar.gz", hash = "sha256:e39b4732d65fbdcde189ae76cf7cd48aeae72919dea1fdfc16593be016256b45", size = 118613, upload-time = "2026-02-21T16:54:40.609Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/85/d0/4da85c2a45054bb661993c93524138ace4956cb075a7ae0c9d1deadc331b/typer-0.24.0-py3-none-any.whl", hash = "sha256:5fc435a9c8356f6160ed6e85a6301fdd6e3d8b2851da502050d1f92c5e9eddc8", size = 56441, upload-time = "2026-02-16T22:08:47.535Z" }, + { url = "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl", hash = "sha256:112c1f0ce578bfb4cab9ffdabc68f031416ebcc216536611ba21f04e9aa84c9e", size = 56085, upload-time = "2026-02-21T16:54:41.616Z" }, ] [[package]] From 2c26f4ce567328890176b4f79cb882ca905a682e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 24 Feb 2026 00:03:44 +0000 Subject: [PATCH 22/28] chore(deps): update dependency faker to v40.5.1 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 508c2e4..97fb7f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ build-backend = "hatchling.build" [dependency-groups] dev = [ "basedpyright==1.38.1", - "faker==40.4.0", + "faker==40.5.1", "pytest==9.0.2", "ruff==0.15.2", ] diff --git a/uv.lock b/uv.lock index 0d04148..101a28c 100644 --- a/uv.lock +++ b/uv.lock @@ -55,14 +55,14 @@ wheels = [ [[package]] name = "faker" -version = "40.4.0" +version = "40.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/7e/dccb7013c9f3d66f2e379383600629fec75e4da2698548bdbf2041ea4b51/faker-40.4.0.tar.gz", hash = "sha256:76f8e74a3df28c3e2ec2caafa956e19e37a132fdc7ea067bc41783affcfee364", size = 1952221, upload-time = "2026-02-06T23:30:15.515Z" } +sdist = { url = "https://files.pythonhosted.org/packages/03/2a/96fff3edcb10f6505143448a4b91535f77b74865cec45be52690ee280443/faker-40.5.1.tar.gz", hash = "sha256:70222361cd82aa10cb86066d1a4e8f47f2bcdc919615c412045a69c4e6da0cd3", size = 1952684, upload-time = "2026-02-23T21:34:38.362Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/63/58efa67c10fb27810d34351b7a10f85f109a7f7e2a07dc3773952459c47b/faker-40.4.0-py3-none-any.whl", hash = "sha256:486d43c67ebbb136bc932406418744f9a0bdf2c07f77703ea78b58b77e9aa443", size = 1987060, upload-time = "2026-02-06T23:30:13.44Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a9/1eed4db92d0aec2f9bfdf1faae0ab0418b5e121dda5701f118a7a4f0cd6a/faker-40.5.1-py3-none-any.whl", hash = "sha256:c69640c1e13bad49b4bcebcbf1b52f9f1a872b6ea186c248ada34d798f1661bf", size = 1987053, upload-time = "2026-02-23T21:34:36.418Z" }, ] [[package]] @@ -378,7 +378,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "basedpyright", specifier = "==1.38.1" }, - { name = "faker", specifier = "==40.4.0" }, + { name = "faker", specifier = "==40.5.1" }, { name = "pytest", specifier = "==9.0.2" }, { name = "ruff", specifier = "==0.15.2" }, ] From bb02dd715b2d3c2df55bfc072bfe7e6e040e315e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 27 Feb 2026 00:05:47 +0000 Subject: [PATCH 23/28] chore(deps): update dependency ruff to v0.15.4 --- pyproject.toml | 2 +- uv.lock | 40 ++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 97fb7f8..d39e93c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,5 +26,5 @@ dev = [ "basedpyright==1.38.1", "faker==40.5.1", "pytest==9.0.2", - "ruff==0.15.2", + "ruff==0.15.4", ] diff --git a/uv.lock b/uv.lock index 101a28c..4274eb4 100644 --- a/uv.lock +++ b/uv.lock @@ -310,27 +310,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.2" +version = "0.15.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/31/d6e536cdebb6568ae75a7f00e4b4819ae0ad2640c3604c305a0428680b0c/ruff-0.15.4.tar.gz", hash = "sha256:3412195319e42d634470cc97aa9803d07e9d5c9223b99bcb1518f0c725f26ae1", size = 4569550, upload-time = "2026-02-26T20:04:14.959Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" }, - { url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" }, - { url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" }, - { url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" }, - { url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" }, - { url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" }, - { url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" }, - { url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" }, - { url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" }, - { url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" }, - { url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" }, - { url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" }, - { url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" }, - { url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" }, + { url = "https://files.pythonhosted.org/packages/f2/82/c11a03cfec3a4d26a0ea1e571f0f44be5993b923f905eeddfc397c13d360/ruff-0.15.4-py3-none-linux_armv6l.whl", hash = "sha256:a1810931c41606c686bae8b5b9a8072adac2f611bb433c0ba476acba17a332e0", size = 10453333, upload-time = "2026-02-26T20:04:20.093Z" }, + { url = "https://files.pythonhosted.org/packages/ce/5d/6a1f271f6e31dffb31855996493641edc3eef8077b883eaf007a2f1c2976/ruff-0.15.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5a1632c66672b8b4d3e1d1782859e98d6e0b4e70829530666644286600a33992", size = 10853356, upload-time = "2026-02-26T20:04:05.808Z" }, + { url = "https://files.pythonhosted.org/packages/b1/d8/0fab9f8842b83b1a9c2bf81b85063f65e93fb512e60effa95b0be49bfc54/ruff-0.15.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a4386ba2cd6c0f4ff75252845906acc7c7c8e1ac567b7bc3d373686ac8c222ba", size = 10187434, upload-time = "2026-02-26T20:03:54.656Z" }, + { url = "https://files.pythonhosted.org/packages/85/cc/cc220fd9394eff5db8d94dec199eec56dd6c9f3651d8869d024867a91030/ruff-0.15.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2496488bdfd3732747558b6f95ae427ff066d1fcd054daf75f5a50674411e75", size = 10535456, upload-time = "2026-02-26T20:03:52.738Z" }, + { url = "https://files.pythonhosted.org/packages/fa/0f/bced38fa5cf24373ec767713c8e4cadc90247f3863605fb030e597878661/ruff-0.15.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3f1c4893841ff2d54cbda1b2860fa3260173df5ddd7b95d370186f8a5e66a4ac", size = 10287772, upload-time = "2026-02-26T20:04:08.138Z" }, + { url = "https://files.pythonhosted.org/packages/2b/90/58a1802d84fed15f8f281925b21ab3cecd813bde52a8ca033a4de8ab0e7a/ruff-0.15.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:820b8766bd65503b6c30aaa6331e8ef3a6e564f7999c844e9a547c40179e440a", size = 11049051, upload-time = "2026-02-26T20:04:03.53Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ac/b7ad36703c35f3866584564dc15f12f91cb1a26a897dc2fd13d7cb3ae1af/ruff-0.15.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9fb74bab47139c1751f900f857fa503987253c3ef89129b24ed375e72873e85", size = 11890494, upload-time = "2026-02-26T20:04:10.497Z" }, + { url = "https://files.pythonhosted.org/packages/93/3d/3eb2f47a39a8b0da99faf9c54d3eb24720add1e886a5309d4d1be73a6380/ruff-0.15.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80c98765949c518142b3a50a5db89343aa90f2c2bf7799de9986498ae6176db", size = 11326221, upload-time = "2026-02-26T20:04:12.84Z" }, + { url = "https://files.pythonhosted.org/packages/ff/90/bf134f4c1e5243e62690e09d63c55df948a74084c8ac3e48a88468314da6/ruff-0.15.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451a2e224151729b3b6c9ffb36aed9091b2996fe4bdbd11f47e27d8f2e8888ec", size = 11168459, upload-time = "2026-02-26T20:04:00.969Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e5/a64d27688789b06b5d55162aafc32059bb8c989c61a5139a36e1368285eb/ruff-0.15.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a8f157f2e583c513c4f5f896163a93198297371f34c04220daf40d133fdd4f7f", size = 11104366, upload-time = "2026-02-26T20:03:48.099Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f6/32d1dcb66a2559763fc3027bdd65836cad9eb09d90f2ed6a63d8e9252b02/ruff-0.15.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:917cc68503357021f541e69b35361c99387cdbbf99bd0ea4aa6f28ca99ff5338", size = 10510887, upload-time = "2026-02-26T20:03:45.771Z" }, + { url = "https://files.pythonhosted.org/packages/ff/92/22d1ced50971c5b6433aed166fcef8c9343f567a94cf2b9d9089f6aa80fe/ruff-0.15.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e9737c8161da79fd7cfec19f1e35620375bd8b2a50c3e77fa3d2c16f574105cc", size = 10285939, upload-time = "2026-02-26T20:04:22.42Z" }, + { url = "https://files.pythonhosted.org/packages/e6/f4/7c20aec3143837641a02509a4668fb146a642fd1211846634edc17eb5563/ruff-0.15.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:291258c917539e18f6ba40482fe31d6f5ac023994ee11d7bdafd716f2aab8a68", size = 10765471, upload-time = "2026-02-26T20:03:58.924Z" }, + { url = "https://files.pythonhosted.org/packages/d0/09/6d2f7586f09a16120aebdff8f64d962d7c4348313c77ebb29c566cefc357/ruff-0.15.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3f83c45911da6f2cd5936c436cf86b9f09f09165f033a99dcf7477e34041cbc3", size = 11263382, upload-time = "2026-02-26T20:04:24.424Z" }, + { url = "https://files.pythonhosted.org/packages/1b/fa/2ef715a1cd329ef47c1a050e10dee91a9054b7ce2fcfdd6a06d139afb7ec/ruff-0.15.4-py3-none-win32.whl", hash = "sha256:65594a2d557d4ee9f02834fcdf0a28daa8b3b9f6cb2cb93846025a36db47ef22", size = 10506664, upload-time = "2026-02-26T20:03:50.56Z" }, + { url = "https://files.pythonhosted.org/packages/d0/a8/c688ef7e29983976820d18710f955751d9f4d4eb69df658af3d006e2ba3e/ruff-0.15.4-py3-none-win_amd64.whl", hash = "sha256:04196ad44f0df220c2ece5b0e959c2f37c777375ec744397d21d15b50a75264f", size = 11651048, upload-time = "2026-02-26T20:04:17.191Z" }, + { url = "https://files.pythonhosted.org/packages/3e/0a/9e1be9035b37448ce2e68c978f0591da94389ade5a5abafa4cf99985d1b2/ruff-0.15.4-py3-none-win_arm64.whl", hash = "sha256:60d5177e8cfc70e51b9c5fad936c634872a74209f934c1e79107d11787ad5453", size = 10966776, upload-time = "2026-02-26T20:03:56.908Z" }, ] [[package]] @@ -380,7 +380,7 @@ dev = [ { name = "basedpyright", specifier = "==1.38.1" }, { name = "faker", specifier = "==40.5.1" }, { name = "pytest", specifier = "==9.0.2" }, - { name = "ruff", specifier = "==0.15.2" }, + { name = "ruff", specifier = "==0.15.4" }, ] [[package]] From 5132814a773b511bf3adb079cff2025bdc5be68d Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 27 Feb 2026 00:05:41 +0000 Subject: [PATCH 24/28] chore(deps): update dependency basedpyright to v1.38.2 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d39e93c..c6b0433 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ build-backend = "hatchling.build" [dependency-groups] dev = [ - "basedpyright==1.38.1", + "basedpyright==1.38.2", "faker==40.5.1", "pytest==9.0.2", "ruff==0.15.4", diff --git a/uv.lock b/uv.lock index 4274eb4..2d0131c 100644 --- a/uv.lock +++ b/uv.lock @@ -22,14 +22,14 @@ wheels = [ [[package]] name = "basedpyright" -version = "1.38.1" +version = "1.38.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nodejs-wheel-binaries" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/ea/4d45e3c66c609496f3069a7c9e5fbd1f9ba54097c41b89048af0d8021ea6/basedpyright-1.38.1.tar.gz", hash = "sha256:e4876aa3ef7c76569ffdcd908d4e260b8d1a1deaa8838f2486f91a10b60d68d6", size = 25267403, upload-time = "2026-02-18T09:20:45.563Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/a3/20aa7c4e83f2f614e0036300f3c352775dede0655c66814da16c37b661a9/basedpyright-1.38.2.tar.gz", hash = "sha256:b433b2b8ba745ed7520cdc79a29a03682f3fb00346d272ece5944e9e5e5daa92", size = 25277019, upload-time = "2026-02-26T11:18:43.594Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/92/42f4dc30a28c052a70c939d8dbb34102674b48c89369010442038d3c888b/basedpyright-1.38.1-py3-none-any.whl", hash = "sha256:24f21661d2754687b64f3bc35efcc78781e11b08c8b2310312ed92bf178ea627", size = 12311610, upload-time = "2026-02-18T09:20:50.09Z" }, + { url = "https://files.pythonhosted.org/packages/ac/12/736cab83626fea3fe65cdafb3ef3d2ee9480c56723f2fd33921537289a5e/basedpyright-1.38.2-py3-none-any.whl", hash = "sha256:153481d37fd19f9e3adedc8629d1d071b10c5f5e49321fb026b74444b7c70e24", size = 12312475, upload-time = "2026-02-26T11:18:40.373Z" }, ] [[package]] @@ -377,7 +377,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "basedpyright", specifier = "==1.38.1" }, + { name = "basedpyright", specifier = "==1.38.2" }, { name = "faker", specifier = "==40.5.1" }, { name = "pytest", specifier = "==9.0.2" }, { name = "ruff", specifier = "==0.15.4" }, From 42177b94bd0ede6b627610eb77dd680fe7fb2cbe Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 5 Mar 2026 00:05:33 +0000 Subject: [PATCH 25/28] chore(deps): update dependency faker to v40.8.0 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c6b0433..e29e80b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ build-backend = "hatchling.build" [dependency-groups] dev = [ "basedpyright==1.38.2", - "faker==40.5.1", + "faker==40.8.0", "pytest==9.0.2", "ruff==0.15.4", ] diff --git a/uv.lock b/uv.lock index 2d0131c..9dcdf52 100644 --- a/uv.lock +++ b/uv.lock @@ -55,14 +55,14 @@ wheels = [ [[package]] name = "faker" -version = "40.5.1" +version = "40.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/03/2a/96fff3edcb10f6505143448a4b91535f77b74865cec45be52690ee280443/faker-40.5.1.tar.gz", hash = "sha256:70222361cd82aa10cb86066d1a4e8f47f2bcdc919615c412045a69c4e6da0cd3", size = 1952684, upload-time = "2026-02-23T21:34:38.362Z" } +sdist = { url = "https://files.pythonhosted.org/packages/70/03/14428edc541467c460d363f6e94bee9acc271f3e62470630fc9a647d0cf2/faker-40.8.0.tar.gz", hash = "sha256:936a3c9be6c004433f20aa4d99095df5dec82b8c7ad07459756041f8c1728875", size = 1956493, upload-time = "2026-03-04T16:18:48.161Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/a9/1eed4db92d0aec2f9bfdf1faae0ab0418b5e121dda5701f118a7a4f0cd6a/faker-40.5.1-py3-none-any.whl", hash = "sha256:c69640c1e13bad49b4bcebcbf1b52f9f1a872b6ea186c248ada34d798f1661bf", size = 1987053, upload-time = "2026-02-23T21:34:36.418Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3b/c6348f1e285e75b069085b18110a4e6325b763a5d35d5e204356fc7c20b3/faker-40.8.0-py3-none-any.whl", hash = "sha256:eb21bdba18f7a8375382eb94fb436fce07046893dc94cb20817d28deb0c3d579", size = 1989124, upload-time = "2026-03-04T16:18:46.45Z" }, ] [[package]] @@ -378,7 +378,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "basedpyright", specifier = "==1.38.2" }, - { name = "faker", specifier = "==40.5.1" }, + { name = "faker", specifier = "==40.8.0" }, { name = "pytest", specifier = "==9.0.2" }, { name = "ruff", specifier = "==0.15.4" }, ] From 1fb1ea161560db51ac29929b9189ced549ee73a0 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 6 Mar 2026 00:06:05 +0000 Subject: [PATCH 26/28] chore(deps): update dependency ruff to v0.15.5 --- pyproject.toml | 2 +- uv.lock | 40 ++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e29e80b..6f6aa14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,5 +26,5 @@ dev = [ "basedpyright==1.38.2", "faker==40.8.0", "pytest==9.0.2", - "ruff==0.15.4", + "ruff==0.15.5", ] diff --git a/uv.lock b/uv.lock index 9dcdf52..36b28a7 100644 --- a/uv.lock +++ b/uv.lock @@ -310,27 +310,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.4" +version = "0.15.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/31/d6e536cdebb6568ae75a7f00e4b4819ae0ad2640c3604c305a0428680b0c/ruff-0.15.4.tar.gz", hash = "sha256:3412195319e42d634470cc97aa9803d07e9d5c9223b99bcb1518f0c725f26ae1", size = 4569550, upload-time = "2026-02-26T20:04:14.959Z" } +sdist = { url = "https://files.pythonhosted.org/packages/77/9b/840e0039e65fcf12758adf684d2289024d6140cde9268cc59887dc55189c/ruff-0.15.5.tar.gz", hash = "sha256:7c3601d3b6d76dce18c5c824fc8d06f4eef33d6df0c21ec7799510cde0f159a2", size = 4574214, upload-time = "2026-03-05T20:06:34.946Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/82/c11a03cfec3a4d26a0ea1e571f0f44be5993b923f905eeddfc397c13d360/ruff-0.15.4-py3-none-linux_armv6l.whl", hash = "sha256:a1810931c41606c686bae8b5b9a8072adac2f611bb433c0ba476acba17a332e0", size = 10453333, upload-time = "2026-02-26T20:04:20.093Z" }, - { url = "https://files.pythonhosted.org/packages/ce/5d/6a1f271f6e31dffb31855996493641edc3eef8077b883eaf007a2f1c2976/ruff-0.15.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5a1632c66672b8b4d3e1d1782859e98d6e0b4e70829530666644286600a33992", size = 10853356, upload-time = "2026-02-26T20:04:05.808Z" }, - { url = "https://files.pythonhosted.org/packages/b1/d8/0fab9f8842b83b1a9c2bf81b85063f65e93fb512e60effa95b0be49bfc54/ruff-0.15.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a4386ba2cd6c0f4ff75252845906acc7c7c8e1ac567b7bc3d373686ac8c222ba", size = 10187434, upload-time = "2026-02-26T20:03:54.656Z" }, - { url = "https://files.pythonhosted.org/packages/85/cc/cc220fd9394eff5db8d94dec199eec56dd6c9f3651d8869d024867a91030/ruff-0.15.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2496488bdfd3732747558b6f95ae427ff066d1fcd054daf75f5a50674411e75", size = 10535456, upload-time = "2026-02-26T20:03:52.738Z" }, - { url = "https://files.pythonhosted.org/packages/fa/0f/bced38fa5cf24373ec767713c8e4cadc90247f3863605fb030e597878661/ruff-0.15.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3f1c4893841ff2d54cbda1b2860fa3260173df5ddd7b95d370186f8a5e66a4ac", size = 10287772, upload-time = "2026-02-26T20:04:08.138Z" }, - { url = "https://files.pythonhosted.org/packages/2b/90/58a1802d84fed15f8f281925b21ab3cecd813bde52a8ca033a4de8ab0e7a/ruff-0.15.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:820b8766bd65503b6c30aaa6331e8ef3a6e564f7999c844e9a547c40179e440a", size = 11049051, upload-time = "2026-02-26T20:04:03.53Z" }, - { url = "https://files.pythonhosted.org/packages/d2/ac/b7ad36703c35f3866584564dc15f12f91cb1a26a897dc2fd13d7cb3ae1af/ruff-0.15.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9fb74bab47139c1751f900f857fa503987253c3ef89129b24ed375e72873e85", size = 11890494, upload-time = "2026-02-26T20:04:10.497Z" }, - { url = "https://files.pythonhosted.org/packages/93/3d/3eb2f47a39a8b0da99faf9c54d3eb24720add1e886a5309d4d1be73a6380/ruff-0.15.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80c98765949c518142b3a50a5db89343aa90f2c2bf7799de9986498ae6176db", size = 11326221, upload-time = "2026-02-26T20:04:12.84Z" }, - { url = "https://files.pythonhosted.org/packages/ff/90/bf134f4c1e5243e62690e09d63c55df948a74084c8ac3e48a88468314da6/ruff-0.15.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451a2e224151729b3b6c9ffb36aed9091b2996fe4bdbd11f47e27d8f2e8888ec", size = 11168459, upload-time = "2026-02-26T20:04:00.969Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e5/a64d27688789b06b5d55162aafc32059bb8c989c61a5139a36e1368285eb/ruff-0.15.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a8f157f2e583c513c4f5f896163a93198297371f34c04220daf40d133fdd4f7f", size = 11104366, upload-time = "2026-02-26T20:03:48.099Z" }, - { url = "https://files.pythonhosted.org/packages/f1/f6/32d1dcb66a2559763fc3027bdd65836cad9eb09d90f2ed6a63d8e9252b02/ruff-0.15.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:917cc68503357021f541e69b35361c99387cdbbf99bd0ea4aa6f28ca99ff5338", size = 10510887, upload-time = "2026-02-26T20:03:45.771Z" }, - { url = "https://files.pythonhosted.org/packages/ff/92/22d1ced50971c5b6433aed166fcef8c9343f567a94cf2b9d9089f6aa80fe/ruff-0.15.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e9737c8161da79fd7cfec19f1e35620375bd8b2a50c3e77fa3d2c16f574105cc", size = 10285939, upload-time = "2026-02-26T20:04:22.42Z" }, - { url = "https://files.pythonhosted.org/packages/e6/f4/7c20aec3143837641a02509a4668fb146a642fd1211846634edc17eb5563/ruff-0.15.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:291258c917539e18f6ba40482fe31d6f5ac023994ee11d7bdafd716f2aab8a68", size = 10765471, upload-time = "2026-02-26T20:03:58.924Z" }, - { url = "https://files.pythonhosted.org/packages/d0/09/6d2f7586f09a16120aebdff8f64d962d7c4348313c77ebb29c566cefc357/ruff-0.15.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3f83c45911da6f2cd5936c436cf86b9f09f09165f033a99dcf7477e34041cbc3", size = 11263382, upload-time = "2026-02-26T20:04:24.424Z" }, - { url = "https://files.pythonhosted.org/packages/1b/fa/2ef715a1cd329ef47c1a050e10dee91a9054b7ce2fcfdd6a06d139afb7ec/ruff-0.15.4-py3-none-win32.whl", hash = "sha256:65594a2d557d4ee9f02834fcdf0a28daa8b3b9f6cb2cb93846025a36db47ef22", size = 10506664, upload-time = "2026-02-26T20:03:50.56Z" }, - { url = "https://files.pythonhosted.org/packages/d0/a8/c688ef7e29983976820d18710f955751d9f4d4eb69df658af3d006e2ba3e/ruff-0.15.4-py3-none-win_amd64.whl", hash = "sha256:04196ad44f0df220c2ece5b0e959c2f37c777375ec744397d21d15b50a75264f", size = 11651048, upload-time = "2026-02-26T20:04:17.191Z" }, - { url = "https://files.pythonhosted.org/packages/3e/0a/9e1be9035b37448ce2e68c978f0591da94389ade5a5abafa4cf99985d1b2/ruff-0.15.4-py3-none-win_arm64.whl", hash = "sha256:60d5177e8cfc70e51b9c5fad936c634872a74209f934c1e79107d11787ad5453", size = 10966776, upload-time = "2026-02-26T20:03:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/47/20/5369c3ce21588c708bcbe517a8fbe1a8dfdb5dfd5137e14790b1da71612c/ruff-0.15.5-py3-none-linux_armv6l.whl", hash = "sha256:4ae44c42281f42e3b06b988e442d344a5b9b72450ff3c892e30d11b29a96a57c", size = 10478185, upload-time = "2026-03-05T20:06:29.093Z" }, + { url = "https://files.pythonhosted.org/packages/44/ed/e81dd668547da281e5dce710cf0bc60193f8d3d43833e8241d006720e42b/ruff-0.15.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6edd3792d408ebcf61adabc01822da687579a1a023f297618ac27a5b51ef0080", size = 10859201, upload-time = "2026-03-05T20:06:32.632Z" }, + { url = "https://files.pythonhosted.org/packages/c4/8f/533075f00aaf19b07c5cd6aa6e5d89424b06b3b3f4583bfa9c640a079059/ruff-0.15.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:89f463f7c8205a9f8dea9d658d59eff49db05f88f89cc3047fb1a02d9f344010", size = 10184752, upload-time = "2026-03-05T20:06:40.312Z" }, + { url = "https://files.pythonhosted.org/packages/66/0e/ba49e2c3fa0395b3152bad634c7432f7edfc509c133b8f4529053ff024fb/ruff-0.15.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba786a8295c6574c1116704cf0b9e6563de3432ac888d8f83685654fe528fd65", size = 10534857, upload-time = "2026-03-05T20:06:19.581Z" }, + { url = "https://files.pythonhosted.org/packages/59/71/39234440f27a226475a0659561adb0d784b4d247dfe7f43ffc12dd02e288/ruff-0.15.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd4b801e57955fe9f02b31d20375ab3a5c4415f2e5105b79fb94cf2642c91440", size = 10309120, upload-time = "2026-03-05T20:06:00.435Z" }, + { url = "https://files.pythonhosted.org/packages/f5/87/4140aa86a93df032156982b726f4952aaec4a883bb98cb6ef73c347da253/ruff-0.15.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391f7c73388f3d8c11b794dbbc2959a5b5afe66642c142a6effa90b45f6f5204", size = 11047428, upload-time = "2026-03-05T20:05:51.867Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f7/4953e7e3287676f78fbe85e3a0ca414c5ca81237b7575bdadc00229ac240/ruff-0.15.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc18f30302e379fe1e998548b0f5e9f4dff907f52f73ad6da419ea9c19d66c8", size = 11914251, upload-time = "2026-03-05T20:06:22.887Z" }, + { url = "https://files.pythonhosted.org/packages/77/46/0f7c865c10cf896ccf5a939c3e84e1cfaeed608ff5249584799a74d33835/ruff-0.15.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc6e7f90087e2d27f98dc34ed1b3ab7c8f0d273cc5431415454e22c0bd2a681", size = 11333801, upload-time = "2026-03-05T20:05:57.168Z" }, + { url = "https://files.pythonhosted.org/packages/d3/01/a10fe54b653061585e655f5286c2662ebddb68831ed3eaebfb0eb08c0a16/ruff-0.15.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cb7169f53c1ddb06e71a9aebd7e98fc0fea936b39afb36d8e86d36ecc2636a", size = 11206821, upload-time = "2026-03-05T20:06:03.441Z" }, + { url = "https://files.pythonhosted.org/packages/7a/0d/2132ceaf20c5e8699aa83da2706ecb5c5dcdf78b453f77edca7fb70f8a93/ruff-0.15.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9b037924500a31ee17389b5c8c4d88874cc6ea8e42f12e9c61a3d754ff72f1ca", size = 11133326, upload-time = "2026-03-05T20:06:25.655Z" }, + { url = "https://files.pythonhosted.org/packages/72/cb/2e5259a7eb2a0f87c08c0fe5bf5825a1e4b90883a52685524596bfc93072/ruff-0.15.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65bb414e5b4eadd95a8c1e4804f6772bbe8995889f203a01f77ddf2d790929dd", size = 10510820, upload-time = "2026-03-05T20:06:37.79Z" }, + { url = "https://files.pythonhosted.org/packages/ff/20/b67ce78f9e6c59ffbdb5b4503d0090e749b5f2d31b599b554698a80d861c/ruff-0.15.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d20aa469ae3b57033519c559e9bc9cd9e782842e39be05b50e852c7c981fa01d", size = 10302395, upload-time = "2026-03-05T20:05:54.504Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e5/719f1acccd31b720d477751558ed74e9c88134adcc377e5e886af89d3072/ruff-0.15.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:15388dd28c9161cdb8eda68993533acc870aa4e646a0a277aa166de9ad5a8752", size = 10754069, upload-time = "2026-03-05T20:06:06.422Z" }, + { url = "https://files.pythonhosted.org/packages/c3/9c/d1db14469e32d98f3ca27079dbd30b7b44dbb5317d06ab36718dee3baf03/ruff-0.15.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b30da330cbd03bed0c21420b6b953158f60c74c54c5f4c1dabbdf3a57bf355d2", size = 11304315, upload-time = "2026-03-05T20:06:10.867Z" }, + { url = "https://files.pythonhosted.org/packages/28/3a/950367aee7c69027f4f422059227b290ed780366b6aecee5de5039d50fa8/ruff-0.15.5-py3-none-win32.whl", hash = "sha256:732e5ee1f98ba5b3679029989a06ca39a950cced52143a0ea82a2102cb592b74", size = 10551676, upload-time = "2026-03-05T20:06:13.705Z" }, + { url = "https://files.pythonhosted.org/packages/b8/00/bf077a505b4e649bdd3c47ff8ec967735ce2544c8e4a43aba42ee9bf935d/ruff-0.15.5-py3-none-win_amd64.whl", hash = "sha256:821d41c5fa9e19117616c35eaa3f4b75046ec76c65e7ae20a333e9a8696bc7fe", size = 11678972, upload-time = "2026-03-05T20:06:45.379Z" }, + { url = "https://files.pythonhosted.org/packages/fe/4e/cd76eca6db6115604b7626668e891c9dd03330384082e33662fb0f113614/ruff-0.15.5-py3-none-win_arm64.whl", hash = "sha256:b498d1c60d2fe5c10c45ec3f698901065772730b411f164ae270bb6bfcc4740b", size = 10965572, upload-time = "2026-03-05T20:06:16.984Z" }, ] [[package]] @@ -380,7 +380,7 @@ dev = [ { name = "basedpyright", specifier = "==1.38.2" }, { name = "faker", specifier = "==40.8.0" }, { name = "pytest", specifier = "==9.0.2" }, - { name = "ruff", specifier = "==0.15.4" }, + { name = "ruff", specifier = "==0.15.5" }, ] [[package]] From ac0a6683de560a779486ba7127c48ec9bc2db7ee Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 13 Mar 2026 00:06:24 +0000 Subject: [PATCH 27/28] chore(deps): update dependency ruff to v0.15.6 --- pyproject.toml | 2 +- uv.lock | 40 ++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6f6aa14..56b39a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,5 +26,5 @@ dev = [ "basedpyright==1.38.2", "faker==40.8.0", "pytest==9.0.2", - "ruff==0.15.5", + "ruff==0.15.6", ] diff --git a/uv.lock b/uv.lock index 36b28a7..735a0c8 100644 --- a/uv.lock +++ b/uv.lock @@ -310,27 +310,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.5" +version = "0.15.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/77/9b/840e0039e65fcf12758adf684d2289024d6140cde9268cc59887dc55189c/ruff-0.15.5.tar.gz", hash = "sha256:7c3601d3b6d76dce18c5c824fc8d06f4eef33d6df0c21ec7799510cde0f159a2", size = 4574214, upload-time = "2026-03-05T20:06:34.946Z" } +sdist = { url = "https://files.pythonhosted.org/packages/51/df/f8629c19c5318601d3121e230f74cbee7a3732339c52b21daa2b82ef9c7d/ruff-0.15.6.tar.gz", hash = "sha256:8394c7bb153a4e3811a4ecdacd4a8e6a4fa8097028119160dffecdcdf9b56ae4", size = 4597916, upload-time = "2026-03-12T23:05:47.51Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/20/5369c3ce21588c708bcbe517a8fbe1a8dfdb5dfd5137e14790b1da71612c/ruff-0.15.5-py3-none-linux_armv6l.whl", hash = "sha256:4ae44c42281f42e3b06b988e442d344a5b9b72450ff3c892e30d11b29a96a57c", size = 10478185, upload-time = "2026-03-05T20:06:29.093Z" }, - { url = "https://files.pythonhosted.org/packages/44/ed/e81dd668547da281e5dce710cf0bc60193f8d3d43833e8241d006720e42b/ruff-0.15.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6edd3792d408ebcf61adabc01822da687579a1a023f297618ac27a5b51ef0080", size = 10859201, upload-time = "2026-03-05T20:06:32.632Z" }, - { url = "https://files.pythonhosted.org/packages/c4/8f/533075f00aaf19b07c5cd6aa6e5d89424b06b3b3f4583bfa9c640a079059/ruff-0.15.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:89f463f7c8205a9f8dea9d658d59eff49db05f88f89cc3047fb1a02d9f344010", size = 10184752, upload-time = "2026-03-05T20:06:40.312Z" }, - { url = "https://files.pythonhosted.org/packages/66/0e/ba49e2c3fa0395b3152bad634c7432f7edfc509c133b8f4529053ff024fb/ruff-0.15.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba786a8295c6574c1116704cf0b9e6563de3432ac888d8f83685654fe528fd65", size = 10534857, upload-time = "2026-03-05T20:06:19.581Z" }, - { url = "https://files.pythonhosted.org/packages/59/71/39234440f27a226475a0659561adb0d784b4d247dfe7f43ffc12dd02e288/ruff-0.15.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd4b801e57955fe9f02b31d20375ab3a5c4415f2e5105b79fb94cf2642c91440", size = 10309120, upload-time = "2026-03-05T20:06:00.435Z" }, - { url = "https://files.pythonhosted.org/packages/f5/87/4140aa86a93df032156982b726f4952aaec4a883bb98cb6ef73c347da253/ruff-0.15.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391f7c73388f3d8c11b794dbbc2959a5b5afe66642c142a6effa90b45f6f5204", size = 11047428, upload-time = "2026-03-05T20:05:51.867Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f7/4953e7e3287676f78fbe85e3a0ca414c5ca81237b7575bdadc00229ac240/ruff-0.15.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc18f30302e379fe1e998548b0f5e9f4dff907f52f73ad6da419ea9c19d66c8", size = 11914251, upload-time = "2026-03-05T20:06:22.887Z" }, - { url = "https://files.pythonhosted.org/packages/77/46/0f7c865c10cf896ccf5a939c3e84e1cfaeed608ff5249584799a74d33835/ruff-0.15.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc6e7f90087e2d27f98dc34ed1b3ab7c8f0d273cc5431415454e22c0bd2a681", size = 11333801, upload-time = "2026-03-05T20:05:57.168Z" }, - { url = "https://files.pythonhosted.org/packages/d3/01/a10fe54b653061585e655f5286c2662ebddb68831ed3eaebfb0eb08c0a16/ruff-0.15.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cb7169f53c1ddb06e71a9aebd7e98fc0fea936b39afb36d8e86d36ecc2636a", size = 11206821, upload-time = "2026-03-05T20:06:03.441Z" }, - { url = "https://files.pythonhosted.org/packages/7a/0d/2132ceaf20c5e8699aa83da2706ecb5c5dcdf78b453f77edca7fb70f8a93/ruff-0.15.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9b037924500a31ee17389b5c8c4d88874cc6ea8e42f12e9c61a3d754ff72f1ca", size = 11133326, upload-time = "2026-03-05T20:06:25.655Z" }, - { url = "https://files.pythonhosted.org/packages/72/cb/2e5259a7eb2a0f87c08c0fe5bf5825a1e4b90883a52685524596bfc93072/ruff-0.15.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65bb414e5b4eadd95a8c1e4804f6772bbe8995889f203a01f77ddf2d790929dd", size = 10510820, upload-time = "2026-03-05T20:06:37.79Z" }, - { url = "https://files.pythonhosted.org/packages/ff/20/b67ce78f9e6c59ffbdb5b4503d0090e749b5f2d31b599b554698a80d861c/ruff-0.15.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d20aa469ae3b57033519c559e9bc9cd9e782842e39be05b50e852c7c981fa01d", size = 10302395, upload-time = "2026-03-05T20:05:54.504Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e5/719f1acccd31b720d477751558ed74e9c88134adcc377e5e886af89d3072/ruff-0.15.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:15388dd28c9161cdb8eda68993533acc870aa4e646a0a277aa166de9ad5a8752", size = 10754069, upload-time = "2026-03-05T20:06:06.422Z" }, - { url = "https://files.pythonhosted.org/packages/c3/9c/d1db14469e32d98f3ca27079dbd30b7b44dbb5317d06ab36718dee3baf03/ruff-0.15.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b30da330cbd03bed0c21420b6b953158f60c74c54c5f4c1dabbdf3a57bf355d2", size = 11304315, upload-time = "2026-03-05T20:06:10.867Z" }, - { url = "https://files.pythonhosted.org/packages/28/3a/950367aee7c69027f4f422059227b290ed780366b6aecee5de5039d50fa8/ruff-0.15.5-py3-none-win32.whl", hash = "sha256:732e5ee1f98ba5b3679029989a06ca39a950cced52143a0ea82a2102cb592b74", size = 10551676, upload-time = "2026-03-05T20:06:13.705Z" }, - { url = "https://files.pythonhosted.org/packages/b8/00/bf077a505b4e649bdd3c47ff8ec967735ce2544c8e4a43aba42ee9bf935d/ruff-0.15.5-py3-none-win_amd64.whl", hash = "sha256:821d41c5fa9e19117616c35eaa3f4b75046ec76c65e7ae20a333e9a8696bc7fe", size = 11678972, upload-time = "2026-03-05T20:06:45.379Z" }, - { url = "https://files.pythonhosted.org/packages/fe/4e/cd76eca6db6115604b7626668e891c9dd03330384082e33662fb0f113614/ruff-0.15.5-py3-none-win_arm64.whl", hash = "sha256:b498d1c60d2fe5c10c45ec3f698901065772730b411f164ae270bb6bfcc4740b", size = 10965572, upload-time = "2026-03-05T20:06:16.984Z" }, + { url = "https://files.pythonhosted.org/packages/9e/2f/4e03a7e5ce99b517e98d3b4951f411de2b0fa8348d39cf446671adcce9a2/ruff-0.15.6-py3-none-linux_armv6l.whl", hash = "sha256:7c98c3b16407b2cf3d0f2b80c80187384bc92c6774d85fefa913ecd941256fff", size = 10508953, upload-time = "2026-03-12T23:05:17.246Z" }, + { url = "https://files.pythonhosted.org/packages/70/60/55bcdc3e9f80bcf39edf0cd272da6fa511a3d94d5a0dd9e0adf76ceebdb4/ruff-0.15.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ee7dcfaad8b282a284df4aa6ddc2741b3f4a18b0555d626805555a820ea181c3", size = 10942257, upload-time = "2026-03-12T23:05:23.076Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f9/005c29bd1726c0f492bfa215e95154cf480574140cb5f867c797c18c790b/ruff-0.15.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3bd9967851a25f038fc8b9ae88a7fbd1b609f30349231dffaa37b6804923c4bb", size = 10322683, upload-time = "2026-03-12T23:05:33.738Z" }, + { url = "https://files.pythonhosted.org/packages/5f/74/2f861f5fd7cbb2146bddb5501450300ce41562da36d21868c69b7a828169/ruff-0.15.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13f4594b04e42cd24a41da653886b04d2ff87adbf57497ed4f728b0e8a4866f8", size = 10660986, upload-time = "2026-03-12T23:05:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/c1/a1/309f2364a424eccb763cdafc49df843c282609f47fe53aa83f38272389e0/ruff-0.15.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2ed8aea2f3fe57886d3f00ea5b8aae5bf68d5e195f487f037a955ff9fbaac9e", size = 10332177, upload-time = "2026-03-12T23:05:56.145Z" }, + { url = "https://files.pythonhosted.org/packages/30/41/7ebf1d32658b4bab20f8ac80972fb19cd4e2c6b78552be263a680edc55ac/ruff-0.15.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70789d3e7830b848b548aae96766431c0dc01a6c78c13381f423bf7076c66d15", size = 11170783, upload-time = "2026-03-12T23:06:01.742Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/6d488f6adca047df82cd62c304638bcb00821c36bd4881cfca221561fdfc/ruff-0.15.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:542aaf1de3154cea088ced5a819ce872611256ffe2498e750bbae5247a8114e9", size = 12044201, upload-time = "2026-03-12T23:05:28.697Z" }, + { url = "https://files.pythonhosted.org/packages/71/68/e6f125df4af7e6d0b498f8d373274794bc5156b324e8ab4bf5c1b4fc0ec7/ruff-0.15.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c22e6f02c16cfac3888aa636e9eba857254d15bbacc9906c9689fdecb1953ab", size = 11421561, upload-time = "2026-03-12T23:05:31.236Z" }, + { url = "https://files.pythonhosted.org/packages/f1/9f/f85ef5fd01a52e0b472b26dc1b4bd228b8f6f0435975442ffa4741278703/ruff-0.15.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98893c4c0aadc8e448cfa315bd0cc343a5323d740fe5f28ef8a3f9e21b381f7e", size = 11310928, upload-time = "2026-03-12T23:05:45.288Z" }, + { url = "https://files.pythonhosted.org/packages/8c/26/b75f8c421f5654304b89471ed384ae8c7f42b4dff58fa6ce1626d7f2b59a/ruff-0.15.6-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:70d263770d234912374493e8cc1e7385c5d49376e41dfa51c5c3453169dc581c", size = 11235186, upload-time = "2026-03-12T23:05:50.677Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d4/d5a6d065962ff7a68a86c9b4f5500f7d101a0792078de636526c0edd40da/ruff-0.15.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:55a1ad63c5a6e54b1f21b7514dfadc0c7fb40093fa22e95143cf3f64ebdcd512", size = 10635231, upload-time = "2026-03-12T23:05:37.044Z" }, + { url = "https://files.pythonhosted.org/packages/d6/56/7c3acf3d50910375349016cf33de24be021532042afbed87942858992491/ruff-0.15.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8dc473ba093c5ec238bb1e7429ee676dca24643c471e11fbaa8a857925b061c0", size = 10340357, upload-time = "2026-03-12T23:06:04.748Z" }, + { url = "https://files.pythonhosted.org/packages/06/54/6faa39e9c1033ff6a3b6e76b5df536931cd30caf64988e112bbf91ef5ce5/ruff-0.15.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:85b042377c2a5561131767974617006f99f7e13c63c111b998f29fc1e58a4cfb", size = 10860583, upload-time = "2026-03-12T23:05:58.978Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/509a201b843b4dfb0b32acdedf68d951d3377988cae43949ba4c4133a96a/ruff-0.15.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cef49e30bc5a86a6a92098a7fbf6e467a234d90b63305d6f3ec01225a9d092e0", size = 11410976, upload-time = "2026-03-12T23:05:39.955Z" }, + { url = "https://files.pythonhosted.org/packages/6c/25/3fc9114abf979a41673ce877c08016f8e660ad6cf508c3957f537d2e9fa9/ruff-0.15.6-py3-none-win32.whl", hash = "sha256:bbf67d39832404812a2d23020dda68fee7f18ce15654e96fb1d3ad21a5fe436c", size = 10616872, upload-time = "2026-03-12T23:05:42.451Z" }, + { url = "https://files.pythonhosted.org/packages/89/7a/09ece68445ceac348df06e08bf75db72d0e8427765b96c9c0ffabc1be1d9/ruff-0.15.6-py3-none-win_amd64.whl", hash = "sha256:aee25bc84c2f1007ecb5037dff75cef00414fdf17c23f07dc13e577883dca406", size = 11787271, upload-time = "2026-03-12T23:05:20.168Z" }, + { url = "https://files.pythonhosted.org/packages/7f/d0/578c47dd68152ddddddf31cd7fc67dc30b7cdf639a86275fda821b0d9d98/ruff-0.15.6-py3-none-win_arm64.whl", hash = "sha256:c34de3dd0b0ba203be50ae70f5910b17188556630e2178fd7d79fc030eb0d837", size = 11060497, upload-time = "2026-03-12T23:05:25.968Z" }, ] [[package]] @@ -380,7 +380,7 @@ dev = [ { name = "basedpyright", specifier = "==1.38.2" }, { name = "faker", specifier = "==40.8.0" }, { name = "pytest", specifier = "==9.0.2" }, - { name = "ruff", specifier = "==0.15.5" }, + { name = "ruff", specifier = "==0.15.6" }, ] [[package]] From 47bba589f43ba512e47bcf7d46522e73c8f29168 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 14 Mar 2026 00:04:44 +0000 Subject: [PATCH 28/28] chore(deps): update dependency faker to v40.11.0 --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 56b39a4..0dc712d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ build-backend = "hatchling.build" [dependency-groups] dev = [ "basedpyright==1.38.2", - "faker==40.8.0", + "faker==40.11.0", "pytest==9.0.2", "ruff==0.15.6", ] diff --git a/uv.lock b/uv.lock index 735a0c8..a843661 100644 --- a/uv.lock +++ b/uv.lock @@ -55,14 +55,14 @@ wheels = [ [[package]] name = "faker" -version = "40.8.0" +version = "40.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/70/03/14428edc541467c460d363f6e94bee9acc271f3e62470630fc9a647d0cf2/faker-40.8.0.tar.gz", hash = "sha256:936a3c9be6c004433f20aa4d99095df5dec82b8c7ad07459756041f8c1728875", size = 1956493, upload-time = "2026-03-04T16:18:48.161Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/dc/b68e5378e5a7db0ab776efcdd53b6fe374b29d703e156fd5bb4c5437069e/faker-40.11.0.tar.gz", hash = "sha256:7c419299103b13126bd02ec14bd2b47b946edb5a5eedf305e66a193b25f9a734", size = 1957570, upload-time = "2026-03-13T14:36:11.844Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/3b/c6348f1e285e75b069085b18110a4e6325b763a5d35d5e204356fc7c20b3/faker-40.8.0-py3-none-any.whl", hash = "sha256:eb21bdba18f7a8375382eb94fb436fce07046893dc94cb20817d28deb0c3d579", size = 1989124, upload-time = "2026-03-04T16:18:46.45Z" }, + { url = "https://files.pythonhosted.org/packages/b1/fa/a86c6ba66f0308c95b9288b1e3eaccd934b545646f63494a86f1ec2f8c8e/faker-40.11.0-py3-none-any.whl", hash = "sha256:0e9816c950528d2a37d74863f3ef389ea9a3a936cbcde0b11b8499942e25bf90", size = 1989457, upload-time = "2026-03-13T14:36:09.792Z" }, ] [[package]] @@ -378,7 +378,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ { name = "basedpyright", specifier = "==1.38.2" }, - { name = "faker", specifier = "==40.8.0" }, + { name = "faker", specifier = "==40.11.0" }, { name = "pytest", specifier = "==9.0.2" }, { name = "ruff", specifier = "==0.15.6" }, ]