Compare commits
28 commits
renovate/l
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 47bba589f4 | |||
| ac0a6683de | |||
| 1fb1ea1615 | |||
| 42177b94bd | |||
| 5132814a77 | |||
| bb02dd715b | |||
| 2c26f4ce56 | |||
| 51ee07dbbe | |||
| 0ed680f0b1 | |||
| 49fb18d342 | |||
| ea42b31a1e | |||
| bfb9b78ef5 | |||
| ad751696cb | |||
| 47a9727198 | |||
| 1dc41ecb3e | |||
| 20a3e8b437 | |||
| d89ad8b131 | |||
| ca6b5bbd4d | |||
| ce5e476b23 | |||
| b4848bb661 | |||
| f9ed0463f7 | |||
| af2debc19b | |||
| 49cd9bcfa0 | |||
| 1e203d9db3 | |||
| 2298bdaa8f | |||
| 646241f355 | |||
| c0911307fd | |||
| 34ba9869d1 |
39 changed files with 952 additions and 389 deletions
4
.envrc
4
.envrc
|
|
@ -1 +1,3 @@
|
||||||
use flake .#impure
|
#!/usr/bin/env bash
|
||||||
|
eval "$(devenv direnvrc)"
|
||||||
|
use devenv
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-lint:
|
check:
|
||||||
name: Lint, Check & Test
|
name: Lint, Check & Test
|
||||||
runs-on: nix
|
runs-on: nix
|
||||||
|
|
||||||
|
|
@ -16,8 +16,12 @@ jobs:
|
||||||
- run: nix --version
|
- run: nix --version
|
||||||
- run: nix flake check
|
- run: nix flake check
|
||||||
|
|
||||||
- name: Install the project
|
build:
|
||||||
run: 'nix develop .#impure --command bash -c "uv sync --locked --all-extras --dev"'
|
name: Build Package
|
||||||
|
runs-on: nix
|
||||||
|
|
||||||
- name: Test with PyTest
|
steps:
|
||||||
run: nix develop .#impure --command bash -c "uv run pytest --junit-xml test-report.xml"
|
- name: Check out Repository
|
||||||
|
uses: https://git.konstantinfickel.de/actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
|
|
||||||
|
- run: nix build
|
||||||
|
|
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -177,3 +177,8 @@ pyrightconfig.json
|
||||||
|
|
||||||
.direnv
|
.direnv
|
||||||
test-report.xml
|
test-report.xml
|
||||||
|
.devenv
|
||||||
|
.devenv.flake.nix
|
||||||
|
.pre-commit-config.yaml
|
||||||
|
|
||||||
|
result
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
3.14.3
|
3.14
|
||||||
|
|
|
||||||
37
README.md
37
README.md
|
|
@ -1,7 +1,36 @@
|
||||||
# streamer
|
# strea.md
|
||||||
|
|
||||||
Searching for `@tags` in time-based [streams](https://www.cs.yale.edu/homes/freeman/lifestreams.html).
|

|
||||||
|
|
||||||
# Usage
|
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.
|
||||||
|
|
||||||
Running `streamer` finds all lines with @Task
|
## Core Concepts
|
||||||
|
|
||||||
|
- **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 Streamd.md`
|
||||||
|
|
||||||
|
Within files, `@`-prefixed markers at the beginning of paragraphs or headings define how a shard is categorized.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
- `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
|
||||||
|
|
||||||
|
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 `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 `streamd todo` finds all shards marked as open tasks and displays them as rich-formatted panels in your terminal.
|
||||||
|
|
|
||||||
123
devenv.lock
Normal file
123
devenv.lock
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
28
devenv.nix
Normal file
28
devenv.nix
Normal file
|
|
@ -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;
|
||||||
|
};
|
||||||
|
}
|
||||||
6
devenv.yaml
Normal file
6
devenv.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
inputs:
|
||||||
|
git-hooks:
|
||||||
|
url: github:cachix/git-hooks.nix
|
||||||
|
inputs:
|
||||||
|
nixpkgs:
|
||||||
|
follows: nixpkgs
|
||||||
82
flake.lock
generated
82
flake.lock
generated
|
|
@ -1,16 +1,75 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1769789167,
|
"lastModified": 1767039857,
|
||||||
"narHash": "sha256-kKB3bqYJU5nzYeIROI82Ef9VtTbu4uA3YydSk/Bioa8=",
|
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "flake-compat",
|
||||||
"rev": "62c8382960464ceb98ea593cb8321a2cf8f9e3e5",
|
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"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",
|
"ref": "nixos-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
|
|
@ -29,11 +88,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1763662255,
|
"lastModified": 1771039651,
|
||||||
"narHash": "sha256-4bocaOyLa3AfiS8KrWjZQYu+IAta05u3gYZzZ6zXbT0=",
|
"narHash": "sha256-WZOfX4APbc6vmL14ZWJXgBeRfEER8H+OIX0D0nSmv0M=",
|
||||||
"owner": "pyproject-nix",
|
"owner": "pyproject-nix",
|
||||||
"repo": "build-system-pkgs",
|
"repo": "build-system-pkgs",
|
||||||
"rev": "042904167604c681a090c07eb6967b4dd4dae88c",
|
"rev": "69bc2b53b79cbd6ce9f66f506fc962b45b5e68b9",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -64,6 +123,7 @@
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"git-hooks": "git-hooks",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"pyproject-build-systems": "pyproject-build-systems",
|
"pyproject-build-systems": "pyproject-build-systems",
|
||||||
"pyproject-nix": "pyproject-nix",
|
"pyproject-nix": "pyproject-nix",
|
||||||
|
|
@ -80,11 +140,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1769957392,
|
"lastModified": 1770770348,
|
||||||
"narHash": "sha256-6PkqwwYf5K2CHi2V+faI/9pqjfz/HxUkI/MVid6hlOY=",
|
"narHash": "sha256-A2GzkmzdYvdgmMEu5yxW+xhossP+txrYb7RuzRaqhlg=",
|
||||||
"owner": "pyproject-nix",
|
"owner": "pyproject-nix",
|
||||||
"repo": "uv2nix",
|
"repo": "uv2nix",
|
||||||
"rev": "d18bc50ae1c3d4be9c41c2d94ea765524400af75",
|
"rev": "5d1b2cb4fe3158043fbafbbe2e46238abbc954b0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
327
flake.nix
327
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 = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
pyproject-nix = {
|
pyproject-nix = {
|
||||||
url = "github:pyproject-nix/pyproject.nix";
|
url = "github:pyproject-nix/pyproject.nix";
|
||||||
|
|
@ -21,204 +21,215 @@
|
||||||
inputs.uv2nix.follows = "uv2nix";
|
inputs.uv2nix.follows = "uv2nix";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
git-hooks = {
|
||||||
|
url = "github:cachix/git-hooks.nix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
{
|
{
|
||||||
self,
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
uv2nix,
|
|
||||||
pyproject-nix,
|
pyproject-nix,
|
||||||
|
uv2nix,
|
||||||
pyproject-build-systems,
|
pyproject-build-systems,
|
||||||
|
git-hooks,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
inherit (nixpkgs) lib;
|
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 = ./.; };
|
workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; };
|
||||||
|
|
||||||
# Create package overlay from workspace.
|
|
||||||
overlay = workspace.mkPyprojectOverlay {
|
overlay = workspace.mkPyprojectOverlay {
|
||||||
# Prefer prebuilt binary wheels as a package source.
|
sourcePreference = "wheel";
|
||||||
# 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";
|
|
||||||
# };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Extend generated overlay with build fixups
|
editableOverlay = workspace.mkEditablePyprojectOverlay {
|
||||||
#
|
root = "$REPO_ROOT";
|
||||||
# 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
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# This example is only using x86_64-linux
|
pythonSets = forAllSystems (
|
||||||
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
inherit (pkgs) stdenv;
|
||||||
|
|
||||||
# Use Python 3.14 from nixpkgs
|
baseSet = pkgs.callPackage pyproject-nix.build.packages {
|
||||||
python = pkgs.python314;
|
python = pkgs.python313;
|
||||||
|
};
|
||||||
|
|
||||||
# Construct package set
|
pyprojectOverrides = _final: prev: {
|
||||||
pythonSet =
|
streamd = prev.streamd.overrideAttrs (old: {
|
||||||
# Use base package set from pyproject.nix builders
|
passthru = old.passthru // {
|
||||||
(pkgs.callPackage pyproject-nix.build.packages {
|
tests = (old.passthru.tests or { }) // {
|
||||||
inherit python;
|
pytest = stdenv.mkDerivation {
|
||||||
}).overrideScope
|
name = "${_final.streamd.name}-pytest";
|
||||||
(
|
inherit (_final.streamd) src;
|
||||||
lib.composeManyExtensions [
|
nativeBuildInputs = [
|
||||||
pyproject-build-systems.overlays.default
|
(_final.mkVirtualEnv "streamd-pytest-env" {
|
||||||
overlay
|
streamd = [ "dev" ];
|
||||||
pyprojectOverrides
|
})
|
||||||
]
|
];
|
||||||
);
|
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.all;
|
||||||
|
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
|
in
|
||||||
{
|
{
|
||||||
# Package a virtual environment as our main application.
|
packages = forAllSystems (
|
||||||
#
|
system:
|
||||||
# Enable no optional dependencies for production build.
|
|
||||||
packages.x86_64-linux =
|
|
||||||
let
|
let
|
||||||
streamer = pythonSet.mkVirtualEnv "streamer-env" workspace.deps.default;
|
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,
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.programs.streamd;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
inherit streamer;
|
options.programs.streamd = {
|
||||||
default = streamer;
|
enable = lib.mkEnableOption "streamd";
|
||||||
};
|
|
||||||
|
|
||||||
# Make streamer runnable with `nix run`
|
base-folder = lib.mkOption {
|
||||||
apps.x86_64-linux = {
|
type = lib.types.str;
|
||||||
default = {
|
description = "Base Folder of streamd";
|
||||||
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.
|
package = lib.mkOption {
|
||||||
editablePythonSet = pythonSet.overrideScope (
|
type = lib.types.package;
|
||||||
lib.composeManyExtensions [
|
default = self.packages.${pkgs.system}.streamd;
|
||||||
editableOverlay
|
defaultText = lib.literalExpression "inputs.streamd.packages.\${pkgs.system}.streamd";
|
||||||
|
description = "The package to use for the streamd binary.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# Apply fixups for building an editable package of your workspace packages
|
config = lib.mkIf cfg.enable {
|
||||||
(final: prev: {
|
assertions = [
|
||||||
streamer = prev.streamer.overrideAttrs (old: {
|
(lib.hm.assertions.assertPlatform "programs.streamd" pkgs lib.platforms.linux)
|
||||||
# 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; [
|
|
||||||
virtualenv
|
|
||||||
uv
|
|
||||||
pre-commit
|
|
||||||
bashInteractive
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
home.packages = [ cfg.package ];
|
||||||
|
|
||||||
|
xdg.configFile."streamd/config.yaml".source =
|
||||||
|
(pkgs.formats.yaml { }).generate "streamd-configuration"
|
||||||
|
{
|
||||||
|
base_folder = cfg.base-folder;
|
||||||
|
};
|
||||||
|
|
||||||
|
home.shellAliases.s = "streamd";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
checks = forAllSystems (
|
||||||
|
system:
|
||||||
|
let
|
||||||
|
pythonSet = pythonSets.${system};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit (pythonSet.streamd.passthru.tests) pytest;
|
||||||
|
pre-commit = mkGitHooksCheck system;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
pkgs.uv
|
||||||
|
];
|
||||||
env = {
|
env = {
|
||||||
# Don't create venv using uv
|
|
||||||
UV_NO_SYNC = "1";
|
UV_NO_SYNC = "1";
|
||||||
|
UV_PYTHON = pythonSet.python.interpreter;
|
||||||
# Force uv to use Python interpreter from venv
|
|
||||||
UV_PYTHON = "${virtualenv}/bin/python";
|
|
||||||
|
|
||||||
# Prevent uv from downloading managed Python's
|
|
||||||
UV_PYTHON_DOWNLOADS = "never";
|
UV_PYTHON_DOWNLOADS = "never";
|
||||||
};
|
};
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
# Undo dependency propagation by nixpkgs.
|
|
||||||
unset PYTHONPATH
|
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)
|
export REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||||
|
${(mkGitHooksCheck system).shellHook}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
[project]
|
[project]
|
||||||
name = "streamer"
|
name = "streamd"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "Searching for tags in streams"
|
description = "Searching for tags in streams"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"click==8.3.1",
|
"click==8.3.1",
|
||||||
"mistletoe==1.5.1",
|
"mistletoe==1.5.1",
|
||||||
"pydantic==2.12.5",
|
"pydantic==2.12.5",
|
||||||
"pydantic-settings[yaml]==2.12.0",
|
"pydantic-settings[yaml]==2.13.1",
|
||||||
"rich==14.3.2",
|
"rich==14.3.3",
|
||||||
"typer==0.21.2",
|
"typer==0.24.1",
|
||||||
"xdg-base-dirs==6.0.2",
|
"xdg-base-dirs==6.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
streamer = "streamer:app"
|
streamd = "streamd:app"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling"]
|
||||||
|
|
@ -23,8 +23,8 @@ build-backend = "hatchling.build"
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = [
|
dev = [
|
||||||
"faker==40.4.0",
|
"basedpyright==1.38.2",
|
||||||
"pyright==1.1.408",
|
"faker==40.11.0",
|
||||||
"pytest==9.0.2",
|
"pytest==9.0.2",
|
||||||
"ruff==0.15.0",
|
"ruff==0.15.6",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
|
from collections.abc import Generator
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from shutil import move
|
from shutil import move
|
||||||
from typing import Annotated, Generator
|
from typing import Annotated
|
||||||
|
|
||||||
import click
|
import click
|
||||||
import typer
|
import typer
|
||||||
|
|
@ -10,18 +11,17 @@ from rich import print
|
||||||
from rich.markdown import Markdown
|
from rich.markdown import Markdown
|
||||||
from rich.panel import Panel
|
from rich.panel import Panel
|
||||||
|
|
||||||
from streamer.localize import (
|
from streamd.localize import (
|
||||||
LocalizedShard,
|
LocalizedShard,
|
||||||
RepositoryConfiguration,
|
RepositoryConfiguration,
|
||||||
localize_stream_file,
|
localize_stream_file,
|
||||||
)
|
)
|
||||||
from streamer.localize.preconfigured_configurations import TaskConfiguration
|
from streamd.localize.preconfigured_configurations import TaskConfiguration
|
||||||
from streamer.parse import parse_markdown_file
|
from streamd.parse import parse_markdown_file
|
||||||
from streamer.query import find_shard_by_position
|
from streamd.query import find_shard_by_position
|
||||||
from streamer.query.find import find_shard_by_set_dimension
|
from streamd.settings import Settings
|
||||||
from streamer.settings import Settings
|
from streamd.timesheet.configuration import BasicTimesheetConfiguration
|
||||||
from streamer.timesheet.configuration import BasicTimesheetConfiguration
|
from streamd.timesheet.extract import extract_timesheets
|
||||||
from streamer.timesheet.extract import extract_timesheets
|
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer()
|
||||||
|
|
||||||
|
|
@ -89,11 +89,11 @@ def timesheet() -> None:
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def new() -> None:
|
def new() -> None:
|
||||||
streamer_directory = Settings().base_folder
|
streamd_directory = Settings().base_folder
|
||||||
|
|
||||||
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||||
preliminary_file_name = f"{timestamp}_wip.md"
|
preliminary_file_name = f"{timestamp}_wip.md"
|
||||||
prelimary_path = os.path.join(streamer_directory, preliminary_file_name)
|
prelimary_path = os.path.join(streamd_directory, preliminary_file_name)
|
||||||
|
|
||||||
content = "# "
|
content = "# "
|
||||||
with open(prelimary_path, "w") as file:
|
with open(prelimary_path, "w") as file:
|
||||||
|
|
@ -111,7 +111,7 @@ def new() -> None:
|
||||||
):
|
):
|
||||||
final_file_name = f"{timestamp} {' '.join(markers)}.md"
|
final_file_name = f"{timestamp} {' '.join(markers)}.md"
|
||||||
|
|
||||||
final_path = os.path.join(streamer_directory, final_file_name)
|
final_path = os.path.join(streamd_directory, final_file_name)
|
||||||
_ = move(prelimary_path, final_path)
|
_ = move(prelimary_path, final_path)
|
||||||
print(f"Saved as [yellow]{final_file_name}")
|
print(f"Saved as [yellow]{final_file_name}")
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from streamer.parse.shard import Shard, StreamFile
|
from streamd.parse.shard import Shard, StreamFile
|
||||||
|
|
||||||
from .extract_datetime import (
|
from .extract_datetime import (
|
||||||
extract_datetime_from_file_name,
|
extract_datetime_from_file_name,
|
||||||
|
|
@ -47,7 +47,10 @@ def localize_shard(
|
||||||
position.update(private_position)
|
position.update(private_position)
|
||||||
|
|
||||||
return LocalizedShard(
|
return LocalizedShard(
|
||||||
**shard.model_dump(exclude={"children"}),
|
markers=shard.markers,
|
||||||
|
tags=shard.tags,
|
||||||
|
start_line=shard.start_line,
|
||||||
|
end_line=shard.end_line,
|
||||||
location=position,
|
location=position,
|
||||||
children=children,
|
children=children,
|
||||||
moment=adjusted_moment,
|
moment=adjusted_moment,
|
||||||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from streamer.parse.shard import Shard
|
from streamd.parse.shard import Shard
|
||||||
|
|
||||||
|
|
||||||
class LocalizedShard(Shard):
|
class LocalizedShard(Shard):
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from streamer.localize.repository_configuration import (
|
from streamd.localize.repository_configuration import (
|
||||||
Dimension,
|
Dimension,
|
||||||
Marker,
|
Marker,
|
||||||
MarkerPlacement,
|
MarkerPlacement,
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class Dimension(BaseModel):
|
class Dimension(BaseModel):
|
||||||
display_name: str
|
display_name: str
|
||||||
comment: Optional[str] = None
|
comment: str | None = None
|
||||||
propagate: bool = False
|
propagate: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -29,7 +27,7 @@ class RepositoryConfiguration(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
def merge_single_dimension(base: Dimension, second: Dimension) -> Dimension:
|
def merge_single_dimension(base: Dimension, second: Dimension) -> Dimension:
|
||||||
second_fields_set = getattr(second, "model_fields_set", set())
|
second_fields_set: set[str] = getattr(second, "model_fields_set", set())
|
||||||
|
|
||||||
return Dimension(
|
return Dimension(
|
||||||
display_name=second.display_name or base.display_name,
|
display_name=second.display_name or base.display_name,
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import re
|
import re
|
||||||
from typing import Iterable
|
from collections.abc import Iterable
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
from mistletoe.block_token import BlockToken
|
from mistletoe.block_token import BlockToken
|
||||||
from mistletoe.span_token import Emphasis, RawText, Strikethrough, Strong, Link
|
from mistletoe.span_token import Emphasis, Link, RawText, Strikethrough, Strong
|
||||||
from mistletoe.token import Token
|
from mistletoe.token import Token
|
||||||
|
|
||||||
from .markdown_tag import Tag
|
from .markdown_tag import Tag
|
||||||
|
|
@ -12,18 +14,21 @@ def extract_markers_and_tags_from_single_token(
|
||||||
marker_boundary_encountered: bool,
|
marker_boundary_encountered: bool,
|
||||||
return_at_first_marker: bool = False,
|
return_at_first_marker: bool = False,
|
||||||
) -> tuple[list[str], list[str], bool]:
|
) -> tuple[list[str], list[str], bool]:
|
||||||
result_markers, result_tags = [], []
|
result_markers: list[str] = []
|
||||||
|
result_tags: list[str] = []
|
||||||
result_marker_boundary_encountered = marker_boundary_encountered
|
result_marker_boundary_encountered = marker_boundary_encountered
|
||||||
|
|
||||||
if isinstance(token, Tag):
|
if isinstance(token, Tag):
|
||||||
|
content = cast(str, token.content)
|
||||||
if marker_boundary_encountered:
|
if marker_boundary_encountered:
|
||||||
result_tags.append(token.content)
|
result_tags.append(content)
|
||||||
else:
|
else:
|
||||||
result_markers.append(token.content)
|
result_markers.append(content)
|
||||||
elif isinstance(token, (Emphasis, Strong, Strikethrough, Link)):
|
elif isinstance(token, (Emphasis, Strong, Strikethrough, Link)):
|
||||||
|
children = list(token.children or [])
|
||||||
markers, tags, child_marker_boundary_encountered = (
|
markers, tags, child_marker_boundary_encountered = (
|
||||||
extract_markers_and_tags_from_tokens(
|
extract_markers_and_tags_from_tokens(
|
||||||
token.children or [],
|
children,
|
||||||
marker_boundary_encountered,
|
marker_boundary_encountered,
|
||||||
return_at_first_marker,
|
return_at_first_marker,
|
||||||
)
|
)
|
||||||
|
|
@ -33,8 +38,10 @@ def extract_markers_and_tags_from_single_token(
|
||||||
result_marker_boundary_encountered = (
|
result_marker_boundary_encountered = (
|
||||||
marker_boundary_encountered or child_marker_boundary_encountered
|
marker_boundary_encountered or child_marker_boundary_encountered
|
||||||
)
|
)
|
||||||
elif isinstance(token, RawText) and re.match(r"^[\s]*$", token.content):
|
elif isinstance(token, RawText):
|
||||||
pass
|
content_raw = cast(str, token.content)
|
||||||
|
if not re.match(r"^[\s]*$", content_raw):
|
||||||
|
result_marker_boundary_encountered = True
|
||||||
else:
|
else:
|
||||||
result_marker_boundary_encountered = True
|
result_marker_boundary_encountered = True
|
||||||
|
|
||||||
|
|
@ -46,7 +53,8 @@ def extract_markers_and_tags_from_tokens(
|
||||||
marker_boundary_encountered: bool,
|
marker_boundary_encountered: bool,
|
||||||
return_at_first_marker: bool = False,
|
return_at_first_marker: bool = False,
|
||||||
) -> tuple[list[str], list[str], bool]:
|
) -> tuple[list[str], list[str], bool]:
|
||||||
result_markers, result_tags = [], []
|
result_markers: list[str] = []
|
||||||
|
result_tags: list[str] = []
|
||||||
result_marker_boundary_encountered = marker_boundary_encountered
|
result_marker_boundary_encountered = marker_boundary_encountered
|
||||||
|
|
||||||
for child in tokens:
|
for child in tokens:
|
||||||
|
|
@ -68,15 +76,15 @@ def extract_markers_and_tags_from_tokens(
|
||||||
|
|
||||||
|
|
||||||
def extract_markers_and_tags(block_token: BlockToken) -> tuple[list[str], list[str]]:
|
def extract_markers_and_tags(block_token: BlockToken) -> tuple[list[str], list[str]]:
|
||||||
markers, tags, _ = extract_markers_and_tags_from_tokens(
|
children = list(block_token.children or [])
|
||||||
block_token.children or [], False
|
markers, tags, _ = extract_markers_and_tags_from_tokens(children, False)
|
||||||
)
|
|
||||||
return markers, tags
|
return markers, tags
|
||||||
|
|
||||||
|
|
||||||
def has_markers(block_token: BlockToken) -> bool:
|
def has_markers(block_token: BlockToken) -> bool:
|
||||||
|
children = list(block_token.children or [])
|
||||||
markers, _, _ = extract_markers_and_tags_from_tokens(
|
markers, _, _ = extract_markers_and_tags_from_tokens(
|
||||||
block_token.children or [], False, return_at_first_marker=True
|
children, False, return_at_first_marker=True
|
||||||
)
|
)
|
||||||
return len(markers) > 0
|
return len(markers) > 0
|
||||||
|
|
||||||
23
src/streamd/parse/markdown_tag.py
Normal file
23
src/streamd/parse/markdown_tag.py
Normal file
|
|
@ -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"]
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
from mistletoe.block_token import (
|
from mistletoe.block_token import (
|
||||||
BlockToken,
|
BlockToken,
|
||||||
|
|
@ -16,16 +17,20 @@ from .shard import Shard, StreamFile
|
||||||
|
|
||||||
|
|
||||||
def get_line_number(block_token: BlockToken) -> int:
|
def get_line_number(block_token: BlockToken) -> int:
|
||||||
return block_token.line_number # type: ignore
|
return cast(int, block_token.line_number) # pyright: ignore[reportAttributeAccessIssue]
|
||||||
|
|
||||||
|
|
||||||
def build_shard(
|
def build_shard(
|
||||||
start_line: int,
|
start_line: int,
|
||||||
end_line: int,
|
end_line: int,
|
||||||
markers: list[str] = [],
|
markers: list[str] | None = None,
|
||||||
tags: list[str] = [],
|
tags: list[str] | None = None,
|
||||||
children: list[Shard] = [],
|
children: list[Shard] | None = None,
|
||||||
) -> Shard:
|
) -> Shard:
|
||||||
|
markers = markers or []
|
||||||
|
tags = tags or []
|
||||||
|
children = children or []
|
||||||
|
|
||||||
if (
|
if (
|
||||||
len(children) == 1
|
len(children) == 1
|
||||||
and len(tags) == 0
|
and len(tags) == 0
|
||||||
|
|
@ -45,14 +50,17 @@ def build_shard(
|
||||||
|
|
||||||
|
|
||||||
def merge_into_first_shard(
|
def merge_into_first_shard(
|
||||||
shards: list[Shard], start_line: int, end_line: int, additional_tags: list[str] = []
|
shards: list[Shard],
|
||||||
):
|
start_line: int,
|
||||||
|
end_line: int,
|
||||||
|
additional_tags: list[str] | None = None,
|
||||||
|
) -> Shard:
|
||||||
return shards[0].model_copy(
|
return shards[0].model_copy(
|
||||||
update={
|
update={
|
||||||
"start_line": start_line,
|
"start_line": start_line,
|
||||||
"end_line": end_line,
|
"end_line": end_line,
|
||||||
"children": shards[1:],
|
"children": shards[1:],
|
||||||
"tags": shards[0].tags + additional_tags,
|
"tags": shards[0].tags + (additional_tags or []),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -65,13 +73,18 @@ def find_paragraph_shard_positions(block_tokens: list[BlockToken]) -> list[int]:
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _heading_level(heading: Heading) -> int:
|
||||||
|
return cast(int, heading.level)
|
||||||
|
|
||||||
|
|
||||||
def find_headings_by_level(
|
def find_headings_by_level(
|
||||||
block_tokens: list[BlockToken], header_level: int
|
block_tokens: list[BlockToken], header_level: int
|
||||||
) -> list[int]:
|
) -> list[int]:
|
||||||
return [
|
return [
|
||||||
index
|
index
|
||||||
for index, block_token in enumerate(block_tokens)
|
for index, block_token in enumerate(block_tokens)
|
||||||
if isinstance(block_token, Heading) and block_token.level == header_level
|
if isinstance(block_token, Heading)
|
||||||
|
and _heading_level(block_token) == header_level
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -83,8 +96,8 @@ def calculate_heading_level_for_next_split(
|
||||||
If only the first token is a heading with a marker, 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)
|
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 = [
|
level_of_headings_without_first_with_marker: list[int] = [
|
||||||
token.level
|
_heading_level(token)
|
||||||
for token in block_tokens[1:]
|
for token in block_tokens[1:]
|
||||||
if isinstance(token, Heading) and has_markers(token)
|
if isinstance(token, Heading) and has_markers(token)
|
||||||
]
|
]
|
||||||
|
|
@ -92,8 +105,8 @@ def calculate_heading_level_for_next_split(
|
||||||
if len(level_of_headings_without_first_with_marker) == 0:
|
if len(level_of_headings_without_first_with_marker) == 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
heading_level_counter = Counter(
|
heading_level_counter: Counter[int] = Counter(
|
||||||
[token.level for token in block_tokens if isinstance(token, Heading)]
|
[_heading_level(token) for token in block_tokens if isinstance(token, Heading)]
|
||||||
)
|
)
|
||||||
|
|
||||||
return min(
|
return min(
|
||||||
|
|
@ -105,10 +118,12 @@ def calculate_heading_level_for_next_split(
|
||||||
def parse_single_block_shards(
|
def parse_single_block_shards(
|
||||||
block_token: BlockToken, start_line: int, end_line: int
|
block_token: BlockToken, start_line: int, end_line: int
|
||||||
) -> tuple[Shard | None, list[str]]:
|
) -> tuple[Shard | None, list[str]]:
|
||||||
markers, tags, children = [], [], []
|
markers: list[str] = []
|
||||||
|
tags: list[str] = []
|
||||||
|
children: list[Shard] = []
|
||||||
|
|
||||||
if isinstance(block_token, List):
|
if isinstance(block_token, List):
|
||||||
list_items: list[ListItem] = ( # type: ignore
|
list_items: list[ListItem] = ( # pyright: ignore[reportAssignmentType]
|
||||||
list(block_token.children) if block_token.children is not None else []
|
list(block_token.children) if block_token.children is not None else []
|
||||||
)
|
)
|
||||||
for index, list_item in enumerate(list_items):
|
for index, list_item in enumerate(list_items):
|
||||||
|
|
@ -119,7 +134,7 @@ def parse_single_block_shards(
|
||||||
else end_line
|
else end_line
|
||||||
)
|
)
|
||||||
list_item_shard, list_item_tags = parse_multiple_block_shards(
|
list_item_shard, list_item_tags = parse_multiple_block_shards(
|
||||||
list_item.children, # type: ignore
|
list_item.children, # pyright: ignore[reportArgumentType]
|
||||||
list_item_start_line,
|
list_item_start_line,
|
||||||
list_item_end_line,
|
list_item_end_line,
|
||||||
)
|
)
|
||||||
|
|
@ -149,7 +164,8 @@ def parse_multiple_block_shards(
|
||||||
)
|
)
|
||||||
|
|
||||||
paragraph_positions = find_paragraph_shard_positions(block_tokens)
|
paragraph_positions = find_paragraph_shard_positions(block_tokens)
|
||||||
children, tags = [], []
|
children: list[Shard] = []
|
||||||
|
tags: list[str] = []
|
||||||
|
|
||||||
is_first_block_only_with_marker = False
|
is_first_block_only_with_marker = False
|
||||||
|
|
||||||
|
|
@ -201,7 +217,7 @@ def parse_header_shards(
|
||||||
|
|
||||||
block_tokens_split_by_heading = split_at(block_tokens, heading_positions)
|
block_tokens_split_by_heading = split_at(block_tokens, heading_positions)
|
||||||
|
|
||||||
children = []
|
children: list[Shard] = []
|
||||||
for i, child_blocks in enumerate(block_tokens_split_by_heading):
|
for i, child_blocks in enumerate(block_tokens_split_by_heading):
|
||||||
child_start_line = get_line_number(child_blocks[0])
|
child_start_line = get_line_number(child_blocks[0])
|
||||||
child_end_line = (
|
child_end_line = (
|
||||||
|
|
@ -229,7 +245,7 @@ def parse_markdown_file(file_name: str, file_content: str) -> StreamFile:
|
||||||
with TagMarkdownRenderer():
|
with TagMarkdownRenderer():
|
||||||
ast = Document(file_content)
|
ast = Document(file_content)
|
||||||
|
|
||||||
block_tokens: list[BlockToken] = ast.children # type: ignore
|
block_tokens: list[BlockToken] = ast.children # pyright: ignore[reportAssignmentType]
|
||||||
if len(block_tokens) > 0:
|
if len(block_tokens) > 0:
|
||||||
if parsed_shard := parse_header_shards(
|
if parsed_shard := parse_header_shards(
|
||||||
block_tokens, shard.start_line, shard.end_line
|
block_tokens, shard.start_line, shard.end_line
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
from streamer.localize import LocalizedShard
|
from streamd.localize import LocalizedShard
|
||||||
|
|
||||||
|
|
||||||
def find_shard(
|
def find_shard(
|
||||||
shards: list[LocalizedShard], query_function: Callable[[LocalizedShard], bool]
|
shards: list[LocalizedShard], query_function: Callable[[LocalizedShard], bool]
|
||||||
) -> list[LocalizedShard]:
|
) -> list[LocalizedShard]:
|
||||||
found_shards = []
|
found_shards: list[LocalizedShard] = []
|
||||||
|
|
||||||
for shard in shards:
|
for shard in shards:
|
||||||
if query_function(shard):
|
if query_function(shard):
|
||||||
|
|
@ -21,8 +21,9 @@ def find_shard_by_position(
|
||||||
) -> list[LocalizedShard]:
|
) -> list[LocalizedShard]:
|
||||||
return find_shard(
|
return find_shard(
|
||||||
shards,
|
shards,
|
||||||
lambda shard: dimension in shard.location
|
lambda shard: (
|
||||||
and shard.location[dimension] == value,
|
dimension in shard.location and shard.location[dimension] == value
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import os
|
import os
|
||||||
|
from typing import ClassVar, override
|
||||||
|
|
||||||
from pydantic_settings import (
|
from pydantic_settings import (
|
||||||
BaseSettings,
|
BaseSettings,
|
||||||
PydanticBaseSettingsSource,
|
PydanticBaseSettingsSource,
|
||||||
|
|
@ -7,15 +9,18 @@ from pydantic_settings import (
|
||||||
)
|
)
|
||||||
from xdg_base_dirs import xdg_config_home
|
from xdg_base_dirs import xdg_config_home
|
||||||
|
|
||||||
SETTINGS_FILE = xdg_config_home() / "streamer" / "config.yaml"
|
SETTINGS_FILE = xdg_config_home() / "streamd" / "config.yaml"
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
model_config = SettingsConfigDict(env_file_encoding="utf-8")
|
model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict(
|
||||||
|
env_file_encoding="utf-8"
|
||||||
|
)
|
||||||
|
|
||||||
base_folder: str = os.getcwd()
|
base_folder: str = os.getcwd()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@override
|
||||||
def settings_customise_sources(
|
def settings_customise_sources(
|
||||||
cls,
|
cls,
|
||||||
settings_cls: type[BaseSettings],
|
settings_cls: type[BaseSettings],
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
|
|
||||||
from streamer.localize import RepositoryConfiguration
|
from streamd.localize import RepositoryConfiguration
|
||||||
from streamer.localize.repository_configuration import (
|
from streamd.localize.repository_configuration import (
|
||||||
Dimension,
|
Dimension,
|
||||||
Marker,
|
Marker,
|
||||||
MarkerPlacement,
|
MarkerPlacement,
|
||||||
|
|
@ -2,9 +2,8 @@ from datetime import datetime
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from streamd.localize import LocalizedShard
|
||||||
from streamer.localize import LocalizedShard
|
from streamd.query.find import find_shard_by_set_dimension
|
||||||
from streamer.query.find import find_shard_by_set_dimension
|
|
||||||
|
|
||||||
from .configuration import TIMESHEET_DIMENSION_NAME, TimesheetPointType
|
from .configuration import TIMESHEET_DIMENSION_NAME, TimesheetPointType
|
||||||
from .timecard import SpecialDayType, Timecard, Timesheet
|
from .timecard import SpecialDayType, Timecard, Timesheet
|
||||||
|
|
@ -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"]
|
|
||||||
283
streamd.svg
Normal file
283
streamd.svg
Normal file
|
|
@ -0,0 +1,283 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="192"
|
||||||
|
height="192"
|
||||||
|
viewBox="0 0 192 192"
|
||||||
|
version="1.1"
|
||||||
|
id="svg5"
|
||||||
|
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||||
|
sodipodi:docname="streamd.svg"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<title
|
||||||
|
id="title1">Streamd</title>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview7"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:snap-bbox-edge-midpoints="true"
|
||||||
|
inkscape:bbox-nodes="true"
|
||||||
|
inkscape:object-paths="true"
|
||||||
|
inkscape:snap-intersection-paths="true"
|
||||||
|
inkscape:snap-object-midpoints="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:snap-smooth-nodes="true"
|
||||||
|
inkscape:zoom="4"
|
||||||
|
inkscape:cx="58.375"
|
||||||
|
inkscape:cy="112.25"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1416"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="layer3"
|
||||||
|
inkscape:snap-grids="true"
|
||||||
|
inkscape:snap-page="true"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:deskcolor="#d1d1d1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid824"
|
||||||
|
empspacing="4"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
spacingy="1"
|
||||||
|
spacingx="1"
|
||||||
|
units="px" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs2">
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient3586">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0.1"
|
||||||
|
offset="0"
|
||||||
|
id="stop3582" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1"
|
||||||
|
id="stop3584" />
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath1598">
|
||||||
|
<ellipse
|
||||||
|
style="fill:#bbdefb"
|
||||||
|
id="ellipse1600"
|
||||||
|
cx="160"
|
||||||
|
cy="40"
|
||||||
|
rx="12"
|
||||||
|
ry="20" />
|
||||||
|
</clipPath>
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
style="color-interpolation-filters:sRGB"
|
||||||
|
id="filter1774"
|
||||||
|
x="-0.043319996"
|
||||||
|
y="-0.043320001"
|
||||||
|
width="1.08664"
|
||||||
|
height="1.08664">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="1.5060667"
|
||||||
|
id="feGaussianBlur1776" />
|
||||||
|
</filter>
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
style="color-interpolation-filters:sRGB"
|
||||||
|
id="filter1839"
|
||||||
|
x="-0.047999999"
|
||||||
|
y="-0.047999999"
|
||||||
|
width="1.096"
|
||||||
|
height="1.096">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="3.04"
|
||||||
|
id="feGaussianBlur1841" />
|
||||||
|
</filter>
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
style="color-interpolation-filters:sRGB"
|
||||||
|
id="filter1886"
|
||||||
|
x="-0.030315789"
|
||||||
|
y="-0.1152"
|
||||||
|
width="1.0606316"
|
||||||
|
height="1.2304">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="1.92"
|
||||||
|
id="feGaussianBlur1888" />
|
||||||
|
</filter>
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath1932">
|
||||||
|
<path
|
||||||
|
style="fill:#e3f2fd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 32,44 v 116 c 0,8 4,12 12,12 40,0 68,-28 115.63984,-28.34001 C 168.99976,143.59319 172,140 172,132 V 44 Z"
|
||||||
|
id="path1934"
|
||||||
|
sodipodi:nodetypes="cccsccc" />
|
||||||
|
</clipPath>
|
||||||
|
<filter
|
||||||
|
inkscape:collect="always"
|
||||||
|
style="color-interpolation-filters:sRGB"
|
||||||
|
id="filter1956"
|
||||||
|
x="-0.030857142"
|
||||||
|
y="-0.108"
|
||||||
|
width="1.0617143"
|
||||||
|
height="1.216">
|
||||||
|
<feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="1.8"
|
||||||
|
id="feGaussianBlur1958" />
|
||||||
|
</filter>
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath1980">
|
||||||
|
<ellipse
|
||||||
|
style="fill:#bbdefb"
|
||||||
|
id="ellipse1982"
|
||||||
|
cx="160"
|
||||||
|
cy="40"
|
||||||
|
rx="12"
|
||||||
|
ry="20" />
|
||||||
|
</clipPath>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3586"
|
||||||
|
id="linearGradient3588"
|
||||||
|
x1="0"
|
||||||
|
y1="0"
|
||||||
|
x2="192"
|
||||||
|
y2="192"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
</defs>
|
||||||
|
<g
|
||||||
|
inkscape:label="Paper"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
style="display:inline"
|
||||||
|
sodipodi:insensitive="true">
|
||||||
|
<path
|
||||||
|
id="path1814"
|
||||||
|
style="opacity:0.2;fill:#000000;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter1839)"
|
||||||
|
d="M 32,20 A 12,20 0 0 0 20,40 12,20 0 0 0 32,60 v 100 c 0,8 4,12 12,12 40,0 68.00079,-27.99983 115.64062,-28.33984 C 169.00055,143.59336 172,140 172,132 V 44 h -0.26758 A 12,20 0 0 0 172,40 12,20 0 0 0 160,20 Z m 125.57812,0.455078 a 12,20 0 0 0 -0.38867,0.128906 12,20 0 0 1 0.38867,-0.128906 z m -2.58984,1.410156 a 12,20 0 0 0 -0.4043,0.333985 12,20 0 0 1 0.4043,-0.333985 z m -2.40039,2.423828 a 12,20 0 0 0 -0.21484,0.314454 12,20 0 0 1 0.21484,-0.314454 z m -1.82031,2.990235 a 12,20 0 0 0 -0.19727,0.373047 12,20 0 0 1 0.19727,-0.373047 z m -1.44531,3.685547 a 12,20 0 0 0 -0.20508,0.697265 12,20 0 0 1 0.20508,-0.697265 z m -0.97266,4.349609 a 12,20 0 0 0 -0.0762,0.650391 12,20 0 0 1 0.0762,-0.650391 z" />
|
||||||
|
<path
|
||||||
|
style="fill:#e0f7fa;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 32,40 v 120 c 0,8 4,12 12,12 40,0 68,-28 115.63984,-28.34001 C 168.99976,143.59319 172,140 172,132 V 40 Z"
|
||||||
|
id="path2678"
|
||||||
|
sodipodi:nodetypes="cccsccc" />
|
||||||
|
<path
|
||||||
|
id="path2431"
|
||||||
|
style="opacity:0.2;fill:#000000;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 172,131 c 0,8 -2.99945,11.59336 -12.35938,11.66016 C 112.00079,143.00017 84,171 44,171 36,171 32,167 32,159 v 1 c 0,8 4,12 12,12 40,0 68.00079,-27.99983 115.64062,-28.33984 C 169.00055,143.59336 172,140 172,132 Z" />
|
||||||
|
<path
|
||||||
|
id="path1863"
|
||||||
|
style="opacity:0.2;fill:#000000;stroke-width:0.470751;filter:url(#filter1886)"
|
||||||
|
d="M 32,20 A 12,20 0 0 0 20,40 12,20 0 0 0 32,60 H 160 A 12,20 0 0 0 172,40 12,20 0 0 0 160,20 Z m 125.57812,0.455078 a 12,20 0 0 0 -0.38867,0.128906 12,20 0 0 1 0.38867,-0.128906 z m -2.58984,1.410156 a 12,20 0 0 0 -0.4043,0.333985 12,20 0 0 1 0.4043,-0.333985 z m -2.40039,2.423828 a 12,20 0 0 0 -0.21484,0.314454 12,20 0 0 1 0.21484,-0.314454 z m -1.82031,2.990235 a 12,20 0 0 0 -0.19727,0.373047 12,20 0 0 1 0.19727,-0.373047 z m -1.44531,3.685547 a 12,20 0 0 0 -0.20508,0.697265 12,20 0 0 1 0.20508,-0.697265 z m -0.97266,4.349609 a 12,20 0 0 0 -0.0762,0.650391 12,20 0 0 1 0.0762,-0.650391 z m -0.0762,8.720703 a 12,20 0 0 0 0.0762,0.650391 12,20 0 0 1 -0.0762,-0.650391 z m 0.84375,4.302735 a 12,20 0 0 0 0.20508,0.697265 12,20 0 0 1 -0.20508,-0.697265 z m 1.45312,4.009765 a 12,20 0 0 0 0.19727,0.373047 12,20 0 0 1 -0.19727,-0.373047 z m 1.80274,3.048828 a 12,20 0 0 0 0.21484,0.314454 12,20 0 0 1 -0.21484,-0.314454 z m 2.21093,2.404297 a 12,20 0 0 0 0.4043,0.333985 12,20 0 0 1 -0.4043,-0.333985 z m 2.60547,1.615235 a 12,20 0 0 0 0.38867,0.128906 12,20 0 0 1 -0.38867,-0.128906 z"
|
||||||
|
clip-path="url(#clipPath1932)" />
|
||||||
|
<ellipse
|
||||||
|
style="fill:#f2f2f2"
|
||||||
|
id="ellipse2158"
|
||||||
|
cx="160"
|
||||||
|
cy="40"
|
||||||
|
rx="12"
|
||||||
|
ry="20" />
|
||||||
|
<path
|
||||||
|
id="rect1442"
|
||||||
|
style="fill:#4dd0e1;stroke-width:0.470751"
|
||||||
|
d="M 32,20 A 12,20 0 0 0 20,40 12,20 0 0 0 32,60 H 160 A 12,20 0 0 1 148,40 12,20 0 0 1 160,20 Z" />
|
||||||
|
<path
|
||||||
|
id="path1936"
|
||||||
|
style="opacity:0.2;fill:#000000;stroke-width:0.470751;filter:url(#filter1956)"
|
||||||
|
d="M 32,20 A 12,20 0 0 0 20,40 12,20 0 0 0 32,60 H 160 A 12,20 0 0 1 148,40 12,20 0 0 1 160,20 Z"
|
||||||
|
clip-path="url(#clipPath1980)" />
|
||||||
|
<path
|
||||||
|
id="rect1406"
|
||||||
|
style="opacity:1;fill:#80deea"
|
||||||
|
d="M 32,20 A 12,20 0 0 0 20,40 h 128 a 12,20 0 0 1 12,-20 z" />
|
||||||
|
<path
|
||||||
|
id="path2390"
|
||||||
|
style="opacity:0.2;fill:#ffffff"
|
||||||
|
d="M 32,20 A 12,20 0 0 0 20,40 h 0.06055 A 12,20 0 0 1 32,20.900391 H 156.64648 A 12,20 0 0 1 160,20 Z" />
|
||||||
|
<path
|
||||||
|
id="path2600"
|
||||||
|
style="opacity:0.2;fill:#000000;stroke-width:0.470751"
|
||||||
|
d="M 20.033203,39.5 C 20.020878,39.666428 20.00981,39.833108 20,40 c 0,11.045695 5.372583,20 12,20 h 128 c -1.1985,-0.03799 -2.38682,-0.375069 -3.52539,-1 H 32 C 25.500897,58.973414 20.195661,50.328485 20.033203,39.5 Z"
|
||||||
|
sodipodi:nodetypes="ccscccc" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer3"
|
||||||
|
inkscape:label="Tag"
|
||||||
|
style="display:inline">
|
||||||
|
<path
|
||||||
|
id="path1772"
|
||||||
|
style="opacity:0.2;fill:#000000;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter1774)"
|
||||||
|
d="M 91.53554,89.53554 C 89.41422,91.65686 88,94.48528 88,97.31371 v 16.97056 c 0,4.24264 0,5.65686 2.82843,8.48529 l 42.42641,42.42639 c 5.65685,5.65686 11.31371,5.65686 16.97056,0 l 16.97056,-16.97056 c 5.65686,-5.65686 5.65686,-11.3137 0,-16.97056 l -42.4264,-42.4264 C 121.94113,86 120.52692,86 116.28428,86 H 99.31371 c -2.82842,0 -5.65685,1.41422 -7.77817,3.53554 z m 4.94975,4.94974 a 8,8 0 0 1 11.3137,0 8,8 0 0 1 0,11.31371 8,8 0 0 1 -11.3137,0 8,8 0 0 1 0,-11.31371 z" />
|
||||||
|
<path
|
||||||
|
id="path7522"
|
||||||
|
style="fill:#d84315;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||||
|
d="M 91.53554,89.53554 C 89.41422,91.65686 88,94.48528 88,97.31371 v 16.97056 c 0,4.24264 0,5.65686 2.82843,8.48529 l 42.42641,42.42639 c 5.65685,5.65686 11.31371,5.65686 16.97056,0 l 16.97056,-16.97056 c 5.65686,-5.65686 5.65686,-11.3137 0,-16.97056 l -42.4264,-42.4264 C 121.94113,86 120.52692,86 116.28428,86 H 99.31371 c -2.82842,0 -5.65685,1.41422 -7.77817,3.53554 z m 4.94975,4.94974 a 8,8 0 0 1 11.3137,0 8,8 0 0 1 0,11.31371 8,8 0 0 1 -11.3137,0 8,8 0 0 1 0,-11.31371 z" />
|
||||||
|
<path
|
||||||
|
style="opacity:0.2;fill:#000000;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 88,113.28516 v 1 c 0,4.24264 -3.05e-4,5.65594 2.828125,8.48437 l 42.425785,42.42578 c 5.65685,5.65686 11.31385,5.65686 16.9707,0 l 16.9707,-16.9707 c 2.99512,-2.99511 4.3894,-5.98927 4.21289,-8.98438 -0.15686,2.66175 -1.55114,5.32263 -4.21289,7.98438 l -16.9707,16.9707 c -5.65685,5.65686 -11.31385,5.65686 -16.9707,0 L 90.828125,121.76953 C 87.999695,118.9411 88,117.5278 88,113.28516 Z"
|
||||||
|
id="path3326" />
|
||||||
|
<path
|
||||||
|
style="opacity:0.2;fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 100.89062,91.240234 a 8,8 0 0 0 -4.406245,2.244141 8,8 0 0 0 -2.244141,5.40625 8,8 0 0 1 2.244141,-4.40625 8,8 0 0 1 11.314455,0 8,8 0 0 1 2.31445,5.158203 8,8 0 0 0 -2.31445,-6.158203 8,8 0 0 0 -6.90821,-2.244141 z"
|
||||||
|
id="path3103" />
|
||||||
|
<path
|
||||||
|
style="opacity:0.2;fill:#000000;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 110.11328,100.64258 a 8,8 0 0 1 -2.31445,5.15625 8,8 0 0 1 -11.314455,0 8,8 0 0 1 -2.244141,-4.4043 8,8 0 0 0 2.244141,5.4043 8,8 0 0 0 11.314455,0 8,8 0 0 0 2.31445,-6.15625 z"
|
||||||
|
id="path3389" />
|
||||||
|
<path
|
||||||
|
style="opacity:0.2;fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 99.314453,86 c -2.82842,0 -5.657977,1.413836 -7.779297,3.535156 C 89.413836,91.656476 88,94.486023 88,97.314453 v 1 c 0,-2.82843 1.413836,-5.657977 3.535156,-7.779297 C 93.656476,88.413836 96.486033,87 99.314453,87 h 16.970707 c 4.24264,0 5.65594,-3.05e-4 8.48437,2.828125 l 42.42578,42.425785 c 2.66175,2.66174 4.05603,5.32458 4.21289,7.98632 0.17651,-2.9951 -1.21777,-5.99121 -4.21289,-8.98632 L 124.76953,88.828125 C 121.9411,85.999695 120.5278,86 116.28516,86 Z"
|
||||||
|
id="path3346" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer4"
|
||||||
|
inkscape:label="Finish"
|
||||||
|
sodipodi:insensitive="true"
|
||||||
|
style="display:inline">
|
||||||
|
<path
|
||||||
|
id="path3525"
|
||||||
|
style="fill:url(#linearGradient3588);fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 32,20 A 12,20 0 0 0 20,40 12,20 0 0 0 32,60 v 100 c 0,8 4,12 12,12 27.15145,0 48.786559,-12.88889 74.77539,-21.2832 l 14.47852,14.47851 c 5.65685,5.65686 11.31385,5.65686 16.9707,0 l 16.9707,-16.9707 c 3.49839,-3.49839 4.82865,-6.99576 4,-10.49414 C 171.74927,136.15451 172,134.25875 172,132 V 44 h -0.26758 A 12,20 0 0 0 172,40 12,20 0 0 0 160,20 Z m 125.57812,0.455078 a 12,20 0 0 0 -0.38867,0.128906 12,20 0 0 1 0.38867,-0.128906 z m -2.58984,1.410156 a 12,20 0 0 0 -0.4043,0.333985 12,20 0 0 1 0.4043,-0.333985 z m -2.40039,2.423828 a 12,20 0 0 0 -0.21484,0.314454 12,20 0 0 1 0.21484,-0.314454 z m -1.82031,2.990235 a 12,20 0 0 0 -0.19727,0.373047 12,20 0 0 1 0.19727,-0.373047 z m -1.44531,3.685547 a 12,20 0 0 0 -0.20508,0.697265 12,20 0 0 1 0.20508,-0.697265 z m -0.97266,4.349609 a 12,20 0 0 0 -0.0762,0.650391 12,20 0 0 1 0.0762,-0.650391 z" />
|
||||||
|
</g>
|
||||||
|
<metadata
|
||||||
|
id="metadata1">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:title>Streamd</dc:title>
|
||||||
|
<dc:creator>
|
||||||
|
<cc:Agent>
|
||||||
|
<dc:title>Konstantin Fickel</dc:title>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:creator>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 14 KiB |
|
|
@ -1,6 +1,6 @@
|
||||||
from datetime import date, datetime, time
|
from datetime import date, datetime, time
|
||||||
|
|
||||||
from streamer.localize.extract_datetime import (
|
from streamd.localize.extract_datetime import (
|
||||||
extract_date_from_marker,
|
extract_date_from_marker,
|
||||||
extract_datetime_from_file_name,
|
extract_datetime_from_file_name,
|
||||||
extract_datetime_from_marker,
|
extract_datetime_from_marker,
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from streamer.localize.repository_configuration import (
|
from streamd.localize.repository_configuration import (
|
||||||
Dimension,
|
Dimension,
|
||||||
Marker,
|
Marker,
|
||||||
MarkerPlacement,
|
MarkerPlacement,
|
||||||
|
|
@ -252,8 +252,8 @@ class TestMergeRepositoryConfiguration:
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
markers={
|
markers={
|
||||||
"Streamer": Marker(
|
"Streamd": Marker(
|
||||||
display_name="Streamer",
|
display_name="Streamd",
|
||||||
placements=[MarkerPlacement(dimension="project")],
|
placements=[MarkerPlacement(dimension="project")],
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -267,8 +267,8 @@ class TestMergeRepositoryConfiguration:
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
markers={
|
markers={
|
||||||
"Streamer": Marker(
|
"Streamd": Marker(
|
||||||
display_name="Streamer2",
|
display_name="Streamd2",
|
||||||
placements=[
|
placements=[
|
||||||
MarkerPlacement(
|
MarkerPlacement(
|
||||||
if_with={"Timesheet"}, dimension="timesheet", value="coding"
|
if_with={"Timesheet"}, dimension="timesheet", value="coding"
|
||||||
|
|
@ -291,9 +291,9 @@ class TestMergeRepositoryConfiguration:
|
||||||
assert merged.dimensions["moment"].display_name == "Moment"
|
assert merged.dimensions["moment"].display_name == "Moment"
|
||||||
assert merged.dimensions["timesheet"].display_name == "Timesheet"
|
assert merged.dimensions["timesheet"].display_name == "Timesheet"
|
||||||
|
|
||||||
assert set(merged.markers.keys()) == {"Streamer", "JobHunting"}
|
assert set(merged.markers.keys()) == {"Streamd", "JobHunting"}
|
||||||
assert merged.markers["Streamer"].display_name == "Streamer2"
|
assert merged.markers["Streamd"].display_name == "Streamd2"
|
||||||
assert merged.markers["Streamer"].placements == [
|
assert merged.markers["Streamd"].placements == [
|
||||||
MarkerPlacement(dimension="project", value=None, if_with=set()),
|
MarkerPlacement(dimension="project", value=None, if_with=set()),
|
||||||
MarkerPlacement(
|
MarkerPlacement(
|
||||||
if_with={"Timesheet"}, dimension="timesheet", value="coding"
|
if_with={"Timesheet"}, dimension="timesheet", value="coding"
|
||||||
|
|
@ -359,7 +359,9 @@ class TestMergeRepositoryConfiguration:
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_merge_repository_configuration_propagate_preserves_base_when_omitted(
|
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)
|
merged = merge_repository_configuration(base, second)
|
||||||
assert merged.dimensions["d"].propagate is expected_propagate
|
assert merged.dimensions["d"].propagate is expected_propagate
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
from faker import Faker
|
from faker import Faker
|
||||||
|
from streamd.parse import Shard, StreamFile, parse_markdown_file
|
||||||
from streamer.parse import Shard, StreamFile, parse_markdown_file
|
|
||||||
|
|
||||||
fake = Faker()
|
fake = Faker()
|
||||||
|
|
||||||
|
|
@ -2,8 +2,8 @@ from __future__ import annotations
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from streamer.localize import LocalizedShard
|
from streamd.localize import LocalizedShard
|
||||||
from streamer.query.find import find_shard, find_shard_by_position
|
from streamd.query.find import find_shard, find_shard_by_position
|
||||||
|
|
||||||
|
|
||||||
def generate_localized_shard(
|
def generate_localized_shard(
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from streamer.localize.localize import localize_stream_file
|
from streamd.localize.localize import localize_stream_file
|
||||||
from streamer.localize.localized_shard import LocalizedShard
|
from streamd.localize.localized_shard import LocalizedShard
|
||||||
from streamer.localize.repository_configuration import (
|
from streamd.localize.repository_configuration import (
|
||||||
Dimension,
|
Dimension,
|
||||||
Marker,
|
Marker,
|
||||||
MarkerPlacement,
|
MarkerPlacement,
|
||||||
RepositoryConfiguration,
|
RepositoryConfiguration,
|
||||||
)
|
)
|
||||||
from streamer.parse.shard import Shard, StreamFile
|
from streamd.parse.shard import Shard, StreamFile
|
||||||
|
|
||||||
repository_configuration = RepositoryConfiguration(
|
repository_configuration = RepositoryConfiguration(
|
||||||
dimensions={
|
dimensions={
|
||||||
|
|
@ -29,8 +29,8 @@ repository_configuration = RepositoryConfiguration(
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
markers={
|
markers={
|
||||||
"Streamer": Marker(
|
"Streamd": Marker(
|
||||||
display_name="Streamer",
|
display_name="Streamd",
|
||||||
placements=[
|
placements=[
|
||||||
MarkerPlacement(dimension="project"),
|
MarkerPlacement(dimension="project"),
|
||||||
MarkerPlacement(
|
MarkerPlacement(
|
||||||
|
|
@ -49,39 +49,39 @@ class TestLocalize:
|
||||||
def test_project_simple_stream_file(self):
|
def test_project_simple_stream_file(self):
|
||||||
stream_file = StreamFile(
|
stream_file = StreamFile(
|
||||||
file_name="20250622-121000 Test File.md",
|
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(
|
assert localize_stream_file(
|
||||||
stream_file, repository_configuration
|
stream_file, repository_configuration
|
||||||
) == LocalizedShard(
|
) == LocalizedShard(
|
||||||
moment=datetime(2025, 6, 22, 12, 10, 0, 0),
|
moment=datetime(2025, 6, 22, 12, 10, 0, 0),
|
||||||
markers=["Streamer"],
|
markers=["Streamd"],
|
||||||
tags=[],
|
tags=[],
|
||||||
start_line=1,
|
start_line=1,
|
||||||
end_line=1,
|
end_line=1,
|
||||||
children=[],
|
children=[],
|
||||||
location={"project": "Streamer", "file": stream_file.file_name},
|
location={"project": "Streamd", "file": stream_file.file_name},
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_timesheet_use_case(self):
|
def test_timesheet_use_case(self):
|
||||||
stream_file = StreamFile(
|
stream_file = StreamFile(
|
||||||
file_name="20260131-210000 Test File.md",
|
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(
|
assert localize_stream_file(
|
||||||
stream_file, repository_configuration
|
stream_file, repository_configuration
|
||||||
) == LocalizedShard(
|
) == LocalizedShard(
|
||||||
moment=datetime(2026, 1, 31, 21, 0, 0, 0),
|
moment=datetime(2026, 1, 31, 21, 0, 0, 0),
|
||||||
markers=["Timesheet", "Streamer"],
|
markers=["Timesheet", "Streamd"],
|
||||||
tags=[],
|
tags=[],
|
||||||
start_line=1,
|
start_line=1,
|
||||||
end_line=1,
|
end_line=1,
|
||||||
children=[],
|
children=[],
|
||||||
location={
|
location={
|
||||||
"file": stream_file.file_name,
|
"file": stream_file.file_name,
|
||||||
"project": "Streamer",
|
"project": "Streamd",
|
||||||
"timesheet": "coding",
|
"timesheet": "coding",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -4,13 +4,13 @@ from datetime import datetime, time
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from streamer.localize.localized_shard import LocalizedShard
|
from streamd.localize.localized_shard import LocalizedShard
|
||||||
from streamer.timesheet.configuration import (
|
from streamd.timesheet.configuration import (
|
||||||
TIMESHEET_DIMENSION_NAME,
|
TIMESHEET_DIMENSION_NAME,
|
||||||
TimesheetPointType,
|
TimesheetPointType,
|
||||||
)
|
)
|
||||||
from streamer.timesheet.extract import extract_timesheets
|
from streamd.timesheet.extract import extract_timesheets
|
||||||
from streamer.timesheet.timecard import SpecialDayType, Timecard, Timesheet
|
from streamd.timesheet.timecard import SpecialDayType, Timecard, Timesheet
|
||||||
|
|
||||||
|
|
||||||
def point(at: datetime, type: TimesheetPointType) -> LocalizedShard:
|
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"):
|
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):
|
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 .*"):
|
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):
|
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"):
|
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):
|
def test_day_with_only_breaks_is_ignored(self):
|
||||||
"""
|
"""
|
||||||
148
uv.lock
generated
148
uv.lock
generated
|
|
@ -1,6 +1,6 @@
|
||||||
version = 1
|
version = 1
|
||||||
revision = 3
|
revision = 3
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.13"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "annotated-doc"
|
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" },
|
{ 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.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "nodejs-wheel-binaries" },
|
||||||
|
]
|
||||||
|
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/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]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
version = "8.3.1"
|
version = "8.3.1"
|
||||||
|
|
@ -43,14 +55,14 @@ wheels = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "faker"
|
name = "faker"
|
||||||
version = "40.4.0"
|
version = "40.11.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
{ 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/94/dc/b68e5378e5a7db0ab776efcdd53b6fe374b29d703e156fd5bb4c5437069e/faker-40.11.0.tar.gz", hash = "sha256:7c419299103b13126bd02ec14bd2b47b946edb5a5eedf305e66a193b25f9a734", size = 1957570, upload-time = "2026-03-13T14:36:11.844Z" }
|
||||||
wheels = [
|
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/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]]
|
[[package]]
|
||||||
|
|
@ -93,12 +105,19 @@ wheels = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nodeenv"
|
name = "nodejs-wheel-binaries"
|
||||||
version = "1.10.0"
|
version = "24.13.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
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 = [
|
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]]
|
[[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" }
|
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 = [
|
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/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/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" },
|
{ 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,24 +204,20 @@ 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/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/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/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]]
|
[[package]]
|
||||||
name = "pydantic-settings"
|
name = "pydantic-settings"
|
||||||
version = "2.12.0"
|
version = "2.13.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
{ name = "python-dotenv" },
|
{ name = "python-dotenv" },
|
||||||
{ name = "typing-inspection" },
|
{ 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/52/6d/fffca34caecc4a3f97bda81b2098da5e8ab7efc9a66e819074a11955d87e/pydantic_settings-2.13.1.tar.gz", hash = "sha256:b4c11847b15237fb0171e1462bf540e294affb9b86db4d9aa5c01730bdbe4025", size = 223826, upload-time = "2026-02-19T13:45:08.055Z" }
|
||||||
wheels = [
|
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/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]
|
[package.optional-dependencies]
|
||||||
|
|
@ -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" },
|
{ 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]]
|
[[package]]
|
||||||
name = "pytest"
|
name = "pytest"
|
||||||
version = "9.0.2"
|
version = "9.0.2"
|
||||||
|
|
@ -277,16 +265,6 @@ version = "6.0.3"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
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" }
|
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 = [
|
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/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/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" },
|
{ 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" },
|
||||||
|
|
@ -319,40 +297,40 @@ wheels = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rich"
|
name = "rich"
|
||||||
version = "14.3.2"
|
version = "14.3.3"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "markdown-it-py" },
|
{ name = "markdown-it-py" },
|
||||||
{ name = "pygments" },
|
{ 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 = [
|
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]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.15.0"
|
version = "0.15.6"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
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/51/df/f8629c19c5318601d3121e230f74cbee7a3732339c52b21daa2b82ef9c7d/ruff-0.15.6.tar.gz", hash = "sha256:8394c7bb153a4e3811a4ecdacd4a8e6a4fa8097028119160dffecdcdf9b56ae4", size = 4597916, upload-time = "2026-03-12T23:05:47.51Z" }
|
||||||
wheels = [
|
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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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]]
|
[[package]]
|
||||||
|
|
@ -365,7 +343,7 @@ wheels = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "streamer"
|
name = "streamd"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|
@ -380,8 +358,8 @@ dependencies = [
|
||||||
|
|
||||||
[package.dev-dependencies]
|
[package.dev-dependencies]
|
||||||
dev = [
|
dev = [
|
||||||
|
{ name = "basedpyright" },
|
||||||
{ name = "faker" },
|
{ name = "faker" },
|
||||||
{ name = "pyright" },
|
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "ruff" },
|
{ name = "ruff" },
|
||||||
]
|
]
|
||||||
|
|
@ -391,23 +369,23 @@ requires-dist = [
|
||||||
{ name = "click", specifier = "==8.3.1" },
|
{ name = "click", specifier = "==8.3.1" },
|
||||||
{ name = "mistletoe", specifier = "==1.5.1" },
|
{ name = "mistletoe", specifier = "==1.5.1" },
|
||||||
{ name = "pydantic", specifier = "==2.12.5" },
|
{ name = "pydantic", specifier = "==2.12.5" },
|
||||||
{ name = "pydantic-settings", extras = ["yaml"], specifier = "==2.12.0" },
|
{ 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.21.2" },
|
{ name = "typer", specifier = "==0.24.1" },
|
||||||
{ name = "xdg-base-dirs", specifier = "==6.0.2" },
|
{ name = "xdg-base-dirs", specifier = "==6.0.2" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
dev = [
|
dev = [
|
||||||
{ name = "faker", specifier = "==40.4.0" },
|
{ name = "basedpyright", specifier = "==1.38.2" },
|
||||||
{ name = "pyright", specifier = "==1.1.408" },
|
{ name = "faker", specifier = "==40.11.0" },
|
||||||
{ name = "pytest", specifier = "==9.0.2" },
|
{ name = "pytest", specifier = "==9.0.2" },
|
||||||
{ name = "ruff", specifier = "==0.15.0" },
|
{ name = "ruff", specifier = "==0.15.6" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typer"
|
name = "typer"
|
||||||
version = "0.21.2"
|
version = "0.24.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "annotated-doc" },
|
{ name = "annotated-doc" },
|
||||||
|
|
@ -415,9 +393,9 @@ dependencies = [
|
||||||
{ name = "rich" },
|
{ name = "rich" },
|
||||||
{ name = "shellingham" },
|
{ 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/f5/24/cb09efec5cc954f7f9b930bf8279447d24618bb6758d4f6adf2574c41780/typer-0.24.1.tar.gz", hash = "sha256:e39b4732d65fbdcde189ae76cf7cd48aeae72919dea1fdfc16593be016256b45", size = 118613, upload-time = "2026-02-21T16:54:40.609Z" }
|
||||||
wheels = [
|
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/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]]
|
[[package]]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue