diff --git a/.claude/commands/ci.md b/.claude/commands/ci.md deleted file mode 100644 index db33f805f..000000000 --- a/.claude/commands/ci.md +++ /dev/null @@ -1,42 +0,0 @@ -# CI Command - -Run continuous integration workflow with automatic issue resolution. - -## Usage - -```bash -/ci -``` - -## Description - -This command executes the full CI pipeline (`mask ci`) and automatically attempts to fix any issues that arise during: - -1. **Quality Checks** - Format, lint, and dead code analysis -2. **Testing** - Run complete test suite with coverage -3. **Building** - Build and validate application containers - -If any step fails, Claude will: -- Analyze the error output -- Identify the root cause -- Apply appropriate fixes (code formatting, dependency issues, test failures, etc.) -- Re-run the failed step to verify the fix -- Continue with the remaining CI steps - -The command ensures all quality gates pass before completing, making it safe for deployment or merge requests. - -## Implementation - -The command will: -1. Run `mask ci` to execute the full CI workflow -2. Monitor output for failures or warnings -3. Automatically resolve common issues: - - Code formatting violations - - Linting errors - - Import/dependency problems - - Test failures - - Build/container issues -4. Re-run failed steps after applying fixes -5. Report final CI status and any unresolved issues - -This provides an automated "fix and retry" approach to CI, reducing manual intervention while maintaining code quality standards. \ No newline at end of file diff --git a/.claude/commands/fix-pull-request-feedback.md b/.claude/commands/fix-pull-request-feedback.md new file mode 100644 index 000000000..bba57510f --- /dev/null +++ b/.claude/commands/fix-pull-request-feedback.md @@ -0,0 +1,19 @@ +# Fix Pull Request Feedback + +> Programmatic feedback resolution + +## Instructions + +Analyze and address comments left on GitHub pull request: $ARGUMENTS. + +Follow these steps: + +- Accept the pull request ID from $ARGUMENTS and fetch outstanding feedback from GitHub using `gh pr view $ARGUMENTS --json comments,reviews` and `gh api repos/:owner/:repo/pulls/$ARGUMENTS/comments` to get comprehensive review data. +- Check the current branch state using git commands to understand what changes have already been made locally, helping avoid duplicate work. +- Parse the fetched feedback to identify unresolved, actionable comments that require code changes (filter out resolved comments, general approvals, or comments already addressed in current branch). +- Use TodoWrite to create a comprehensive checklist of all feedback items that need addressing, including the comment author, file location, and specific change requested. +- For each todo item in the checklist, read the relevant files, implement the requested changes, and mark the todo as in_progress then completed as you work through it. +- After implementing changes for each feedback item, run the appropriate validation command based on the language of the modified files: `mask development python all` for Python changes or `mask development rust all` for Rust changes. +- If Claude is in "accept edits" mode, continue through all changes automatically; if in "approve edits" mode, stop at each proposed change for user review and approval before proceeding. +- After all feedback has been addressed and validation commands have passed, generate a concise bullet point summary of all changes made, organized by file or by feedback topic. +- If validation commands fail, fix the issues and re-run the validation before moving to the next feedback item or generating the final summary. diff --git a/.claude/commands/infrastructure.md b/.claude/commands/infrastructure.md deleted file mode 100644 index 6fbca3520..000000000 --- a/.claude/commands/infrastructure.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -argument-hint: [message] -allowed-tools: Bash(*), Git(*), Pulumi(*) -description: Manage infra (up & down) -argument-hint: up | down -model: claude-3-5-haiku-20241022 ---- - -# Task -Interpret the first token of "$ARGUMENTS" as the action (up|down). Default to up. - -Then: -- If `up`, run: `flox activate --mask infrastructure up` -- If `down`, run: `flox activate -- mask infrastructure down` diff --git a/.claude/commands/lint.md b/.claude/commands/lint.md deleted file mode 100644 index 9088f36e7..000000000 --- a/.claude/commands/lint.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -argument-hint: [message] -allowed-tools: Bash(*), Git(*), Pulumi(*) -description: Manage infra (up & down) -model: claude-3-5-haiku-20241022 ---- - -# Task -- run: `flox activate --mask lint` -- fix any linting errors diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 9cbed98af..912c6bbca 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -1,29 +1,24 @@ { - "permissions": { - "allow": [ - "Bash(aws lightsail:*)", - "Bash(cat:*)", - "Bash(curl:*)", - "Bash(docker:*)", - "Bash(flox activate:*)", - "Bash(gh issue:*)", - "Bash(git add:*)", - "Bash(ln:*)", - "Bash(mask:*)", - "Bash(mise:*)", - "Bash(mkdir:*)", - "Bash(open:*)", - "Bash(pre-commit:*)", - "Bash(pulumi:*)", - "Bash(python -m pytest:*)", - "Bash(rm:*)", - "Bash(timeout 5 curl -I http://localhost:*)", - "Bash(uv:*)", - "WebFetch(domain:docs.github.com)", - "WebSearch" - ], - "deny": [], - "defaultMode": "acceptEdits" - }, - "enableAllProjectMcpServers": false -} \ No newline at end of file + "permissions": { + "allow": [ + "Bash(cat:*)", + "Bash(curl:*)", + "Bash(docker:*)", + "Bash(flox activate:*)", + "Bash(gh issue:*)", + "Bash(mask:*)", + "Bash(mkdir:*)", + "Bash(pre-commit:*)", + "Bash(pulumi:*)", + "Bash(rm:*)", + "Bash(timeout 5 curl -I http://localhost:*)", + "Bash(uv:*)", + "WebFetch(domain:docs.github.com)", + "WebSearch" + ], + "deny": [], + "defaultMode": "acceptEdits" + }, + "enableAllProjectMcpServers": false +} + diff --git a/.dockerignore b/.dockerignore index fe6bd5064..2c9f2a189 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,4 @@ .venv/ **/__pycache__/ +*.pyc + diff --git a/.flox/env/manifest.lock b/.flox/env/manifest.lock index cc58555d3..18777c81f 100644 --- a/.flox/env/manifest.lock +++ b/.flox/env/manifest.lock @@ -46,6 +46,9 @@ "x86_64-linux" ] }, + "gh": { + "pkg-path": "gh" + }, "gum": { "pkg-path": "gum" }, @@ -119,27 +122,27 @@ { "attr_path": "rust-analyzer", "broken": false, - "derivation": "/nix/store/704kac3gwb51bxfk1l03v1jjcvl5i3as-rust-analyzer-2025-08-25.drv", + "derivation": "/nix/store/5yp1z5rpignnnyd5j6wllwd7zn03fqiq-rust-analyzer-2025-10-28.drv", "description": "Modular compiler frontend for the Rust language", "install_id": "rust-analyzer", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "rust-analyzer-2025-08-25", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "name": "rust-analyzer-2025-10-28", "pname": "rust-analyzer", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:02:12.900121Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-04T00:36:47.279901Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2025-08-25", + "version": "2025-10-28", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/i4j351dsjw9jprb6aavfx6h9f56r42mv-rust-analyzer-2025-08-25" + "out": "/nix/store/z63nrc6qyz8d6cj2aknh62w8sxbfgl57-rust-analyzer-2025-10-28" }, "system": "aarch64-darwin", "group": "rust-analyzer", @@ -148,27 +151,27 @@ { "attr_path": "rust-analyzer", "broken": false, - "derivation": "/nix/store/df5ynwbwjykqppvnyn0zv5xs0bj2w0jf-rust-analyzer-2025-08-25.drv", + "derivation": "/nix/store/89whiiy4mf70fma6s4fbmrxm6qj2fzfk-rust-analyzer-2025-10-28.drv", "description": "Modular compiler frontend for the Rust language", "install_id": "rust-analyzer", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "rust-analyzer-2025-08-25", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "name": "rust-analyzer-2025-10-28", "pname": "rust-analyzer", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:31:43.824876Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:31:02.704172Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2025-08-25", + "version": "2025-10-28", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/gjjn5pcnsd5vkh8p8rzdjbwlhaj9prz0-rust-analyzer-2025-08-25" + "out": "/nix/store/2yasv8af8g67phhwr2gnmys06bjj53ax-rust-analyzer-2025-10-28" }, "system": "aarch64-linux", "group": "rust-analyzer", @@ -177,27 +180,27 @@ { "attr_path": "rust-analyzer", "broken": false, - "derivation": "/nix/store/kbacbm9qdp094ycqpq1nr2wxmvvacpwr-rust-analyzer-2025-08-25.drv", + "derivation": "/nix/store/8s5q839liwggqa7qghfwgpzg4lfx702m-rust-analyzer-2025-10-28.drv", "description": "Modular compiler frontend for the Rust language", "install_id": "rust-analyzer", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "rust-analyzer-2025-08-25", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "name": "rust-analyzer-2025-10-28", "pname": "rust-analyzer", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:58:04.586014Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:56:23.553783Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2025-08-25", + "version": "2025-10-28", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/3cgw8w8xqf626h9bkcwawwnqbggbmxj3-rust-analyzer-2025-08-25" + "out": "/nix/store/r1afkswg4jc0kdrfag27ghn27xgf7cy6-rust-analyzer-2025-10-28" }, "system": "x86_64-darwin", "group": "rust-analyzer", @@ -206,27 +209,27 @@ { "attr_path": "rust-analyzer", "broken": false, - "derivation": "/nix/store/d01azp0j8cmlwgwajqsk7b3rckcrmarx-rust-analyzer-2025-08-25.drv", + "derivation": "/nix/store/gmal103ypiy314y75w08xclg6kbg600h-rust-analyzer-2025-10-28.drv", "description": "Modular compiler frontend for the Rust language", "install_id": "rust-analyzer", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "rust-analyzer-2025-08-25", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "name": "rust-analyzer-2025-10-28", "pname": "rust-analyzer", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:29:07.391982Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T17:23:04.056087Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2025-08-25", + "version": "2025-10-28", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/13irk3d1x0qihfhz2c1jv3d170p9sbnc-rust-analyzer-2025-08-25" + "out": "/nix/store/pflbq4iyh3rpbanba11lp3s9y859i55y-rust-analyzer-2025-10-28" }, "system": "x86_64-linux", "group": "rust-analyzer", @@ -235,17 +238,17 @@ { "attr_path": "cargo", "broken": false, - "derivation": "/nix/store/8pzinyw4h41rl9pv504s021p6gxw5ir9-cargo-1.89.0.drv", + "derivation": "/nix/store/5r0l78j53v9vqvc8yb28kw4ml9wabivm-cargo-1.89.0.drv", "description": "Downloads your Rust project's dependencies and builds your project", "install_id": "cargo", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "cargo-1.89.0", "pname": "cargo", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:42.298517Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-04T00:35:18.202964Z", "stabilities": [ "unstable" ], @@ -255,7 +258,7 @@ "out" ], "outputs": { - "out": "/nix/store/gzv6psv17kv7x9s01w8jhi0h2cg6z15p-cargo-1.89.0" + "out": "/nix/store/f61dvjzzqj7c9xv07naqx6ga84vj10ip-cargo-1.89.0" }, "system": "aarch64-darwin", "group": "rust-toolchain", @@ -264,17 +267,17 @@ { "attr_path": "cargo", "broken": false, - "derivation": "/nix/store/98qr5asfdsl0jlhphm333b716kg8hb84-cargo-1.89.0.drv", + "derivation": "/nix/store/9b48lwz5mva14p0p0m2m6xxcc4vq6yzg-cargo-1.89.0.drv", "description": "Downloads your Rust project's dependencies and builds your project", "install_id": "cargo", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "cargo-1.89.0", "pname": "cargo", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:29:40.209171Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:28:57.461564Z", "stabilities": [ "unstable" ], @@ -284,7 +287,7 @@ "out" ], "outputs": { - "out": "/nix/store/ahyjafkgyn6zji9qlvv92z8gxmcmaky4-cargo-1.89.0" + "out": "/nix/store/cp19l4m09lp45cm86ilvqpl1n1bwf5fz-cargo-1.89.0" }, "system": "aarch64-linux", "group": "rust-toolchain", @@ -293,17 +296,17 @@ { "attr_path": "cargo", "broken": false, - "derivation": "/nix/store/bafagc2an2g39mgpzbp52gzbzqh01n19-cargo-1.89.0.drv", + "derivation": "/nix/store/9c96ifqn99sc26fyvrwgrl7217bn9qil-cargo-1.89.0.drv", "description": "Downloads your Rust project's dependencies and builds your project", "install_id": "cargo", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "cargo-1.89.0", "pname": "cargo", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:35.693924Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:54:57.240090Z", "stabilities": [ "unstable" ], @@ -313,7 +316,7 @@ "out" ], "outputs": { - "out": "/nix/store/2a5rg88c4kc4mzjbbyah89c2hhyzjjp6-cargo-1.89.0" + "out": "/nix/store/mdrdfm4q2076c8pp3gk798nzd6g0b5jn-cargo-1.89.0" }, "system": "x86_64-darwin", "group": "rust-toolchain", @@ -322,17 +325,17 @@ { "attr_path": "cargo", "broken": false, - "derivation": "/nix/store/8lgsrn6kkn3pzmr20kfw0dpici3g26qs-cargo-1.89.0.drv", + "derivation": "/nix/store/cdxbvr8pkywshy5h5x1s8lcmxfmyks6b-cargo-1.89.0.drv", "description": "Downloads your Rust project's dependencies and builds your project", "install_id": "cargo", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "cargo-1.89.0", "pname": "cargo", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:26:56.292713Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T17:20:46.748193Z", "stabilities": [ "unstable" ], @@ -342,7 +345,7 @@ "out" ], "outputs": { - "out": "/nix/store/xq6ns6hdgl7fdshisp5mb65f1jlysm0h-cargo-1.89.0" + "out": "/nix/store/ynhfvh8h1da3l2hnm15ab2fh3h8a6lf4-cargo-1.89.0" }, "system": "x86_64-linux", "group": "rust-toolchain", @@ -351,17 +354,17 @@ { "attr_path": "clippy", "broken": false, - "derivation": "/nix/store/hagqy5xiqk2bj7v036pkldcy6q6vlg0c-clippy-1.89.0.drv", + "derivation": "/nix/store/p5hwl8zlmrp3219ixq5gjz22iv8mr592-clippy-1.89.0.drv", "description": "Bunch of lints to catch common mistakes and improve your Rust code", "install_id": "clippy", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "clippy-1.89.0", "pname": "clippy", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:42.480384Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-04T00:35:18.375302Z", "stabilities": [ "unstable" ], @@ -371,7 +374,7 @@ "out" ], "outputs": { - "out": "/nix/store/lir6xy0c48yv9ql01rh37j1pn7aprx26-clippy-1.89.0" + "out": "/nix/store/i3390dnz9cddhzz3s9kh7vqmmbxq5fbk-clippy-1.89.0" }, "system": "aarch64-darwin", "group": "rust-toolchain", @@ -380,17 +383,17 @@ { "attr_path": "clippy", "broken": false, - "derivation": "/nix/store/b9lyixcyfgp0zd7wpi7yz07k56kf74cy-clippy-1.89.0.drv", + "derivation": "/nix/store/b9rfh88naayckmnn6gc3zf81xs4xnzff-clippy-1.89.0.drv", "description": "Bunch of lints to catch common mistakes and improve your Rust code", "install_id": "clippy", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "clippy-1.89.0", "pname": "clippy", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:29:40.438541Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:28:57.680916Z", "stabilities": [ "unstable" ], @@ -400,8 +403,8 @@ "out" ], "outputs": { - "debug": "/nix/store/clcyvq3wnj9hcpi55c0735999p1x7blr-clippy-1.89.0-debug", - "out": "/nix/store/7yrdzgagn32yvn6l0g9m7jgj113l9271-clippy-1.89.0" + "debug": "/nix/store/b71z3inpp723452f3jyq7rhng3khadyn-clippy-1.89.0-debug", + "out": "/nix/store/rsyy2pz3hbwghyq1l09jqpg3lr31v365-clippy-1.89.0" }, "system": "aarch64-linux", "group": "rust-toolchain", @@ -410,17 +413,17 @@ { "attr_path": "clippy", "broken": false, - "derivation": "/nix/store/gl2wp9wp5xk7jb7ni7pvnk40i58q2ib1-clippy-1.89.0.drv", + "derivation": "/nix/store/qp6mmi777aflzi2qmkqp90wsw9dwvc9a-clippy-1.89.0.drv", "description": "Bunch of lints to catch common mistakes and improve your Rust code", "install_id": "clippy", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "clippy-1.89.0", "pname": "clippy", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:35.904970Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:54:57.417700Z", "stabilities": [ "unstable" ], @@ -430,7 +433,7 @@ "out" ], "outputs": { - "out": "/nix/store/khg7wkc43bigb8l9gf8snj5b80lylyld-clippy-1.89.0" + "out": "/nix/store/0cdfy1i477bfzhacv93cs8i13282c2jq-clippy-1.89.0" }, "system": "x86_64-darwin", "group": "rust-toolchain", @@ -439,17 +442,17 @@ { "attr_path": "clippy", "broken": false, - "derivation": "/nix/store/qf1ahw46ck02hi9mivq2spk5aa6f630l-clippy-1.89.0.drv", + "derivation": "/nix/store/0z47sqchm2pczv3h4fp730aqqy76igfq-clippy-1.89.0.drv", "description": "Bunch of lints to catch common mistakes and improve your Rust code", "install_id": "clippy", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "clippy-1.89.0", "pname": "clippy", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:26:56.539669Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T17:20:46.988856Z", "stabilities": [ "unstable" ], @@ -459,8 +462,8 @@ "out" ], "outputs": { - "debug": "/nix/store/81c1ha8p1dscxbksy1zgdm9b5pga7gpz-clippy-1.89.0-debug", - "out": "/nix/store/mzsh6fr9kzck0xh97d9kfd8h2iyfcyfb-clippy-1.89.0" + "debug": "/nix/store/ypqv62aqhanfvkrnfg612pbby11wsbnf-clippy-1.89.0-debug", + "out": "/nix/store/0yy1f5k22s6x9n6hva5n7v2fpnv3r7zw-clippy-1.89.0" }, "system": "x86_64-linux", "group": "rust-toolchain", @@ -469,15 +472,15 @@ { "attr_path": "rustPlatform.rustLibSrc", "broken": false, - "derivation": "/nix/store/s21qvhv8hzb2gmcvmfyp6b00zpd182k6-rust-lib-src.drv", + "derivation": "/nix/store/jrkzzcy77ckj0fka38kg65yab9a2f0lx-rust-lib-src.drv", "install_id": "rust-lib-src", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rust-lib-src", "pname": "rustLibSrc", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:03:15.071255Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-04T00:37:54.881351Z", "stabilities": [ "unstable" ], @@ -487,7 +490,7 @@ "out" ], "outputs": { - "out": "/nix/store/90x1dg19kg8slq7jk5zvix7f7q7j51xq-rust-lib-src" + "out": "/nix/store/fyggs0s1lab9ax9gicqc1mgs4n5xj2d5-rust-lib-src" }, "system": "aarch64-darwin", "group": "rust-toolchain", @@ -496,15 +499,15 @@ { "attr_path": "rustPlatform.rustLibSrc", "broken": false, - "derivation": "/nix/store/74c0xd1305d2nl7rn9cyrjgy61dlb3a6-rust-lib-src.drv", + "derivation": "/nix/store/aqnjcfnafka5mgh694xzlg0nakdh5plh-rust-lib-src.drv", "install_id": "rust-lib-src", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rust-lib-src", "pname": "rustLibSrc", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:33:02.524482Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:32:27.224394Z", "stabilities": [ "unstable" ], @@ -514,7 +517,7 @@ "out" ], "outputs": { - "out": "/nix/store/v6warxcrlb1ksscwp9dywbskmsdpw9wv-rust-lib-src" + "out": "/nix/store/fjv3wbnhg8j5jp923mdin804xxw6jfqi-rust-lib-src" }, "system": "aarch64-linux", "group": "rust-toolchain", @@ -523,15 +526,15 @@ { "attr_path": "rustPlatform.rustLibSrc", "broken": false, - "derivation": "/nix/store/p40zkwiym67p1s1ng1826vv3x2bvfbia-rust-lib-src.drv", + "derivation": "/nix/store/i7sxmg5w1x62xq6nl2rwx0klyibcjmc1-rust-lib-src.drv", "install_id": "rust-lib-src", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rust-lib-src", "pname": "rustLibSrc", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:59:06.785792Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:57:26.442568Z", "stabilities": [ "unstable" ], @@ -541,7 +544,7 @@ "out" ], "outputs": { - "out": "/nix/store/na43p9zh9d0x222vva4mb2b34anhj4l2-rust-lib-src" + "out": "/nix/store/9bjj0ilq2a4l4ybva4g44vadp725fmgc-rust-lib-src" }, "system": "x86_64-darwin", "group": "rust-toolchain", @@ -550,15 +553,15 @@ { "attr_path": "rustPlatform.rustLibSrc", "broken": false, - "derivation": "/nix/store/74hdj06bvh6rx572jr2jwx30jpkbnkyz-rust-lib-src.drv", + "derivation": "/nix/store/ws9yx7lpqska14v8irsyc792aga0nvnw-rust-lib-src.drv", "install_id": "rust-lib-src", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rust-lib-src", "pname": "rustLibSrc", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:30:29.473856Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T17:24:38.625914Z", "stabilities": [ "unstable" ], @@ -568,7 +571,7 @@ "out" ], "outputs": { - "out": "/nix/store/497imwr2k586w2ll2r8rji5jz92f2y9j-rust-lib-src" + "out": "/nix/store/77xvx5vjwapbik9pwy5clbiz0r72279i-rust-lib-src" }, "system": "x86_64-linux", "group": "rust-toolchain", @@ -577,17 +580,17 @@ { "attr_path": "rustc", "broken": false, - "derivation": "/nix/store/h7y7alkm8wya8dj6ifwbmfm55kfr2awx-rustc-wrapper-1.89.0.drv", + "derivation": "/nix/store/9v4pdmxxrd8dv915h45pqd2sn6q0gf5h-rustc-wrapper-1.89.0.drv", "description": "Safe, concurrent, practical language (wrapper script)", "install_id": "rustc", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rustc-wrapper-1.89.0", "pname": "rustc", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:02:12.946244Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-04T00:36:47.325918Z", "stabilities": [ "unstable" ], @@ -598,9 +601,9 @@ "out" ], "outputs": { - "doc": "/nix/store/jbw8jvpsjglk09wyxknnjfrsy42x654d-rustc-wrapper-1.89.0-doc", - "man": "/nix/store/hqw8xk2qvyv7afmvllj2c4lzxylacw92-rustc-wrapper-1.89.0-man", - "out": "/nix/store/ir2arizs2b2azr189dmyg4lhp0vps9nn-rustc-wrapper-1.89.0" + "doc": "/nix/store/b38f38i4l6pvw5x06ng3y2g34xx97ain-rustc-wrapper-1.89.0-doc", + "man": "/nix/store/sp5l2qbp6drmkbk80z6ks5hdnbaivsq4-rustc-wrapper-1.89.0-man", + "out": "/nix/store/5j36vpc3dcbqpjy73nxbsp6bx0g1k3fv-rustc-wrapper-1.89.0" }, "system": "aarch64-darwin", "group": "rust-toolchain", @@ -609,17 +612,17 @@ { "attr_path": "rustc", "broken": false, - "derivation": "/nix/store/qa2jln5j19qim4npi9dhqrdm3isydm2x-rustc-wrapper-1.89.0.drv", + "derivation": "/nix/store/r3wd9nbl7ydl5zv8v0nb1yl0ax2895c2-rustc-wrapper-1.89.0.drv", "description": "Safe, concurrent, practical language (wrapper script)", "install_id": "rustc", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rustc-wrapper-1.89.0", "pname": "rustc", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:31:43.879924Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:31:02.763829Z", "stabilities": [ "unstable" ], @@ -630,9 +633,9 @@ "out" ], "outputs": { - "doc": "/nix/store/kwaljcc4wij7gn4g6w7g1chdgyhgfv17-rustc-wrapper-1.89.0-doc", - "man": "/nix/store/n1xxlafvvfa6yy0bqpifv95vz2nyfjyn-rustc-wrapper-1.89.0-man", - "out": "/nix/store/yxh9cs2lshqgk6h0kp256yms3w8qwmsz-rustc-wrapper-1.89.0" + "doc": "/nix/store/ky97k3ch6szgmwj4jvhhzwxs2dpj87ri-rustc-wrapper-1.89.0-doc", + "man": "/nix/store/9nxjc3iv8h9qd1fcgdk4nrd0gjpmr9z0-rustc-wrapper-1.89.0-man", + "out": "/nix/store/59s3wpvdgm48kphsfn7gpnd3793c1rji-rustc-wrapper-1.89.0" }, "system": "aarch64-linux", "group": "rust-toolchain", @@ -641,17 +644,17 @@ { "attr_path": "rustc", "broken": false, - "derivation": "/nix/store/d4hipi0d0csrs077yzjd13s5daj2fh4v-rustc-wrapper-1.89.0.drv", + "derivation": "/nix/store/gw59ljiqcjivxzzdphv7rsvw4fch7ig3-rustc-wrapper-1.89.0.drv", "description": "Safe, concurrent, practical language (wrapper script)", "install_id": "rustc", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rustc-wrapper-1.89.0", "pname": "rustc", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:58:04.631386Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:56:23.595084Z", "stabilities": [ "unstable" ], @@ -662,9 +665,9 @@ "out" ], "outputs": { - "doc": "/nix/store/7nkka183wnqgwdfd27a8bzkxwpczmbd1-rustc-wrapper-1.89.0-doc", - "man": "/nix/store/zainldlgd3zz8wsxgri4w4qlzdyrjhah-rustc-wrapper-1.89.0-man", - "out": "/nix/store/h1vqiwjdahfzvy9w192kz4pjqsic2bkp-rustc-wrapper-1.89.0" + "doc": "/nix/store/f5fnw9k37frcag45pqcd1z4q9f22q7lb-rustc-wrapper-1.89.0-doc", + "man": "/nix/store/cvjs8z1q0k86i6bwyhcdbrw90pbf6vl3-rustc-wrapper-1.89.0-man", + "out": "/nix/store/83wfwlnxqrb6nazzi3gb42baqbjn1n6f-rustc-wrapper-1.89.0" }, "system": "x86_64-darwin", "group": "rust-toolchain", @@ -673,17 +676,17 @@ { "attr_path": "rustc", "broken": false, - "derivation": "/nix/store/4bycw2rdgf33gmn1z26knv8grxxh06w5-rustc-wrapper-1.89.0.drv", + "derivation": "/nix/store/scfhx31076gi40xisf1gaqw6f7830sv0-rustc-wrapper-1.89.0.drv", "description": "Safe, concurrent, practical language (wrapper script)", "install_id": "rustc", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rustc-wrapper-1.89.0", "pname": "rustc", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:29:07.448628Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T17:23:04.117531Z", "stabilities": [ "unstable" ], @@ -694,9 +697,9 @@ "out" ], "outputs": { - "doc": "/nix/store/7ns2kwk74yn86csi2cpcxpnl3qg32s19-rustc-wrapper-1.89.0-doc", - "man": "/nix/store/1qas0d89hs3lzccywq1zhpwgf3rnh8p1-rustc-wrapper-1.89.0-man", - "out": "/nix/store/hcginxlb1vivl6v6vjmi61s96082270d-rustc-wrapper-1.89.0" + "doc": "/nix/store/15vjayx5plj1h5bqvlif6wdg6m6p6kkh-rustc-wrapper-1.89.0-doc", + "man": "/nix/store/20pcgwwz1hpbzimv9j4vmpbn83yyjrq0-rustc-wrapper-1.89.0-man", + "out": "/nix/store/kgln61a78z8aj4amxgp0lyjj508xxwkr-rustc-wrapper-1.89.0" }, "system": "x86_64-linux", "group": "rust-toolchain", @@ -705,17 +708,17 @@ { "attr_path": "rustfmt", "broken": false, - "derivation": "/nix/store/xir3jl5wi4vfjwar2zn5v1j2ywi4rg0x-rustfmt-1.89.0.drv", + "derivation": "/nix/store/3kgv2ac1vcdz1q8yn2w3w4h5kd066ipy-rustfmt-1.89.0.drv", "description": "Tool for formatting Rust code according to style guidelines", "install_id": "rustfmt", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rustfmt-1.89.0", "pname": "rustfmt", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:02:12.965374Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-04T00:36:47.346012Z", "stabilities": [ "unstable" ], @@ -725,7 +728,7 @@ "out" ], "outputs": { - "out": "/nix/store/m46axwglrbpxm3d0a2zzm62wpv956461-rustfmt-1.89.0" + "out": "/nix/store/5f1n6pbc2hy76n2gzhwa78b3zix3ggg5-rustfmt-1.89.0" }, "system": "aarch64-darwin", "group": "rust-toolchain", @@ -734,17 +737,17 @@ { "attr_path": "rustfmt", "broken": false, - "derivation": "/nix/store/ar3l4ivzdsv0pg2whg157nl0pin2y74k-rustfmt-1.89.0.drv", + "derivation": "/nix/store/z1naxivxg7kx9vmksh51gcqzljr643xb-rustfmt-1.89.0.drv", "description": "Tool for formatting Rust code according to style guidelines", "install_id": "rustfmt", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rustfmt-1.89.0", "pname": "rustfmt", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:31:43.908007Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:31:02.795214Z", "stabilities": [ "unstable" ], @@ -754,7 +757,7 @@ "out" ], "outputs": { - "out": "/nix/store/lk7ill5b5n7rivr3b24q7gszjdgw7xdh-rustfmt-1.89.0" + "out": "/nix/store/38j5bn7l5qk5panxsdr7fi92zg7nz9hh-rustfmt-1.89.0" }, "system": "aarch64-linux", "group": "rust-toolchain", @@ -763,17 +766,17 @@ { "attr_path": "rustfmt", "broken": false, - "derivation": "/nix/store/nm87f091ajs5wmyk4nfb1m30b13zr11m-rustfmt-1.89.0.drv", + "derivation": "/nix/store/3ismbnwhj4mhyiynnh2wn4y6fjbszz00-rustfmt-1.89.0.drv", "description": "Tool for formatting Rust code according to style guidelines", "install_id": "rustfmt", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rustfmt-1.89.0", "pname": "rustfmt", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:58:04.650001Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T16:56:23.613817Z", "stabilities": [ "unstable" ], @@ -783,7 +786,7 @@ "out" ], "outputs": { - "out": "/nix/store/x0x8ikn0gz0alg07fh0hnf0znl2mzm2m-rustfmt-1.89.0" + "out": "/nix/store/ihazzv14jps09j69ijla4npx1wbqydxp-rustfmt-1.89.0" }, "system": "x86_64-darwin", "group": "rust-toolchain", @@ -792,17 +795,17 @@ { "attr_path": "rustfmt", "broken": false, - "derivation": "/nix/store/jv3cxvxnmg2ax4n1x4nldr63s5fi7idw-rustfmt-1.89.0.drv", + "derivation": "/nix/store/7wrnhk2ic58zdl14zrip24gn6l3czpag-rustfmt-1.89.0.drv", "description": "Tool for formatting Rust code according to style guidelines", "install_id": "rustfmt", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "name": "rustfmt-1.89.0", "pname": "rustfmt", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:29:07.481389Z", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", + "rev_count": 888552, + "rev_date": "2025-11-02T19:18:41Z", + "scrape_date": "2025-11-05T17:23:04.149887Z", "stabilities": [ "unstable" ], @@ -812,7 +815,7 @@ "out" ], "outputs": { - "out": "/nix/store/26qhfy2g59mg6q1y0xdgd8ji06v7vnww-rustfmt-1.89.0" + "out": "/nix/store/a6yc6xyjml0lggp1kr4mn8zccyq5rkiy-rustfmt-1.89.0" }, "system": "x86_64-linux", "group": "rust-toolchain", @@ -821,28 +824,28 @@ { "attr_path": "awscli2", "broken": false, - "derivation": "/nix/store/61k4r7alrcgjb6pwlwmbqg8pngdgjzl6-awscli2-2.28.1.drv", + "derivation": "/nix/store/zw39bpfakx85qyxjvnmzkil5cchc839y-awscli2-2.31.39.drv", "description": "Unified tool to manage your AWS services", "install_id": "awscli2", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "awscli2-2.28.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "awscli2-2.31.39", "pname": "awscli2", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:42.181738Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:54:46.724814Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2.28.1", + "version": "2.31.39", "outputs_to_install": [ "out" ], "outputs": { - "dist": "/nix/store/hp729y4fn4z9bk0lf25v0ys8xm7a5m80-awscli2-2.28.1-dist", - "out": "/nix/store/q7b2y1yn15sqipi20ccxkb73ad0vn4x2-awscli2-2.28.1" + "dist": "/nix/store/nhnmx2dgfd8rd8pnyv396qzsq4gf0933-awscli2-2.31.39-dist", + "out": "/nix/store/h4b0scch07rfyy3jr5lv3cmj7myhn1nl-awscli2-2.31.39" }, "system": "aarch64-darwin", "group": "toplevel", @@ -851,28 +854,28 @@ { "attr_path": "awscli2", "broken": false, - "derivation": "/nix/store/jyaqvdybcghmpvq2z7yliwrk281n2al6-awscli2-2.28.1.drv", + "derivation": "/nix/store/3v75xnrafbqja29sfdf7faixmbackfsq-awscli2-2.31.39.drv", "description": "Unified tool to manage your AWS services", "install_id": "awscli2", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "awscli2-2.28.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "awscli2-2.31.39", "pname": "awscli2", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:29:40.014211Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:04:24.538916Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2.28.1", + "version": "2.31.39", "outputs_to_install": [ "out" ], "outputs": { - "dist": "/nix/store/xpk90k08j0hvcfamnzv32863p4527p0j-awscli2-2.28.1-dist", - "out": "/nix/store/5axh2h7wqxrxdhbndfjdxxphmjqd7h2r-awscli2-2.28.1" + "dist": "/nix/store/gc65qq3jlkk17ajk4yscz5j1kws6bcmb-awscli2-2.31.39-dist", + "out": "/nix/store/bxbryfgqh3srva8c7snqr97iir5qrjka-awscli2-2.31.39" }, "system": "aarch64-linux", "group": "toplevel", @@ -881,28 +884,28 @@ { "attr_path": "awscli2", "broken": false, - "derivation": "/nix/store/wcvsklmab320fn7dc6aar6g7i9rzy73z-awscli2-2.28.1.drv", + "derivation": "/nix/store/fx76wqrc7qjqcjcf8vgfcv9rah4f4jny-awscli2-2.31.39.drv", "description": "Unified tool to manage your AWS services", "install_id": "awscli2", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "awscli2-2.28.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "awscli2-2.31.39", "pname": "awscli2", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:35.577980Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:14:44.854614Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2.28.1", + "version": "2.31.39", "outputs_to_install": [ "out" ], "outputs": { - "dist": "/nix/store/0wh0d7dfzzd7xxkriq9fr3dn2r7kf23q-awscli2-2.28.1-dist", - "out": "/nix/store/4ksgk89nvhdc67n1bp2avlcxyf49dn6z-awscli2-2.28.1" + "dist": "/nix/store/dxaq2vpl8pykf25bydc433mq521iha4q-awscli2-2.31.39-dist", + "out": "/nix/store/lpzh5s8cgp0z8a5l8dscmx2v0hcr3adm-awscli2-2.31.39" }, "system": "x86_64-darwin", "group": "toplevel", @@ -911,28 +914,28 @@ { "attr_path": "awscli2", "broken": false, - "derivation": "/nix/store/g1z7dxlrpprzfrpbvd392cvr9qy95mmm-awscli2-2.28.1.drv", + "derivation": "/nix/store/v8jyr5rkv67a0myavkr192y48dja3bs7-awscli2-2.31.39.drv", "description": "Unified tool to manage your AWS services", "install_id": "awscli2", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "awscli2-2.28.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "awscli2-2.31.39", "pname": "awscli2", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:26:56.105929Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:23:58.995964Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2.28.1", + "version": "2.31.39", "outputs_to_install": [ "out" ], "outputs": { - "dist": "/nix/store/kzndsmpzn6a996pcpxpmzd3yb9vx2jag-awscli2-2.28.1-dist", - "out": "/nix/store/xnagpklklap740m98j6jgd14sv94b1cb-awscli2-2.28.1" + "dist": "/nix/store/b2l8xsgwsw7sg0jwwbsz53rpnv1sc1ns-awscli2-2.31.39-dist", + "out": "/nix/store/g0i13qaim2j6amiz22qzxinxyvgs0pb3-awscli2-2.31.39" }, "system": "x86_64-linux", "group": "toplevel", @@ -941,27 +944,27 @@ { "attr_path": "bacon", "broken": false, - "derivation": "/nix/store/lz3zbmgdhbj6c7wskl55s2k3z4b488fa-bacon-3.18.0.drv", + "derivation": "/nix/store/3zgks60slrh0jw0vvmb2fsr1p4wy4gbd-bacon-3.20.1.drv", "description": "Background rust code checker", "install_id": "bacon", "license": "AGPL-3.0-only", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "bacon-3.18.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "bacon-3.20.1", "pname": "bacon", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:42.203726Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:54:46.747051Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.18.0", + "version": "3.20.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/ac0syqynvyli94a6xnspdywq3f4d53l1-bacon-3.18.0" + "out": "/nix/store/qy63ba3mfvwwcf4d4izxml8wmwrkfwcy-bacon-3.20.1" }, "system": "aarch64-darwin", "group": "toplevel", @@ -970,27 +973,27 @@ { "attr_path": "bacon", "broken": false, - "derivation": "/nix/store/3g0n7jfj7ddlcql5vcrhngggvwrb6vcs-bacon-3.18.0.drv", + "derivation": "/nix/store/gacbcjngrsa5s1972hvgzlplkzyv5r0c-bacon-3.20.1.drv", "description": "Background rust code checker", "install_id": "bacon", "license": "AGPL-3.0-only", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "bacon-3.18.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "bacon-3.20.1", "pname": "bacon", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:29:40.039662Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:04:24.565960Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.18.0", + "version": "3.20.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/pkvskm6alpzinmmrcayb0fa3naqw5kpi-bacon-3.18.0" + "out": "/nix/store/927clr1by9530r3x70fv0zq35ddrlr1p-bacon-3.20.1" }, "system": "aarch64-linux", "group": "toplevel", @@ -999,27 +1002,27 @@ { "attr_path": "bacon", "broken": false, - "derivation": "/nix/store/kcbxnazl89djvd4x8xy58vrcnsyys2k4-bacon-3.18.0.drv", + "derivation": "/nix/store/cx6mgh51dj8ngwag6zabf812cpaph78c-bacon-3.20.1.drv", "description": "Background rust code checker", "install_id": "bacon", "license": "AGPL-3.0-only", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "bacon-3.18.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "bacon-3.20.1", "pname": "bacon", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:35.599148Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:14:44.876817Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.18.0", + "version": "3.20.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/sw39s1i457mzpdmpg4wns3217m6pyn6w-bacon-3.18.0" + "out": "/nix/store/6p5462sqw8sng6j8hlwm5lfzbgrbk052-bacon-3.20.1" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1028,27 +1031,27 @@ { "attr_path": "bacon", "broken": false, - "derivation": "/nix/store/3hv9r0ishjmc06by469q785dhwn37s4g-bacon-3.18.0.drv", + "derivation": "/nix/store/qbvgkp7v2jdfxfcrrxkfl1kmfcs6q69z-bacon-3.20.1.drv", "description": "Background rust code checker", "install_id": "bacon", "license": "AGPL-3.0-only", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "bacon-3.18.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "bacon-3.20.1", "pname": "bacon", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:26:56.133339Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:23:59.025282Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.18.0", + "version": "3.20.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/g9i3aplxqlk9wiwcgdpknbq7xd8d6qkc-bacon-3.18.0" + "out": "/nix/store/3gd0fd1pzdv8ysf43vin8qfa1b4yqihs-bacon-3.20.1" }, "system": "x86_64-linux", "group": "toplevel", @@ -1057,27 +1060,27 @@ { "attr_path": "cargo-nextest", "broken": false, - "derivation": "/nix/store/9zdsbcs5d2lqz2k2pipqw71n9vrn5n7k-cargo-nextest-0.9.103.drv", + "derivation": "/nix/store/927dck1rnl06dqlixmlfc05sx8dfm872-cargo-nextest-0.9.114.drv", "description": "Next-generation test runner for Rust projects", "install_id": "cargo-nextest", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "cargo-nextest-0.9.103", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "cargo-nextest-0.9.114", "pname": "cargo-nextest", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:42.309164Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:54:46.851075Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.9.103", + "version": "0.9.114", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/9zjrh275pw8hqw1hvlh0hxg54ywsziyc-cargo-nextest-0.9.103" + "out": "/nix/store/xq51fbjkz9wnnc9ns52nmf7j7b791iqv-cargo-nextest-0.9.114" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1086,27 +1089,27 @@ { "attr_path": "cargo-nextest", "broken": false, - "derivation": "/nix/store/9n8jbs30ns85456g6fc4ywyhbdlv75sq-cargo-nextest-0.9.103.drv", + "derivation": "/nix/store/w5046lyzc9rm8g24b0brm4vibv5b3rhd-cargo-nextest-0.9.114.drv", "description": "Next-generation test runner for Rust projects", "install_id": "cargo-nextest", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "cargo-nextest-0.9.103", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "cargo-nextest-0.9.114", "pname": "cargo-nextest", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:29:40.221369Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:04:24.713743Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.9.103", + "version": "0.9.114", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/cih4m7jkv446v5hspcs2vam3qi6wg2dj-cargo-nextest-0.9.103" + "out": "/nix/store/5k1gkiibiygxr08rbhdr48f0qwafxzap-cargo-nextest-0.9.114" }, "system": "aarch64-linux", "group": "toplevel", @@ -1115,27 +1118,27 @@ { "attr_path": "cargo-nextest", "broken": false, - "derivation": "/nix/store/56l75x88f555m1q95jcsznvv63pwahcz-cargo-nextest-0.9.103.drv", + "derivation": "/nix/store/4s6gjjqw5mszhmvv0ncq61y057cyb9pc-cargo-nextest-0.9.114.drv", "description": "Next-generation test runner for Rust projects", "install_id": "cargo-nextest", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "cargo-nextest-0.9.103", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "cargo-nextest-0.9.114", "pname": "cargo-nextest", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:35.704649Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:14:44.978809Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.9.103", + "version": "0.9.114", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/bkx7p1ksh3jymc9lvhz89a4rjgz48fw8-cargo-nextest-0.9.103" + "out": "/nix/store/lml5dkj93sbi9452jg16qqfqbd6iwxnb-cargo-nextest-0.9.114" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1144,27 +1147,27 @@ { "attr_path": "cargo-nextest", "broken": false, - "derivation": "/nix/store/hkqqh71ar6vfrywhhxiah1llw46gahig-cargo-nextest-0.9.103.drv", + "derivation": "/nix/store/0kcal05m0iz59mycgqv2igsh0dzxds5n-cargo-nextest-0.9.114.drv", "description": "Next-generation test runner for Rust projects", "install_id": "cargo-nextest", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "cargo-nextest-0.9.103", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "cargo-nextest-0.9.114", "pname": "cargo-nextest", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:26:56.305750Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:23:59.192993Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.9.103", + "version": "0.9.114", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/czv3wpy2ix6233j6qjg1nb4cz7c1dsla-cargo-nextest-0.9.103" + "out": "/nix/store/z2l7mvxaxmlahk5mrqn0n72sfjs9lmlk-cargo-nextest-0.9.114" }, "system": "x86_64-linux", "group": "toplevel", @@ -1173,27 +1176,27 @@ { "attr_path": "cargo-tarpaulin", "broken": false, - "derivation": "/nix/store/afhbhbhjjfn5zh3sxgyy5nk5nyp92fsk-cargo-tarpaulin-0.32.8.drv", + "derivation": "/nix/store/247jy6mkjq0hk6a4csxa4kqmpqg6v3j7-cargo-tarpaulin-0.34.1.drv", "description": "Code coverage tool for Rust projects", "install_id": "cargo-tarpaulin", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "cargo-tarpaulin-0.32.8", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "cargo-tarpaulin-0.34.1", "pname": "cargo-tarpaulin", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:42.313470Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:54:46.855491Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.32.8", + "version": "0.34.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/p4l4znf9xpiynnk8aa94c5k9hkwmvhjd-cargo-tarpaulin-0.32.8" + "out": "/nix/store/qgni7qpyjxw0bl6wv6rzj4k8ynjk7n0q-cargo-tarpaulin-0.34.1" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1202,27 +1205,27 @@ { "attr_path": "cargo-tarpaulin", "broken": false, - "derivation": "/nix/store/shdjnigsgncgcxr5ri3d952zisvrbn6c-cargo-tarpaulin-0.32.8.drv", + "derivation": "/nix/store/q4mzxb5d6338byzg1l6vchkrg4hr60wv-cargo-tarpaulin-0.34.1.drv", "description": "Code coverage tool for Rust projects", "install_id": "cargo-tarpaulin", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "cargo-tarpaulin-0.32.8", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "cargo-tarpaulin-0.34.1", "pname": "cargo-tarpaulin", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:29:40.226629Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:04:24.719115Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.32.8", + "version": "0.34.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/xdr17pam7xsk73l9fmv1jym0gvh0jiss-cargo-tarpaulin-0.32.8" + "out": "/nix/store/la343c25ikgcckbflxbyb021bdkfb91w-cargo-tarpaulin-0.34.1" }, "system": "aarch64-linux", "group": "toplevel", @@ -1231,27 +1234,27 @@ { "attr_path": "cargo-tarpaulin", "broken": false, - "derivation": "/nix/store/zg28lka7z3xr62xkksk0wf8r69cpfqx2-cargo-tarpaulin-0.32.8.drv", + "derivation": "/nix/store/jszjdjknhqdhkkl8zx5i5b4pj3a44h4j-cargo-tarpaulin-0.34.1.drv", "description": "Code coverage tool for Rust projects", "install_id": "cargo-tarpaulin", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "cargo-tarpaulin-0.32.8", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "cargo-tarpaulin-0.34.1", "pname": "cargo-tarpaulin", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:35.709003Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:14:44.983255Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.32.8", + "version": "0.34.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/qi4sp9iqam5nq9y5j11q6w60m0x3z2dk-cargo-tarpaulin-0.32.8" + "out": "/nix/store/vlj059zdwq36rgbbn3n4dsppbhr1acyj-cargo-tarpaulin-0.34.1" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1260,27 +1263,27 @@ { "attr_path": "cargo-tarpaulin", "broken": false, - "derivation": "/nix/store/20dz8xn891k2x3vs4j1cldx61873fcw6-cargo-tarpaulin-0.32.8.drv", + "derivation": "/nix/store/1mr9y80xv7gikfainpxcj252brri6sg1-cargo-tarpaulin-0.34.1.drv", "description": "Code coverage tool for Rust projects", "install_id": "cargo-tarpaulin", "license": "[ MIT, Apache-2.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "cargo-tarpaulin-0.32.8", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "cargo-tarpaulin-0.34.1", "pname": "cargo-tarpaulin", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:26:56.311327Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:23:59.199467Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.32.8", + "version": "0.34.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/im5q945spww3clfrgn340l1ci28m97pm-cargo-tarpaulin-0.32.8" + "out": "/nix/store/265q582fxg6hlir9cybv03yvpdswmczk-cargo-tarpaulin-0.34.1" }, "system": "x86_64-linux", "group": "toplevel", @@ -1289,17 +1292,17 @@ { "attr_path": "cargo-watch", "broken": false, - "derivation": "/nix/store/50xch411hq51l4xscdpycxh8wrgn6hzw-cargo-watch-8.5.3.drv", + "derivation": "/nix/store/2kbnr5iy03g9zy1vbk8f6bv6czwrzn02-cargo-watch-8.5.3.drv", "description": "Cargo subcommand for watching over Cargo project's source", "install_id": "cargo-watch", "license": "CC0-1.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "cargo-watch-8.5.3", "pname": "cargo-watch", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:42.315542Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:54:46.857501Z", "stabilities": [ "unstable" ], @@ -1309,7 +1312,7 @@ "out" ], "outputs": { - "out": "/nix/store/8z3fidapv1vi7imnp9k45xndf6z5cakw-cargo-watch-8.5.3" + "out": "/nix/store/ldzyzsif42p4ldiql98rvdxsi1a6dbbf-cargo-watch-8.5.3" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1318,17 +1321,17 @@ { "attr_path": "cargo-watch", "broken": false, - "derivation": "/nix/store/1l9kr4kavikag5vaqbmb4v99nzgira3b-cargo-watch-8.5.3.drv", + "derivation": "/nix/store/7zfn2m4b7lzs50979cnxmif80acs9329-cargo-watch-8.5.3.drv", "description": "Cargo subcommand for watching over Cargo project's source", "install_id": "cargo-watch", "license": "CC0-1.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "cargo-watch-8.5.3", "pname": "cargo-watch", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:29:40.229113Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:04:24.721661Z", "stabilities": [ "unstable" ], @@ -1338,7 +1341,7 @@ "out" ], "outputs": { - "out": "/nix/store/wd39imycil2809qnvciswlc5bhrzrav2-cargo-watch-8.5.3" + "out": "/nix/store/7dd32r4b9cmhzgabki59jb0m0cd9cj0d-cargo-watch-8.5.3" }, "system": "aarch64-linux", "group": "toplevel", @@ -1347,17 +1350,17 @@ { "attr_path": "cargo-watch", "broken": false, - "derivation": "/nix/store/2md65a9j282i5fah90v6cgyb5gd7siv3-cargo-watch-8.5.3.drv", + "derivation": "/nix/store/02frlqbfqjr22xb0w62i29kj0clvisdr-cargo-watch-8.5.3.drv", "description": "Cargo subcommand for watching over Cargo project's source", "install_id": "cargo-watch", "license": "CC0-1.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "cargo-watch-8.5.3", "pname": "cargo-watch", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:35.711063Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:14:44.985275Z", "stabilities": [ "unstable" ], @@ -1367,7 +1370,7 @@ "out" ], "outputs": { - "out": "/nix/store/9gqn98483j95j2f91j6q6vjizlx9802c-cargo-watch-8.5.3" + "out": "/nix/store/zqnwrgaf88ydiik4rkcxjmn68lagdk83-cargo-watch-8.5.3" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1376,17 +1379,17 @@ { "attr_path": "cargo-watch", "broken": false, - "derivation": "/nix/store/dg1b7z2ncj7rqrq62mycqg68r2ra6vsq-cargo-watch-8.5.3.drv", + "derivation": "/nix/store/b91gzxji46ikv2qpmd11295k2vgc1q4i-cargo-watch-8.5.3.drv", "description": "Cargo subcommand for watching over Cargo project's source", "install_id": "cargo-watch", "license": "CC0-1.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "cargo-watch-8.5.3", "pname": "cargo-watch", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:26:56.313975Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:23:59.202151Z", "stabilities": [ "unstable" ], @@ -1396,7 +1399,7 @@ "out" ], "outputs": { - "out": "/nix/store/jpi7ws4aj11cf7g1g7czj7lhli9zlk50-cargo-watch-8.5.3" + "out": "/nix/store/667973sg79sd73vwh5x25r8cdvkwjzy6-cargo-watch-8.5.3" }, "system": "x86_64-linux", "group": "toplevel", @@ -1405,27 +1408,27 @@ { "attr_path": "clang", "broken": false, - "derivation": "/nix/store/wb65lsb0lqnf9km0jcs3vbyz5qi9aib4-clang-wrapper-19.1.7.drv", + "derivation": "/nix/store/idcxg1k8c3kkmf5ipixs883f4knl128w-clang-wrapper-21.1.2.drv", "description": "C language family frontend for LLVM (wrapper script)", "install_id": "clang", "license": "[ NCSA, Apache-2.0, LLVM-exception ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "clang-wrapper-19.1.7", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "clang-wrapper-21.1.2", "pname": "clang", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:42.465872Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:54:47.001910Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "19.1.7", + "version": "21.1.2", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/zzx6cfl99zknfrj9v7lmrshwzslfjv26-clang-wrapper-19.1.7" + "out": "/nix/store/qk20nysrc2170f1mal5k6r0axqn6jmfj-clang-wrapper-21.1.2" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1434,27 +1437,27 @@ { "attr_path": "clang", "broken": false, - "derivation": "/nix/store/dwvs4irz4mdn0zbwp1kr6abkaysy77m6-clang-wrapper-19.1.7.drv", + "derivation": "/nix/store/p7prdk64xk4kzag8jq9n40ba7c7mmhfz-clang-wrapper-21.1.2.drv", "description": "C language family frontend for LLVM (wrapper script)", "install_id": "clang", "license": "[ NCSA, Apache-2.0, LLVM-exception ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "clang-wrapper-19.1.7", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "clang-wrapper-21.1.2", "pname": "clang", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:35.890352Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:14:45.131454Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "19.1.7", + "version": "21.1.2", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/fk99cziyah7im2bahq2gw71cj90hwcq6-clang-wrapper-19.1.7" + "out": "/nix/store/fvj17s7clsf2n4rhyq0qqcrqhzybdqrz-clang-wrapper-21.1.2" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1463,29 +1466,29 @@ { "attr_path": "duckdb", "broken": false, - "derivation": "/nix/store/kx3k42whkpzh0mwkpja5gvn8gink9h5q-duckdb-1.3.2.drv", + "derivation": "/nix/store/84vqrxv78fwh5ziplh2an01i7cw90hk3-duckdb-1.4.1.drv", "description": "Embeddable SQL OLAP Database Management System", "install_id": "duckdb", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "duckdb-1.3.2", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "duckdb-1.4.1", "pname": "duckdb", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:42.812796Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:54:47.349252Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "1.3.2", + "version": "1.4.1", "outputs_to_install": [ "out" ], "outputs": { - "dev": "/nix/store/vw3pzk0iwddd8jr55vc55p7ybgwxgzcr-duckdb-1.3.2-dev", - "lib": "/nix/store/pfb541a9yf1psx12pg67097qs3k11wij-duckdb-1.3.2-lib", - "out": "/nix/store/7bpw31vp03b0qdhbzdp6hj9g3prvv8w0-duckdb-1.3.2" + "dev": "/nix/store/vcmqii2326vihngws6bsnl6zrgvhdhnr-duckdb-1.4.1-dev", + "lib": "/nix/store/hym8f9ii9f974i4cf3844pjxqkqhp4zd-duckdb-1.4.1-lib", + "out": "/nix/store/hi8xhsg36pmbsp5qisnqnpfw4p5nmkaz-duckdb-1.4.1" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1494,29 +1497,29 @@ { "attr_path": "duckdb", "broken": false, - "derivation": "/nix/store/i5ji6qg4dq1aq8hnmc1fyd5lb99jx9ad-duckdb-1.3.2.drv", + "derivation": "/nix/store/1n704qxp5463q2mqlsp3ggyx8izdmf28-duckdb-1.4.1.drv", "description": "Embeddable SQL OLAP Database Management System", "install_id": "duckdb", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "duckdb-1.3.2", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "duckdb-1.4.1", "pname": "duckdb", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:29:40.902088Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:04:25.410716Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "1.3.2", + "version": "1.4.1", "outputs_to_install": [ "out" ], "outputs": { - "dev": "/nix/store/js5nrmkkz8p00y7jqdg9z5rz5p146gag-duckdb-1.3.2-dev", - "lib": "/nix/store/g9bm91si9ak5737ymzrksj77ndskkjgi-duckdb-1.3.2-lib", - "out": "/nix/store/h8bb0ir6nni6gcxbdgs2v84bfbklrack-duckdb-1.3.2" + "dev": "/nix/store/150xzj9lxffw1idzv40vr0rbjxgv979f-duckdb-1.4.1-dev", + "lib": "/nix/store/qrzwf04y0n6gsjw8mgdcz4fxsfyb5qfw-duckdb-1.4.1-lib", + "out": "/nix/store/3zyrjdpfqawlb4xhgyqa9k61brqqybs5-duckdb-1.4.1" }, "system": "aarch64-linux", "group": "toplevel", @@ -1525,29 +1528,29 @@ { "attr_path": "duckdb", "broken": false, - "derivation": "/nix/store/icljnxh89addyr323ip5liml3pjh6nwk-duckdb-1.3.2.drv", + "derivation": "/nix/store/w2v9lxmkcjk3cb0kkkz7fjsmyh057sr3-duckdb-1.4.1.drv", "description": "Embeddable SQL OLAP Database Management System", "install_id": "duckdb", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "duckdb-1.3.2", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "duckdb-1.4.1", "pname": "duckdb", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:36.219317Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:14:45.474401Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "1.3.2", + "version": "1.4.1", "outputs_to_install": [ "out" ], "outputs": { - "dev": "/nix/store/mpncgwifhgjs2i56c10ladffpy09p8dh-duckdb-1.3.2-dev", - "lib": "/nix/store/cgj9spcv5jcdgzvm3a4ilxkzmdf58x6v-duckdb-1.3.2-lib", - "out": "/nix/store/2rs21mm0bvckydxqw9xsm9qird0czbwa-duckdb-1.3.2" + "dev": "/nix/store/4z97qlwnwcqnmp6acb0pqgdxj4pkjgly-duckdb-1.4.1-dev", + "lib": "/nix/store/20l3sli2k84i0rviqvjgyqfzhh2a7cwf-duckdb-1.4.1-lib", + "out": "/nix/store/ygm6rnc7xbszalyrr32fsi5l5qpxw0wc-duckdb-1.4.1" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1556,29 +1559,29 @@ { "attr_path": "duckdb", "broken": false, - "derivation": "/nix/store/af2yd04r8vj8qci0av5c5znjyhizgbgx-duckdb-1.3.2.drv", + "derivation": "/nix/store/g06zd6vpnv7kyib6xdqczm8d40ilradn-duckdb-1.4.1.drv", "description": "Embeddable SQL OLAP Database Management System", "install_id": "duckdb", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "duckdb-1.3.2", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "duckdb-1.4.1", "pname": "duckdb", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:26:57.039384Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:23:59.949822Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "1.3.2", + "version": "1.4.1", "outputs_to_install": [ "out" ], "outputs": { - "dev": "/nix/store/dclx0f74jhvbl7v62aa6faljacrjnyjv-duckdb-1.3.2-dev", - "lib": "/nix/store/wdj9y14qbcfyw5z421x1s2vfh03z30mh-duckdb-1.3.2-lib", - "out": "/nix/store/06dyg83b7gsyzwd54sns7qj4dka3xxsv-duckdb-1.3.2" + "dev": "/nix/store/x64zllqs83v151kspmkzj6vna96r5pci-duckdb-1.4.1-dev", + "lib": "/nix/store/wwx1nqbn8jahgv6cd7bgar2gk68c3y0j-duckdb-1.4.1-lib", + "out": "/nix/store/8ik10l1g01kniml8p8c6h7gj2n5azi98-duckdb-1.4.1" }, "system": "x86_64-linux", "group": "toplevel", @@ -1587,27 +1590,27 @@ { "attr_path": "fselect", "broken": false, - "derivation": "/nix/store/alpam122sgj5z9jv0mg03yps8raw5lpy-fselect-0.9.0.drv", + "derivation": "/nix/store/9ip7h7bd6nw89vg47s1671gbs0yizkxh-fselect-0.9.1.drv", "description": "Find files with SQL-like queries", "install_id": "fselect", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "fselect-0.9.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "fselect-0.9.1", "pname": "fselect", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:43.128801Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:54:47.665605Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.9.0", + "version": "0.9.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/1z13j35rszliy8ldccqh20q9vvlf5nqs-fselect-0.9.0" + "out": "/nix/store/h8jfrxk6ni9fxia6rl4sgrwwafj0pivf-fselect-0.9.1" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1616,27 +1619,27 @@ { "attr_path": "fselect", "broken": false, - "derivation": "/nix/store/wl7bmvlvhs1bkdd1idz400qydvmkxyr1-fselect-0.9.0.drv", + "derivation": "/nix/store/7b2vhaj4gvrkr7vzgnziwp83frs7aqxc-fselect-0.9.1.drv", "description": "Find files with SQL-like queries", "install_id": "fselect", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "fselect-0.9.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "fselect-0.9.1", "pname": "fselect", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:29:41.379985Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:04:25.902094Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.9.0", + "version": "0.9.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/g45k5mnw69qgwgkxzk16jimcs8n3l8ig-fselect-0.9.0" + "out": "/nix/store/0y5cq9ll30rbw0cnwrcsplpi8jj3kimg-fselect-0.9.1" }, "system": "aarch64-linux", "group": "toplevel", @@ -1645,27 +1648,27 @@ { "attr_path": "fselect", "broken": false, - "derivation": "/nix/store/833wgi3zjf8c3p8srgzswznpbyka108w-fselect-0.9.0.drv", + "derivation": "/nix/store/im8n0xd835r5vn4y5yqrj782rk10s1yc-fselect-0.9.1.drv", "description": "Find files with SQL-like queries", "install_id": "fselect", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "fselect-0.9.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "fselect-0.9.1", "pname": "fselect", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:36.519399Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:14:45.774937Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.9.0", + "version": "0.9.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/in5vm4f0y0mvfkqf5kfa2ls4kas4869f-fselect-0.9.0" + "out": "/nix/store/sp3yz6xkswndjb637k7g7x57hmdd33lp-fselect-0.9.1" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1674,27 +1677,27 @@ { "attr_path": "fselect", "broken": false, - "derivation": "/nix/store/c1k1dvy24dhjvjvkz5jxlwpl9zb1rf7c-fselect-0.9.0.drv", + "derivation": "/nix/store/2rvpkrf3i7sdgx35ly1s07d78c3dqbxg-fselect-0.9.1.drv", "description": "Find files with SQL-like queries", "install_id": "fselect", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "fselect-0.9.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "fselect-0.9.1", "pname": "fselect", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:26:57.574535Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:24:00.509869Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.9.0", + "version": "0.9.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/vsb3bsfaw8qx0javbkxd7l1y79pnlr1r-fselect-0.9.0" + "out": "/nix/store/m6g3f9zz4msmwlq85gm656yxnkainvb7-fselect-0.9.1" }, "system": "x86_64-linux", "group": "toplevel", @@ -1703,17 +1706,17 @@ { "attr_path": "gcc", "broken": false, - "derivation": "/nix/store/xgd6sn2nbpk6p8hfkwfnaggapfa486id-gcc-wrapper-14.3.0.drv", + "derivation": "/nix/store/mkfdpq06yl2cc7pglhg9xp9ss0sdq041-gcc-wrapper-14.3.0.drv", "description": "GNU Compiler Collection, version 14.3.0 (wrapper script)", "install_id": "gcc", "license": "GPL-3.0-or-later", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "gcc-wrapper-14.3.0", "pname": "gcc", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:29:41.456152Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:04:25.977551Z", "stabilities": [ "unstable" ], @@ -1724,9 +1727,9 @@ "out" ], "outputs": { - "info": "/nix/store/x2q2m245k44wxcskdknl5xdqrsya7fcy-gcc-wrapper-14.3.0-info", - "man": "/nix/store/f5k9bkq97gqc4ajmbavv3wxdwcqmng64-gcc-wrapper-14.3.0-man", - "out": "/nix/store/hf8w753nxqwkc5y5kjx33fx8fxw2dczp-gcc-wrapper-14.3.0" + "info": "/nix/store/ibhizkj7d278admccd3b6d3cab5ny147-gcc-wrapper-14.3.0-info", + "man": "/nix/store/2f2wsf8vcd02j3lzjmvp21cw8gx1aj4m-gcc-wrapper-14.3.0-man", + "out": "/nix/store/48ywmq5vl4jld47z5f1p662vwi0anw6y-gcc-wrapper-14.3.0" }, "system": "aarch64-linux", "group": "toplevel", @@ -1735,17 +1738,17 @@ { "attr_path": "gcc", "broken": false, - "derivation": "/nix/store/i9kj1nhzkg91xsq8ny4z4hipl0b42kad-gcc-wrapper-14.3.0.drv", + "derivation": "/nix/store/xd09z9hp96djzb97y37k6pfmd12w3509-gcc-wrapper-14.3.0.drv", "description": "GNU Compiler Collection, version 14.3.0 (wrapper script)", "install_id": "gcc", "license": "GPL-3.0-or-later", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "gcc-wrapper-14.3.0", "pname": "gcc", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:26:57.657160Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:24:00.592469Z", "stabilities": [ "unstable" ], @@ -1756,9 +1759,125 @@ "out" ], "outputs": { - "info": "/nix/store/12sy2qyk3qir1rg4jdrdnj91jaw50my2-gcc-wrapper-14.3.0-info", - "man": "/nix/store/ds5j2vvwhdvfgkjp7jnfx82bqswks46x-gcc-wrapper-14.3.0-man", - "out": "/nix/store/95k9rsn1zsw1yvir8mj824ldhf90i4qw-gcc-wrapper-14.3.0" + "info": "/nix/store/3rfwb68rg2nna0b4cj222wyz5iwkgkww-gcc-wrapper-14.3.0-info", + "man": "/nix/store/bb8rnwrvpa8z5x3yxr9sndqs31zl11bc-gcc-wrapper-14.3.0-man", + "out": "/nix/store/vr15iyyykg9zai6fpgvhcgyw7gckl78w-gcc-wrapper-14.3.0" + }, + "system": "x86_64-linux", + "group": "toplevel", + "priority": 5 + }, + { + "attr_path": "gh", + "broken": false, + "derivation": "/nix/store/kpanq99ay20lmy3pl153dy0dlxq21hjs-gh-2.83.1.drv", + "description": "GitHub CLI tool", + "install_id": "gh", + "license": "MIT", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "gh-2.83.1", + "pname": "gh", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:54:47.758471Z", + "stabilities": [ + "unstable" + ], + "unfree": false, + "version": "2.83.1", + "outputs_to_install": [ + "out" + ], + "outputs": { + "out": "/nix/store/jcfc6p66x7qnrwf2dn83gaar13swpfka-gh-2.83.1" + }, + "system": "aarch64-darwin", + "group": "toplevel", + "priority": 5 + }, + { + "attr_path": "gh", + "broken": false, + "derivation": "/nix/store/m5266dcmf4v447cgzrg1hy6if1rk5m69-gh-2.83.1.drv", + "description": "GitHub CLI tool", + "install_id": "gh", + "license": "MIT", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "gh-2.83.1", + "pname": "gh", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:04:26.052962Z", + "stabilities": [ + "unstable" + ], + "unfree": false, + "version": "2.83.1", + "outputs_to_install": [ + "out" + ], + "outputs": { + "out": "/nix/store/vr17vpprzabs961dj075z5wl6nw6b4w4-gh-2.83.1" + }, + "system": "aarch64-linux", + "group": "toplevel", + "priority": 5 + }, + { + "attr_path": "gh", + "broken": false, + "derivation": "/nix/store/f172gzlfk9q298a17780nqc0qjhd58qa-gh-2.83.1.drv", + "description": "GitHub CLI tool", + "install_id": "gh", + "license": "MIT", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "gh-2.83.1", + "pname": "gh", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:14:45.866326Z", + "stabilities": [ + "unstable" + ], + "unfree": false, + "version": "2.83.1", + "outputs_to_install": [ + "out" + ], + "outputs": { + "out": "/nix/store/v1xrng4rrjshc9ini30l07rsc2dbi7fh-gh-2.83.1" + }, + "system": "x86_64-darwin", + "group": "toplevel", + "priority": 5 + }, + { + "attr_path": "gh", + "broken": false, + "derivation": "/nix/store/hrxn58n11njrwa1ppw492s2barf9y39q-gh-2.83.1.drv", + "description": "GitHub CLI tool", + "install_id": "gh", + "license": "MIT", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "gh-2.83.1", + "pname": "gh", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:24:00.674085Z", + "stabilities": [ + "unstable" + ], + "unfree": false, + "version": "2.83.1", + "outputs_to_install": [ + "out" + ], + "outputs": { + "out": "/nix/store/y12yx7z4g4a3jbzh28h6yrpvcf6px5kl-gh-2.83.1" }, "system": "x86_64-linux", "group": "toplevel", @@ -1767,17 +1886,17 @@ { "attr_path": "gum", "broken": false, - "derivation": "/nix/store/i7da40pyfvk25xwk2xkg7rlzv3zqf4s3-gum-0.17.0.drv", + "derivation": "/nix/store/a5jkn7x5z8wmi74lz5r4ik0yq7kmhbqd-gum-0.17.0.drv", "description": "Tasty Bubble Gum for your shell", "install_id": "gum", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "gum-0.17.0", "pname": "gum", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:44.120342Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:54:48.099994Z", "stabilities": [ "unstable" ], @@ -1787,7 +1906,7 @@ "out" ], "outputs": { - "out": "/nix/store/6acx1nn0f2i5v6dkdzaap2hdngkp1lpz-gum-0.17.0" + "out": "/nix/store/rpj06p0p66g1644iph4hz5bc2pb881mc-gum-0.17.0" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1796,17 +1915,17 @@ { "attr_path": "gum", "broken": false, - "derivation": "/nix/store/vn184rxp6dqbd1lacq122him8nif1ljj-gum-0.17.0.drv", + "derivation": "/nix/store/zi9xa8m7ljjiangffwc8y7ps5bchskvi-gum-0.17.0.drv", "description": "Tasty Bubble Gum for your shell", "install_id": "gum", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "gum-0.17.0", "pname": "gum", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:29:42.434628Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:04:26.990480Z", "stabilities": [ "unstable" ], @@ -1816,7 +1935,7 @@ "out" ], "outputs": { - "out": "/nix/store/caisq1py34nrn7q3lx4sswkm0zlpdr4n-gum-0.17.0" + "out": "/nix/store/r349n4jjvw190ayfcqb6s17hmjbslmk6-gum-0.17.0" }, "system": "aarch64-linux", "group": "toplevel", @@ -1825,17 +1944,17 @@ { "attr_path": "gum", "broken": false, - "derivation": "/nix/store/xzwzl56m1rwcb5pbmq85cvhyhfd1angc-gum-0.17.0.drv", + "derivation": "/nix/store/vhamd62n09hfnwms97z1hyj982jmq1b5-gum-0.17.0.drv", "description": "Tasty Bubble Gum for your shell", "install_id": "gum", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "gum-0.17.0", "pname": "gum", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:36.984532Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:14:46.239842Z", "stabilities": [ "unstable" ], @@ -1845,7 +1964,7 @@ "out" ], "outputs": { - "out": "/nix/store/w467h914divp2k8qyk5x14hci2jm7ww6-gum-0.17.0" + "out": "/nix/store/f598g2fggah67vk41srma5ii2h651d1s-gum-0.17.0" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1854,17 +1973,17 @@ { "attr_path": "gum", "broken": false, - "derivation": "/nix/store/3l47qcfk0x158cx0f3ql2pggnxgd6v9p-gum-0.17.0.drv", + "derivation": "/nix/store/7zc145nc8ac8xzdiyp1fvx4rs47l1v1l-gum-0.17.0.drv", "description": "Tasty Bubble Gum for your shell", "install_id": "gum", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "gum-0.17.0", "pname": "gum", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:26:58.732150Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:24:01.696306Z", "stabilities": [ "unstable" ], @@ -1874,7 +1993,7 @@ "out" ], "outputs": { - "out": "/nix/store/jbjrj4hbf2bgdvr6vl4dalwn31s669p4-gum-0.17.0" + "out": "/nix/store/j92y0a4ymgnaj3h011mi174vczbw1iak-gum-0.17.0" }, "system": "x86_64-linux", "group": "toplevel", @@ -1883,28 +2002,28 @@ { "attr_path": "libiconv", "broken": false, - "derivation": "/nix/store/d21w5kgpc8829hzmmhfcw7iq5fndkv3h-libiconv-109.drv", + "derivation": "/nix/store/cqmiyahmdcjxs3q1j6fklsmkj9h2dmnw-libiconv-109.100.2.drv", "description": "Iconv(3) implementation", "install_id": "libiconv", "license": "[ BSD-2-Clause, BSD-3-Clause, APSL-1.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "libiconv-109", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "libiconv-109.100.2", "pname": "libiconv", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:00:59.125319Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:55:03.069953Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "109", + "version": "109.100.2", "outputs_to_install": [ "out" ], "outputs": { - "dev": "/nix/store/7s8gizw7d3hw8wyf7npayp5dk47727mz-libiconv-109-dev", - "out": "/nix/store/clci1zxqwa39qp135b1lfbbwad9qa4g0-libiconv-109" + "dev": "/nix/store/wwhxjbysdz2nlzggimqwwf5jpmz3lq4g-libiconv-109.100.2-dev", + "out": "/nix/store/9kffgbvhza212ishsam4p8wklh92ih9v-libiconv-109.100.2" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1913,28 +2032,28 @@ { "attr_path": "libiconv", "broken": false, - "derivation": "/nix/store/zsbd141b7rq2639c2lq5xsn0xcdc9i9s-libiconv-109.drv", + "derivation": "/nix/store/a8m4k0z7in93zq7y8in3w6ab3biyxhk9-libiconv-109.100.2.drv", "description": "Iconv(3) implementation", "install_id": "libiconv", "license": "[ BSD-2-Clause, BSD-3-Clause, APSL-1.0 ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "libiconv-109", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "libiconv-109.100.2", "pname": "libiconv", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:52.096823Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:15:01.274953Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "109", + "version": "109.100.2", "outputs_to_install": [ "out" ], "outputs": { - "dev": "/nix/store/sqrlc5n1sar9aynzqym3gbm2p98hx7cn-libiconv-109-dev", - "out": "/nix/store/4idh8sgmy2wafmvmbab8dw0053jgwr8c-libiconv-109" + "dev": "/nix/store/y0hbafr9r8p1gj6b3r94da25f3cym6x2-libiconv-109.100.2-dev", + "out": "/nix/store/ala8mxpss08vad0a7c9fkwqy5hz9wwqc-libiconv-109.100.2" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1943,17 +2062,17 @@ { "attr_path": "mask", "broken": false, - "derivation": "/nix/store/szjnp3963v7dswjzffggb0yqnrmqg3pa-mask-0.11.6.drv", + "derivation": "/nix/store/l4c04mil7fax4iqzw831jfn45jilwvrj-mask-0.11.6.drv", "description": "CLI task runner defined by a simple markdown file", "install_id": "mask", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "mask-0.11.6", "pname": "mask", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:01:02.794961Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:55:06.375737Z", "stabilities": [ "unstable" ], @@ -1963,7 +2082,7 @@ "out" ], "outputs": { - "out": "/nix/store/2g2qvzgjq5zw0l146va1p03mc39xy4va-mask-0.11.6" + "out": "/nix/store/iipnz1qs8m301c54698wz1k0nlnfl0aj-mask-0.11.6" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1972,17 +2091,17 @@ { "attr_path": "mask", "broken": false, - "derivation": "/nix/store/a9zcvh6x9342bi0l5jyz1l8a74y0zdr7-mask-0.11.6.drv", + "derivation": "/nix/store/w8lxi3q36s033svx23axbl8v8bcimbbi-mask-0.11.6.drv", "description": "CLI task runner defined by a simple markdown file", "install_id": "mask", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "mask-0.11.6", "pname": "mask", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:30:13.874798Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:04:56.573529Z", "stabilities": [ "unstable" ], @@ -1992,7 +2111,7 @@ "out" ], "outputs": { - "out": "/nix/store/yr6j5mkqg8y7w1c9v8kv1crjy83vnpby-mask-0.11.6" + "out": "/nix/store/wvxzsh66d4cph54710lpyla1spwpl74c-mask-0.11.6" }, "system": "aarch64-linux", "group": "toplevel", @@ -2001,17 +2120,17 @@ { "attr_path": "mask", "broken": false, - "derivation": "/nix/store/8lhg3symrg5ggm6d8jpk0hj1c55cnsyy-mask-0.11.6.drv", + "derivation": "/nix/store/83bsn3xwc363ib1235dys6jfqhraaq14-mask-0.11.6.drv", "description": "CLI task runner defined by a simple markdown file", "install_id": "mask", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "mask-0.11.6", "pname": "mask", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:55.479919Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:15:04.615218Z", "stabilities": [ "unstable" ], @@ -2021,7 +2140,7 @@ "out" ], "outputs": { - "out": "/nix/store/xdassl0ji7vs1zljimqa1n24y8myvw7p-mask-0.11.6" + "out": "/nix/store/8rlxpabb4ah863wd72ccjq9absihcfw3-mask-0.11.6" }, "system": "x86_64-darwin", "group": "toplevel", @@ -2030,17 +2149,17 @@ { "attr_path": "mask", "broken": false, - "derivation": "/nix/store/72yafxkmwfh8gaan7nkzd3m9pqlv4rry-mask-0.11.6.drv", + "derivation": "/nix/store/0zrvnqins516cjqynzxsmz4zn8hvyk17-mask-0.11.6.drv", "description": "CLI task runner defined by a simple markdown file", "install_id": "mask", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "mask-0.11.6", "pname": "mask", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:27:32.404732Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:24:33.417620Z", "stabilities": [ "unstable" ], @@ -2050,7 +2169,7 @@ "out" ], "outputs": { - "out": "/nix/store/8h9hdwpgzknxadrz6fwinix214dbvm4c-mask-0.11.6" + "out": "/nix/store/zq958m0w8paxngjz57ca6pj7ijmi1rgs-mask-0.11.6" }, "system": "x86_64-linux", "group": "toplevel", @@ -2059,27 +2178,27 @@ { "attr_path": "nushell", "broken": false, - "derivation": "/nix/store/gkb7s9w7rybwxkm18wyb40fwqjnjjl3d-nushell-0.106.1.drv", + "derivation": "/nix/store/4826irgb4j6qcd9whzgvyb7i2yk0ld75-nushell-0.108.0.drv", "description": "Modern shell written in Rust", "install_id": "nushell", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "nushell-0.106.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "nushell-0.108.0", "pname": "nushell", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:01:06.047148Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:55:09.486515Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.106.1", + "version": "0.108.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/b2s37l8wvp66jgk2v35bzqd64sngm2wg-nushell-0.106.1" + "out": "/nix/store/ww7g4npjwsjgcakwpc4dvz3mh07w4r6b-nushell-0.108.0" }, "system": "aarch64-darwin", "group": "toplevel", @@ -2088,27 +2207,27 @@ { "attr_path": "nushell", "broken": false, - "derivation": "/nix/store/qs2ddzjbzx70b5q5w8mn144mb92g7y48-nushell-0.106.1.drv", + "derivation": "/nix/store/qbfddm6q84h832xfq7lc5iaxpxcl6in0-nushell-0.108.0.drv", "description": "Modern shell written in Rust", "install_id": "nushell", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "nushell-0.106.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "nushell-0.108.0", "pname": "nushell", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:30:18.961673Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:05:01.203719Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.106.1", + "version": "0.108.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/lbmj19psdibypl9ydarygy2xjh4jgfa3-nushell-0.106.1" + "out": "/nix/store/2dk36164b2chh2753wh31r7zbxlx1ak5-nushell-0.108.0" }, "system": "aarch64-linux", "group": "toplevel", @@ -2117,27 +2236,27 @@ { "attr_path": "nushell", "broken": false, - "derivation": "/nix/store/g0v371ay35x71fg16wc4axlqqm5wk7np-nushell-0.106.1.drv", + "derivation": "/nix/store/1r171cwlqnpwpijir9sm4n4wfd1f8pcp-nushell-0.108.0.drv", "description": "Modern shell written in Rust", "install_id": "nushell", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "nushell-0.106.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "nushell-0.108.0", "pname": "nushell", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:56:58.580106Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:15:07.593755Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.106.1", + "version": "0.108.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/3ssawg0rxz7bxcsvh2x3yjp4i7db906d-nushell-0.106.1" + "out": "/nix/store/3pzkarcw1f1lmjx2icxm9jblz6favln8-nushell-0.108.0" }, "system": "x86_64-darwin", "group": "toplevel", @@ -2146,27 +2265,27 @@ { "attr_path": "nushell", "broken": false, - "derivation": "/nix/store/iqpr0338808jnls2hczymy25h1py4mbg-nushell-0.106.1.drv", + "derivation": "/nix/store/5sxn1q0gfz0yw0v9a418ndkkk8cv4wn6-nushell-0.108.0.drv", "description": "Modern shell written in Rust", "install_id": "nushell", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "nushell-0.106.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "nushell-0.108.0", "pname": "nushell", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:27:37.651873Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:24:38.425037Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.106.1", + "version": "0.108.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/7pn92hjbp0c3jn4p0jvbjisddvx9y6fp-nushell-0.106.1" + "out": "/nix/store/kx4ic1nmgsfh3qhr74vxq7g97pal7mn4-nushell-0.108.0" }, "system": "x86_64-linux", "group": "toplevel", @@ -2175,32 +2294,32 @@ { "attr_path": "openssl", "broken": false, - "derivation": "/nix/store/z4lr6rqyi0w7hgsyv5kvnhjrakirr751-openssl-3.5.1.drv", + "derivation": "/nix/store/zfg836p7bhddd7yv8iiifjp7mz4w7bcz-openssl-3.6.0.drv", "description": "Cryptographic library that implements the SSL and TLS protocols", "install_id": "openssl", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "openssl-3.5.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "openssl-3.6.0", "pname": "openssl", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:01:08.506148Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:55:12.101165Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.5.1", + "version": "3.6.0", "outputs_to_install": [ "bin", "man" ], "outputs": { - "bin": "/nix/store/bpawzvf8z4yjmwr3zc7haxhv99sl8s2a-openssl-3.5.1-bin", - "dev": "/nix/store/4fwifkd3zn4m6y7zacyhpwy5frj63knk-openssl-3.5.1-dev", - "doc": "/nix/store/69p0m85qi4rw0ka8jqciba0p9q3140b0-openssl-3.5.1-doc", - "man": "/nix/store/2jh1wcwhjylfxzly4hbb5fz55b1lxxm5-openssl-3.5.1-man", - "out": "/nix/store/0ais7wnqw8xzj0331c2jka53s6g14wqb-openssl-3.5.1" + "bin": "/nix/store/z9prisxci5h5lsk3rdknd4jzq7k9q13d-openssl-3.6.0-bin", + "dev": "/nix/store/h0qgqik0mk0wn7rmm2kk3grfi1wzly74-openssl-3.6.0-dev", + "doc": "/nix/store/yx3ip21fdaaxpjn5fbir02mqnaw9cm4f-openssl-3.6.0-doc", + "man": "/nix/store/ii9mnzr3i92mgk9dkgg65739mavd0j6f-openssl-3.6.0-man", + "out": "/nix/store/3z54dgks2mz3dhwddj158sdibll8xmq5-openssl-3.6.0" }, "system": "aarch64-darwin", "group": "toplevel", @@ -2209,33 +2328,33 @@ { "attr_path": "openssl", "broken": false, - "derivation": "/nix/store/ka1rgg9jrhim4p54h6cb4jih6g51qcww-openssl-3.5.1.drv", + "derivation": "/nix/store/l531wmdavsf9g286x1i396s2y5drcxjf-openssl-3.6.0.drv", "description": "Cryptographic library that implements the SSL and TLS protocols", "install_id": "openssl", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "openssl-3.5.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "openssl-3.6.0", "pname": "openssl", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:30:22.445758Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:05:05.153515Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.5.1", + "version": "3.6.0", "outputs_to_install": [ "bin", "man" ], "outputs": { - "bin": "/nix/store/4zzrcin7jdph1ybm7pkwlypv4khmqgf3-openssl-3.5.1-bin", - "debug": "/nix/store/n0r6fn7sd0bvmpwm8s5nlmm626jilcra-openssl-3.5.1-debug", - "dev": "/nix/store/hg5ryywl9xqg82kvzwvqkx4m2yckkdsg-openssl-3.5.1-dev", - "doc": "/nix/store/91mrccm5jwv94w8lvh7c0wf0cygj0yal-openssl-3.5.1-doc", - "man": "/nix/store/slgd9x3x372g5bm73qbijj41rqb560fd-openssl-3.5.1-man", - "out": "/nix/store/rzlvprd99wlbiv2wsqgp23kmxhkm1yfr-openssl-3.5.1" + "bin": "/nix/store/wb6q44n9kcb5acmaa4rgqsajadx1fhhl-openssl-3.6.0-bin", + "debug": "/nix/store/ci6d4k1sj4bnr892lsrqqmjiihqsk0bl-openssl-3.6.0-debug", + "dev": "/nix/store/pq8b7fb3282g68pmk14mbyi20qn6chid-openssl-3.6.0-dev", + "doc": "/nix/store/vaplp6w56dyz38986bgkf0pbg3r486b2-openssl-3.6.0-doc", + "man": "/nix/store/c9n1alb7ypzjvzd47m16fiwfczz23qs3-openssl-3.6.0-man", + "out": "/nix/store/nj50gkyx813dxvfmsg1q8m330hmf3h86-openssl-3.6.0" }, "system": "aarch64-linux", "group": "toplevel", @@ -2244,32 +2363,32 @@ { "attr_path": "openssl", "broken": false, - "derivation": "/nix/store/ncpm3s6gw15xqq45zs140p0m8rx5axnp-openssl-3.5.1.drv", + "derivation": "/nix/store/1hy2n24d6a1k1nxhq0pgl1zf5vf1j4l2-openssl-3.6.0.drv", "description": "Cryptographic library that implements the SSL and TLS protocols", "install_id": "openssl", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "openssl-3.5.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "openssl-3.6.0", "pname": "openssl", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:57:01.027570Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:15:10.037378Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.5.1", + "version": "3.6.0", "outputs_to_install": [ "bin", "man" ], "outputs": { - "bin": "/nix/store/4w92hq61lhdzin9mkvzlxvd603pgwm9w-openssl-3.5.1-bin", - "dev": "/nix/store/63827r05nfpr7bg23zpivb9sn33cshy4-openssl-3.5.1-dev", - "doc": "/nix/store/3kbg9sqs4i8j7rkr6q7gb25c0bjqylyr-openssl-3.5.1-doc", - "man": "/nix/store/h59wasb1qrmvsgz79bl0sqnrhx0vccha-openssl-3.5.1-man", - "out": "/nix/store/v3cq87zwjd4f91y0i1023kkb9wvwc71z-openssl-3.5.1" + "bin": "/nix/store/m3xwn9n0jypwjgi256idfzs979g30j29-openssl-3.6.0-bin", + "dev": "/nix/store/dirjrfjk8jgsbdpslgb51cav6qaxn2vm-openssl-3.6.0-dev", + "doc": "/nix/store/va1zhkz0nfmycvd0h239hi4w40qgaxcx-openssl-3.6.0-doc", + "man": "/nix/store/hw43f3y1vl7ydrd4samnwnrwqqwkpisv-openssl-3.6.0-man", + "out": "/nix/store/q9a4wssx24xsy28w8kifdqizc01fh7sc-openssl-3.6.0" }, "system": "x86_64-darwin", "group": "toplevel", @@ -2278,33 +2397,33 @@ { "attr_path": "openssl", "broken": false, - "derivation": "/nix/store/7d5p0ip9nd3aj3r1a2pmhsxxizqqnis8-openssl-3.5.1.drv", + "derivation": "/nix/store/gbdp0ycqp6x4gmpd6rbnis361b7amhzv-openssl-3.6.0.drv", "description": "Cryptographic library that implements the SSL and TLS protocols", "install_id": "openssl", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "openssl-3.5.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "openssl-3.6.0", "pname": "openssl", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:27:41.383379Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:24:42.186730Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.5.1", + "version": "3.6.0", "outputs_to_install": [ "bin", "man" ], "outputs": { - "bin": "/nix/store/nn4b544v4sanvsf22mjiw3qh8mwh6pzh-openssl-3.5.1-bin", - "debug": "/nix/store/rj7yspi9mw9zcbma7v3h2zbh03bkjb82-openssl-3.5.1-debug", - "dev": "/nix/store/qqfiw89h8j4pilcyqapldzq5vf0vqgxy-openssl-3.5.1-dev", - "doc": "/nix/store/g9nxr4sig9dkhfvgc0ma1qb6fs3xm5dn-openssl-3.5.1-doc", - "man": "/nix/store/kmyzbfp60f9b85lhpr3njswxlm76b0av-openssl-3.5.1-man", - "out": "/nix/store/gi615r79j260ihhzdkhrg6qva9wfrbyy-openssl-3.5.1" + "bin": "/nix/store/k0gl1zc7f5hk87lylxwbipb0b870bcmk-openssl-3.6.0-bin", + "debug": "/nix/store/sqv8kbdgfxlr2d6nysr8c2715qpsi6f5-openssl-3.6.0-debug", + "dev": "/nix/store/ydrckgnllgg8nmhdwni81h7xhcpnrlhd-openssl-3.6.0-dev", + "doc": "/nix/store/cgp9ig35iwicfb9spcrgyg2m5dmlcgrv-openssl-3.6.0-doc", + "man": "/nix/store/a9jdl6xq9fc98ykpvqmc9kf0b0j9y8wh-openssl-3.6.0-man", + "out": "/nix/store/61i74yjkj9p1qphfl7018ja4sdwkipx0-openssl-3.6.0" }, "system": "x86_64-linux", "group": "toplevel", @@ -2313,17 +2432,17 @@ { "attr_path": "pkgconf", "broken": false, - "derivation": "/nix/store/04hwp9239wg0qgpp59zxmz3nqvigs53a-pkgconf-wrapper-2.4.3.drv", + "derivation": "/nix/store/ckhl1jlx8hfqffk8z8kjs004jbwbgky9-pkgconf-wrapper-2.4.3.drv", "description": "Package compiler and linker metadata toolkit (wrapper script)", "install_id": "pkgconf", "license": "ISC", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pkgconf-wrapper-2.4.3", "pname": "pkgconf", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:01:19.590063Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:55:23.371522Z", "stabilities": [ "unstable" ], @@ -2334,9 +2453,9 @@ "out" ], "outputs": { - "doc": "/nix/store/flxmxlx5yngm9iahiaqxs9yssifqlb0s-pkgconf-wrapper-2.4.3-doc", - "man": "/nix/store/wxfhr42czigr07v0hc7z3a70v6z6kzrq-pkgconf-wrapper-2.4.3-man", - "out": "/nix/store/3m1pxpp6mmygcsmfkcdm8ilb9rmlwl73-pkgconf-wrapper-2.4.3" + "doc": "/nix/store/06pvq3vz6rmf748pq4myxnm4l33agn69-pkgconf-wrapper-2.4.3-doc", + "man": "/nix/store/mq3rml5gvlrz750c8ls0bzmh1sldyf8w-pkgconf-wrapper-2.4.3-man", + "out": "/nix/store/s12d3v0q8yjq6796z3fbz44d3g0l00w1-pkgconf-wrapper-2.4.3" }, "system": "aarch64-darwin", "group": "toplevel", @@ -2345,17 +2464,17 @@ { "attr_path": "pkgconf", "broken": false, - "derivation": "/nix/store/ynafcxlpih0ibvy7vh05iqkbhs4v9kz6-pkgconf-wrapper-2.4.3.drv", + "derivation": "/nix/store/rwng518c72is686s2gnip02461mjl76y-pkgconf-wrapper-2.4.3.drv", "description": "Package compiler and linker metadata toolkit (wrapper script)", "install_id": "pkgconf", "license": "ISC", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pkgconf-wrapper-2.4.3", "pname": "pkgconf", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:30:37.176468Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:05:20.305964Z", "stabilities": [ "unstable" ], @@ -2366,9 +2485,9 @@ "out" ], "outputs": { - "doc": "/nix/store/hgkjq5603abx9rwj11syrwzc2j4p34fq-pkgconf-wrapper-2.4.3-doc", - "man": "/nix/store/6h4gdhgyd5dg95pwwpzf8m2j8zzk6hfy-pkgconf-wrapper-2.4.3-man", - "out": "/nix/store/a6dz1nlij42svhps4ks0b7r0byhxi15i-pkgconf-wrapper-2.4.3" + "doc": "/nix/store/12057h5a00iqkd9asdabp5n06awfj4sh-pkgconf-wrapper-2.4.3-doc", + "man": "/nix/store/wxhfqi26araqcmfpyv8g0kddygfnw33r-pkgconf-wrapper-2.4.3-man", + "out": "/nix/store/s9ncdhslhxmpwkydf2cykdcjlap8m0z9-pkgconf-wrapper-2.4.3" }, "system": "aarch64-linux", "group": "toplevel", @@ -2377,17 +2496,17 @@ { "attr_path": "pkgconf", "broken": false, - "derivation": "/nix/store/im2s3ri9qabghvvhg2cq255jg5k0p0ll-pkgconf-wrapper-2.4.3.drv", + "derivation": "/nix/store/gfx0i17p2xhwnhf87lh4z0p2f3rk1p46-pkgconf-wrapper-2.4.3.drv", "description": "Package compiler and linker metadata toolkit (wrapper script)", "install_id": "pkgconf", "license": "ISC", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pkgconf-wrapper-2.4.3", "pname": "pkgconf", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:57:12.187997Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:15:20.796205Z", "stabilities": [ "unstable" ], @@ -2398,9 +2517,9 @@ "out" ], "outputs": { - "doc": "/nix/store/s6ifvb059132y92mzqqrna22zjncq9js-pkgconf-wrapper-2.4.3-doc", - "man": "/nix/store/3lp94590v7pl6w72i6abplky5kx5v4n7-pkgconf-wrapper-2.4.3-man", - "out": "/nix/store/d81wrf9kj80iqkqp9yp06jmpqbjqdd9r-pkgconf-wrapper-2.4.3" + "doc": "/nix/store/p5ychnax5h5cjx9n4vvxk07z6hzzvfhl-pkgconf-wrapper-2.4.3-doc", + "man": "/nix/store/wbjfn3zfvv6l7pc7g70vkwp5b0v9wn5y-pkgconf-wrapper-2.4.3-man", + "out": "/nix/store/v1j6z0nawzchy5lygq4apmdccdyrv2br-pkgconf-wrapper-2.4.3" }, "system": "x86_64-darwin", "group": "toplevel", @@ -2409,17 +2528,17 @@ { "attr_path": "pkgconf", "broken": false, - "derivation": "/nix/store/0hw1djq9bcvxf0pf51mfjq6ar0nnys9k-pkgconf-wrapper-2.4.3.drv", + "derivation": "/nix/store/r8j9br8hq457ibf4w03h26cr019da7nz-pkgconf-wrapper-2.4.3.drv", "description": "Package compiler and linker metadata toolkit (wrapper script)", "install_id": "pkgconf", "license": "ISC", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pkgconf-wrapper-2.4.3", "pname": "pkgconf", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:27:56.835240Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:24:57.205369Z", "stabilities": [ "unstable" ], @@ -2430,9 +2549,9 @@ "out" ], "outputs": { - "doc": "/nix/store/8x9xcfr5pqhlh14rlvw1zqhqa83ryghg-pkgconf-wrapper-2.4.3-doc", - "man": "/nix/store/k3fabn4ms19p23wqavm7c3akc7cc3b7r-pkgconf-wrapper-2.4.3-man", - "out": "/nix/store/8jqc8ncn0whif781s3124cjsndfhkmid-pkgconf-wrapper-2.4.3" + "doc": "/nix/store/qzrg9qx4d7wjnsskas2nvq517zbrq3i2-pkgconf-wrapper-2.4.3-doc", + "man": "/nix/store/fqmfjh4q9yhx8jr11g8k4vbvy2lryx4r-pkgconf-wrapper-2.4.3-man", + "out": "/nix/store/fixvzqqw9d554r9nkq77w17jb3j7spvh-pkgconf-wrapper-2.4.3" }, "system": "x86_64-linux", "group": "toplevel", @@ -2441,17 +2560,17 @@ { "attr_path": "pulumi", "broken": false, - "derivation": "/nix/store/7m7zm1i9x0cnjhvh26h4xlyz0ki2jxf3-pulumi-3.192.0.drv", + "derivation": "/nix/store/hym21va7rk5h132zmq85pfdwga5x8rv8-pulumi-3.192.0.drv", "description": "Cloud development platform that makes creating cloud programs easy and productive", "install_id": "pulumi", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pulumi-3.192.0", "pname": "pulumi", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:01:21.633256Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:55:25.395848Z", "stabilities": [ "unstable" ], @@ -2461,7 +2580,7 @@ "out" ], "outputs": { - "out": "/nix/store/yzvgdzvmsryggm9yc4c03n9ssmymk9yq-pulumi-3.192.0" + "out": "/nix/store/x3g22wqqxd3z7i8w7zlhzjrd2drmhnjc-pulumi-3.192.0" }, "system": "aarch64-darwin", "group": "toplevel", @@ -2470,17 +2589,17 @@ { "attr_path": "pulumi", "broken": false, - "derivation": "/nix/store/dnnhb97qlyawx51w3lym5x37n7wf0jdk-pulumi-3.192.0.drv", + "derivation": "/nix/store/wr9qs7jlw9002ia47qjjf2i72cz1idky-pulumi-3.192.0.drv", "description": "Cloud development platform that makes creating cloud programs easy and productive", "install_id": "pulumi", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pulumi-3.192.0", "pname": "pulumi", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:30:40.250132Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:05:23.217060Z", "stabilities": [ "unstable" ], @@ -2490,7 +2609,7 @@ "out" ], "outputs": { - "out": "/nix/store/4v1nh8nsz09xfy1636dq22cqpg8mic3q-pulumi-3.192.0" + "out": "/nix/store/9664da92yrpav90598wfswvljxpk3bv6-pulumi-3.192.0" }, "system": "aarch64-linux", "group": "toplevel", @@ -2499,17 +2618,17 @@ { "attr_path": "pulumi", "broken": false, - "derivation": "/nix/store/0lc6lhh6c1mi0gii31l29lfb20599nyi-pulumi-3.192.0.drv", + "derivation": "/nix/store/36xn4mh2j8dfyhyjd3ndld0xw7sbdp43-pulumi-3.192.0.drv", "description": "Cloud development platform that makes creating cloud programs easy and productive", "install_id": "pulumi", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pulumi-3.192.0", "pname": "pulumi", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:57:14.224051Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:15:22.695516Z", "stabilities": [ "unstable" ], @@ -2519,7 +2638,7 @@ "out" ], "outputs": { - "out": "/nix/store/n048j54k4qz3pz0scy4jsm3jc6h0sjkh-pulumi-3.192.0" + "out": "/nix/store/z5gim4z0gsnjh86fg6brbgkqxxgmhdn5-pulumi-3.192.0" }, "system": "x86_64-darwin", "group": "toplevel", @@ -2528,17 +2647,17 @@ { "attr_path": "pulumi", "broken": false, - "derivation": "/nix/store/k4askrhwrcq1cwajc4v8ajk9j175p02d-pulumi-3.192.0.drv", + "derivation": "/nix/store/v1xyjcx52vf71pspb5njp76ln85adrf7-pulumi-3.192.0.drv", "description": "Cloud development platform that makes creating cloud programs easy and productive", "install_id": "pulumi", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pulumi-3.192.0", "pname": "pulumi", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:28:00.154285Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:25:00.181240Z", "stabilities": [ "unstable" ], @@ -2548,7 +2667,7 @@ "out" ], "outputs": { - "out": "/nix/store/xr3cwx2iak4xw02lm6fsyc495275iqv7-pulumi-3.192.0" + "out": "/nix/store/jm5wch46f8x9rg2xk3ws3xvrk7av6hwh-pulumi-3.192.0" }, "system": "x86_64-linux", "group": "toplevel", @@ -2557,17 +2676,17 @@ { "attr_path": "pulumiPackages.pulumi-python", "broken": false, - "derivation": "/nix/store/0jvby0lzckkjqrfvsdwgxy7n7ag674z7-pulumi-python-3.192.0.drv", + "derivation": "/nix/store/x2z7812rahwkgqc81b4c0h1w3894bxxq-pulumi-python-3.192.0.drv", "description": "Language host for Pulumi programs written in Python", "install_id": "pulumi-python", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pulumi-python-3.192.0", "pname": "pulumi-python", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:01:21.655014Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:55:25.417654Z", "stabilities": [ "unstable" ], @@ -2577,7 +2696,7 @@ "out" ], "outputs": { - "out": "/nix/store/fbhjxy5sp826sh71xd0ygfjz1jii7j2b-pulumi-python-3.192.0" + "out": "/nix/store/dl9kwahysmkkah9vik10jfc9idmbg7m2-pulumi-python-3.192.0" }, "system": "aarch64-darwin", "group": "toplevel", @@ -2586,17 +2705,17 @@ { "attr_path": "pulumiPackages.pulumi-python", "broken": false, - "derivation": "/nix/store/sdk4imbpmsv4szcszh5cn93cwhcq395f-pulumi-python-3.192.0.drv", + "derivation": "/nix/store/p3s1hgwrj3smr1czgxv7bszy1gn43nii-pulumi-python-3.192.0.drv", "description": "Language host for Pulumi programs written in Python", "install_id": "pulumi-python", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pulumi-python-3.192.0", "pname": "pulumi-python", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:30:40.276747Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:05:23.243727Z", "stabilities": [ "unstable" ], @@ -2606,7 +2725,7 @@ "out" ], "outputs": { - "out": "/nix/store/pmqc9v3sda2m7lfw37589b59p8mxjxb1-pulumi-python-3.192.0" + "out": "/nix/store/0xd2bi1xznd9vjjzj3vhzrnz2vawnzp8-pulumi-python-3.192.0" }, "system": "aarch64-linux", "group": "toplevel", @@ -2615,17 +2734,17 @@ { "attr_path": "pulumiPackages.pulumi-python", "broken": false, - "derivation": "/nix/store/qgpza3czrpizq6yqpkc1qrfdbnf3pssb-pulumi-python-3.192.0.drv", + "derivation": "/nix/store/65g7vzi3h2wkhz4vy7g7rqfal1lhszvg-pulumi-python-3.192.0.drv", "description": "Language host for Pulumi programs written in Python", "install_id": "pulumi-python", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pulumi-python-3.192.0", "pname": "pulumi-python", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:57:14.244597Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:15:22.717670Z", "stabilities": [ "unstable" ], @@ -2635,7 +2754,7 @@ "out" ], "outputs": { - "out": "/nix/store/syqsx03q4k4bwryqlz6qzib3nwpj5a52-pulumi-python-3.192.0" + "out": "/nix/store/3jypf27h6x3svgl2w00pdcfgby9gwn65-pulumi-python-3.192.0" }, "system": "x86_64-darwin", "group": "toplevel", @@ -2644,17 +2763,17 @@ { "attr_path": "pulumiPackages.pulumi-python", "broken": false, - "derivation": "/nix/store/xl6lx00dgcz9cl3ig0h9v039s242lpag-pulumi-python-3.192.0.drv", + "derivation": "/nix/store/48qzj1gap87zh85hwi0flk2578qmzx4p-pulumi-python-3.192.0.drv", "description": "Language host for Pulumi programs written in Python", "install_id": "pulumi-python", "license": "Apache-2.0", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "pulumi-python-3.192.0", "pname": "pulumi-python", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:28:00.186199Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:25:00.207516Z", "stabilities": [ "unstable" ], @@ -2664,7 +2783,7 @@ "out" ], "outputs": { - "out": "/nix/store/4qni29lp47gh4kackxmxbigjdq38wabj-pulumi-python-3.192.0" + "out": "/nix/store/93cbr2r1285rsskzardrm0hlhxfajdqx-pulumi-python-3.192.0" }, "system": "x86_64-linux", "group": "toplevel", @@ -2673,27 +2792,27 @@ { "attr_path": "ruff", "broken": false, - "derivation": "/nix/store/j4p240nxbr58gl451m3zs7xc4wf453j2-ruff-0.12.10.drv", + "derivation": "/nix/store/vk2sc95dqy0gl5dfzx13v8x65b4kmxwm-ruff-0.14.7.drv", "description": "Extremely fast Python linter and code formatter", "install_id": "ruff", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "ruff-0.12.10", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "ruff-0.14.7", "pname": "ruff", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:02:12.833563Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:56:16.904244Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.12.10", + "version": "0.14.7", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/x0bw6ng4439wn8snvhf0gfbyllpw2c3y-ruff-0.12.10" + "out": "/nix/store/bmb6v5nxksa1vxswcq0ab0wxkvz47wav-ruff-0.14.7" }, "system": "aarch64-darwin", "group": "toplevel", @@ -2702,27 +2821,27 @@ { "attr_path": "ruff", "broken": false, - "derivation": "/nix/store/2pai8dm3gnzqdh0am0qnxbd1x1ylhqpb-ruff-0.12.10.drv", + "derivation": "/nix/store/az87wfhwzgfn61z4yppnpghxm1a33lf0-ruff-0.14.7.drv", "description": "Extremely fast Python linter and code formatter", "install_id": "ruff", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "ruff-0.12.10", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "ruff-0.14.7", "pname": "ruff", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:31:43.737670Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:06:26.260475Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.12.10", + "version": "0.14.7", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/jldy883qg0hg4fjqjbdgpvxc14hnrv07-ruff-0.12.10" + "out": "/nix/store/b9fp0pjgb2manbyf4f0lcjvjhw272ms5-ruff-0.14.7" }, "system": "aarch64-linux", "group": "toplevel", @@ -2731,27 +2850,27 @@ { "attr_path": "ruff", "broken": false, - "derivation": "/nix/store/mzkm7m0501c0kqkbkfyn8jaamn0kxbv5-ruff-0.12.10.drv", + "derivation": "/nix/store/r0gd9g5skllf3sm10l92qv9yzhlgj37m-ruff-0.14.7.drv", "description": "Extremely fast Python linter and code formatter", "install_id": "ruff", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "ruff-0.12.10", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "ruff-0.14.7", "pname": "ruff", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:58:04.518721Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:16:10.048167Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.12.10", + "version": "0.14.7", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/nrpd9i0ynmzxz3pslkid1qigm82ml26i-ruff-0.12.10" + "out": "/nix/store/33qwlnmm8v70pxai24npcap2qwkjbwak-ruff-0.14.7" }, "system": "x86_64-darwin", "group": "toplevel", @@ -2760,27 +2879,27 @@ { "attr_path": "ruff", "broken": false, - "derivation": "/nix/store/y65ksv4fmm157sqwdk7qkivsb2h0w4j5-ruff-0.12.10.drv", + "derivation": "/nix/store/zsiaacrsbdg8qpnd8bw7d61dqd08wnpi-ruff-0.14.7.drv", "description": "Extremely fast Python linter and code formatter", "install_id": "ruff", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "ruff-0.12.10", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "ruff-0.14.7", "pname": "ruff", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:29:07.297007Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:26:03.178298Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.12.10", + "version": "0.14.7", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/zjiz7z2r425qlyza4w13hzbjanxpd1wr-ruff-0.12.10" + "out": "/nix/store/pbxzpf01aj49gqpncv1iqm70lj0xcd7r-ruff-0.14.7" }, "system": "x86_64-linux", "group": "toplevel", @@ -2789,27 +2908,27 @@ { "attr_path": "uv", "broken": false, - "derivation": "/nix/store/yqzgb7nrnw13fmq82yjqn7i12vjbvfqb-uv-0.8.14.drv", + "derivation": "/nix/store/cypg31kavj8d2f05l074bpckavpylcwc-uv-0.9.15.drv", "description": "Extremely fast Python package installer and resolver, written in Rust", "install_id": "uv", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "uv-0.8.14", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "uv-0.9.15", "pname": "uv", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:03:00.033764Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:57:11.406924Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.8.14", + "version": "0.9.15", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/jvsjlmb0h8kfflmr1fjqaqvv8znp99pr-uv-0.8.14" + "out": "/nix/store/ygjvbgmlcwcsn49h6iqmv1zb63945fil-uv-0.9.15" }, "system": "aarch64-darwin", "group": "toplevel", @@ -2818,27 +2937,27 @@ { "attr_path": "uv", "broken": false, - "derivation": "/nix/store/bgclbwc8748map9smhkvhw8d33xh7jib-uv-0.8.14.drv", + "derivation": "/nix/store/9gprkj36z4dh6rw1yavf35grs211acg8-uv-0.9.15.drv", "description": "Extremely fast Python package installer and resolver, written in Rust", "install_id": "uv", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "uv-0.8.14", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "uv-0.9.15", "pname": "uv", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:32:42.929178Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:07:32.126948Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.8.14", + "version": "0.9.15", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/3yyvvd9k79im73nsafnrqqadi7ln7lgd-uv-0.8.14" + "out": "/nix/store/ixkl2madqd89qy5yhhr963pq5jdlffwx-uv-0.9.15" }, "system": "aarch64-linux", "group": "toplevel", @@ -2847,27 +2966,27 @@ { "attr_path": "uv", "broken": false, - "derivation": "/nix/store/99i0j1sjaas1ha0zfd3hyiizmqxfsncm-uv-0.8.14.drv", + "derivation": "/nix/store/8qjrnz1y5al2mr9xjvlrq1dj9zxb48qj-uv-0.9.15.drv", "description": "Extremely fast Python package installer and resolver, written in Rust", "install_id": "uv", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "uv-0.8.14", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "uv-0.9.15", "pname": "uv", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:58:52.098121Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:16:59.955553Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.8.14", + "version": "0.9.15", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/lsl4wjgvsfvka6dm0lirlgpfks3r9937-uv-0.8.14" + "out": "/nix/store/94x53a87w6dhzpbhqbyylwpax4cy6kp8-uv-0.9.15" }, "system": "x86_64-darwin", "group": "toplevel", @@ -2876,27 +2995,27 @@ { "attr_path": "uv", "broken": false, - "derivation": "/nix/store/qayr0hjxrk3xiqnkfp61am3bcg3107qf-uv-0.8.14.drv", + "derivation": "/nix/store/k3c1wqg5bmymhscwcxrfl42gd7i9vki3-uv-0.9.15.drv", "description": "Extremely fast Python package installer and resolver, written in Rust", "install_id": "uv", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", - "name": "uv-0.8.14", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", + "name": "uv-0.9.15", "pname": "uv", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:30:08.494710Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:27:07.783505Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.8.14", + "version": "0.9.15", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/d4klvr31w9qc9qpypwaxmz6f9xy3339y-uv-0.8.14" + "out": "/nix/store/qpjjd520lh2pjif58wmlrjd4a5mmm55w-uv-0.9.15" }, "system": "x86_64-linux", "group": "toplevel", @@ -2905,17 +3024,17 @@ { "attr_path": "python313Packages.vulture", "broken": false, - "derivation": "/nix/store/lbbmjh5ljldcb7qqnb4dlw68fxy46vvv-python3.13-vulture-2.14.drv", + "derivation": "/nix/store/6rp823v7s40fqscx1j8dp5m0m7v9vi4r-python3.13-vulture-2.14.drv", "description": "Finds unused code in Python programs", "install_id": "vulture", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "python3.13-vulture-2.14", "pname": "vulture", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:02:04.064047Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:56:08.936314Z", "stabilities": [ "unstable" ], @@ -2925,8 +3044,8 @@ "out" ], "outputs": { - "dist": "/nix/store/qnbp4pbkimwk87q4hf2w8ai3wv42flkh-python3.13-vulture-2.14-dist", - "out": "/nix/store/2gc4bhzbqp4d8z6a6cyll6klhn094h02-python3.13-vulture-2.14" + "dist": "/nix/store/jr2vfc6h5d2haplqmg0pjxli287ija62-python3.13-vulture-2.14-dist", + "out": "/nix/store/58qgn7q850qrimkw4gmxxbcd0yxzsmdf-python3.13-vulture-2.14" }, "system": "aarch64-darwin", "group": "toplevel", @@ -2935,17 +3054,17 @@ { "attr_path": "python313Packages.vulture", "broken": false, - "derivation": "/nix/store/4jcifamm39drl0nlvsxamx9iblimxci9-python3.13-vulture-2.14.drv", + "derivation": "/nix/store/fydfhidy6snq18gcrwkgmzs8byxyd8n5-python3.13-vulture-2.14.drv", "description": "Finds unused code in Python programs", "install_id": "vulture", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "python3.13-vulture-2.14", "pname": "vulture", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:31:32.377732Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:06:15.917900Z", "stabilities": [ "unstable" ], @@ -2955,8 +3074,8 @@ "out" ], "outputs": { - "dist": "/nix/store/w0910fc67iy6wy3wzwmcrg85z6h4jra0-python3.13-vulture-2.14-dist", - "out": "/nix/store/wyxb0gy6y7g2p4klw9hfpjk1i9nhk5w8-python3.13-vulture-2.14" + "dist": "/nix/store/r034gyxcdwwagh6jsfc72hybb3jxiai0-python3.13-vulture-2.14-dist", + "out": "/nix/store/7vr41jnwznkwlvskdi28c4k9brjcpwz4-python3.13-vulture-2.14" }, "system": "aarch64-linux", "group": "toplevel", @@ -2965,17 +3084,17 @@ { "attr_path": "python313Packages.vulture", "broken": false, - "derivation": "/nix/store/whc7i6gcfbgxpij6x9vl0kzpifl8phs8-python3.13-vulture-2.14.drv", + "derivation": "/nix/store/0hnax5inwn7swy0jfbpnlab1jdm9pgs8-python3.13-vulture-2.14.drv", "description": "Finds unused code in Python programs", "install_id": "vulture", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "python3.13-vulture-2.14", "pname": "vulture", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:57:55.437430Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:16:02.603893Z", "stabilities": [ "unstable" ], @@ -2985,8 +3104,8 @@ "out" ], "outputs": { - "dist": "/nix/store/6njcdnz8qpr6gxbi0w8kisrszxbfzh95-python3.13-vulture-2.14-dist", - "out": "/nix/store/hbajl4dywp8hi764gl32q5cj7i1rsyaa-python3.13-vulture-2.14" + "dist": "/nix/store/8hds3dm0ha3figidiadrrw1qgf8dp4vh-python3.13-vulture-2.14-dist", + "out": "/nix/store/3yas5bqdwk3z7f0nrx68cc1lr5p6gg18-python3.13-vulture-2.14" }, "system": "x86_64-darwin", "group": "toplevel", @@ -2995,17 +3114,17 @@ { "attr_path": "python313Packages.vulture", "broken": false, - "derivation": "/nix/store/pzs4ybig09k0d4p220wzzskn4m2scn8b-python3.13-vulture-2.14.drv", + "derivation": "/nix/store/k29xbyn1in0wlypzj8976jpmp3fk8dk0-python3.13-vulture-2.14.drv", "description": "Finds unused code in Python programs", "install_id": "vulture", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "python3.13-vulture-2.14", "pname": "vulture", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:28:54.572068Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:25:52.611390Z", "stabilities": [ "unstable" ], @@ -3015,8 +3134,8 @@ "out" ], "outputs": { - "dist": "/nix/store/11xhmyzw0sn48hn71izhfc9j2n1w1d7l-python3.13-vulture-2.14-dist", - "out": "/nix/store/0rihzyrjx84wn0vfcr9rjfy7iw3mc94k-python3.13-vulture-2.14" + "dist": "/nix/store/52a4fn7fjp49vfwjrp1wn78qxgg5d0h1-python3.13-vulture-2.14-dist", + "out": "/nix/store/pq7bmragdlpm8p5qb2k3qhk9qrpx24k5-python3.13-vulture-2.14" }, "system": "x86_64-linux", "group": "toplevel", @@ -3025,17 +3144,17 @@ { "attr_path": "yamllint", "broken": false, - "derivation": "/nix/store/51vi05vkk5yyh4qz9v10alfjpph45jn8-python3.13-yamllint-1.37.1.drv", + "derivation": "/nix/store/5zyc0cmvxqjrkzlzy56p77igz2qs875f-python3.13-yamllint-1.37.1.drv", "description": "Linter for YAML files", "install_id": "yamllint", "license": "GPL-3.0-or-later", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "python3.13-yamllint-1.37.1", "pname": "yamllint", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:03:13.634574Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T02:57:25.492249Z", "stabilities": [ "unstable" ], @@ -3045,8 +3164,8 @@ "out" ], "outputs": { - "dist": "/nix/store/nc9v27cadla3hzarrypl7xqv714aj851-python3.13-yamllint-1.37.1-dist", - "out": "/nix/store/1ajlhkwnvxnirqacd95ccvcp4n4a2l6d-python3.13-yamllint-1.37.1" + "dist": "/nix/store/b25szjv62npp6d4ja4kg8zaj5igbybz7-python3.13-yamllint-1.37.1-dist", + "out": "/nix/store/wlr4gk3fcg7hkwdragab8m711p2p7cpn-python3.13-yamllint-1.37.1" }, "system": "aarch64-darwin", "group": "toplevel", @@ -3055,17 +3174,17 @@ { "attr_path": "yamllint", "broken": false, - "derivation": "/nix/store/62gqjm3pq4wcn11mk5h91png1fqi01ar-python3.13-yamllint-1.37.1.drv", + "derivation": "/nix/store/2yr3s25q2d3s4pkn5qa41dnb4rixy3yz-python3.13-yamllint-1.37.1.drv", "description": "Linter for YAML files", "install_id": "yamllint", "license": "GPL-3.0-or-later", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "python3.13-yamllint-1.37.1", "pname": "yamllint", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:33:00.420899Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:07:50.846018Z", "stabilities": [ "unstable" ], @@ -3075,8 +3194,8 @@ "out" ], "outputs": { - "dist": "/nix/store/llpps8kklgvx2m7xa8vnbfhcdrkirii7-python3.13-yamllint-1.37.1-dist", - "out": "/nix/store/wdn4zyww6gv95lhz0jvcfrf0an4vfbjf-python3.13-yamllint-1.37.1" + "dist": "/nix/store/409wlxqsscq1cjw5aw4hhxk1wrwcchkl-python3.13-yamllint-1.37.1-dist", + "out": "/nix/store/png3qzx4ri1lsb0janbw11zk4xag6kpn-python3.13-yamllint-1.37.1" }, "system": "aarch64-linux", "group": "toplevel", @@ -3085,17 +3204,17 @@ { "attr_path": "yamllint", "broken": false, - "derivation": "/nix/store/hfr7rzlqqkpsah6s863cbc9bg2pdqqk1-python3.13-yamllint-1.37.1.drv", + "derivation": "/nix/store/73dqfxg191547gv079s3crb9vjxqv6gv-python3.13-yamllint-1.37.1.drv", "description": "Linter for YAML files", "install_id": "yamllint", "license": "GPL-3.0-or-later", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "python3.13-yamllint-1.37.1", "pname": "yamllint", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T02:59:05.426128Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:17:13.188287Z", "stabilities": [ "unstable" ], @@ -3105,8 +3224,8 @@ "out" ], "outputs": { - "dist": "/nix/store/hjh468yvb9nrw6jhizirvrjym8ngq35q-python3.13-yamllint-1.37.1-dist", - "out": "/nix/store/6yfzxvgkr2v043462sm2h6g2pjkm506n-python3.13-yamllint-1.37.1" + "dist": "/nix/store/myh77nwjyn3lkrxy4xy3bpa9nw1jgbll-python3.13-yamllint-1.37.1-dist", + "out": "/nix/store/m86rk8mwlxvavv0d2k1yqavnh9iy2kp6-python3.13-yamllint-1.37.1" }, "system": "x86_64-darwin", "group": "toplevel", @@ -3115,17 +3234,17 @@ { "attr_path": "yamllint", "broken": false, - "derivation": "/nix/store/9x1wh1phq3qkjy8n0y866wlv1nii7ly5-python3.13-yamllint-1.37.1.drv", + "derivation": "/nix/store/nbc4s7yxhy9cchfk8y9mmysjklpdyjn2-python3.13-yamllint-1.37.1.drv", "description": "Linter for YAML files", "install_id": "yamllint", "license": "GPL-3.0-or-later", - "locked_url": "https://github.com/flox/nixpkgs?rev=c23193b943c6c689d70ee98ce3128239ed9e32d1", + "locked_url": "https://github.com/flox/nixpkgs?rev=f61125a668a320878494449750330ca58b78c557", "name": "python3.13-yamllint-1.37.1", "pname": "yamllint", - "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1", - "rev_count": 861038, - "rev_date": "2025-09-13T06:43:22Z", - "scrape_date": "2025-09-15T03:30:27.283049Z", + "rev": "f61125a668a320878494449750330ca58b78c557", + "rev_count": 907002, + "rev_date": "2025-12-05T15:54:32Z", + "scrape_date": "2025-12-07T03:27:26.338321Z", "stabilities": [ "unstable" ], @@ -3135,8 +3254,8 @@ "out" ], "outputs": { - "dist": "/nix/store/wpnf4f2x6qjkkk31s0505qiima771vxw-python3.13-yamllint-1.37.1-dist", - "out": "/nix/store/0v7zz7l98yw23xwk2j4fkccbj36dpjml-python3.13-yamllint-1.37.1" + "dist": "/nix/store/kfjgy56k09d5zh3w3gx36r1nxsqfy4rq-python3.13-yamllint-1.37.1-dist", + "out": "/nix/store/26giqsvab90axm0l5c131kpv7dyl4a09-python3.13-yamllint-1.37.1" }, "system": "x86_64-linux", "group": "toplevel", diff --git a/.flox/env/manifest.toml b/.flox/env/manifest.toml index f6e958e48..36c8be33c 100644 --- a/.flox/env/manifest.toml +++ b/.flox/env/manifest.toml @@ -1,6 +1,7 @@ version = 1 [install] +gh.pkg-path = "gh" pulumi.pkg-path = "pulumi" pulumi-python.pkg-path = "pulumiPackages.pulumi-python" ruff.pkg-path = "ruff" diff --git a/.github/workflows/close_stale_issues_and_pull_requests.yaml b/.github/workflows/close_stale_issues_and_pull_requests.yaml index da7fe7882..9986ae86c 100644 --- a/.github/workflows/close_stale_issues_and_pull_requests.yaml +++ b/.github/workflows/close_stale_issues_and_pull_requests.yaml @@ -2,7 +2,7 @@ name: Close stale issues and pull requests on: schedule: - - cron: '30 1 * * *' + - cron: 30 1 * * * permissions: issues: write pull-requests: write @@ -14,16 +14,12 @@ jobs: - name: Close stale issues and pull requests uses: actions/stale@v9 with: - stale-issue-message: >- - Marked stale due to inactivity. - Remove stale label or comment or this will be closed. - stale-pr-message: >- - Marked stale due to inactivity. - Remove stale label or comment or this will be closed. + stale-issue-message: Marked stale due to inactivity. Remove stale label or comment or this will be closed. + stale-pr-message: Marked stale due to inactivity. Remove stale label or comment or this will be closed. stale-issue-label: stale stale-pr-label: stale - close-issue-message: 'Closed due to inactivity.' - close-pr-message: 'Closed due to inactivity.' + close-issue-message: Closed due to inactivity. + close-pr-message: Closed due to inactivity. days-before-stale: 7 days-before-close: 7 exempt-draft-pr: true diff --git a/.github/workflows/create_or_update_portfolio.yaml b/.github/workflows/create_or_update_portfolio.yaml new file mode 100644 index 000000000..1f197dd95 --- /dev/null +++ b/.github/workflows/create_or_update_portfolio.yaml @@ -0,0 +1,21 @@ +--- +name: Create or update portfolio +on: + schedule: + - cron: 0 15 * * 1-5 # launch at 15:00 UTC (10:00 AM EST / 11:00 AM EDT) on weekdays +jobs: + create_or_update_portfolio: + name: Create or update portfolio on weekday schedule + runs-on: ubuntu-latest + environment: pulumi + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install Flox + uses: flox/install-flox-action@v2 + - name: Create or update with Pulumi + uses: flox/activate-action@v1 + env: + PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} + with: + command: mask infrastructure services invoke portfoliomanager diff --git a/.github/workflows/launch_infrastructure.yaml b/.github/workflows/launch_infrastructure.yaml index a43e238e5..5c2483078 100644 --- a/.github/workflows/launch_infrastructure.yaml +++ b/.github/workflows/launch_infrastructure.yaml @@ -2,20 +2,58 @@ name: Launch infrastructure on: schedule: - - cron: '0 13 * * 1,2,3,4,5' # launch at 8:00 AM EST + - cron: 0 13 * * 1,2,3,4,5 # launch at 8:00 AM EST + push: + branches: + - master +concurrency: + group: infrastructure-deployment + cancel-in-progress: false jobs: launch_infrastructure: name: Launch infrastructure on weekday schedule runs-on: ubuntu-latest environment: pulumi + permissions: + id-token: write + contents: read steps: - name: Checkout code uses: actions/checkout@v4 + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v5 + with: + role-to-assume: ${{ secrets.AWS_INFRASTRUCTURE_ROLE_ARN }} + aws-region: ${{ secrets.AWS_REGION }} - name: Install Flox uses: flox/install-flox-action@v2 + - name: Build data manager image + uses: flox/activate-action@v1 + with: + command: mask infrastructure images build datamanager server + - name: Push data manager image + uses: flox/activate-action@v1 + with: + command: mask infrastructure images push datamanager server + - name: Build portfolio manager image + uses: flox/activate-action@v1 + with: + command: mask infrastructure images build portfoliomanager server + - name: Push portfolio manager image + uses: flox/activate-action@v1 + with: + command: mask infrastructure images push portfoliomanager server + - name: Build equity price model image + uses: flox/activate-action@v1 + with: + command: mask infrastructure images build equitypricemodel server + - name: Push equity price model image + uses: flox/activate-action@v1 + with: + command: mask infrastructure images push equitypricemodel server - name: Deploy with Pulumi uses: flox/activate-action@v1 env: PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} with: - command: mise tasks run infrastructure:up + command: mask infrastructure stack up diff --git a/.github/workflows/run_python_code_checks.yaml b/.github/workflows/run_python_code_checks.yaml index 47b3aa8b7..ff08e8b70 100644 --- a/.github/workflows/run_python_code_checks.yaml +++ b/.github/workflows/run_python_code_checks.yaml @@ -1,7 +1,6 @@ --- name: Python code checks on: - push: pull_request: jobs: run_python_code_checks: @@ -20,4 +19,4 @@ jobs: uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} - path-to-lcov: coverage_output/.python_coverage.xml + file: coverage/.python.xml diff --git a/.github/workflows/run_rust_code_checks.yaml b/.github/workflows/run_rust_code_checks.yaml index ce8b0df47..06f6f371b 100644 --- a/.github/workflows/run_rust_code_checks.yaml +++ b/.github/workflows/run_rust_code_checks.yaml @@ -1,7 +1,6 @@ --- name: Rust code checks on: - push: pull_request: jobs: run_rust_code_checks: diff --git a/.github/workflows/sync_data.yaml b/.github/workflows/sync_data.yaml new file mode 100644 index 000000000..832e82095 --- /dev/null +++ b/.github/workflows/sync_data.yaml @@ -0,0 +1,21 @@ +--- +name: Sync data +on: + schedule: + - cron: 0 10 * * 1-5 # launch at 10:00 UTC (5:00 AM EST / 6:00 AM EDT) +jobs: + fetch_data: + name: Sync data on weekday schedule + runs-on: ubuntu-latest + environment: pulumi + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install Flox + uses: flox/install-flox-action@v2 + - name: Fetch with Pulumi + uses: flox/activate-action@v1 + env: + PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} + with: + command: mask infrastructure services invoke datamanager diff --git a/.github/workflows/teardown_infrastructure.yaml b/.github/workflows/teardown_infrastructure.yaml index 412be254f..6076be43d 100644 --- a/.github/workflows/teardown_infrastructure.yaml +++ b/.github/workflows/teardown_infrastructure.yaml @@ -2,7 +2,7 @@ name: Teardown infrastructure on: schedule: - - cron: '0 23 * * 1,2,3,4,5' # teardown at 6:00 PM EST + - cron: 0 23 * * 1,2,3,4,5 # teardown at 6:00 PM EST jobs: teardown_infrastructure: name: Teardown infrastructure on weekday schedule @@ -18,4 +18,4 @@ jobs: env: PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }} with: - command: mise tasks run infrastructure:down + command: mask infrastructure stack down diff --git a/.gitignore b/.gitignore index d20feff0b..bf19f585a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,19 +6,18 @@ .ruff_cache/ .pytest_cache/ .venv/ -.python_coverage.* -coverage_output/ +coverage/ __pycache__/ -infrastructure/Pulumi.infrastructure.yaml infrastructure/Pulumi.production.yaml .envrc .coverage* -.coverage/ -coverage.xml -infrastructure/swarm.pem *.csv *.egg-info/ wandb/ /target/ **/target/ - +data/ +**/model.tar.gz +**/*.safetensor +**/*.json +notes.md diff --git a/CLAUDE.md b/CLAUDE.md index 593d28cbf..8175b80ae 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,107 +1,33 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Development Commands - -### Core Development -- **Install dependencies**: `mask development python install` (after `flox activate`) -- **Format code**: `mask development python format` (uses ruff) -- **Lint code**: `mask development python lint` (ruff with comprehensive ruleset) -- **Run tests**: `mask development python test` (pytest with coverage) -- **Check for dead code**: `mask development python dead-code` (vulture) -- **Run all quality checks**: `mask development quality` - -### Testing -- **Run tests with coverage**: `uv run coverage run --parallel-mode -m pytest && uv run coverage combine && uv run coverage report` -- **Single test file**: `uv run pytest applications/*/tests/test_.py` -- **Coverage output**: Available in `coverage_output/.python_coverage.xml` - -### Infrastructure & Deployment -- **Deploy infrastructure**: `mask infrastructure base up` -- **Teardown infrastructure**: `mask infrastructure base down` -- **Deploy applications**: `mask applications up` -- **Test endpoints**: `mask test` -- **Check Docker contexts**: `docker context ls` - -### Development Environment -- **Environment manager**: Flox (`flox activate` to enter development shell) -- **Package manager**: uv (workspace with `applications/*` and `libraries/python`) -- **Python version**: 3.12.10 (strict requirement across all projects) - -## Architecture Overview - -### Workspace Structure -This is a **UV workspace** with multiple applications and shared libraries: - -- **Root workspace** (`pyproject.toml`): Main project configuration with workspace members -- **Applications** (`applications/*/`): Microservices deployed as Docker containers - - `datamanager`: Data collection service (FastAPI on port 8080) - - `portfoliomanager`: Portfolio prediction service (FastAPI on port 8081) - - `models`: ML model training and data processing workflows -- **Libraries** (`libraries/python/`): Shared `internal` package with common utilities -- **Infrastructure** (`infrastructure/`): Pulumi-based cloud deployment - -### Shared Internal Library (`libraries/python/src/internal/`) -Core components used across applications: -- **ML Components**: TFT models, LSTM/MHSA networks, loss functions -- **Data Types**: Equity bars, datasets, cloud events, money types -- **Utilities**: Date handling, data summaries - -### Deployment Architecture -- **Local Development**: Docker Swarm on localhost -- **Production**: Pulumi-managed cloud infrastructure with Docker Swarm -- **Container Registry**: DockerHub (`pocketsizefund/*` images) -- **Monitoring**: Grafana, Prometheus, Portainer -- **Networking**: Traefik reverse proxy with Let's Encrypt TLS - -### Service Communication -- **HTTP APIs**: FastAPI applications with health endpoints (`/health`) -- **Cloud Events**: Standardized event format for inter-service communication -- **Docker Networks**: Overlay networks (`public`, `internal`, `app-network`) - -## Code Standards - -### Python Configuration -- **Formatter**: Ruff (replaces black/isort) -- **Linter**: Ruff with comprehensive ruleset (90+ rule categories enabled) -- **Type Checking**: Pyright with relaxed import resolution -- **Testing**: Pytest with strict configuration -- **Coverage**: Line coverage tracking with parallel execution - -### Key Dependencies -- **Web Framework**: FastAPI (consistent across services) -- **ML Stack**: TinyGrad, NumPy, Polars -- **Data**: PyArrow, Polars for data processing -- **Cloud**: Boto3, Azure libraries, Google Cloud SDK -- **Monitoring**: Structlog for structured logging - -## Development Principles - -From the project README, the team follows these principles: -- Test in production -- Always roll forward -- Systems over process -- No code is good code -- Never write documentation -- Git is truth - -## Infrastructure Secrets - -Required Docker Swarm secrets for deployment: -- `GRAFANA_ADMIN_PASSWORD` -- `ALPACA_API_KEY`, `ALPACA_API_SECRET`, `ALPACA_BASE_URL` -- `EDGAR_USER_AGENT`, `DATA_BUCKET` -- `POLYGON_API_KEY`, `DUCKDB_ACCESS_KEY`, `DUCKDB_SECRET` -- `WEIGHTS_AND_BIASES_API_KEY` - -Create with: `echo "value" | docker secret create SECRET_NAME -` - -## Common Workflow - -1. **Setup**: `flox activate && mise run python:install` -2. **Develop**: Make changes to application or shared library code -3. **Quality**: `mise run lint` (format, lint, test, dead code check) -4. **Local Deploy**: `mask infrastructure base up` (deploys to both local and production) -5. **Test**: `mask test` (validates service endpoints) -6. **Monitor**: Access Grafana, Portainer, or service logs via Docker contexts \ No newline at end of file +# claude + +> Agentic tooling context + +## Notes + +- Rust and Python are the primary project languages +- [Flox](https://flox.dev/) manages project environment and packages +- [Mask](https://github.com/jacobdeichert/mask) is used for command management +- [Pulumi](https://www.pulumi.com/) manages cloud infrastructure via the Python SDK +- Python code follows [uv](https://github.com/astral-sh/uv) workspace conventions +- Rust code follows Cargo workspace conventions +- AWS is the target cloud provider +- Models are primarily built using [tinygrad](https://docs.tinygrad.org/) +- Python servers primarily use [FastAPI](https://fastapi.tiangolo.com/) +- Use `mask development` commands for respective language final code checks +- Add in-line code comments only where necessary for clarity +- Use full word variables in code whenever possible +- Follow Rust and Python recommended casing conventions +- Strictly use Python version 3.12.10 +- Scan and remove unused dependencies from `pyproject.toml` files +- Move duplicate dependencies into root workspace `pyproject.toml` +- Include type hints on all Python function parameters and return types +- Rust servers primarily use [Axum](https://docs.rs/axum/latest/axum/) +- Use Polars for [Python](https://docs.pola.rs/api/python/stable/reference/index.html) and [Rust](https://docs.rs/polars/latest/polars/) dataframes +- Use `typing` module `cast` function for `tinygrad` method outputs when necessary with union types +- When adding `ValueError` exceptions, create a separate variable called `message` to hold the error string before raising +- When logging after an exception, use `logger.exception()` to capture stack trace with the `structlog` package +- `tools/` folder contains development utilities and scripts +- `applications/` folder contains deployable services and training workflows +- `libraries/` folder contains shared code resources +- `infrastructure/` folder contains Pulumi infrastructure as code +- See `README.md` "Principles" section for developer philosophy diff --git a/Cargo.lock b/Cargo.lock index 4ffe0b00e..ee64bfca1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -36,7 +27,7 @@ checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "const-random", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -44,9 +35,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -81,6 +72,24 @@ dependencies = [ "libc", ] +[[package]] +name = "ar_archive_writer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a" +dependencies = [ + "object", +] + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "argminmax" version = "0.6.3" @@ -152,7 +161,7 @@ dependencies = [ "arrow-schema", "chrono", "half", - "hashbrown 0.16.0", + "hashbrown 0.16.1", "num", ] @@ -179,7 +188,7 @@ dependencies = [ "arrow-schema", "arrow-select", "atoi", - "base64 0.22.1", + "base64", "chrono", "comfy-table", "half", @@ -297,7 +306,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -308,7 +317,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -343,9 +352,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-config" -version = "1.8.6" +version = "1.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bc1b40fb26027769f16960d2f4a6bc20c4bb755d403e552c8c1a73af433c246" +checksum = "96571e6996817bf3d58f6b569e4b9fd2e9d2fcf9f7424eed07b2ce9bb87535e5" dependencies = [ "aws-credential-types", "aws-runtime", @@ -362,7 +371,7 @@ dependencies = [ "bytes", "fastrand", "hex", - "http 1.3.1", + "http 1.4.0", "ring", "time", "tokio", @@ -373,9 +382,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.6" +version = "1.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d025db5d9f52cbc413b167136afb3d8aeea708c0d8884783cf6253be5e22f6f2" +checksum = "3cd362783681b15d136480ad555a099e82ecd8e2d10a841e14dfd0078d67fee3" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -385,9 +394,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.14.0" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786" +checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" dependencies = [ "aws-lc-sys", "zeroize", @@ -395,11 +404,10 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.31.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd" +checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" dependencies = [ - "bindgen", "cc", "cmake", "dunce", @@ -408,9 +416,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.10" +version = "1.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c034a1bc1d70e16e7f4e4caf7e9f7693e4c9c24cd91cf17c2a0b21abaebc7c8b" +checksum = "d81b5b2898f6798ad58f484856768bca817e3cd9de0974c24ae0f1113fe88f1b" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -433,9 +441,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.106.0" +version = "1.118.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c230530df49ed3f2b7b4d9c8613b72a04cdac6452eede16d587fc62addfabac" +checksum = "d3e6b7079f85d9ea9a70643c9f89f50db70f5ada868fa9cfe08c1ffdf51abc13" dependencies = [ "aws-credential-types", "aws-runtime", @@ -455,7 +463,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "lru", "percent-encoding", @@ -467,9 +475,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.84.0" +version = "1.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357a841807f6b52cb26123878b3326921e2a25faca412fabdd32bd35b7edd5d3" +checksum = "8ee6402a36f27b52fe67661c6732d684b2635152b676aa2babbfb5204f99115d" dependencies = [ "aws-credential-types", "aws-runtime", @@ -489,9 +497,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.86.0" +version = "1.93.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1cc7fb324aa12eb4404210e6381195c5b5e9d52c2682384f295f38716dd3c7" +checksum = "a45a7f750bbd170ee3677671ad782d90b894548f4e4ae168302c57ec9de5cb3e" dependencies = [ "aws-credential-types", "aws-runtime", @@ -511,9 +519,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.86.0" +version = "1.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d835f123f307cafffca7b9027c14979f1d403b417d8541d67cf252e8a21e35" +checksum = "55542378e419558e6b1f398ca70adb0b2088077e79ad9f14eb09441f2f7b2164" dependencies = [ "aws-credential-types", "aws-runtime", @@ -534,9 +542,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.3.4" +version = "1.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084c34162187d39e3740cb635acd73c4e3a551a36146ad6fe8883c929c9f876c" +checksum = "69e523e1c4e8e7e8ff219d732988e22bfeae8a1cafdbe6d9eca1546fa080be7c" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", @@ -549,7 +557,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "p256", "percent-encoding", "ring", @@ -562,9 +570,9 @@ dependencies = [ [[package]] name = "aws-smithy-async" -version = "1.2.5" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e190749ea56f8c42bf15dd76c65e14f8f765233e6df9b0506d9d934ebef867c" +checksum = "9ee19095c7c4dda59f1697d028ce704c24b2d33c6718790c7f1d5a3015b4107c" dependencies = [ "futures-util", "pin-project-lite", @@ -573,9 +581,9 @@ dependencies = [ [[package]] name = "aws-smithy-checksums" -version = "0.63.8" +version = "0.63.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d2df0314b8e307995a3b86d44565dfe9de41f876901a7d71886c756a25979f" +checksum = "87294a084b43d649d967efe58aa1f9e0adc260e13a6938eb904c0ae9b45824ae" dependencies = [ "aws-smithy-http", "aws-smithy-types", @@ -593,9 +601,9 @@ dependencies = [ [[package]] name = "aws-smithy-eventstream" -version = "0.60.11" +version = "0.60.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "182b03393e8c677347fb5705a04a9392695d47d20ef0a2f8cfe28c8e6b9b9778" +checksum = "dc12f8b310e38cad85cf3bef45ad236f470717393c613266ce0a89512286b650" dependencies = [ "aws-smithy-types", "bytes", @@ -604,9 +612,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.62.3" +version = "0.62.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c4dacf2d38996cf729f55e7a762b30918229917eca115de45dfa8dfb97796c9" +checksum = "826141069295752372f8203c17f28e30c464d22899a43a0c9fd9c458d469c88b" dependencies = [ "aws-smithy-eventstream", "aws-smithy-runtime-api", @@ -614,8 +622,9 @@ dependencies = [ "bytes", "bytes-utils", "futures-core", + "futures-util", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "percent-encoding", "pin-project-lite", @@ -625,9 +634,9 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.1.1" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147e8eea63a40315d704b97bf9bc9b8c1402ae94f89d5ad6f7550d963309da1b" +checksum = "59e62db736db19c488966c8d787f52e6270be565727236fd5579eaa301e7bc4a" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -635,47 +644,47 @@ dependencies = [ "h2 0.3.27", "h2 0.4.12", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "hyper 0.14.32", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-rustls 0.24.2", "hyper-rustls 0.27.7", "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.32", - "rustls-native-certs 0.8.1", + "rustls 0.23.35", + "rustls-native-certs", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.3", + "tokio-rustls 0.26.4", "tower", "tracing", ] [[package]] name = "aws-smithy-json" -version = "0.61.5" +version = "0.61.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa31b350998e703e9826b2104dd6f63be0508666e1aba88137af060e8944047" +checksum = "49fa1213db31ac95288d981476f78d05d9cbb0353d22cdf3472cc05bb02f6551" dependencies = [ "aws-smithy-types", ] [[package]] name = "aws-smithy-observability" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9364d5989ac4dd918e5cc4c4bdcc61c9be17dcd2586ea7f69e348fc7c6cab393" +checksum = "17f616c3f2260612fe44cede278bafa18e73e6479c4e393e2c4518cf2a9a228a" dependencies = [ "aws-smithy-runtime-api", ] [[package]] name = "aws-smithy-query" -version = "0.60.7" +version = "0.60.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fbd61ceb3fe8a1cb7352e42689cec5335833cd9f94103a61e98f9bb61c64bb" +checksum = "ae5d689cf437eae90460e944a58b5668530d433b4ff85789e69d2f2a556e057d" dependencies = [ "aws-smithy-types", "urlencoding", @@ -683,9 +692,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.9.2" +version = "1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa63ad37685ceb7762fa4d73d06f1d5493feb88e3f27259b9ed277f4c01b185" +checksum = "65fda37911905ea4d3141a01364bc5509a0f32ae3f3b22d6e330c0abfb62d247" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -696,7 +705,7 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "http-body 1.0.1", "pin-project-lite", @@ -707,15 +716,15 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.9.0" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07f5e0fc8a6b3f2303f331b94504bbf754d85488f402d6f1dd7a6080f99afe56" +checksum = "ab0d43d899f9e508300e587bf582ba54c27a452dd0a9ea294690669138ae14a2" dependencies = [ "aws-smithy-async", "aws-smithy-types", "bytes", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "pin-project-lite", "tokio", "tracing", @@ -724,16 +733,16 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.3.2" +version = "1.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d498595448e43de7f4296b7b7a18a8a02c61ec9349128c80a368f7c3b4ab11a8" +checksum = "905cb13a9895626d49cf2ced759b062d913834c7482c38e49557eac4e6193f01" dependencies = [ "base64-simd", "bytes", "bytes-utils", "futures-core", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "http-body 1.0.1", "http-body-util", @@ -750,18 +759,18 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.10" +version = "0.60.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db87b96cb1b16c024980f133968d52882ca0daaee3a086c6decc500f6c99728" +checksum = "11b2f670422ff42bf7065031e72b45bc52a3508bd089f743ea90731ca2b6ea57" dependencies = [ "xmlparser", ] [[package]] name = "aws-types" -version = "1.3.8" +version = "1.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b069d19bf01e46298eaedd7c6f283fe565a59263e53eebec945f3e6398f42390" +checksum = "1d980627d2dd7bfc32a3c025685a033eeab8d365cc840c631ef59d1b8f428164" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -773,18 +782,18 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.4" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", "bytes", "form_urlencoded", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-util", "itoa", "matchit", @@ -792,8 +801,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -807,51 +815,29 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", "tracing", ] -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base16ct" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -870,9 +856,9 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" [[package]] name = "bincode" @@ -894,33 +880,13 @@ dependencies = [ "virtue", ] -[[package]] -name = "bindgen" -version = "0.72.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.106", -] - [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -959,9 +925,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" dependencies = [ "borsh-derive", "cfg_aliases", @@ -969,15 +935,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1009,9 +975,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "bytecheck" @@ -1037,22 +1003,22 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1063,9 +1029,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" dependencies = [ "serde", ] @@ -1097,9 +1063,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.38" +version = "1.2.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "9f50d563227a1c37cc0a263f64eca3334388c01c5e4c4861a9def205c614383c" dependencies = [ "find-msvc-tools", "jobserver", @@ -1107,20 +1073,11 @@ dependencies = [ "shlex", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -1139,7 +1096,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -1152,22 +1109,11 @@ dependencies = [ "phf", ] -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "cmake" -version = "0.1.54" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" dependencies = [ "cc", ] @@ -1276,9 +1222,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -1291,15 +1237,15 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc-fast" -version = "1.3.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf62af4cc77d8fe1c22dde4e721d87f2f54056139d8c412e1366b740305f56f" +checksum = "6ddc2d09feefeee8bd78101665bd8645637828fa9317f9f292496dbbd8c65ff3" dependencies = [ "crc", "digest", - "libc", "rand 0.9.2", "regex", + "rustversion", ] [[package]] @@ -1407,9 +1353,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -1436,7 +1382,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1447,7 +1393,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1461,7 +1407,7 @@ dependencies = [ "chrono", "duckdb", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "polars", "reqwest", "serde", @@ -1495,13 +1441,24 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "digest" version = "0.10.7" @@ -1521,23 +1478,23 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "document-features" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" dependencies = [ "litrs", ] [[package]] name = "duckdb" -version = "1.4.0" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2207e2cc81719eca29ef65cf904df49505cb0346c460ba6272c99cc5d7eb655" +checksum = "d7eeb487dde618b9f6ab26a451775ad5fac3fabe1ca2b64cbbe90b105f264ccd" dependencies = [ "arrow", "cast", @@ -1624,7 +1581,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -1702,15 +1659,15 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "libz-rs-sys", @@ -1840,7 +1797,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -1892,30 +1849,24 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "glob" version = "0.3.3" @@ -1963,7 +1914,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.3.1", + "http 1.4.0", "indexmap", "slab", "tokio", @@ -1973,13 +1924,14 @@ dependencies = [ [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", "num-traits", + "zerocopy", ] [[package]] @@ -2016,9 +1968,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "hashlink" @@ -2052,11 +2004,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2072,12 +2024,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -2099,7 +2050,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -2110,7 +2061,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "pin-project-lite", ] @@ -2159,16 +2110,16 @@ dependencies = [ [[package]] name = "hyper" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ "atomic-waker", "bytes", "futures-channel", "futures-core", "h2 0.4.12", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "httparse", "httpdate", @@ -2191,7 +2142,6 @@ dependencies = [ "hyper 0.14.32", "log", "rustls 0.21.12", - "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", ] @@ -2202,15 +2152,16 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.3.1", - "hyper 1.7.0", + "http 1.4.0", + "hyper 1.8.1", "hyper-util", - "rustls 0.23.32", - "rustls-native-certs 0.8.1", + "rustls 0.23.35", + "rustls-native-certs", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.3", + "tokio-rustls 0.26.4", "tower-service", + "webpki-roots", ] [[package]] @@ -2221,7 +2172,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-util", "native-tls", "tokio", @@ -2231,23 +2182,23 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", - "hyper 1.7.0", + "hyper 1.8.1", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.6.1", "system-configuration", "tokio", "tower-service", @@ -2281,9 +2232,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -2294,9 +2245,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -2307,11 +2258,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -2322,42 +2272,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -2404,27 +2350,16 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.16.1", "serde", "serde_core", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -2433,23 +2368,14 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", ] -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.14.0" @@ -2461,9 +2387,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010" [[package]] name = "jobserver" @@ -2471,15 +2397,15 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.80" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -2561,32 +2487,24 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.176" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libduckdb-sys" -version = "1.4.0" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d70696fa43ca9ed04ab7d8bfd4f3f1df73cabd3c872d67ddc9f55bb8dd4d1a" +checksum = "c8c60c2d269e63ae5197e4fe9075efffed35dfda0095a5ac8b41f3c765b18456" dependencies = [ "flate2", "pkg-config", + "reqwest", "serde", "serde_json", "tar", "vcpkg", -] - -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link 0.2.0", + "zip", ] [[package]] @@ -2597,20 +2515,20 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" dependencies = [ "bitflags", "libc", - "redox_syscall", + "redox_syscall 0.6.0", ] [[package]] name = "libz-rs-sys" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd" +checksum = "c10501e7805cee23da17c7790e59df2870c0d4043ec6d03f67d31e2b53e77415" dependencies = [ "zlib-rs", ] @@ -2623,31 +2541,30 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litrs" -version = "0.4.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lru" @@ -2710,15 +2627,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmap2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" dependencies = [ "libc", ] @@ -2729,12 +2646,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2742,17 +2653,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -2772,16 +2684,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "now" version = "0.1.3" @@ -2793,11 +2695,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.50.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2882,9 +2784,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] @@ -2896,16 +2798,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c1be0c6c22ec0817cdc77d3842f721a17fd30ab6965001415b5402a74e6b740" dependencies = [ "async-trait", - "base64 0.22.1", + "base64", "bytes", "chrono", "form_urlencoded", "futures", - "http 1.3.1", + "http 1.4.0", "http-body-util", "humantime", - "hyper 1.7.0", - "itertools 0.14.0", + "hyper 1.8.1", + "itertools", "parking_lot", "percent-encoding", "quick-xml", @@ -2932,9 +2834,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl" -version = "0.10.73" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ "bitflags", "cfg-if", @@ -2953,7 +2855,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -2964,9 +2866,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.109" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", @@ -2999,9 +2901,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -3009,15 +2911,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -3095,7 +2997,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5f7feb5d56b954e691dff22a8b2d78d77433dcc93c35fe21c3777fdc121b697" dependencies = [ "getrandom 0.2.16", - "getrandom 0.3.3", + "getrandom 0.3.4", "polars-arrow", "polars-core", "polars-error", @@ -3124,7 +3026,7 @@ dependencies = [ "either", "ethnum", "getrandom 0.2.16", - "getrandom 0.3.3", + "getrandom 0.3.4", "hashbrown 0.15.5", "itoa", "lz4", @@ -3386,7 +3288,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf6062173fdc9ba05775548beb66e76643a148d9aeadc9984ed712bc4babd76" dependencies = [ "argminmax", - "base64 0.22.1", + "base64", "bytemuck", "chrono", "chrono-tz", @@ -3422,7 +3324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc1d769180dec070df0dc4b89299b364bf2cfe32b218ecc4ddd8f1a49ae60669" dependencies = [ "async-stream", - "base64 0.22.1", + "base64", "brotli", "bytemuck", "ethnum", @@ -3633,9 +3535,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -3655,16 +3557,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.106", -] - [[package]] name = "proc-macro-crate" version = "3.4.0" @@ -3700,19 +3592,20 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.26" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" +checksum = "d11f2fedc3b7dafdc2851bc52f277377c5473d378859be234bc7ebb593144d01" dependencies = [ + "ar_archive_writer", "cc", ] @@ -3738,9 +3631,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.38.3" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" dependencies = [ "memchr", "serde", @@ -3758,8 +3651,8 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.32", - "socket2 0.6.0", + "rustls 0.23.35", + "socket2 0.6.1", "thiserror", "tokio", "tracing", @@ -3773,12 +3666,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "getrandom 0.3.3", + "getrandom 0.3.4", "lru-slab", "rand 0.9.2", "ring", "rustc-hash", - "rustls 0.23.32", + "rustls 0.23.35", "rustls-pki-types", "slab", "thiserror", @@ -3796,16 +3689,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.0", + "socket2 0.6.1", "tracing", "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -3889,7 +3782,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -3948,43 +3841,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.111", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", ] [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5" dependencies = [ "bitflags", ] [[package]] name = "ref-cast" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "regex" -version = "1.11.2" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -3994,9 +3896,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -4005,15 +3907,15 @@ dependencies = [ [[package]] name = "regex-lite" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943f41321c63ef1c92fd763bfe054d2668f7f225a5c29f0105903dc2fc04ba30" +checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rend" @@ -4026,20 +3928,21 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.23" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2 0.4.12", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-rustls 0.27.7", "hyper-tls", "hyper-util", @@ -4050,8 +3953,8 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.32", - "rustls-native-certs 0.8.1", + "rustls 0.23.35", + "rustls-native-certs", "rustls-pki-types", "serde", "serde_json", @@ -4059,7 +3962,7 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.3", + "tokio-rustls 0.26.4", "tokio-util", "tower", "tower-http", @@ -4069,6 +3972,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", + "webpki-roots", ] [[package]] @@ -4149,9 +4053,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.38.0" +version = "1.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8975fc98059f365204d635119cf9c5a60ae67b841ed49b5422a9a7e56cdfac0" +checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" dependencies = [ "arrayvec", "borsh", @@ -4163,12 +4067,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -4194,7 +4092,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -4211,57 +4109,36 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.32" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "aws-lc-rs", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.6", + "rustls-webpki 0.103.8", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework 2.11.1", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.5.0", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", + "security-framework 3.5.1", ] [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" dependencies = [ "web-time", "zeroize", @@ -4279,9 +4156,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.6" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "aws-lc-rs", "ring", @@ -4297,9 +4174,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "62049b2877bf12821e8f9ad256ee38fdc31db7387ec2d3b3f403024de2034aea" [[package]] name = "same-file" @@ -4316,7 +4193,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -4379,9 +4256,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.5.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc198e42d9b7510827939c9a15f5062a0c913f3371d765977e586d2fe6c16f4a" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ "bitflags", "core-foundation 0.10.1", @@ -4408,9 +4285,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -4418,29 +4295,29 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "217ca874ae0207aac254aa02c957ded05585a90892cc8d87f9e5fa49669dadd8" dependencies = [ "indexmap", "itoa", @@ -4533,9 +4410,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -4550,6 +4427,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + [[package]] name = "simd-json" version = "0.15.1" @@ -4557,7 +4440,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c962f626b54771990066e5435ec8331d1462576cd2d1e62f24076ae014f92112" dependencies = [ "ahash 0.8.12", - "getrandom 0.3.3", + "getrandom 0.3.4", "halfbrown", "once_cell", "ref-cast", @@ -4597,9 +4480,9 @@ checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "slotmap" -version = "1.0.7" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" dependencies = [ "version_check", ] @@ -4628,12 +4511,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -4657,15 +4540,15 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stacker" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b" +checksum = "e1f8b29fb42aafcea4edeeb6b2f2d7ecd0d969c48b4cf0d2e64aafc471dd6e59" dependencies = [ "cc", "cfg-if", @@ -4725,7 +4608,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -4747,9 +4630,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -4773,7 +4656,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -4821,30 +4704,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -4897,9 +4780,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -4922,33 +4805,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", + "socket2 0.6.1", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -4973,11 +4853,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.32", + "rustls 0.23.35", "tokio", ] @@ -5007,9 +4887,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -5021,18 +4901,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.2" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.23.6" +version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap", "toml_datetime", @@ -5042,9 +4922,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.3" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" dependencies = [ "winnow", ] @@ -5067,14 +4947,14 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags", "bytes", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "iri-string", "pin-project-lite", @@ -5098,9 +4978,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -5110,20 +4990,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -5142,9 +5022,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ "matchers", "nu-ansi-term", @@ -5166,9 +5046,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-bidi" @@ -5178,15 +5058,15 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] @@ -5208,9 +5088,9 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "untrusted" @@ -5250,13 +5130,13 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.18.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", - "serde", + "serde_core", "wasm-bindgen", ] @@ -5287,7 +5167,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -5357,15 +5237,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -5377,9 +5248,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.103" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", @@ -5388,25 +5259,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.53" +version = "0.4.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" dependencies = [ "cfg-if", "js-sys", @@ -5417,9 +5274,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.103" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5427,22 +5284,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.103" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.111", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.103" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] @@ -5462,9 +5319,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.80" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", @@ -5480,6 +5337,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi" version = "0.3.9" @@ -5502,7 +5368,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -5513,96 +5379,72 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.62.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.0", - "windows-result 0.4.0", - "windows-strings 0.5.0", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-registry" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" -dependencies = [ - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", -] - -[[package]] -name = "windows-result" -version = "0.3.4" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-link 0.1.3", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] name = "windows-result" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" -dependencies = [ - "windows-link 0.2.0", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -5629,16 +5471,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -5659,19 +5501,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -5682,9 +5524,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -5694,9 +5536,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -5706,9 +5548,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -5718,9 +5560,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -5730,9 +5572,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -5742,9 +5584,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -5754,9 +5596,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -5766,15 +5608,15 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] @@ -5787,9 +5629,9 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wyz" @@ -5824,11 +5666,10 @@ checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -5836,34 +5677,34 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", ] [[package]] @@ -5883,21 +5724,21 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -5906,9 +5747,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -5917,20 +5758,46 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.111", +] + +[[package]] +name = "zip" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b" +dependencies = [ + "arbitrary", + "crc32fast", + "flate2", + "indexmap", + "memchr", + "zopfli", ] [[package]] name = "zlib-rs" -version = "0.5.2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3" + +[[package]] +name = "zopfli" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] [[package]] name = "zstd" diff --git a/Dockerfile.tests b/Dockerfile.tests deleted file mode 100644 index 2bb9a57ff..000000000 --- a/Dockerfile.tests +++ /dev/null @@ -1,36 +0,0 @@ -FROM python:3.12.10 - -COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv - -RUN apt-get update && apt-get install -y \ - build-essential \ - clang \ - libc6-dev \ - linux-libc-dev \ - && rm -rf /var/lib/apt/lists/* - -ENV PYTHON=1 - -WORKDIR /tests - -COPY pyproject.toml uv.lock ./ - -COPY applications/datamanager/pyproject.toml ./applications/datamanager/ - -COPY applications/portfoliomanager/pyproject.toml ./applications/portfoliomanager/ - -COPY applications/models/pyproject.toml ./applications/models/ - -COPY infrastructure/pyproject.toml ./infrastructure/ - -COPY libraries/python/pyproject.toml ./libraries/python/ - -RUN uv sync --all-packages --all-groups - -COPY applications/ ./applications/ - -COPY libraries/ ./libraries/ - -RUN uv sync --all-packages --all-groups - -RUN mkdir -p /tests/coverage_output diff --git a/README.md b/README.md index cdbb9c502..ec41ba4f3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # pocketsizefund -> Open source quantitative hedge fund 🍊 +> Open source capital management [![Python code checks](https://github.com/pocketsizefund/pocketsizefund/actions/workflows/run_python_code_checks.yaml/badge.svg)](https://github.com/pocketsizefund/pocketsizefund/actions/workflows/run_python_code_checks.yaml) [![Rust code checks](https://github.com/pocketsizefund/pocketsizefund/actions/workflows/run_rust_code_checks.yaml/badge.svg)](https://github.com/pocketsizefund/pocketsizefund/actions/workflows/run_rust_code_checks.yaml) @@ -16,12 +16,15 @@ The project is actively a work-in-progress. ### Setup -Run the commands below the repository root directory. +Run the commands below in the root directory. ```sh brew install flox # https://flox.dev/ for more information flox activate +uv venv +source .venv/bin/activate mask --help # see all available Mask tasks +mask setup mask development python install ``` diff --git a/applications/datamanager/.claude/settings.local.json b/applications/datamanager/.claude/settings.local.json deleted file mode 100644 index 868bdffee..000000000 --- a/applications/datamanager/.claude/settings.local.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(cat:*)", - "Bash(docker:*)", - "Bash(cargo:*)", - "Bash(http POST:*)", - "Bash(curl:*)", - "Bash(RUST_LOG=debug curl -X POST -H \"Content-Type: application/json\" -d '{\"\"date\"\": \"\"2025-08-25\"\"}' http://localhost:8089/equity)", - "Bash(RUST_BACKTRACE=1 cargo run)", - "Bash(lsof:*)", - "Bash(kill:*)", - "Bash(RUST_LOG=info cargo run)", - "Bash(pkill:*)", - "Bash(RUST_LOG=debug cargo run)", - "Bash(brew install:*)", - "Bash(export:*)" - ], - "deny": [], - "defaultMode": "acceptEdits" - } -} - diff --git a/applications/datamanager/Dockerfile b/applications/datamanager/Dockerfile index c0840f4bd..28cf2ed0f 100644 --- a/applications/datamanager/Dockerfile +++ b/applications/datamanager/Dockerfile @@ -1,15 +1,53 @@ -FROM python:3.12.10 -COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv +FROM lukemathwalker/cargo-chef:0.1.72-rust-1.89.0-slim AS chef -ENV PYTHONPATH=/app/src +RUN apt-get update && apt-get install -y --no-install-recommends \ + pkg-config \ + libssl-dev \ + build-essential \ + && rm -rf /var/lib/apt/lists/* + +RUN rustup toolchain install stable + +RUN rustup default stable WORKDIR /app -COPY pyproject.toml ./ -RUN uv sync --no-dev +FROM chef AS planner + +COPY applications/datamanager/ applications/datamanager/ + +COPY Cargo.toml Cargo.lock ./ + +COPY applications/datamanager/Cargo.toml ./applications/datamanager/Cargo.toml + +RUN cargo chef prepare --recipe-path recipe.json + +FROM chef AS builder + +COPY --from=planner /app/recipe.json recipe.json + +RUN cargo chef cook --release --recipe-path recipe.json -COPY ./src ./src +COPY applications/datamanager/src/ applications/datamanager/src/ + +RUN cargo build --release --bin datamanager + +FROM debian:bullseye-slim AS server + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates openssl && \ + update-ca-certificates && \ + rm -rf /var/lib/apt/lists/* + +ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + +ENV SSL_CERT_DIR=/etc/ssl/certs + +WORKDIR /app + +COPY --from=builder /app/target/release/datamanager /usr/local/bin EXPOSE 8080 -ENTRYPOINT ["uv", "run", "uvicorn", "datamanager.main:application", "--host", "0.0.0.0", "--port", "8080", "--app-dir", "src"] +ENTRYPOINT ["/usr/local/bin/datamanager"] + diff --git a/applications/datamanager/pyproject.toml b/applications/datamanager/pyproject.toml deleted file mode 100644 index 661768406..000000000 --- a/applications/datamanager/pyproject.toml +++ /dev/null @@ -1,15 +0,0 @@ -[project] -name = "datamanager" -version = "0.1.0" -description = "Data collection and management service" -requires-python = "==3.12.10" -dependencies = [ - "fastapi>=0.116.1", - "structlog>=25.4.0", - "uvicorn>=0.35.0", - "duckdb>=1.4.0", -] - -[tool.uv] -package = true -src = ["src"] diff --git a/applications/datamanager/src/data.rs b/applications/datamanager/src/data.rs index b008d5b68..b3f98c65a 100644 --- a/applications/datamanager/src/data.rs +++ b/applications/datamanager/src/data.rs @@ -1,6 +1,7 @@ use crate::errors::Error; use polars::prelude::*; use serde::Deserialize; +use std::io::Cursor; #[derive(Debug, Deserialize)] pub struct EquityBar { @@ -87,6 +88,7 @@ pub struct Portfolio { pub timestamp: i64, pub side: String, pub dollar_amount: f64, + pub action: String, } pub fn create_portfolio_dataframe(portfolio_rows: Vec) -> Result { @@ -95,13 +97,57 @@ pub fn create_portfolio_dataframe(portfolio_rows: Vec) -> Result portfolio_rows.iter().map(|p| p.timestamp).collect::>(), "side" => portfolio_rows.iter().map(|p| p.side.as_str()).collect::>(), "dollar_amount" => portfolio_rows.iter().map(|p| p.dollar_amount).collect::>(), + "action" => portfolio_rows.iter().map(|p| p.action.as_str()).collect::>(), ) .map_err(|e| Error::Other(format!("Failed to create DataFrame: {}", e)))?; let portfolio_dataframe = portfolio_dataframe .lazy() .with_columns([col("ticker").str().to_uppercase().alias("ticker")]) + .with_columns([col("side").str().to_uppercase().alias("side")]) + .with_columns([col("action").str().to_uppercase().alias("action")]) .collect()?; Ok(portfolio_dataframe) } + +pub fn create_equity_details_dataframe(csv_content: String) -> Result { + let cursor = Cursor::new(csv_content.as_bytes()); + let mut dataframe = CsvReadOptions::default() + .with_has_header(true) + .into_reader_with_file_handle(cursor) + .finish() + .map_err(|e| Error::Other(format!("Failed to parse CSV: {}", e)))?; + + let required_columns = vec!["sector", "industry"]; + let column_names = dataframe.get_column_names(); + for column in &required_columns { + if !column_names.iter().any(|c| c.as_str() == *column) { + let message = format!("CSV missing required column: {}", column); + return Err(Error::Other(message)); + } + } + + dataframe = dataframe + .select(required_columns) + .map_err(|e| Error::Other(format!("Failed to select columns: {}", e)))?; + + let equity_details_dataframe = dataframe + .lazy() + .with_columns([ + col("sector") + .str() + .to_uppercase() + .fill_null(lit("NOT AVAILABLE")) + .alias("sector"), + col("industry") + .str() + .to_uppercase() + .fill_null(lit("NOT AVAILABLE")) + .alias("industry"), + ]) + .collect() + .map_err(|e| Error::Other(format!("Failed to transform columns: {}", e)))?; + + Ok(equity_details_dataframe) +} diff --git a/applications/datamanager/src/equity_bars.rs b/applications/datamanager/src/equity_bars.rs index 205c5c9a2..0abc9881d 100644 --- a/applications/datamanager/src/equity_bars.rs +++ b/applications/datamanager/src/equity_bars.rs @@ -17,9 +17,10 @@ pub struct DailySync { } #[derive(Deserialize)] -pub struct DateRangeParameters { - start_date: Option>, - end_date: Option>, +pub struct QueryParameters { + tickers: Option, + start_timestamp: Option>, + end_timestamp: Option>, } #[derive(Deserialize, Debug)] @@ -49,14 +50,34 @@ struct PolygonResponse { results: Option>, } -pub async fn fetch( +pub async fn query( AxumState(state): AxumState, - Query(parameters): Query, + Query(parameters): Query, ) -> impl IntoResponse { - info!("Fetching equity data from S3 partitioned files"); + info!("Querying equity data from S3 partitioned files"); + + let tickers: Option> = match ¶meters.tickers { + Some(tickers_str) if !tickers_str.is_empty() => { + let vec: Vec = tickers_str + .split(',') + .map(|s| s.trim().to_uppercase()) + .collect(); + if vec.is_empty() { + None + } else { + Some(vec) + } + } + _ => None, + }; - match query_equity_bars_parquet_from_s3(&state, parameters.start_date, parameters.end_date) - .await + match query_equity_bars_parquet_from_s3( + &state, + tickers, + parameters.start_timestamp, + parameters.end_timestamp, + ) + .await { Ok(parquet_data) => { let mut response = Response::new(Body::from(parquet_data)); @@ -115,7 +136,7 @@ pub async fn sync( } }; - let raw_text = match response.error_for_status() { + let text_content = match response.error_for_status() { Ok(response) => match response.text().await { Ok(text) => text, Err(err) => { @@ -133,7 +154,7 @@ pub async fn sync( } }; - let json_value: serde_json::Value = match serde_json::from_str(&raw_text) { + let json_content: serde_json::Value = match serde_json::from_str(&text_content) { Ok(value) => value, Err(err) => { info!("Failed to parse JSON response: {}", err); @@ -145,7 +166,7 @@ pub async fn sync( } }; - let results_array = match json_value.get("results") { + let results = match json_content.get("results") { Some(results) => results, None => { info!("No results field found in response"); @@ -157,25 +178,26 @@ pub async fn sync( } }; - let bars: Vec = match serde_json::from_value(results_array.clone()) { + let bars: Vec = match serde_json::from_value(results.clone()) { Ok(bars) => bars, Err(err) => { info!("Failed to parse results into BarResult structs: {}", err); - return (StatusCode::BAD_GATEWAY, raw_text).into_response(); + return (StatusCode::BAD_GATEWAY, text_content).into_response(); } }; let tickers: Vec = bars.iter().map(|b| b.ticker.clone()).collect(); let volumes: Vec> = bars.iter().map(|b| b.v).collect(); - let vw_prices: Vec> = bars.iter().map(|b| b.vw.map(|vw| vw as f64)).collect(); + let volume_weighted_average_prices: Vec> = + bars.iter().map(|b| b.vw.map(|vw| vw as f64)).collect(); let open_prices: Vec> = bars.iter().map(|b| b.o.map(|o| o as f64)).collect(); let close_prices: Vec> = bars.iter().map(|b| b.c.map(|c| c as f64)).collect(); let high_prices: Vec> = bars.iter().map(|b| b.h.map(|h| h as f64)).collect(); let low_prices: Vec> = bars.iter().map(|b| b.l.map(|l| l as f64)).collect(); let timestamps: Vec = bars.iter().map(|b| b.t as i64).collect(); - let num_transactions: Vec> = bars.iter().map(|b| b.n).collect(); + let transactions: Vec> = bars.iter().map(|b| b.n).collect(); - let df_result = df! { + let bars_data = df! { "ticker" => tickers, "timestamp" => timestamps, "open_price" => open_prices, @@ -183,32 +205,32 @@ pub async fn sync( "low_price" => low_prices, "close_price" => close_prices, "volume" => volumes, - "volume_weighted_average_price" => vw_prices, - "transactions" => num_transactions, + "volume_weighted_average_price" => volume_weighted_average_prices, + "transactions" => transactions, }; - match df_result { - Ok(df) => { + match bars_data { + Ok(data) => { info!( "Created DataFrame with {} rows and {} columns", - df.height(), - df.width() + data.height(), + data.width() ); - debug!("DataFrame schema: {:?}", df.schema()); + debug!("DataFrame schema: {:?}", data.schema()); - match write_equity_bars_dataframe_to_s3(&state, &df, &payload.date).await { + match write_equity_bars_dataframe_to_s3(&state, &data, &payload.date).await { Ok(s3_key) => { info!("Successfully uploaded DataFrame to S3 at key: {}", s3_key); - let response_msg = format!( + let response_message = format!( "DataFrame created with {} rows and uploaded to S3: {}", - df.height(), + data.height(), s3_key ); - (StatusCode::OK, response_msg).into_response() + (StatusCode::OK, response_message).into_response() } Err(err) => { info!("Failed to upload to S3: {}", err); - let json_output = df.to_string(); + let json_output = data.to_string(); ( StatusCode::BAD_GATEWAY, format!( @@ -222,7 +244,7 @@ pub async fn sync( } Err(err) => { info!("Failed to create DataFrame: {}", err); - (StatusCode::INTERNAL_SERVER_ERROR, raw_text).into_response() + (StatusCode::INTERNAL_SERVER_ERROR, text_content).into_response() } } } diff --git a/applications/datamanager/src/equity_details.rs b/applications/datamanager/src/equity_details.rs new file mode 100644 index 000000000..5dc8ceafc --- /dev/null +++ b/applications/datamanager/src/equity_details.rs @@ -0,0 +1,56 @@ +use crate::state::State; +use crate::storage::read_equity_details_dataframe_from_s3; +use axum::{ + extract::State as AxumState, + http::{header, StatusCode}, + response::IntoResponse, +}; +use polars::prelude::*; +use tracing::info; + +pub async fn get(AxumState(state): AxumState) -> impl IntoResponse { + info!("Fetching equity details CSV from S3"); + + match read_equity_details_dataframe_from_s3(&state).await { + Ok(dataframe) => { + let mut buffer = Vec::new(); + let mut writer = CsvWriter::new(&mut buffer); + + match writer.finish(&mut dataframe.clone()) { + Ok(_) => { + let csv_content = String::from_utf8(buffer).unwrap_or_else(|_| { + info!("Failed to convert CSV buffer to UTF-8"); + String::new() + }); + + let mut response = csv_content.into_response(); + response.headers_mut().insert( + header::CONTENT_TYPE, + "text/csv; charset=utf-8".parse().unwrap_or_else(|_| { + info!("Failed to set Content-Type header"); + header::HeaderValue::from_static("text/csv") + }), + ); + *response.status_mut() = StatusCode::OK; + response + } + Err(err) => { + info!("Failed to write DataFrame as CSV: {}", err); + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Failed to convert DataFrame to CSV: {}", err), + ) + .into_response() + } + } + } + Err(err) => { + info!("Failed to fetch equity details from S3: {}", err); + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Failed to fetch equity details: {}", err), + ) + .into_response() + } + } +} diff --git a/applications/datamanager/src/main.rs b/applications/datamanager/src/main.rs index d9cb919c9..5a1ca0a2d 100644 --- a/applications/datamanager/src/main.rs +++ b/applications/datamanager/src/main.rs @@ -1,5 +1,6 @@ mod data; mod equity_bars; +mod equity_details; mod errors; mod health; mod portfolios; diff --git a/applications/datamanager/src/portfolios.rs b/applications/datamanager/src/portfolios.rs index 4b59fcc95..a9f5e0672 100644 --- a/applications/datamanager/src/portfolios.rs +++ b/applications/datamanager/src/portfolios.rs @@ -1,7 +1,7 @@ use crate::state::State; use crate::storage::{query_portfolio_dataframe_from_s3, write_portfolio_dataframe_to_s3}; use axum::{ - extract::{Json, State as AxumState}, + extract::{Json, Query, State as AxumState}, http::StatusCode, response::IntoResponse, }; @@ -46,10 +46,20 @@ pub async fn save( } } -pub async fn get(AxumState(state): AxumState) -> impl IntoResponse { +#[derive(Deserialize)] +pub struct QueryParameters { + timestamp: Option>, +} + +pub async fn get( + AxumState(state): AxumState, + Query(parameters): Query, +) -> impl IntoResponse { info!("Fetching portfolio from S3"); - match query_portfolio_dataframe_from_s3(&state, &Utc::now()).await { + let timestamp: Option> = parameters.timestamp; + + match query_portfolio_dataframe_from_s3(&state, timestamp).await { Ok(dataframe) => (StatusCode::OK, dataframe.to_string()).into_response(), Err(err) => { info!("Failed to fetch portfolio from S3: {}", err); diff --git a/applications/datamanager/src/predictions.rs b/applications/datamanager/src/predictions.rs index 7fe2bd1ce..dee9f9f18 100644 --- a/applications/datamanager/src/predictions.rs +++ b/applications/datamanager/src/predictions.rs @@ -10,24 +10,23 @@ use axum::{ use chrono::{DateTime, Utc}; use polars::prelude::*; use serde::Deserialize; -use serde_json; use tracing::info; use urlencoding::decode; #[derive(Deserialize)] -pub struct SavePredictionsPayload { +pub struct SavePayload { pub data: DataFrame, pub timestamp: DateTime, } #[derive(Deserialize)] -pub struct QueryPredictionsParameters { - pub data: String, // URL-encoded JSON string +pub struct QueryParameters { + pub tickers_and_timestamps: String, // URL-encoded JSON string } pub async fn save( AxumState(state): AxumState, - Json(payload): Json, + Json(payload): Json, ) -> impl IntoResponse { let predictions = payload.data; @@ -57,11 +56,11 @@ pub async fn save( pub async fn query( AxumState(state): AxumState, - Query(parameters): Query, + Query(parameters): Query, ) -> impl IntoResponse { info!("Fetching predictions from S3"); - let decoded = match decode(¶meters.data) { + let decoded = match decode(¶meters.tickers_and_timestamps) { Ok(decoded) => decoded.into_owned(), Err(e) => { return ( diff --git a/applications/datamanager/src/router.rs b/applications/datamanager/src/router.rs index 351a66b1b..d68bb3a96 100644 --- a/applications/datamanager/src/router.rs +++ b/applications/datamanager/src/router.rs @@ -1,4 +1,5 @@ use crate::equity_bars; +use crate::equity_details; use crate::health; use crate::portfolios; use crate::predictions; @@ -19,7 +20,8 @@ pub async fn create_app() -> Router { .route("/portfolios", post(portfolios::save)) .route("/portfolios", get(portfolios::get)) .route("/equity-bars", post(equity_bars::sync)) - .route("/equity-bars", get(equity_bars::fetch)) + .route("/equity-bars", get(equity_bars::query)) + .route("/equity-details", get(equity_details::get)) .with_state(state) .layer(TraceLayer::new_for_http()) } diff --git a/applications/datamanager/src/state.rs b/applications/datamanager/src/state.rs index 91a55dbea..25e8a22a7 100644 --- a/applications/datamanager/src/state.rs +++ b/applications/datamanager/src/state.rs @@ -1,13 +1,6 @@ use aws_sdk_s3::Client as S3Client; use reqwest::Client as HTTPClient; -#[derive(Clone)] -pub struct AlpacaSecrets { - pub base: String, - pub key: String, - pub secret: String, -} - #[derive(Clone)] pub struct PolygonSecrets { pub base: String, @@ -18,7 +11,6 @@ pub struct PolygonSecrets { pub struct State { pub http_client: HTTPClient, pub polygon: PolygonSecrets, - pub alpaca: AlpacaSecrets, pub s3_client: S3Client, pub bucket_name: String, } @@ -33,7 +25,7 @@ impl State { let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await; let s3_client = S3Client::new(&config); let bucket_name = - std::env::var("S3_BUCKET_NAME").unwrap_or("pocketsizefund-ml-data".to_string()); + std::env::var("AWS_S3_DATA_BUCKET_NAME").unwrap_or("pocketsizefund-data".to_string()); Self { http_client, @@ -43,14 +35,6 @@ impl State { key: std::env::var("POLYGON_API_KEY") .expect("POLYGON_API_KEY must be set in environment"), }, - alpaca: AlpacaSecrets { - base: std::env::var("ALPACA_BASE_URL") - .unwrap_or("https://data.alpaca.markets".to_string()), - key: std::env::var("ALPACA_API_KEY") - .expect("ALPACA_API_KEY must be set in environment"), - secret: std::env::var("ALPACA_API_SECRET") - .expect("ALPACA_API_SECRET must be set in environment"), - }, s3_client, bucket_name, } diff --git a/applications/datamanager/src/storage.rs b/applications/datamanager/src/storage.rs index 7fda8b5bf..aa62aba9d 100644 --- a/applications/datamanager/src/storage.rs +++ b/applications/datamanager/src/storage.rs @@ -1,6 +1,6 @@ use crate::data::{ - create_equity_bar_dataframe, create_portfolio_dataframe, create_predictions_dataframe, - EquityBar, Portfolio, Prediction, + create_equity_bar_dataframe, create_equity_details_dataframe, create_portfolio_dataframe, + create_predictions_dataframe, EquityBar, Portfolio, Prediction, }; use crate::errors::Error; use crate::state::State; @@ -16,38 +16,38 @@ use tracing::{debug, info}; pub async fn write_equity_bars_dataframe_to_s3( state: &State, dataframe: &DataFrame, - date: &DateTime, + timestamp: &DateTime, ) -> Result { - write_dataframe_to_s3(state, dataframe, date, "bars".to_string()).await + write_dataframe_to_s3(state, dataframe, timestamp, "bars".to_string()).await } pub async fn write_portfolio_dataframe_to_s3( state: &State, dataframe: &DataFrame, - date: &DateTime, + timestamp: &DateTime, ) -> Result { - write_dataframe_to_s3(state, dataframe, date, "portfolios".to_string()).await + write_dataframe_to_s3(state, dataframe, timestamp, "portfolios".to_string()).await } pub async fn write_predictions_dataframe_to_s3( state: &State, dataframe: &DataFrame, - date: &DateTime, + timestamp: &DateTime, ) -> Result { - write_dataframe_to_s3(state, dataframe, date, "predictions".to_string()).await + write_dataframe_to_s3(state, dataframe, timestamp, "predictions".to_string()).await } async fn write_dataframe_to_s3( state: &State, dataframe: &DataFrame, - date: &DateTime, + timestamp: &DateTime, dataframe_type: String, ) -> Result { info!("Uploading DataFrame to S3 as parquet"); - let year = date.format("%Y"); - let month = date.format("%m"); - let day = date.format("%d"); + let year = timestamp.format("%Y"); + let month = timestamp.format("%m"); + let day = timestamp.format("%d"); let key = format!( "equity/{}/daily/year={}/month={}/day={}/data.parquet", @@ -130,12 +130,13 @@ async fn create_duckdb_connection() -> Result { pub async fn query_equity_bars_parquet_from_s3( state: &State, - start_date: Option>, - end_date: Option>, + tickers: Option>, + start_timestamp: Option>, + end_timestamp: Option>, ) -> Result, Error> { let connection = create_duckdb_connection().await?; - let (start_date, end_date) = match (start_date, end_date) { + let (start_timestamp, end_timestamp) = match (start_timestamp, end_timestamp) { (Some(start), Some(end)) => (start, end), _ => { let end_date = chrono::Utc::now(); @@ -144,15 +145,18 @@ pub async fn query_equity_bars_parquet_from_s3( } }; - info!("Querying data from {} to {}", start_date, end_date); + info!( + "Querying data from {} to {}", + start_timestamp, end_timestamp + ); let mut s3_paths = Vec::new(); - let mut current_date = start_date; + let mut current_timestamp = start_timestamp; - while current_date <= end_date { - let year = current_date.format("%Y"); - let month = current_date.format("%m"); - let day = current_date.format("%d"); + while current_timestamp <= end_timestamp { + let year = current_timestamp.format("%Y"); + let month = current_timestamp.format("%m"); + let day = current_timestamp.format("%d"); let s3_path = format!( "s3://{}/equity/bars/daily/year={}/month={}/day={}/data.parquet", @@ -160,7 +164,7 @@ pub async fn query_equity_bars_parquet_from_s3( ); s3_paths.push(s3_path); - current_date += chrono::Duration::days(1); + current_timestamp += chrono::Duration::days(1); } if s3_paths.is_empty() { @@ -177,6 +181,27 @@ pub async fn query_equity_bars_parquet_from_s3( .collect::>() .join(" UNION ALL "); + let ticker_filter = match &tickers { + Some(ticker_list) if !ticker_list.is_empty() => { + // Validate ticker format to prevent SQL injection + for ticker in ticker_list { + if !ticker + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '.' || c == '-') + { + return Err(Error::Other(format!("Invalid ticker format: {}", ticker))); + } + } + let ticker_values = ticker_list + .iter() + .map(|t| format!("'{}'", t.replace('\'', "''"))) + .collect::>() + .join(", "); + format!("WHERE ticker IN ({})", ticker_values) + } + _ => String::new(), + }; + let query_sql = format!( " SELECT @@ -190,9 +215,10 @@ pub async fn query_equity_bars_parquet_from_s3( volume_weighted_average_price, transactions FROM ({}) + {} ORDER BY timestamp, ticker ", - s3_paths_str + s3_paths_str, ticker_filter ); debug!("Executing query SQL: {}", query_sql); @@ -318,33 +344,78 @@ pub async fn query_predictions_dataframe_from_s3( pub async fn query_portfolio_dataframe_from_s3( state: &State, - timestamp: &DateTime, + timestamp: Option>, ) -> Result { let connection = create_duckdb_connection().await?; - let year = timestamp.format("%Y"); - let month = timestamp.format("%m"); - let day = timestamp.format("%d"); - let s3_path = format!( - "s3://{}/equity/portfolios/daily/year={}/month={}/day={}/data.parquet", - state.bucket_name, year, month, day - ); - info!("Querying 1 S3 file"); - let s3_paths_query = format!("SELECT * FROM '{}'", s3_path); + let query = match timestamp { + Some(ts) => { + let year = ts.format("%Y"); + let month = ts.format("%m"); + let day = ts.format("%d"); + let s3_path = format!( + "s3://{}/equity/portfolios/daily/year={}/month={}/day={}/data.parquet", + state.bucket_name, year, month, day + ); + info!( + "Querying specific date portfolio: {}/{}/{}", + year, month, day + ); - let query = format!( - " - SELECT - ticker, - timestamp, - side, - dollar_amount - FROM ({}) - ORDER BY timestamp, ticker - ", - s3_paths_query, - ); - debug!("Executing export SQL: {}", query); + format!( + " + SELECT + ticker, + timestamp, + side, + dollar_amount, + action + FROM '{}' + ORDER BY timestamp, ticker + ", + s3_path + ) + } + None => { + let s3_wildcard = format!( + "s3://{}/equity/portfolios/daily/**/*.parquet", + state.bucket_name + ); + info!("Querying most recent portfolio from all files"); + + format!( + " + WITH partitioned_data AS ( + SELECT + ticker, + timestamp, + side, + dollar_amount, + year, + month, + day + FROM read_parquet('{}', hive_partitioning=1) + ), + max_date AS ( + SELECT MAX(year::int * 10000 + month::int * 100 + day::int) as date_int + FROM partitioned_data + ) + SELECT + ticker, + timestamp, + side, + dollar_amount, + action + FROM partitioned_data + WHERE (year::int * 10000 + month::int * 100 + day::int) = (SELECT date_int FROM max_date) + ORDER BY timestamp, ticker + ", + s3_wildcard + ) + } + }; + + debug!("Executing query SQL: {}", query); let mut statement = connection.prepare(&query)?; @@ -355,6 +426,7 @@ pub async fn query_portfolio_dataframe_from_s3( timestamp: row.get::<_, i64>(1)?, side: row.get::<_, String>(2)?, dollar_amount: row.get::<_, f64>(3)?, + action: row.get::<_, String>(4)?, }) })? .collect::, _>>() @@ -364,3 +436,42 @@ pub async fn query_portfolio_dataframe_from_s3( Ok(portfolio_dataframe) } + +pub async fn read_equity_details_dataframe_from_s3(state: &State) -> Result { + info!("Reading equity details CSV from S3"); + + let key = "equity/details/categories.csv"; + + let response = state + .s3_client + .get_object() + .bucket(&state.bucket_name) + .key(key) + .send() + .await + .map_err(|e| Error::Other(format!("Failed to get object from S3: {}", e)))?; + + let bytes = response + .body + .collect() + .await + .map_err(|e| Error::Other(format!("Failed to read response body: {}", e)))? + .into_bytes(); + + let csv_content = String::from_utf8(bytes.to_vec()) + .map_err(|e| Error::Other(format!("Failed to convert bytes to UTF-8: {}", e)))?; + + info!( + "Successfully read CSV from S3, size: {} bytes", + csv_content.len() + ); + + let dataframe = create_equity_details_dataframe(csv_content)?; + + info!( + "Successfully processed DataFrame with {} rows", + dataframe.height() + ); + + Ok(dataframe) +} diff --git a/applications/equitypricemodel/Dockerfile b/applications/equitypricemodel/Dockerfile new file mode 100644 index 000000000..81ec75635 --- /dev/null +++ b/applications/equitypricemodel/Dockerfile @@ -0,0 +1,60 @@ +FROM python:3.12.10-slim AS builder + +COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv + +WORKDIR /app + +COPY pyproject.toml uv.lock ./ + +COPY applications/equitypricemodel/ applications/equitypricemodel/ + +COPY libraries/python/ libraries/python/ + +RUN uv sync --no-dev --no-cache + +FROM python:3.12.10-slim AS trainer + +RUN apt-get update && \ + apt-get install -y --no-install-recommends build-essential clang && \ + rm -rf /var/lib/apt/lists/* + +ENV CPU=1 + +WORKDIR /app + +COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv + +COPY --from=builder /app /app + +ENV PYTHONPATH=/app/applications/equitypricemodel/src + +ENTRYPOINT ["uv", "run", "python", "applications/equitypricemodel/src/equitypricemodel/trainer.py"] + +FROM python:3.12.10-slim AS server + +RUN apt-get update && \ + apt-get install -y --no-install-recommends build-essential clang && \ + rm -rf /var/lib/apt/lists/* + +ENV PYTHONPATH=/app/applications/equitypricemodel/src + +WORKDIR /app + +COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv + +COPY --from=builder /app /app + +# pre-downloaded model artifacts to local for image building + +COPY applications/equitypricemodel/src/equitypricemodel/tide_states.safetensor /app/tide_states.safetensor + +COPY applications/equitypricemodel/src/equitypricemodel/tide_parameters.json /app/tide_parameters.json + +COPY applications/equitypricemodel/src/equitypricemodel/tide_data_mappings.json /app/tide_data_mappings.json + +COPY applications/equitypricemodel/src/equitypricemodel/tide_data_scaler.json /app/tide_data_scaler.json + +EXPOSE 8080 + +ENTRYPOINT ["uv", "run", "uvicorn", "equitypricemodel.server:application", "--host", "0.0.0.0", "--port", "8080", "--app-dir", "src"] + diff --git a/applications/equitypricemodel/pyproject.toml b/applications/equitypricemodel/pyproject.toml new file mode 100644 index 000000000..0cae1ce40 --- /dev/null +++ b/applications/equitypricemodel/pyproject.toml @@ -0,0 +1,13 @@ +[project] +name = "equitypricemodel" +version = "0.1.0" +description = "Equity price time-series dense encoder model architecture" +requires-python = "==3.12.10" +dependencies = ["internal>=0.1.0", "python-dotenv>=1.2.1"] + +[tool.uv.sources] +internal = { workspace = true } + +[tool.uv] +package = true +src = ["src"] diff --git a/applications/equitypricemodel/src/equitypricemodel/combine_data.py b/applications/equitypricemodel/src/equitypricemodel/combine_data.py new file mode 100644 index 000000000..5c94643de --- /dev/null +++ b/applications/equitypricemodel/src/equitypricemodel/combine_data.py @@ -0,0 +1,86 @@ +import sys + +import polars as pl +import structlog + +from .categories_schema import categories_schema + + +def combine_data( + categories_csv_path: str, + equity_bars_csv_path: str, + output_csv_path: str, +) -> None: + logger = structlog.get_logger() + + try: + categories_data = pl.read_csv(categories_csv_path) + except Exception as e: + logger.exception( + "Failed to read categories CSV", path=categories_csv_path, error=str(e) + ) + raise + + try: + categories_data = categories_schema.validate(categories_data) + except Exception as e: + logger.exception("Categories data validation failed", error=str(e)) + raise + + try: + equity_bars_data = pl.read_csv(equity_bars_csv_path) + except Exception as e: + logger.exception( + "Failed to read equity bars CSV", path=equity_bars_csv_path, error=str(e) + ) + raise + + consolidated_data = categories_data.join(equity_bars_data, on="ticker", how="inner") + + retained_columns = ( + "ticker", + "timestamp", + "open_price", + "high_price", + "low_price", + "close_price", + "volume", + "volume_weighted_average_price", + "sector", + "industry", + ) + + missing_columns = [ + col for col in retained_columns if col not in consolidated_data.columns + ] + if missing_columns: + logger.error( + "Missing required columns in consolidated data", + missing_columns=missing_columns, + ) + message = f"Missing required columns: {', '.join(missing_columns)}" + raise ValueError(message) + + filtered_data = consolidated_data.select(retained_columns) + + try: + filtered_data.write_csv(output_csv_path) + except Exception as e: + logger.exception( + "Failed to write output CSV", + output_csv_path=output_csv_path, + error=str(e), + ) + raise + + +if __name__ == "__main__": + logger = structlog.get_logger() + + if len(sys.argv) != 4: # noqa: PLR2004 + logger.error( + "Requires categories CSV, equity bars CSV, and output CSV paths as arguments", # noqa: E501 + ) + sys.exit(1) + + combine_data(sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/libraries/python/src/internal/company_information.py b/applications/equitypricemodel/src/equitypricemodel/equity_details_schema.py similarity index 92% rename from libraries/python/src/internal/company_information.py rename to applications/equitypricemodel/src/equitypricemodel/equity_details_schema.py index 4da755ad2..b083c203e 100644 --- a/libraries/python/src/internal/company_information.py +++ b/applications/equitypricemodel/src/equitypricemodel/equity_details_schema.py @@ -1,6 +1,6 @@ import pandera.polars as pa -company_information_schema = pa.DataFrameSchema( +equity_details_schema = pa.DataFrameSchema( { "sector": pa.Column( dtype=str, diff --git a/libraries/python/src/internal/prediction.py b/applications/equitypricemodel/src/equitypricemodel/predictions_schema.py similarity index 90% rename from libraries/python/src/internal/prediction.py rename to applications/equitypricemodel/src/equitypricemodel/predictions_schema.py index 71201c0aa..8e0f5615e 100644 --- a/libraries/python/src/internal/prediction.py +++ b/applications/equitypricemodel/src/equitypricemodel/predictions_schema.py @@ -50,7 +50,7 @@ def check_monotonic_quantiles(data: PolarsData) -> bool: return True -prediction_schema = pa.DataFrameSchema( +predictions_schema = pa.DataFrameSchema( columns={ "ticker": pa.Column( dtype=str, @@ -73,17 +73,19 @@ def check_monotonic_quantiles(data: PolarsData) -> bool: coerce=True, checks=[ pa.Check( - check_fn=lambda df: check_dates_count_per_ticker(df), + check_fn=lambda data: check_dates_count_per_ticker( + data=data, dates_count=7 + ), name="check_dates_count_per_ticker", error="Each ticker must have expected date count", ), pa.Check( - check_fn=lambda df: check_same_dates_per_ticker(df), + check_fn=lambda data: check_same_dates_per_ticker(data=data), name="check_same_dates_per_ticker", error="All tickers must have same date values", ), pa.Check( - check_fn=lambda df: check_monotonic_quantiles(df), + check_fn=lambda data: check_monotonic_quantiles(data=data), name="quantile_monotonic", error="Quantiles must be monotonic: q10 ≤ q50 ≤ q90", ), diff --git a/applications/portfoliomanager/src/portfoliomanager/preprocess.py b/applications/equitypricemodel/src/equitypricemodel/preprocess.py similarity index 50% rename from applications/portfoliomanager/src/portfoliomanager/preprocess.py rename to applications/equitypricemodel/src/equitypricemodel/preprocess.py index 527c124d7..373b5aecb 100644 --- a/applications/portfoliomanager/src/portfoliomanager/preprocess.py +++ b/applications/equitypricemodel/src/equitypricemodel/preprocess.py @@ -11,11 +11,12 @@ def filter_equity_bars( return ( data.group_by("ticker") .agg( - avg_close_price=pl.col("close_price").mean(), - avg_volume=pl.col("volume").mean(), + average_close_price=pl.col("close_price").mean(), + average_volume=pl.col("volume").mean(), ) .filter( - (pl.col("avg_close_price") > minimum_average_close_price) - & (pl.col("avg_volume") > minimum_average_volume) + (pl.col("average_close_price") > minimum_average_close_price) + & (pl.col("average_volume") > minimum_average_volume) ) + .drop(["average_close_price", "average_volume"]) ) diff --git a/applications/equitypricemodel/src/equitypricemodel/server.py b/applications/equitypricemodel/src/equitypricemodel/server.py new file mode 100644 index 000000000..2ec20ec93 --- /dev/null +++ b/applications/equitypricemodel/src/equitypricemodel/server.py @@ -0,0 +1,182 @@ +import io +import json +import os +from datetime import UTC, datetime, timedelta + +import polars as pl +import requests +import structlog +from fastapi import FastAPI, Response, status +from internal.equity_bars_schema import equity_bars_schema + +from .equity_details_schema import equity_details_schema +from .predictions_schema import predictions_schema +from .preprocess import filter_equity_bars +from .tide_data import Data +from .tide_model import Model + +logger = structlog.get_logger() + +DATAMANAGER_BASE_URL = os.getenv("PSF_DATAMANAGER_BASE_URL", "http://datamanager:8080") + + +application = FastAPI() + + +tide_model = Model.load(directory_path=".") + + +@application.post("/predictions") +def create_predictions() -> Response: + logger.info("Starting prediction generation process") + + end_date = datetime.now(tz=UTC) + start_date = end_date - timedelta( + days=35 + ) # data preprocessing fills in more than 35 days + + try: + equity_bars_response = requests.get( + url=f"{DATAMANAGER_BASE_URL}/equity-bars", + params={ + "start_date": start_date.isoformat(), + "end_date": end_date.isoformat(), + }, + timeout=60, + ) + + equity_bars_response.raise_for_status() + + except Exception as e: + logger.exception( + "Failed to fetch equity bars data", + start_date=start_date.isoformat(), + end_date=end_date.isoformat(), + error=f"{e}", + ) + + return Response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + try: + equity_details_response = requests.get( + url=f"{DATAMANAGER_BASE_URL}/equity-details", + timeout=60, + ) + + equity_details_response.raise_for_status() + + except Exception as e: + logger.exception( + "Failed to fetch equity details data", + error=f"{e}", + ) + + return Response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + try: + data = parse_responses( + equity_bars_response=equity_bars_response, + equity_details_response=equity_details_response, + ) + except Exception as e: + logger.exception( + "Failed to parse and consolidate data responses", + error=f"{e}", + ) + return Response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + current_timestamp = datetime.now(tz=UTC) + + tide_data = Data.load(directory_path=".") + + tide_data.preprocess_and_set_data(data=data) + + batches = tide_data.get_batches(data_type="predict") + + if not batches: + logger.error("No data batches available for prediction") + return Response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + raw_predictions = tide_model.predict( + inputs=batches[-1] + ) # preprocessing generates more than 35 days + + predictions = tide_data.postprocess_predictions( + input_batch=batches[-1], + predictions=raw_predictions, + current_datetime=current_timestamp, + ) + + # filter to only the 7th timestep + processed_prediction_timestamp = current_timestamp + timedelta(days=6) + processed_predictions = predictions.filter( + pl.col("timestamp") + == int( + processed_prediction_timestamp.replace( + hour=0, minute=0, second=0, microsecond=0 + ).timestamp() + ) + ) + + processed_predictions = predictions_schema.validate(processed_predictions) + + try: + save_predictions_response = requests.post( + url=f"{DATAMANAGER_BASE_URL}/predictions", + json={ + "timestamp": current_timestamp.isoformat(), + "data": processed_predictions.to_dicts(), + }, + timeout=60, + ) + + save_predictions_response.raise_for_status() + + except Exception as e: + logger.exception( + "Failed to save predictions data", + timestamp=current_timestamp.isoformat(), + error=f"{e}", + ) + raise + + logger.info("Successfully generated and saved predictions") + + return Response( + content=json.dumps({"data": processed_predictions.to_dict()}).encode("utf-8"), + status_code=status.HTTP_200_OK, + ) + + +def parse_responses( + equity_bars_response: requests.Response, + equity_details_response: requests.Response, +) -> pl.DataFrame: + equity_bars_data = pl.read_parquet(io.BytesIO(equity_bars_response.content)) + + equity_bars_data = equity_bars_schema.validate(equity_bars_data) + + equity_bars_data = filter_equity_bars(equity_bars_data) + + equity_details_data = pl.DataFrame(equity_details_response.json()) + + equity_details_data = equity_details_schema.validate(equity_details_data) + + consolidated_data = equity_details_data.join( + equity_bars_data, on="ticker", how="inner" + ) + + retained_columns = ( + "ticker", + "timestamp", + "open_price", + "high_price", + "low_price", + "close_price", + "volume", + "volume_weighted_average_price", + "sector", + "industry", + ) + + return consolidated_data.select(retained_columns) diff --git a/libraries/python/src/internal/tft_dataset.py b/applications/equitypricemodel/src/equitypricemodel/tide_data.py similarity index 71% rename from libraries/python/src/internal/tft_dataset.py rename to applications/equitypricemodel/src/equitypricemodel/tide_data.py index 1e2a82574..6529c3da4 100644 --- a/libraries/python/src/internal/tft_dataset.py +++ b/applications/equitypricemodel/src/equitypricemodel/tide_data.py @@ -1,5 +1,8 @@ +import json +import os from datetime import date, datetime, timedelta +import numpy as np import pandera.polars as pa import polars as pl from tinygrad.tensor import Tensor @@ -23,8 +26,8 @@ def inverse_transform(self, data: pl.DataFrame) -> pl.DataFrame: return data * self.standard_deviations + self.means -class TFTDataset: - """Temporal fusion transformer dataset preprocessing and postprocessing.""" +class Data: + """Time-series dense encoder data preprocessing and postprocessing.""" def __init__(self) -> None: pass @@ -124,8 +127,6 @@ def preprocess_and_set_data(self, data: pl.DataFrame) -> None: .drop("temporary_weekday") ) - data = data.unique(subset=["ticker", "timestamp"]) - # ensure all rows have values instead of nulls data = data.with_columns( [ @@ -135,8 +136,8 @@ def preprocess_and_set_data(self, data: pl.DataFrame) -> None: pl.col("close_price").fill_null(0.0), pl.col("volume").fill_null(0.0), pl.col("volume_weighted_average_price").fill_null(0.0), - pl.col("sector").fill_null("Not Available"), - pl.col("industry").fill_null("Not Available"), + pl.col("sector").fill_null("NOT AVAILABLE"), + pl.col("industry").fill_null("NOT AVAILABLE"), pl.col("ticker").fill_null("UNKNOWN"), pl.col("timestamp").fill_null( pl.col("date") @@ -170,9 +171,23 @@ def preprocess_and_set_data(self, data: pl.DataFrame) -> None: pl.col("close_price").pct_change().over("ticker").alias("daily_return") ) - data = data.filter(pl.col("daily_return").is_not_null()) + data = data.with_columns( + [ + pl.col("ticker").str.to_uppercase(), + pl.col("sector").str.to_uppercase(), + pl.col("industry").str.to_uppercase(), + ] + ) + + data = data.filter(pl.col("ticker") != "UNKNOWN") + + data = data.filter( + pl.col("daily_return").is_not_null() & pl.col("daily_return").is_not_nan() + ) + + data = data.unique(subset=["ticker", "timestamp"]) - data = dataset_schema.validate(data) + data = data_schema.validate(data) self.scaler = Scaler() @@ -253,20 +268,19 @@ def get_dimensions(self) -> dict[str, int]: "encoder_categorical_features": len(self.categorical_columns), "encoder_continuous_features": len(self.continuous_columns), "decoder_categorical_features": len(self.categorical_columns), - "decoder_continuous_features": 0, # not using decoder_continuous_features for now # noqa: E501 + "decoder_continuous_features": 0, # not using decoder_continuous_features for now # noqa: E501 "static_categorical_features": len(self.static_categorical_columns), - "static_continuous_features": 0, # not using static_continuous_features for now # noqa: E501 + "static_continuous_features": 0, # not using static_continuous_features for now # noqa: E501 } - def get_batches( + def get_batches( # noqa: C901 self, data_type: str = "train", # "train", "validate", or "predict" validation_split: float = 0.8, input_length: int = 35, output_length: int = 7, + batch_size: int = 32, ) -> list[dict[str, Tensor]]: - batches = [] - if data_type not in {"train", "validate", "predict"}: message = f"Invalid data type: {data_type}. Must be 'train', 'validate', or 'predict'." # noqa: E501 raise ValueError(message) @@ -300,6 +314,8 @@ def get_batches( ) raise ValueError(message) + # collect all samples first + samples = [] for ticker in self.batch_data["ticker"].unique(): ticker_data = self.batch_data.filter(pl.col("ticker") == ticker).sort( "time_idx" @@ -311,36 +327,110 @@ def get_batches( i + input_length : i + input_length + output_length ] - # not using decoder_continuous_features (future-known numerical data - # e.g. economic indicators, if available) or static_continuous_features - # (constant numerical data per stock e.g. market cap, P/E ratio) for now - batch = { - "encoder_categorical_features": Tensor( - encoder_slice[self.categorical_columns].to_numpy() - ), # historical categorical data varying over time e.g. day of week, holiday status # noqa: E501 - "encoder_continuous_features": Tensor( - encoder_slice[self.continuous_columns].to_numpy() - ), # historical numerical data varying over time e.g. price, volume - "decoder_categorical_features": Tensor( - decoder_slice[self.categorical_columns].to_numpy() - ), # future-known categorical data e.g. future day of week, scheduled events # noqa: E501 - "static_categorical_features": Tensor( - ticker_data[self.static_categorical_columns].head(1).to_numpy() - ), # constant categorical data per stock e.g. ticker, sector + static_data = ticker_data[self.static_categorical_columns].head(1) + + sample = { + "encoder_categorical": encoder_slice[ + self.categorical_columns + ].to_numpy(writable=True), + "encoder_continuous": encoder_slice[ + self.continuous_columns + ].to_numpy(writable=True), + "decoder_categorical": decoder_slice[ + self.categorical_columns + ].to_numpy(writable=True), + "static_categorical": static_data.to_numpy(writable=True), } if data_type in {"train", "validate"}: - batch["targets"] = Tensor( - decoder_slice[["daily_return"]].to_numpy() + sample["targets"] = decoder_slice[["daily_return"]].to_numpy( + writable=True ) - batches.append(batch) + samples.append(sample) + + # now batch the samples + batches = [] + for i in range(0, len(samples), batch_size): + batch_samples = samples[i : i + batch_size] + + batch = { + "encoder_categorical_features": Tensor( + np.stack([s["encoder_categorical"] for s in batch_samples]) + ), + "encoder_continuous_features": Tensor( + np.stack([s["encoder_continuous"] for s in batch_samples]) + ), + "decoder_categorical_features": Tensor( + np.stack([s["decoder_categorical"] for s in batch_samples]) + ), + "static_categorical_features": Tensor( + np.stack([s["static_categorical"] for s in batch_samples]) + ), + } + + if data_type in {"train", "validate"}: + batch["targets"] = Tensor( + np.stack([s["targets"] for s in batch_samples]) + ) + + batches.append(batch) return batches + def save(self, directory_path: str) -> None: + os.makedirs(directory_path, exist_ok=True) # noqa: PTH103 + + with open(os.path.join(directory_path, "tide_data_mappings.json"), "w") as f: # noqa: PTH118, PTH123 + json.dump(self.mappings, f) + + with open(os.path.join(directory_path, "tide_data_scaler.json"), "w") as f: # noqa: PTH118, PTH123 + # convert DataFrames to dictionary of scalars (first row) + means_dict = { + col: self.scaler.means[col].item() for col in self.scaler.means.columns + } + stdevs_dict = { + col: self.scaler.standard_deviations[col].item() + for col in self.scaler.standard_deviations.columns + } + + json.dump( + { + "means": means_dict, + "standard_deviations": stdevs_dict, + "continuous_columns": self.continuous_columns, + "categorical_columns": self.categorical_columns, + "static_categorical_columns": self.static_categorical_columns, + }, + f, + ) + + @classmethod + def load(cls, directory_path: str) -> "Data": + data = cls() + with open(os.path.join(directory_path, "tide_data_mappings.json")) as f: # noqa: PTH118, PTH123 + data.mappings = json.load(f) + + with open(os.path.join(directory_path, "tide_data_scaler.json")) as f: # noqa: PTH118, PTH123 + scaler_data = json.load(f) + + data.scaler = Scaler() + data.scaler.means = pl.DataFrame(scaler_data["means"]) + data.scaler.standard_deviations = pl.DataFrame( + scaler_data["standard_deviations"] + ) + + data.continuous_columns = scaler_data["continuous_columns"] + data.categorical_columns = scaler_data["categorical_columns"] + data.static_categorical_columns = scaler_data["static_categorical_columns"] + + return data + def postprocess_predictions( self, - input_batch: Tensor, # static_categorical_features + input_batch: dict[ + str, Tensor + ], # batch dictionary with static_categorical_features predictions: Tensor, # quantiles current_datetime: datetime, ) -> pl.DataFrame: @@ -392,7 +482,7 @@ def postprocess_predictions( return pl.DataFrame(rows) -dataset_schema = pa.DataFrameSchema( +data_schema = pa.DataFrameSchema( { "ticker": pa.Column( dtype=str, @@ -404,19 +494,21 @@ def postprocess_predictions( ), "open_price": pa.Column( dtype=float, - checks=pa.Check.greater_than(0), + checks=pa.Check.greater_than_or_equal_to( + 0 + ), # zeros are allowed for missing days ), "high_price": pa.Column( dtype=float, - checks=pa.Check.greater_than(0), + checks=pa.Check.greater_than_or_equal_to(0), ), "low_price": pa.Column( dtype=float, - checks=pa.Check.greater_than(0), + checks=pa.Check.greater_than_or_equal_to(0), ), "close_price": pa.Column( dtype=float, - checks=pa.Check.greater_than(0), + checks=pa.Check.greater_than_or_equal_to(0), ), "volume": pa.Column( dtype=int, diff --git a/applications/equitypricemodel/src/equitypricemodel/tide_model.py b/applications/equitypricemodel/src/equitypricemodel/tide_model.py new file mode 100644 index 000000000..fa63e0b06 --- /dev/null +++ b/applications/equitypricemodel/src/equitypricemodel/tide_model.py @@ -0,0 +1,361 @@ +import json +import os +from typing import cast + +import structlog +from tinygrad.nn import Linear +from tinygrad.nn.optim import Adam +from tinygrad.nn.state import ( + get_parameters, + get_state_dict, + load_state_dict, + safe_load, + safe_save, +) +from tinygrad.tensor import Tensor + + +def quantile_loss( + predictions: Tensor, + targets: Tensor, + quantiles: list[float] | None = None, +) -> Tensor: + if quantiles is None: + quantiles = [0.1, 0.5, 0.9] + + if not all(0 <= q <= 1 for q in quantiles): + message = "All quantiles must be between 0 and 1" + raise ValueError(message) + + errors_total = Tensor(0.0) + for index, quantile in enumerate(quantiles): + error = targets.sub(predictions[:, :, index]) + quantile_tensor = Tensor(quantile) + errors_total = errors_total.add( + Tensor.where( + error > 0, + cast("Tensor", quantile_tensor.mul(error)), + cast("Tensor", (quantile_tensor.sub(1)).mul(error)), + ).mean() + ) + + return cast("Tensor", errors_total.div(len(quantiles))) + + +class _ResidualBlock: + """Residual block with layer normalization and dropout""" + + def __init__( + self, + input_size: int, + hidden_size: int, + dropout_rate: float = 0.1, + ) -> None: + self.input_size = input_size + self.hidden_size = hidden_size + self.dropout_rate = dropout_rate + + self.dense = Linear(in_features=input_size, out_features=hidden_size) + + self.skip_connection = None + if input_size != hidden_size: + self.skip_connection = Linear( + in_features=input_size, + out_features=hidden_size, + ) + + def forward(self, x: Tensor) -> Tensor: + x = x.cast("float32") # ensure float32 precision + + out = self.dense(x).relu() # relu activation + + if Tensor.training and self.dropout_rate > 0: + out = out.dropout(p=self.dropout_rate) + + skip = x + if self.skip_connection is not None: + skip = self.skip_connection(x) + + out = cast("Tensor", out.add(skip)) # add residual connection + + mean = out.mean(axis=-1, keepdim=True) + variance = ((out.sub(mean)) ** 2).mean(axis=-1, keepdim=True) + return cast( + "Tensor", + (out - mean) / (variance + Tensor(1e-5).cast("float32")).sqrt(), + ) + + +class Model: + """ + TiDE architecture for time series forecasting + + Model paper reference: https://arxiv.org/pdf/2304.08424""" + + def __init__( # noqa: PLR0913 + self, + input_size: int, + hidden_size: int = 128, + num_encoder_layers: int = 2, + num_decoder_layers: int = 2, + output_length: int = 7, # number of days to forecast + dropout_rate: float = 0.1, + quantiles: list[float] | None = None, + ) -> None: + self.input_size = input_size + self.hidden_size = hidden_size + self.num_encoder_layers = num_encoder_layers + self.num_decoder_layers = num_decoder_layers + self.output_length = output_length + self.dropout_rate = dropout_rate + self.quantiles = quantiles or [0.1, 0.5, 0.9] + + self.feature_projection = Linear( + in_features=self.input_size, + out_features=self.hidden_size, + ) + + self.encoder_blocks: list[_ResidualBlock] = [] + for _ in range(self.num_encoder_layers): + block_input_size = self.hidden_size + self.encoder_blocks.append( + _ResidualBlock( + input_size=block_input_size, + hidden_size=self.hidden_size, + dropout_rate=self.dropout_rate, + ) + ) + + self.decoder_blocks: list[_ResidualBlock] = [] + for _ in range(self.num_decoder_layers): + block_input_size = self.hidden_size + self.decoder_blocks.append( + _ResidualBlock( + input_size=block_input_size, + hidden_size=self.hidden_size, + dropout_rate=self.dropout_rate, + ) + ) + + self.temporal_projection = Linear( # projects to output sequence length + in_features=self.hidden_size, + out_features=self.hidden_size * self.output_length, + ) + + # final output layer for quantiles + self.output_layer = Linear( + in_features=self.hidden_size, + out_features=len(self.quantiles), + ) + + self.logger = structlog.get_logger() + + def forward(self, x: Tensor) -> Tensor: + """ + Forward pass through TiDE model + Args: + x: Input tensor of shape (batch_size, flattened_features) + Returns: + Tensor of shape (batch_size, output_length, num_quantiles) + """ + x = x.cast("float32") # ensure float32 precision + batch_size = x.shape[0] + + x = self.feature_projection(x).relu() + + for encoder_block in self.encoder_blocks: + x = encoder_block.forward(x) + + encoder_output = cast("Tensor", x) + + for decoder_block in self.decoder_blocks: + x = decoder_block.forward(x) + + # add skip connection from encoder to decoder output + x = cast("Tensor", x.add(encoder_output)) + + # temporal projection to output sequence length + x = self.temporal_projection(x).relu() + + # reshape to (batch_size, output_length, hidden_size) + x = x.reshape(batch_size, self.output_length, self.hidden_size) + + # apply output layer across the sequence dimension + predictions: list[Tensor] = [] + for t in range(self.output_length): + prediction_batch = self.output_layer( + x[:, t, :] + ) # (batch_size, num_quantiles) + predictions.append(prediction_batch) + + predictions_first = predictions[0] + predictions_rest = predictions[1:] + + # stack predictions: (batch_size, output_length, num_quantiles e.g. (32, 7, 3)) + return predictions_first.stack(*predictions_rest, dim=1) + + def train( + self, + train_batches: list, + epochs: int = 10, + learning_rate: float = 0.001, + ) -> list: + """Train the TiDE model using quantile loss""" + prev_training = Tensor.training + Tensor.training = True + + parameters = get_parameters(self) + optimizer = Adam(params=parameters, lr=learning_rate) + losses = [] + + try: + for epoch in range(epochs): + self.logger.info("Starting training epoch", epoch=epoch + 1) + epoch_losses = [] + + for batch in train_batches: + combined_input_features, targets, batch_size = ( + self._combine_input_features(batch) + ) + + # predictions shape: (batch_size, output_length, num_quantiles) + predictions = self.forward(combined_input_features) + + # reshape targets to (batch_size, output_length) + targets_reshaped = targets.reshape(batch_size, self.output_length) + + loss = quantile_loss(predictions, targets_reshaped, self.quantiles) + + optimizer.zero_grad() + loss.backward() + optimizer.step() + + epoch_losses.append(loss.numpy().item()) + + if not epoch_losses: + self.logger.warning( + "No training batches processed", epoch=epoch + 1 + ) + continue + + epoch_loss = sum(epoch_losses) / len(epoch_losses) + + self.logger.info( + "Completed training epoch", + epoch=epoch + 1, + loss=f"{epoch_loss:.4f}", + ) + + losses.append(epoch_loss) + finally: + Tensor.training = prev_training + + return losses + + def validate(self, validation_batches: list) -> float: + """Validate the model using quantile loss""" + Tensor.training = False + validation_losses = [] + + for batch in validation_batches: + combined_input, targets, batch_size = self._combine_input_features(batch) + + predictions = self.forward(combined_input) + + targets_reshaped = targets.reshape(batch_size, self.output_length) + + loss = quantile_loss(predictions, targets_reshaped, self.quantiles) + validation_losses.append(loss.numpy().item()) + + if not validation_losses: + self.logger.warning("No validation batches provided; returning NaN loss") + return float("nan") + + return sum(validation_losses) / len(validation_losses) + + def save( + self, + directory_path: str, + ) -> None: + os.makedirs(directory_path, exist_ok=True) # noqa: PTH103 + + states = get_state_dict(self) + + safe_save(states, os.path.join(directory_path, "tide_states.safetensor")) # noqa: PTH118 + + parameters = { + "input_size": self.input_size, + "hidden_size": self.hidden_size, + "num_encoder_layers": self.num_encoder_layers, + "num_decoder_layers": self.num_decoder_layers, + "output_length": self.output_length, + "dropout_rate": self.dropout_rate, + "quantiles": self.quantiles, + } + + parameters_file_path = os.path.join(directory_path, "tide_parameters.json") # noqa: PTH118 + with open(parameters_file_path, "w") as parameters_file: # noqa: PTH123 + json.dump(parameters, parameters_file) + + @classmethod + def load( + cls, + directory_path: str, + ) -> "Model": + states_file_path = os.path.join(directory_path, "tide_states.safetensor") # noqa: PTH118 + states = safe_load(states_file_path) + with open( # noqa: PTH123 + os.path.join(directory_path, "tide_parameters.json") # noqa: PTH118 + ) as parameters_file: + parameters = json.load(parameters_file) + + model = cls(**parameters) + + load_state_dict(model, states) + + return model + + def predict( + self, + inputs: dict[str, Tensor], + ) -> Tensor: + combined_input_features, _, _ = self._combine_input_features(inputs) + + return self.forward(combined_input_features) + + def _combine_input_features( + self, + inputs: dict[str, Tensor], + ) -> tuple[Tensor, Tensor, int]: + batch_size = inputs["encoder_continuous_features"].shape[0] + + encoder_cont_flat = inputs["encoder_continuous_features"].reshape( + batch_size, -1 + ) + encoder_cat_flat = ( + inputs["encoder_categorical_features"] + .reshape(batch_size, -1) + .cast("float32") + ) + decoder_cat_flat = ( + inputs["decoder_categorical_features"] + .reshape(batch_size, -1) + .cast("float32") + ) + static_cat_flat = ( + inputs["static_categorical_features"] + .reshape(batch_size, -1) + .cast("float32") + ) + + return ( + Tensor.cat( + encoder_cont_flat, + encoder_cat_flat, + decoder_cat_flat, + static_cat_flat, + dim=1, + ), + inputs["targets"], + int(batch_size), + ) diff --git a/applications/equitypricemodel/src/equitypricemodel/trainer.py b/applications/equitypricemodel/src/equitypricemodel/trainer.py new file mode 100644 index 000000000..01595e41f --- /dev/null +++ b/applications/equitypricemodel/src/equitypricemodel/trainer.py @@ -0,0 +1,91 @@ +import os +from typing import cast + +import polars as pl +from equitypricemodel.tide_data import Data +from equitypricemodel.tide_model import Model + +training_data_input_path = os.path.join( # noqa: PTH118 + "/opt/ml/input/data/train", + "filtered_tft_training_data.parquet", +) + +model_output_path = "/opt/ml/model" + + +configuration = { + "architecture": "TiDE", + "learning_rate": 0.003, + "epoch_count": 20, + "validation_split": 0.8, + "input_length": 35, + "output_length": 7, + "hidden_size": 64, + "num_encoder_layers": 2, + "num_decoder_layers": 2, + "dropout_rate": 0.1, +} + +training_data = pl.read_parquet(training_data_input_path) + + +tide_data = Data() + +tide_data.preprocess_and_set_data(data=training_data) + + +dimensions = tide_data.get_dimensions() + +train_batches = tide_data.get_batches( + data_type="train", + validation_split=configuration["validation_split"], + input_length=configuration["input_length"], + output_length=configuration["output_length"], +) + +sample_batch = train_batches[0] + +batch_size = sample_batch["encoder_continuous_features"].shape[0] + +# calculate each component's flattened size - days * features (e.g. 35 * 7) +encoder_continuous_size = ( + sample_batch["encoder_continuous_features"].reshape(batch_size, -1).shape[1] +) +encoder_categorical_size = ( + sample_batch["encoder_categorical_features"].reshape(batch_size, -1).shape[1] +) +decoder_categorical_size = ( + sample_batch["decoder_categorical_features"].reshape(batch_size, -1).shape[1] +) +static_categorical_size = ( + sample_batch["static_categorical_features"].reshape(batch_size, -1).shape[1] +) + +input_size = cast( + "int", + encoder_continuous_size + + encoder_categorical_size + + decoder_categorical_size + + static_categorical_size, +) + +tide_model = Model( + input_size=input_size, + hidden_size=configuration["hidden_size"], + num_encoder_layers=configuration["num_encoder_layers"], + num_decoder_layers=configuration["num_decoder_layers"], + output_length=configuration["output_length"], + dropout_rate=configuration["dropout_rate"], + quantiles=[0.1, 0.5, 0.9], +) + + +losses = tide_model.train( + train_batches=train_batches, + epochs=configuration["epoch_count"], + learning_rate=configuration["learning_rate"], +) + +tide_model.save(directory_path=model_output_path) + +tide_data.save(directory_path=model_output_path) diff --git a/libraries/python/tests/test_company_information.py b/applications/equitypricemodel/tests/test_equity_details_schema.py similarity index 64% rename from libraries/python/tests/test_company_information.py rename to applications/equitypricemodel/tests/test_equity_details_schema.py index a5fd4b0c9..7f2e2d452 100644 --- a/libraries/python/tests/test_company_information.py +++ b/applications/equitypricemodel/tests/test_equity_details_schema.py @@ -1,10 +1,10 @@ import polars as pl import pytest -from internal.company_information import company_information_schema +from equitypricemodel.equity_details_schema import equity_details_schema from pandera.errors import SchemaError -def test_company_information_schema_valid_data() -> None: +def test_equity_details_schema_valid_data() -> None: valid_data = pl.DataFrame( { "sector": ["TECHNOLOGY"], @@ -12,11 +12,11 @@ def test_company_information_schema_valid_data() -> None: } ) - validated_df = company_information_schema.validate(valid_data) + validated_df = equity_details_schema.validate(valid_data) assert validated_df.shape == (1, 2) -def test_company_information_schema_sector_lowercase_fails() -> None: +def test_equity_details_schema_sector_lowercase_fails() -> None: data = pl.DataFrame( { "sector": ["technology"], @@ -25,10 +25,10 @@ def test_company_information_schema_sector_lowercase_fails() -> None: ) with pytest.raises(SchemaError): - company_information_schema.validate(data) + equity_details_schema.validate(data) -def test_company_information_schema_industry_lowercase_fails() -> None: +def test_equity_details_schema_industry_lowercase_fails() -> None: data = pl.DataFrame( { "sector": ["TECHNOLOGY"], @@ -37,10 +37,10 @@ def test_company_information_schema_industry_lowercase_fails() -> None: ) with pytest.raises(SchemaError): - company_information_schema.validate(data) + equity_details_schema.validate(data) -def test_company_information_schema_both_fields_uppercase_passes() -> None: +def test_equity_details_schema_both_fields_uppercase_passes() -> None: data = pl.DataFrame( { "sector": ["HEALTHCARE"], @@ -48,12 +48,12 @@ def test_company_information_schema_both_fields_uppercase_passes() -> None: } ) - validated_df = company_information_schema.validate(data) + validated_df = equity_details_schema.validate(data) assert validated_df["sector"][0] == "HEALTHCARE" assert validated_df["industry"][0] == "PHARMACEUTICALS" -def test_company_information_schema_whitespace_fails() -> None: +def test_equity_details_schema_whitespace_fails() -> None: data = pl.DataFrame( { "sector": [" TECHNOLOGY "], @@ -62,10 +62,10 @@ def test_company_information_schema_whitespace_fails() -> None: ) with pytest.raises(SchemaError): - company_information_schema.validate(data) + equity_details_schema.validate(data) -def test_company_information_schema_industry_whitespace_fails() -> None: +def test_equity_details_schema_industry_whitespace_fails() -> None: data = pl.DataFrame( { "sector": ["TECHNOLOGY"], @@ -74,10 +74,10 @@ def test_company_information_schema_industry_whitespace_fails() -> None: ) with pytest.raises(SchemaError): - company_information_schema.validate(data) + equity_details_schema.validate(data) -def test_company_information_schema_no_whitespace_passes() -> None: +def test_equity_details_schema_no_whitespace_passes() -> None: data = pl.DataFrame( { "sector": ["HEALTHCARE"], @@ -85,12 +85,12 @@ def test_company_information_schema_no_whitespace_passes() -> None: } ) - validated_df = company_information_schema.validate(data) + validated_df = equity_details_schema.validate(data) assert validated_df["sector"][0] == "HEALTHCARE" assert validated_df["industry"][0] == "PHARMACEUTICALS" -def test_company_information_schema_null_sector() -> None: +def test_equity_details_schema_null_sector() -> None: data = pl.DataFrame( { "sector": [None], @@ -98,12 +98,12 @@ def test_company_information_schema_null_sector() -> None: } ) - validated_df = company_information_schema.validate(data) + validated_df = equity_details_schema.validate(data) assert validated_df["sector"][0] == "NOT AVAILABLE" assert validated_df["industry"][0] == "SOFTWARE" -def test_company_information_schema_null_industry() -> None: +def test_equity_details_schema_null_industry() -> None: data = pl.DataFrame( { "sector": ["TECHNOLOGY"], @@ -111,12 +111,12 @@ def test_company_information_schema_null_industry() -> None: } ) - validated_df = company_information_schema.validate(data) + validated_df = equity_details_schema.validate(data) assert validated_df["industry"][0] == "NOT AVAILABLE" assert validated_df["sector"][0] == "TECHNOLOGY" -def test_company_information_schema_missing_sector_column() -> None: +def test_equity_details_schema_missing_sector_column() -> None: data = pl.DataFrame( { "industry": ["SOFTWARE"], @@ -124,10 +124,10 @@ def test_company_information_schema_missing_sector_column() -> None: ) with pytest.raises((SchemaError, pl.exceptions.ColumnNotFoundError)): - company_information_schema.validate(data) + equity_details_schema.validate(data) -def test_company_information_schema_missing_industry_column() -> None: +def test_equity_details_schema_missing_industry_column() -> None: data = pl.DataFrame( { "sector": ["TECHNOLOGY"], @@ -135,10 +135,10 @@ def test_company_information_schema_missing_industry_column() -> None: ) with pytest.raises((SchemaError, pl.exceptions.ColumnNotFoundError)): - company_information_schema.validate(data) + equity_details_schema.validate(data) -def test_company_information_schema_type_coercion() -> None: +def test_equity_details_schema_type_coercion() -> None: data = pl.DataFrame( { "sector": [123], # coerced to string @@ -146,14 +146,14 @@ def test_company_information_schema_type_coercion() -> None: } ) - validated_df = company_information_schema.validate(data) + validated_df = equity_details_schema.validate(data) assert validated_df["sector"].dtype == pl.String assert validated_df["industry"].dtype == pl.String assert validated_df["sector"][0] == "123" assert validated_df["industry"][0] == "456" -def test_company_information_schema_multiple_rows() -> None: +def test_equity_details_schema_multiple_rows() -> None: data = pl.DataFrame( { "sector": ["TECHNOLOGY", "HEALTHCARE", "FINANCE"], @@ -161,7 +161,7 @@ def test_company_information_schema_multiple_rows() -> None: } ) - validated_df = company_information_schema.validate(data) + validated_df = equity_details_schema.validate(data) assert validated_df.shape == (3, 2) assert validated_df["sector"].to_list() == ["TECHNOLOGY", "HEALTHCARE", "FINANCE"] assert validated_df["industry"].to_list() == [ @@ -171,7 +171,7 @@ def test_company_information_schema_multiple_rows() -> None: ] -def test_company_information_schema_mixed_case_fails() -> None: +def test_equity_details_schema_mixed_case_fails() -> None: data = pl.DataFrame( { "sector": ["TeChnOlOgY"], @@ -180,10 +180,10 @@ def test_company_information_schema_mixed_case_fails() -> None: ) with pytest.raises(SchemaError): - company_information_schema.validate(data) + equity_details_schema.validate(data) -def test_company_information_schema_empty_string() -> None: +def test_equity_details_schema_empty_string() -> None: data = pl.DataFrame( { "sector": [""], @@ -191,11 +191,11 @@ def test_company_information_schema_empty_string() -> None: } ) - validated_df = company_information_schema.validate(data) + validated_df = equity_details_schema.validate(data) assert validated_df["sector"][0] == "" -def test_company_information_schema_whitespace_only_fails() -> None: +def test_equity_details_schema_whitespace_only_fails() -> None: data = pl.DataFrame( { "sector": [" "], @@ -205,10 +205,10 @@ def test_company_information_schema_whitespace_only_fails() -> None: # whitespace-only strings should fail validation with pytest.raises(SchemaError): - company_information_schema.validate(data) + equity_details_schema.validate(data) -def test_company_information_schema_special_characters() -> None: +def test_equity_details_schema_special_characters() -> None: data = pl.DataFrame( { "sector": ["REAL-ESTATE"], @@ -216,6 +216,6 @@ def test_company_information_schema_special_characters() -> None: } ) - validated_df = company_information_schema.validate(data) + validated_df = equity_details_schema.validate(data) assert validated_df["sector"][0] == "REAL-ESTATE" assert validated_df["industry"][0] == "RETAIL & WHOLESALE" diff --git a/libraries/python/tests/test_prediction.py b/applications/equitypricemodel/tests/test_predictions_schema.py similarity index 80% rename from libraries/python/tests/test_prediction.py rename to applications/equitypricemodel/tests/test_predictions_schema.py index 3d7bc6747..6cf2ccc34 100644 --- a/libraries/python/tests/test_prediction.py +++ b/applications/equitypricemodel/tests/test_predictions_schema.py @@ -2,11 +2,11 @@ import polars as pl import pytest -from internal.prediction import prediction_schema +from equitypricemodel.predictions_schema import predictions_schema from pandera.errors import SchemaError -def test_prediction_schema_valid_data() -> None: +def test_predictions_schema_valid_data() -> None: base_date = datetime(2024, 1, 1, tzinfo=UTC) valid_data = pl.DataFrame( @@ -21,11 +21,11 @@ def test_prediction_schema_valid_data() -> None: } ) - validated_df = prediction_schema.validate(valid_data) + validated_df = predictions_schema.validate(valid_data) assert validated_df.shape == (7, 5) -def test_prediction_schema_ticker_lowercase_fails() -> None: +def test_predictions_schema_ticker_lowercase_fails() -> None: base_date = datetime(2024, 1, 1, tzinfo=UTC) data = pl.DataFrame( @@ -41,10 +41,10 @@ def test_prediction_schema_ticker_lowercase_fails() -> None: ) with pytest.raises(SchemaError): - prediction_schema.validate(data) + predictions_schema.validate(data) -def test_prediction_schema_negative_timestamp_fails() -> None: +def test_predictions_schema_negative_timestamp_fails() -> None: base_date = datetime(2024, 1, 1, tzinfo=UTC) data = pl.DataFrame( @@ -62,10 +62,10 @@ def test_prediction_schema_negative_timestamp_fails() -> None: data[1, "timestamp"] = -1.0 # introduce a negative timestamp with pytest.raises(SchemaError): - prediction_schema.validate(data) + predictions_schema.validate(data) -def test_prediction_schema_duplicate_ticker_timestamp_fails() -> None: +def test_predictions_schema_duplicate_ticker_timestamp_fails() -> None: base_date = datetime(2024, 1, 1, tzinfo=UTC) data = pl.DataFrame( @@ -80,10 +80,10 @@ def test_prediction_schema_duplicate_ticker_timestamp_fails() -> None: ) with pytest.raises(SchemaError): - prediction_schema.validate(data) + predictions_schema.validate(data) -def test_prediction_schema_multiple_tickers_same_dates() -> None: +def test_predictions_schema_multiple_tickers_same_dates() -> None: base_date = datetime(2024, 1, 1, tzinfo=UTC) valid_data = pl.DataFrame( @@ -97,11 +97,11 @@ def test_prediction_schema_multiple_tickers_same_dates() -> None: } ) - validated_df = prediction_schema.validate(valid_data) + validated_df = predictions_schema.validate(valid_data) assert validated_df.shape == (14, 5) -def test_prediction_schema_multiple_tickers_different_dates_fails() -> None: +def test_predictions_schema_multiple_tickers_different_dates_fails() -> None: base_date = datetime(2024, 1, 1, tzinfo=UTC) data = pl.DataFrame( @@ -119,10 +119,10 @@ def test_prediction_schema_multiple_tickers_different_dates_fails() -> None: with pytest.raises( SchemaError, match="Expected all tickers to have the same dates" ): - prediction_schema.validate(data) + predictions_schema.validate(data) -def test_prediction_schema_wrong_date_count_per_ticker_fails() -> None: +def test_predictions_schema_wrong_date_count_per_ticker_fails() -> None: base_date = datetime(2024, 1, 1, tzinfo=UTC) data = pl.DataFrame( @@ -140,10 +140,10 @@ def test_prediction_schema_wrong_date_count_per_ticker_fails() -> None: with pytest.raises( SchemaError, match="Each ticker must have exactly 7 unique dates" ): - prediction_schema.validate(data) + predictions_schema.validate(data) -def test_prediction_schema_float_quantile_values() -> None: +def test_predictions_schema_float_quantile_values() -> None: base_date = datetime(2024, 1, 1, tzinfo=UTC) valid_data = pl.DataFrame( @@ -158,5 +158,5 @@ def test_prediction_schema_float_quantile_values() -> None: } ) - validated_df = prediction_schema.validate(valid_data) + validated_df = predictions_schema.validate(valid_data) assert validated_df.shape == (7, 5) diff --git a/applications/portfoliomanager/tests/test_preprocess.py b/applications/equitypricemodel/tests/test_preprocess.py similarity index 88% rename from applications/portfoliomanager/tests/test_preprocess.py rename to applications/equitypricemodel/tests/test_preprocess.py index f2afdf5c8..7b5a1a2f9 100644 --- a/applications/portfoliomanager/tests/test_preprocess.py +++ b/applications/equitypricemodel/tests/test_preprocess.py @@ -1,6 +1,5 @@ import polars as pl -import pytest -from portfoliomanager.preprocess import filter_equity_bars +from equitypricemodel.preprocess import filter_equity_bars def test_filter_equity_bars_above_thresholds() -> None: @@ -20,8 +19,6 @@ def test_filter_equity_bars_above_thresholds() -> None: assert len(result) == 1 assert result["ticker"][0] == "AAPL" - assert result["avg_close_price"][0] == 20.0 # noqa: PLR2004 - assert result["avg_volume"][0] == 2_000_000.0 # noqa: PLR2004 def test_filter_equity_bars_below_price_threshold() -> None: @@ -109,8 +106,6 @@ def test_filter_equity_bars_just_above_thresholds() -> None: assert len(result) == 1 assert result["ticker"][0] == "AAPL" - assert result["avg_close_price"][0] == pytest.approx(10.01) - assert result["avg_volume"][0] == pytest.approx(1_000_001.0) def test_filter_equity_bars_empty_dataframe() -> None: @@ -140,8 +135,6 @@ def test_filter_equity_bars_single_row() -> None: assert len(result) == 1 assert result["ticker"][0] == "AAPL" - assert result["avg_close_price"][0] == 15.0 # noqa: PLR2004 - assert result["avg_volume"][0] == 1_500_000.0 # noqa: PLR2004 def test_filter_equity_bars_mixed_values() -> None: @@ -190,8 +183,6 @@ def test_filter_equity_bars_multiple_tickers() -> None: assert len(result) == 1 assert result["ticker"][0] == "AAPL" - assert result["avg_close_price"][0] == 20.0 # noqa: PLR2004 - assert result["avg_volume"][0] == 2_000_000.0 # noqa: PLR2004 def test_filter_equity_bars_data_immutability() -> None: diff --git a/applications/models/Dockerfile b/applications/models/Dockerfile deleted file mode 100644 index 8a22e5e12..000000000 --- a/applications/models/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM python:3.12.10 diff --git a/applications/models/pyproject.toml b/applications/models/pyproject.toml deleted file mode 100644 index c26828a8f..000000000 --- a/applications/models/pyproject.toml +++ /dev/null @@ -1,22 +0,0 @@ -[project] -name = "models" -version = "0.1.0" -description = "Data and model tools and workflows" -requires-python = "==3.12.10" -dependencies = [ - "internal", - "boto3>=1.38.23", - "botocore>=1.38.23", - "requests>=2.31.0", - "pyarrow>=20.0.0", - "polygon-api-client>=1.14.6", - "flytekit>=1.16.1", - "polars>=1.29.0", - "loguru>=0.7.3", - "pydantic>=2.8.2", - "wandb>=0.21.1", - "alpaca-py>=0.42.0", -] - -[tool.uv.sources] -internal = { workspace = true } diff --git a/applications/models/src/models/combine_tft_data_sources.py b/applications/models/src/models/combine_tft_data_sources.py deleted file mode 100644 index ba233cd71..000000000 --- a/applications/models/src/models/combine_tft_data_sources.py +++ /dev/null @@ -1,44 +0,0 @@ -import os -from datetime import datetime -from zoneinfo import ZoneInfo - -import polars as pl -from internal.company_information import company_information_schema -from internal.equity_bar import equity_bar_schema - -filepath = "applications/models/src/models/" - -categories_path = filepath + "categories.csv" -equity_bars_path = filepath + "equity_bars.csv" - -if not os.path.exists(categories_path): # noqa: PTH110 - message = f"Required file not found: {categories_path}" - raise FileNotFoundError(message) -if not os.path.exists(equity_bars_path): # noqa: PTH110 - message = f"Required file not found: {equity_bars_path}" - raise FileNotFoundError(message) - -categories = company_information_schema.validate(pl.read_csv(categories_path)) -equity_bars = equity_bar_schema.validate(pl.read_csv(equity_bars_path)) - - -combined_data = equity_bars.join( - categories.select(["ticker", "sector", "industry"]), on="ticker", how="left" -).select( - [ - "ticker", - "timestamp", - "open_price", - "high_price", - "low_price", - "close_price", - "volume", - "volume_weighted_average_price", - "sector", - "industry", - ] -) - -timestamp = datetime.now(tz=ZoneInfo("America/New_York")).strftime("%Y%m%d_%H%M%S") -output_filename = f"{filepath}training_data_{timestamp}.csv" -combined_data.write_csv(output_filename) diff --git a/applications/models/src/models/get_alpaca_equity_bars.py b/applications/models/src/models/get_alpaca_equity_bars.py deleted file mode 100644 index 596c47e13..000000000 --- a/applications/models/src/models/get_alpaca_equity_bars.py +++ /dev/null @@ -1,138 +0,0 @@ -import os -import time -from datetime import datetime, timedelta -from typing import cast -from zoneinfo import ZoneInfo - -import polars as pl -from alpaca.data.enums import Adjustment, DataFeed -from alpaca.data.historical import StockHistoricalDataClient -from alpaca.data.models import BarSet -from alpaca.data.requests import StockBarsRequest -from alpaca.data.timeframe import TimeFrame, TimeFrameUnit -from alpaca.trading import TradingClient -from alpaca.trading.enums import AssetClass, AssetStatus -from alpaca.trading.models import Asset -from alpaca.trading.requests import GetAssetsRequest -from internal.equity_bar import equity_bar_schema -from loguru import logger - -if __name__ == "__main__": - rate_limit_sleep = 0.5 # seconds - - api_key = os.getenv("ALPACA_API_KEY_ID") - secret_key = os.getenv("ALPACA_API_SECRET_KEY") - - if not api_key or not secret_key: - message = "Missing required environment variables: ALPACA_API_KEY_ID and/or ALPACA_API_SECRET_KEY" # noqa: E501 - logger.error(message) - raise ValueError(message) - - alpaca_trading_client = TradingClient( - api_key=api_key, - secret_key=secret_key, - paper=os.getenv("ALPACA_PAPER", "true").lower() == "true", - ) - - alpaca_data_client = StockHistoricalDataClient( - api_key=api_key, - secret_key=secret_key, - sandbox=os.getenv("ALPACA_PAPER", "true").lower() == "true", - ) - - try: - assets: list[Asset] = cast( - "list[Asset]", - alpaca_trading_client.get_all_assets( - GetAssetsRequest( - status=AssetStatus.ACTIVE, - asset_class=AssetClass.US_EQUITY, - attributes="has_options", - ) - ), - ) - - except Exception as e: - logger.error(f"Error fetching Alpaca assets: {e}") - raise - - time.sleep(rate_limit_sleep) - - end = datetime.now(tz=ZoneInfo("America/New_York")) - start = end - timedelta(days=365 * 6) - - saved_files: list[str] = [] - for i, asset in enumerate(assets): - ticker = asset.symbol - - logger.info(f"Fetching {i + 1}/{len(assets)}: {ticker}") - - try: - equity_bars: BarSet = cast( - "BarSet", - alpaca_data_client.get_stock_bars( - StockBarsRequest( - symbol_or_symbols=ticker, - start=start, - end=end, - limit=10000, - timeframe=TimeFrame( - amount=1, - unit=TimeFrameUnit("Day"), - ), - adjustment=Adjustment("all"), - feed=DataFeed("iex"), - ) - ), - ) - - except Exception as e: # noqa: BLE001 - logger.error(f"Error fetching equity bars for {ticker}: {e}") - - time.sleep(rate_limit_sleep) - - continue - - if len(equity_bars.dict()) == 0: - logger.info(f"No equity bars found for {ticker}.") - - time.sleep(rate_limit_sleep) - - continue - - equity_bars_data = pl.DataFrame(equity_bars[ticker]) - - equity_bars_data = equity_bars_data.rename( - { - "symbol": "ticker", - "open": "open_price", - "high": "high_price", - "low": "low_price", - "close": "close_price", - "vwap": "volume_weighted_average_price", - } - ) - equity_bars_data = equity_bars_data.with_columns( - ( - pl.col("timestamp").map_elements(lambda x: int(x.timestamp() * 1000)) - ).alias("timestamp") - ) - - file_path = f"equity_bars_{ticker}.csv" - equity_bars_data.write_csv(file_path) - saved_files.append(file_path) - - logger.info(f"Saved bars for {ticker} to {file_path}.") - - time.sleep(rate_limit_sleep) - - logger.info("Finished fetching all tickers.") - - if saved_files: - all_equity_bars = pl.concat([pl.read_csv(fp) for fp in saved_files]) - all_equity_bars = equity_bar_schema.validate(all_equity_bars) - all_equity_bars.write_csv("equity_bars.csv") - logger.info("Finished saving combined equity bars.") - - else: - logger.warning("No equity bars saved; skipping combined file.") diff --git a/applications/models/src/models/train_tft_model.py b/applications/models/src/models/train_tft_model.py deleted file mode 100644 index cdaee01bf..000000000 --- a/applications/models/src/models/train_tft_model.py +++ /dev/null @@ -1,162 +0,0 @@ -from datetime import datetime # noqa: I001 -from zoneinfo import ZoneInfo - -import polars as pl -from flytekit import task, workflow -from loguru import logger -import wandb -from wandb import Run - -from internal.tft_dataset import TFTDataset -from internal.tft_model import Parameters, TFTModel - -configuration = { - "architecture": "TFT", - "learning_rate": 0.02, - "epoch_count": 10, - "validation_split": 0.8, -} - -timezone = ZoneInfo("America/New_York") - - -@task -def read_local_data(filepath: str) -> TFTDataset: - start_time = datetime.now(tz=timezone) - logger.info(f"Reading data from {filepath}") - data = pl.read_csv(filepath) - - runtime_seconds = (datetime.now(tz=timezone) - start_time).total_seconds() - - logger.info(f"Data read successfully in {runtime_seconds} seconds") - - return TFTDataset(data=data) - - -@task -def train_model( - dataset: TFTDataset, - wandb_run: Run, - validation_split: float = 0.8, - epoch_count: int = 10, - learning_rate: float = 1e-3, -) -> TFTModel: - start_time = datetime.now(tz=timezone) - logger.info("Training temporal fusion transformer model") - dimensions = dataset.get_dimensions() - - parameters = Parameters( - hidden_size=64, - output_size=1, - lstm_layer_count=3, - attention_head_size=4, - dropout_rate=0.1, - quantiles=[0.1, 0.5, 0.9], - decoder_categorical_dimension=dimensions["decoder_categorical_features"], - decoder_continuous_dimension=dimensions["decoder_continuous_features"], - encoder_categorical_dimension=dimensions["encoder_categorical_features"], - encoder_continuous_dimension=dimensions["encoder_continuous_features"], - static_categorical_dimension=dimensions["static_categorical_features"], - static_continuous_dimension=dimensions["static_continuous_features"], - input_length=35, - output_length=7, - ) - - model = TFTModel(parameters=parameters) - - batches = dataset.get_batches( - data_type="train", - validation_split=validation_split, - input_length=parameters.input_length, - output_length=parameters.output_length, - ) - - logger.info(f"Training model with {len(batches)} batches") - - losses = model.train( - inputs_list=batches, - epoch_count=epoch_count, - learning_rate=learning_rate, - ) - - for loss in losses: - wandb_run.log({"loss": loss}) - - wandb_run.finish() - - runtime_seconds = (datetime.now(tz=timezone) - start_time).total_seconds() - - logger.info(f"Model trained successfully in {runtime_seconds} seconds") - - return model - - -@task -def validate_model( - data: TFTDataset, - model: TFTModel, - validation_split: float = 0.8, -) -> None: - start_time = datetime.now(tz=timezone) - logger.info("Validating temporal fusion transformer model") - - batches = data.get_batches( - data_type="validate", - validation_split=validation_split, - input_length=model.input_length, - output_length=model.output_length, - ) - - validation_result = model.validate( - inputs_list=batches, - ) - - runtime_seconds = (datetime.now(tz=timezone) - start_time).total_seconds() - - logger.info(f"Validation completed in {runtime_seconds} seconds") - - logger.info(f"Validation result {validation_result}") - - -@task -def save_model(model: TFTModel) -> None: - start_time = datetime.now(tz=timezone) - logger.info("Saving temporal fusion transformer model") - - model.save() - - runtime_seconds = (datetime.now(tz=timezone) - start_time).total_seconds() - - logger.info(f"Model saved successfully in {runtime_seconds} seconds") - - -@workflow -def train_tft_model() -> None: - if wandb.run is not None: - wandb.finish() # close active run if it exists - - wandb_run = wandb.init( - project="Pocket Size Fund", - config=configuration, - name=f"tft-model-run-{datetime.now(tz=ZoneInfo('America/New_York')).strftime('%Y-%m-%d_%H-%M-%S')}", - ) - - dataset = read_local_data( - filepath="applications/models/src/models/training_data.csv" - ) # type: ignore[assignment] - - model = train_model( - dataset=dataset, # type: ignore[arg-type] - validation_split=configuration["validation_split"], - epoch_count=configuration["epoch_count"], - learning_rate=configuration["learning_rate"], - wandb_run=wandb_run, - ) - - validate_model( - data=dataset, # type: ignore[arg-type] - model=model, # type: ignore[arg-type] - validation_split=configuration["validation_split"], - ) - - save_model(model=model) # type: ignore[arg-type] diff --git a/applications/portfoliomanager/Dockerfile b/applications/portfoliomanager/Dockerfile index 9f92512ad..dd6e33593 100644 --- a/applications/portfoliomanager/Dockerfile +++ b/applications/portfoliomanager/Dockerfile @@ -1,15 +1,32 @@ -FROM python:3.12.10 +FROM python:3.12.10 AS builder + COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv -ENV PYTHONPATH=/app/src +WORKDIR /app + +COPY pyproject.toml uv.lock ./ + +COPY applications/portfoliomanager/ applications/portfoliomanager/ + +COPY libraries/python/ libraries/python/ + +RUN uv sync --no-dev --no-cache + +FROM python:3.12.10-slim AS server + +RUN apt-get update && \ + apt-get install -y --no-install-recommends build-essential clang && \ + rm -rf /var/lib/apt/lists/* + +ENV PYTHONPATH=/app/applications/portfoliomanager/src WORKDIR /app -COPY pyproject.toml ./ -RUN uv sync --no-dev +COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv + +COPY --from=builder /app /app -COPY ./src ./src +EXPOSE 8080 -EXPOSE 8081 +ENTRYPOINT ["uv", "run", "uvicorn", "portfoliomanager.server:application", "--host", "0.0.0.0", "--port", "8080", "--app-dir", "src"] -ENTRYPOINT ["uv", "run", "uvicorn", "portfoliomanager.main:application", "--host", "0.0.0.0", "--port", "8081", "--app-dir", "src"] \ No newline at end of file diff --git a/applications/portfoliomanager/pyproject.toml b/applications/portfoliomanager/pyproject.toml index 3ccf69dde..785774568 100644 --- a/applications/portfoliomanager/pyproject.toml +++ b/applications/portfoliomanager/pyproject.toml @@ -4,12 +4,10 @@ version = "0.1.0" description = "Portfolio prediction and construction service" requires-python = "==3.12.10" dependencies = [ - "internal", - "fastapi>=0.116.1", - "uvicorn>=0.35.0", - "httpx>=0.27.0", - "pandera[polars,pandas]>=0.26.0", - "alpaca-py>=0.42.1", + "internal>=0.1.0", + "httpx>=0.27.0", + "pandera[polars,pandas]>=0.26.0", + "alpaca-py>=0.42.1", ] [tool.uv] diff --git a/applications/portfoliomanager/src/portfoliomanager/alpaca_client.py b/applications/portfoliomanager/src/portfoliomanager/alpaca_client.py index 4ab6b134a..1127a9668 100644 --- a/applications/portfoliomanager/src/portfoliomanager/alpaca_client.py +++ b/applications/portfoliomanager/src/portfoliomanager/alpaca_client.py @@ -1,23 +1,24 @@ import time from typing import cast -import pandera.polars as pa -import polars as pl -from alpaca.trading import Position, TradeAccount, TradingClient +from alpaca.trading import ( + ClosePositionRequest, + OrderRequest, + TradeAccount, + TradingClient, +) +from alpaca.trading.enums import OrderSide, OrderType, TimeInForce + +from .enums import TradeSide class AlpacaAccount: def __init__( self, cash_amount: float, - positions: pl.DataFrame, ) -> None: self.cash_amount = cash_amount - position_schema.validate(positions) - - self.positions = positions - class AlpacaClient: def __init__( @@ -34,78 +35,44 @@ def __init__( paper=is_paper, ) + self.is_paper = is_paper + def get_account(self) -> AlpacaAccount: account: TradeAccount = cast("TradeAccount", self.trading_client.get_account()) time.sleep(self.rate_limit_sleep) - account_positions: list[Position] = cast( - "list[Position]", self.trading_client.get_all_positions() - ) - if not account_positions: - time.sleep(self.rate_limit_sleep) - empty_positions = pl.DataFrame( - { - "ticker": pl.Series([], dtype=pl.String), - "side": pl.Series([], dtype=pl.String), - "dollar_amount": pl.Series([], dtype=pl.Float64), - "share_amount": pl.Series([], dtype=pl.Float64), - } - ) - - return AlpacaAccount( - cash_amount=float(cast("str", account.cash)), - positions=empty_positions, - ) - - position_data = [ - { - "ticker": account_position.symbol, - "side": str(account_position.side).replace("PositionSide.", "").upper(), - "dollar_amount": float(cast("str", account_position.market_value)), - "share_amount": float(cast("str", account_position.qty)), - } - for account_position in account_positions - ] - - time.sleep(self.rate_limit_sleep) - - positions = pl.DataFrame(position_data) - - position_schema.validate(positions) - return AlpacaAccount( cash_amount=float(cast("str", account.cash)), - positions=positions, ) + def open_position( + self, + ticker: str, + side: TradeSide, + dollar_amount: float, + ) -> None: + self.trading_client.submit_order( + order_data=OrderRequest( + symbol=ticker.upper(), + notional=dollar_amount, + side=OrderSide(side.value.lower()), + type=OrderType.MARKET, + time_in_force=TimeInForce.DAY, # required for notional trades + ), + ) -def is_uppercase(data: pa.PolarsData) -> pl.LazyFrame: - return data.lazyframe.select( - pl.col(data.key).str.to_uppercase() == pl.col(data.key) - ) + time.sleep(self.rate_limit_sleep) + def close_position( + self, + ticker: str, + ) -> None: + self.trading_client.close_position( + symbol_or_asset_id=ticker.upper(), + close_options=ClosePositionRequest( + percentage="100", + ), + ) -position_schema = pa.DataFrameSchema( - { - "ticker": pa.Column( - dtype=str, - checks=[pa.Check(is_uppercase)], - ), - "side": pa.Column( - dtype=str, - checks=[ - pa.Check.isin(["LONG", "SHORT"]), - pa.Check(is_uppercase), - ], - ), - "dollar_amount": pa.Column( - dtype=float, - checks=[pa.Check.greater_than(0)], - ), - "share_amount": pa.Column( - dtype=float, - checks=[pa.Check.greater_than(0)], - ), - }, -) + time.sleep(self.rate_limit_sleep) diff --git a/applications/portfoliomanager/src/portfoliomanager/enums.py b/applications/portfoliomanager/src/portfoliomanager/enums.py new file mode 100644 index 000000000..946b55f4b --- /dev/null +++ b/applications/portfoliomanager/src/portfoliomanager/enums.py @@ -0,0 +1,19 @@ +from enum import Enum + + +class PositionAction(Enum): + PDT_LOCKED = "PDT_LOCKED" + CLOSE_POSITION = "CLOSE_POSITION" + MAINTAIN_POSITION = "MAINTAIN_POSITION" + OPEN_POSITION = "OPEN_POSITION" + UNSPECIFIED = "UNSPECIFIED" + + +class TradeSide(Enum): + BUY = "BUY" + SELL = "SELL" + + +class PositionSide(Enum): + LONG = "LONG" + SHORT = "SHORT" diff --git a/applications/portfoliomanager/src/portfoliomanager/main.py b/applications/portfoliomanager/src/portfoliomanager/main.py deleted file mode 100644 index 4856c8b29..000000000 --- a/applications/portfoliomanager/src/portfoliomanager/main.py +++ /dev/null @@ -1,38 +0,0 @@ -import os -from typing import Any - -import httpx -from fastapi import FastAPI, HTTPException, Response, status - -app: FastAPI = FastAPI() - -DATAMANAGER_URL = os.getenv("DATAMANAGER_URL", "http://datamanager:8080") -HTTP_200_OK = 200 - - -@app.get("/health") -def health_check() -> Response: - return Response(status_code=status.HTTP_200_OK) - - -@app.get("/datamanager/health") -async def check_datamanager_health() -> dict[str, Any]: - """Check if datamanager service is healthy""" - try: - async with httpx.AsyncClient() as client: - response = await client.get( - f"{DATAMANAGER_URL}/portfolio-check", timeout=5.0 - ) - return { - "datamanager_status": "healthy" - if response.status_code == HTTP_200_OK - else "unhealthy", - "status_code": response.status_code, - } - except httpx.RequestError as e: - raise HTTPException( - status_code=503, detail=f"Cannot reach datamanager: {e!s}" - ) from e - - -application = app diff --git a/libraries/python/src/internal/portfolio.py b/applications/portfoliomanager/src/portfoliomanager/portfolio_schema.py similarity index 74% rename from libraries/python/src/internal/portfolio.py rename to applications/portfoliomanager/src/portfoliomanager/portfolio_schema.py index cab3a0448..a09ee3652 100644 --- a/libraries/python/src/internal/portfolio.py +++ b/applications/portfoliomanager/src/portfoliomanager/portfolio_schema.py @@ -2,6 +2,8 @@ import polars as pl from pandera.polars import PolarsData +from .enums import PositionAction, PositionSide + def is_uppercase(data: PolarsData) -> pl.LazyFrame: return data.lazyframe.select( @@ -15,8 +17,8 @@ def check_position_side_counts( ) -> bool: counts = data.lazyframe.select( pl.len().alias("total_count"), - (pl.col("side") == "LONG").sum().alias("long_count"), - (pl.col("side") == "SHORT").sum().alias("short_count"), + (pl.col("side") == PositionSide.LONG.value).sum().alias("long_count"), + (pl.col("side") == PositionSide.SHORT.value).sum().alias("short_count"), ).collect() total_count = counts.get_column("total_count").item() long_count = counts.get_column("long_count").item() @@ -44,12 +46,12 @@ def check_position_side_sums( maximum_imbalance_percentage: float = 0.05, # 5% ) -> bool: sums = data.lazyframe.select( - pl.when(pl.col("side") == "LONG") + pl.when(pl.col("side") == PositionSide.LONG.value) .then(pl.col("dollar_amount")) .otherwise(0.0) .sum() .alias("long_sum"), - pl.when(pl.col("side") == "SHORT") + pl.when(pl.col("side") == PositionSide.SHORT.value) .then(pl.col("dollar_amount")) .otherwise(0.0) .sum() @@ -88,7 +90,12 @@ def check_position_side_sums( "side": pa.Column( dtype=str, checks=[ - pa.Check.isin(["LONG", "SHORT"]), + pa.Check.isin( + [ + PositionSide.LONG.value.upper(), + PositionSide.SHORT.value.upper(), + ] + ), pa.Check(is_uppercase), ], ), @@ -96,6 +103,22 @@ def check_position_side_sums( dtype=float, checks=[pa.Check.greater_than(0)], ), + "action": pa.Column( + dtype=str, + checks=[ + pa.Check.isin( + [ + PositionAction.PDT_LOCKED.value, + PositionAction.CLOSE_POSITION.value, + PositionAction.OPEN_POSITION.value, + PositionAction.MAINTAIN_POSITION.value, + PositionAction.UNSPECIFIED.value, + ] + ), + pa.Check(is_uppercase), + ], + required=False, + ), }, unique=["ticker"], coerce=True, diff --git a/applications/portfoliomanager/src/portfoliomanager/risk_management.py b/applications/portfoliomanager/src/portfoliomanager/risk_management.py index 438e62694..7ee855424 100644 --- a/applications/portfoliomanager/src/portfoliomanager/risk_management.py +++ b/applications/portfoliomanager/src/portfoliomanager/risk_management.py @@ -3,14 +3,16 @@ import polars as pl +from .enums import PositionAction, PositionSide -def add_positions_action_column( - positions: pl.DataFrame, - current_datetime: datetime, + +def add_portfolio_action_column( + prior_portfolio: pl.DataFrame, + current_timestamp: datetime, ) -> pl.DataFrame: - positions = positions.clone() + prior_portfolio = prior_portfolio.clone() - return positions.with_columns( + return prior_portfolio.with_columns( pl.when( pl.col("timestamp") .cast(pl.Float64) @@ -18,22 +20,22 @@ def add_positions_action_column( lambda ts: datetime.fromtimestamp(ts, tz=UTC).date(), return_dtype=pl.Date, ) - == current_datetime.date() + == current_timestamp.date() ) - .then(pl.lit("PDT_LOCKED")) - .otherwise(pl.lit("UNSPECIFIED")) + .then(pl.lit(PositionAction.PDT_LOCKED.value)) + .otherwise(pl.lit(PositionAction.UNSPECIFIED.value)) .alias("action") ) def add_equity_bars_returns_and_realized_volatility_columns( - equity_bars: pl.DataFrame, + prior_equity_bars: pl.DataFrame, ) -> pl.DataFrame: - equity_bars = equity_bars.clone() + prior_equity_bars = prior_equity_bars.clone() minimum_bars_per_ticker_required = 30 - ticker_counts = equity_bars.group_by("ticker").agg(pl.len().alias("count")) + ticker_counts = prior_equity_bars.group_by("ticker").agg(pl.len().alias("count")) insufficient_tickers = ticker_counts.filter( pl.col("count") < minimum_bars_per_ticker_required ) @@ -43,9 +45,9 @@ def add_equity_bars_returns_and_realized_volatility_columns( message = f"Tickers with insufficient data (< {minimum_bars_per_ticker_required} rows): {insufficient_list}" # noqa: E501 raise ValueError(message) - equity_bars = equity_bars.sort(["ticker", "timestamp"]) + prior_equity_bars = prior_equity_bars.sort(["ticker", "timestamp"]) daily_returns = pl.col("close_price").pct_change().over("ticker") - return equity_bars.with_columns( + return prior_equity_bars.with_columns( pl.when(pl.col("close_price").is_not_null()) .then(daily_returns) .otherwise(None) @@ -64,18 +66,18 @@ def add_equity_bars_returns_and_realized_volatility_columns( ) -def add_positions_performance_columns( - positions: pl.DataFrame, - original_predictions: pl.DataFrame, # per original position ticker and timestamp - original_equity_bars: pl.DataFrame, # per original position ticker and timestamp +def add_portfolio_performance_columns( + prior_portfolio: pl.DataFrame, + prior_predictions: pl.DataFrame, # per original ticker and timestamp + prior_equity_bars: pl.DataFrame, # per original ticker and timestamp current_timestamp: datetime, ) -> pl.DataFrame: - positions = positions.clone() - original_predictions = original_predictions.clone() - original_equity_bars = original_equity_bars.clone() + prior_portfolio = prior_portfolio.clone() + prior_predictions = prior_predictions.clone() + prior_equity_bars = prior_equity_bars.clone() - position_predictions = positions.join( - other=original_predictions, + prior_portfolio_predictions = prior_portfolio.join( + other=prior_predictions, on=["ticker", "timestamp"], how="left", ).select( @@ -88,17 +90,15 @@ def add_positions_performance_columns( pl.col("quantile_90").alias("original_upper_threshold"), ) - original_equity_bars_with_returns = original_equity_bars.sort( - ["ticker", "timestamp"] - ) + prior_equity_bars_with_returns = prior_equity_bars.sort(["ticker", "timestamp"]) position_returns = [] - for row in position_predictions.iter_rows(named=True): + for row in prior_portfolio_predictions.iter_rows(named=True): ticker = row["ticker"] position_timestamp = row["timestamp"] - ticker_bars = original_equity_bars_with_returns.filter( + ticker_bars = prior_equity_bars_with_returns.filter( (pl.col("ticker") == ticker) & (pl.col("timestamp") >= position_timestamp) & (pl.col("timestamp") <= current_timestamp.timestamp()) @@ -120,27 +120,27 @@ def add_positions_performance_columns( returns = pl.DataFrame(position_returns) - positions_with_data = position_predictions.join( + prior_portfolio_with_data = prior_portfolio_predictions.join( other=returns, on=["ticker", "timestamp"], how="left", ) - return positions_with_data.with_columns( - pl.when(pl.col("action") == "PDT_LOCKED") - .then(pl.lit("PDT_LOCKED")) + return prior_portfolio_with_data.with_columns( + pl.when(pl.col("action") == PositionAction.PDT_LOCKED.value) + .then(pl.lit(PositionAction.PDT_LOCKED.value)) .when( - (pl.col("action") != "PDT_LOCKED") + (pl.col("action") != PositionAction.PDT_LOCKED.value) & ( ( - (pl.col("side") == "LONG") + (pl.col("side") == PositionSide.LONG.value) & ( pl.col("cumulative_simple_return") <= pl.col("original_lower_threshold") ) ) | ( - (pl.col("side") == "SHORT") + (pl.col("side") == PositionSide.SHORT.value) & ( pl.col("cumulative_simple_return") >= pl.col("original_upper_threshold") @@ -148,25 +148,25 @@ def add_positions_performance_columns( ) ) ) - .then(pl.lit("CLOSE_POSITION")) + .then(pl.lit(PositionAction.CLOSE_POSITION.value)) .when( ( - (pl.col("side") == "LONG") + (pl.col("side") == PositionSide.LONG.value) & ( pl.col("cumulative_simple_return") >= pl.col("original_upper_threshold") ) ) | ( - (pl.col("side") == "SHORT") + (pl.col("side") == PositionSide.SHORT.value) & ( pl.col("cumulative_simple_return") <= pl.col("original_lower_threshold") ) ) ) - .then(pl.lit("MAINTAIN_POSITION")) - .otherwise(pl.lit("UNSPECIFIED")) + .then(pl.lit(PositionAction.MAINTAIN_POSITION.value)) + .otherwise(pl.lit(PositionAction.UNSPECIFIED.value)) .alias("action") ).drop( [ @@ -177,12 +177,14 @@ def add_positions_performance_columns( ) -def add_predictions_zscore_ranked_columns(predictions: pl.DataFrame) -> pl.DataFrame: - predictions = predictions.clone() +def add_predictions_zscore_ranked_columns( + current_predictions: pl.DataFrame, +) -> pl.DataFrame: + current_predictions = current_predictions.clone() - quantile_50_mean = predictions.select(pl.col("quantile_50").mean()).item() + quantile_50_mean = current_predictions.select(pl.col("quantile_50").mean()).item() quantile_50_standard_deviation = ( - predictions.select(pl.col("quantile_50").std()).item() or 1e-8 + current_predictions.select(pl.col("quantile_50").std()).item() or 1e-8 ) z_score_return = ( @@ -193,26 +195,26 @@ def add_predictions_zscore_ranked_columns(predictions: pl.DataFrame) -> pl.DataF composite_score = z_score_return / (1 + inter_quartile_range) - return predictions.with_columns( + return current_predictions.with_columns( z_score_return.alias("z_score_return"), inter_quartile_range.alias("inter_quartile_range"), composite_score.alias("composite_score"), - pl.lit("UNSPECIFIED").alias("action"), + pl.lit(PositionAction.UNSPECIFIED.value).alias("action"), ).sort(["composite_score", "inter_quartile_range"], descending=[True, False]) def create_optimal_portfolio( - predictions: pl.DataFrame, - positions: pl.DataFrame, + current_predictions: pl.DataFrame, + prior_portfolio: pl.DataFrame, maximum_capital: float, current_timestamp: datetime, ) -> pl.DataFrame: - predictions = predictions.clone() - positions = positions.clone() + current_predictions = current_predictions.clone() + prior_portfolio = prior_portfolio.clone() minimum_inter_quartile_range = 0.75 high_uncertainty_tickers = ( - predictions.filter( + current_predictions.filter( pl.col("inter_quartile_range") > minimum_inter_quartile_range ) .select("ticker") @@ -220,7 +222,7 @@ def create_optimal_portfolio( .to_list() ) - closed_positions, maintained_positions = _filter_positions(positions) + closed_positions, maintained_positions = _filter_positions(prior_portfolio) closed_position_tickers = closed_positions.select("ticker").to_series().to_list() maintained_position_tickers = ( @@ -231,16 +233,22 @@ def create_optimal_portfolio( high_uncertainty_tickers + closed_position_tickers + maintained_position_tickers ) - available_predictions = predictions.filter( + available_predictions = current_predictions.filter( ~pl.col("ticker").is_in(excluded_tickers) ) - maintained_long_capital = _filter_side_capital_amount(maintained_positions, "LONG") + maintained_long_capital = _filter_side_capital_amount( + maintained_positions, PositionSide.LONG.value + ) maintained_short_capital = _filter_side_capital_amount( - maintained_positions, "SHORT" + maintained_positions, PositionSide.SHORT.value + ) + closed_long_capital = _filter_side_capital_amount( + closed_positions, PositionSide.LONG.value + ) + closed_short_capital = _filter_side_capital_amount( + closed_positions, PositionSide.SHORT.value ) - closed_long_capital = _filter_side_capital_amount(closed_positions, "LONG") - closed_short_capital = _filter_side_capital_amount(closed_positions, "SHORT") target_side_capital = maximum_capital / 2 available_long_capital = max( @@ -252,9 +260,11 @@ def create_optimal_portfolio( target_side_capital - maintained_short_capital + closed_short_capital, ) - maintained_long_count = maintained_positions.filter(pl.col("side") == "LONG").height + maintained_long_count = maintained_positions.filter( + pl.col("side") == PositionSide.LONG.value + ).height maintained_short_count = maintained_positions.filter( - pl.col("side") == "SHORT" + pl.col("side") == PositionSide.SHORT.value ).height new_long_positions_needed = max(0, 10 - maintained_long_count) @@ -283,17 +293,17 @@ def create_optimal_portfolio( long_positions = long_candidates.select( pl.col("ticker"), pl.lit(current_timestamp.timestamp()).cast(pl.Float64).alias("timestamp"), - pl.lit("LONG").alias("side"), + pl.lit(PositionSide.LONG.value).alias("side"), pl.lit(dollar_amount_per_long).alias("dollar_amount"), - pl.lit("UNSPECIFIED").alias("action"), + pl.lit(PositionAction.OPEN_POSITION.value).alias("action"), ) short_positions = short_candidates.select( pl.col("ticker"), pl.lit(current_timestamp.timestamp()).cast(pl.Float64).alias("timestamp"), - pl.lit("SHORT").alias("side"), + pl.lit(PositionSide.SHORT.value).alias("side"), pl.lit(dollar_amount_per_short).alias("dollar_amount"), - pl.lit("UNSPECIFIED").alias("action"), + pl.lit(PositionAction.OPEN_POSITION.value).alias("action"), ) return _collect_portfolio_positions( @@ -328,8 +338,12 @@ def _filter_positions(positions: pl.DataFrame) -> tuple[pl.DataFrame, pl.DataFra ), ) - closed_positions = positions.filter(pl.col("action") == "CLOSE_POSITION") - maintained_positions = positions.filter(pl.col("action") == "MAINTAIN_POSITION") + closed_positions = positions.filter( + pl.col("action") == PositionAction.CLOSE_POSITION.value + ) + maintained_positions = positions.filter( + pl.col("action") == PositionAction.MAINTAIN_POSITION.value + ) return closed_positions, maintained_positions @@ -381,4 +395,5 @@ def _collect_portfolio_positions( pl.col("timestamp").cast(pl.Float64), "side", "dollar_amount", + "action", ).sort(["ticker", "side"]) diff --git a/applications/portfoliomanager/src/portfoliomanager/server.py b/applications/portfoliomanager/src/portfoliomanager/server.py new file mode 100644 index 000000000..bc920ae26 --- /dev/null +++ b/applications/portfoliomanager/src/portfoliomanager/server.py @@ -0,0 +1,362 @@ +import io +import json +import os +from datetime import UTC, datetime +from typing import cast + +import polars as pl +import requests +import structlog +from fastapi import FastAPI, Response, status +from internal.equity_bars_schema import equity_bars_schema + +from .alpaca_client import AlpacaClient +from .enums import PositionAction, PositionSide, TradeSide +from .portfolio_schema import portfolio_schema +from .risk_management import ( + add_equity_bars_returns_and_realized_volatility_columns, + add_portfolio_action_column, + add_portfolio_performance_columns, + add_predictions_zscore_ranked_columns, + create_optimal_portfolio, +) + +logger = structlog.get_logger() + +application: FastAPI = FastAPI() + +DATAMANAGER_BASE_URL = os.getenv("PSF_DATAMANAGER_BASE_URL", "http://datamanager:8080") +EQUITYPRICEMODEL_BASE_URL = os.getenv( + "PSF_EQUITYPRICEMODEL_BASE_URL", + "http://equitypricemodel:8080", +) + +ALPACA_API_KEY_ID = os.getenv("ALPACA_API_KEY_ID", "") +ALPACA_API_SECRET = os.getenv("ALPACA_API_SECRET", "") + +if not ALPACA_API_KEY_ID or not ALPACA_API_SECRET: + logger.error( + "Missing Alpaca credentials", + api_key_id_set=bool(ALPACA_API_KEY_ID), + api_secret_set=bool(ALPACA_API_SECRET), + ) + message = ( + "ALPACA_API_KEY_ID and ALPACA_API_SECRET environment variables are required" + ) + raise ValueError(message) + +alpaca_client = AlpacaClient( + api_key=ALPACA_API_KEY_ID, + api_secret=ALPACA_API_SECRET, + is_paper=os.getenv("ALPACA_IS_PAPER", "true").lower() == "true", +) + +logger.info("Portfolio manager initialized", is_paper=alpaca_client.is_paper) + + +@application.get("/health") +def health_check() -> Response: + return Response(status_code=status.HTTP_200_OK) + + +@application.post("/portfolio") +def create_portfolio() -> Response: # noqa: PLR0911, C901 + current_timestamp = datetime.now(tz=UTC) + logger.info("Starting portfolio rebalance", timestamp=current_timestamp.isoformat()) + + try: + account = alpaca_client.get_account() + logger.info("Retrieved account", cash_amount=account.cash_amount) + except Exception as e: + logger.exception("Failed to retrieve account", error=str(e)) + return Response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + try: + current_predictions = get_current_predictions() + logger.info("Retrieved predictions", count=len(current_predictions)) + except Exception as e: + logger.exception("Failed to retrieve predictions", error=str(e)) + return Response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + try: + prior_portfolio = get_prior_portfolio(current_timestamp=current_timestamp) + logger.info("Retrieved prior portfolio", count=len(prior_portfolio)) + except Exception as e: + logger.exception("Failed to retrieve prior portfolio", error=str(e)) + return Response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + try: + optimal_portfolio = get_optimal_portfolio( + current_predictions=current_predictions, + prior_portfolio=prior_portfolio, + maximum_capital=float(account.cash_amount), + current_timestamp=current_timestamp, + ) + logger.info("Created optimal portfolio", count=len(optimal_portfolio)) + except Exception as e: + logger.exception("Failed to create optimal portfolio", error=str(e)) + return Response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + try: + open_positions, close_positions = get_positions( + prior_portfolio=prior_portfolio, + optimal_portfolio=optimal_portfolio, + ) + logger.info( + "Determined positions to open and close", + open_count=len(open_positions), + close_count=len(close_positions), + ) + except Exception as e: + logger.exception( + "Failed to determine positions to open and close", + error=str(e), + ) + return Response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + close_results = [] + for close_position in close_positions: + try: + alpaca_client.close_position( + ticker=close_position["ticker"], + ) + logger.info("Closed position", ticker=close_position["ticker"]) + close_results.append( + { + "ticker": close_position["ticker"], + "action": "close", + "status": "success", + } + ) + except Exception as e: + logger.exception( + "Failed to close position", + ticker=close_position["ticker"], + error=str(e), + ) + close_results.append( + { + "ticker": close_position["ticker"], + "action": "close", + "status": "failed", + "error": str(e), + } + ) + + open_results = [] + for open_position in open_positions: + try: + alpaca_client.open_position( + ticker=open_position["ticker"], + side=open_position["side"], + dollar_amount=open_position["dollar_amount"], + ) + logger.info( + "Opened position", + ticker=open_position["ticker"], + side=open_position["side"], + dollar_amount=open_position["dollar_amount"], + ) + open_results.append( + { + "ticker": open_position["ticker"], + "action": "open", + "side": open_position["side"], + "dollar_amount": open_position["dollar_amount"], + "status": "success", + } + ) + except Exception as e: + logger.exception( + "Failed to open position", + ticker=open_position["ticker"], + error=str(e), + ) + open_results.append( + { + "ticker": open_position["ticker"], + "action": "open", + "side": open_position["side"], + "dollar_amount": open_position["dollar_amount"], + "status": "failed", + "error": str(e), + } + ) + + all_results = close_results + open_results + failed_trades = [r for r in all_results if r["status"] == "failed"] + + logger.info( + "Portfolio rebalance completed", + total_trades=len(all_results), + failed_trades=len(failed_trades), + ) + + if failed_trades: + return Response(status_code=status.HTTP_207_MULTI_STATUS) + + return Response(status_code=status.HTTP_200_OK) + + +def get_current_predictions() -> pl.DataFrame: + current_predictions_response = requests.get( + url=f"{EQUITYPRICEMODEL_BASE_URL}/predictions", + timeout=60, + ) + + current_predictions_response.raise_for_status() + + current_predictions = pl.DataFrame(current_predictions_response.json()) + + return add_predictions_zscore_ranked_columns( + current_predictions=current_predictions + ) + + +def get_prior_portfolio(current_timestamp: datetime) -> pl.DataFrame: # TEMP + prior_portfolio_response = requests.get( + url=f"{DATAMANAGER_BASE_URL}/portfolios", + timeout=60, + ) + + prior_portfolio_response.raise_for_status() + + prior_portfolio = pl.DataFrame(prior_portfolio_response.json()) + + if prior_portfolio.is_empty(): + return pl.DataFrame( + { + "ticker": [], + "timestamp": [], + "side": [], + "dollar_amount": [], + "action": [], + } + ) + + tickers = prior_portfolio["ticker"].unique().to_list() + timestamps = prior_portfolio["timestamp"].cast(pl.Float64) + start_timestamp = datetime.fromtimestamp(cast("float", timestamps.min()), tz=UTC) + + prior_equity_bars_response = requests.get( + url=f"{DATAMANAGER_BASE_URL}/equity-bars", + params={ + "tickers": ",".join(tickers), + "start_timestamp": start_timestamp.isoformat(), + "end_timestamp": current_timestamp.isoformat(), + }, + timeout=60, + ) + + prior_equity_bars_response.raise_for_status() + + tickers_and_timestamps = [ + {"ticker": row[0], "timestamp": row[1]} + for row in prior_portfolio[["ticker", "timestamp"]].rows() + ] + + prior_predictions_response = requests.get( + url=f"{DATAMANAGER_BASE_URL}/predictions", + params={"tickers_and_timestamps": json.dumps(tickers_and_timestamps)}, + timeout=60, + ) + + prior_predictions_response.raise_for_status() + + prior_portfolio = add_portfolio_action_column( + prior_portfolio=prior_portfolio, + current_timestamp=current_timestamp, + ) + + prior_equity_bars = pl.read_parquet(io.BytesIO(prior_equity_bars_response.content)) + + prior_equity_bars = equity_bars_schema.validate(prior_equity_bars) + + prior_equity_bars = add_equity_bars_returns_and_realized_volatility_columns( + prior_equity_bars=prior_equity_bars + ) + + prior_predictions = pl.DataFrame(prior_predictions_response.json()) + + return add_portfolio_performance_columns( + prior_portfolio=prior_portfolio, + prior_equity_bars=prior_equity_bars, + prior_predictions=prior_predictions, + current_timestamp=current_timestamp, + ) + + +def get_optimal_portfolio( + current_predictions: pl.DataFrame, + prior_portfolio: pl.DataFrame, + maximum_capital: float, + current_timestamp: datetime, +) -> pl.DataFrame: + optimal_portfolio = create_optimal_portfolio( + current_predictions=current_predictions, + prior_portfolio=prior_portfolio, + maximum_capital=maximum_capital, + current_timestamp=current_timestamp, + ) + + optimal_portfolio = portfolio_schema.validate(optimal_portfolio) + + save_portfolio_response = requests.post( + url=f"{DATAMANAGER_BASE_URL}/portfolios", + json={ + "timestamp": current_timestamp.isoformat(), + "data": optimal_portfolio.to_dicts(), + }, + timeout=60, + ) + + save_portfolio_response.raise_for_status() + + return optimal_portfolio + + +def get_positions( + prior_portfolio: pl.DataFrame, + optimal_portfolio: pl.DataFrame, +) -> tuple[list[dict], list[dict]]: + prior_portfolio = prior_portfolio.clone() + optimal_portfolio = optimal_portfolio.clone() + + close_positions = [] + if not prior_portfolio.is_empty(): + prior_tickers = set(prior_portfolio["ticker"].to_list()) + optimal_tickers = set(optimal_portfolio["ticker"].to_list()) + closing_tickers = prior_tickers - optimal_tickers + + if closing_tickers: + close_positions = [ + { + "ticker": row["ticker"], + "side": ( + TradeSide.SELL + if row["side"] == PositionSide.LONG.value + else TradeSide.BUY + ), + "dollar_amount": row["dollar_amount"], + } + for row in prior_portfolio.filter( + pl.col("ticker").is_in(list(closing_tickers)) + ).iter_rows(named=True) + ] + + open_positions = [ + { + "ticker": row["ticker"], + "side": ( + TradeSide.BUY + if row["side"] == PositionSide.LONG.value + else TradeSide.SELL + ), + "dollar_amount": row["dollar_amount"], + } + for row in optimal_portfolio.filter( + pl.col("action") == PositionAction.OPEN_POSITION.value + ).iter_rows(named=True) + ] + + return open_positions, close_positions diff --git a/libraries/python/tests/test_portfolio.py b/applications/portfoliomanager/tests/test_portfolio_schema.py similarity index 98% rename from libraries/python/tests/test_portfolio.py rename to applications/portfoliomanager/tests/test_portfolio_schema.py index f2da49f1f..6f6d0a26a 100644 --- a/libraries/python/tests/test_portfolio.py +++ b/applications/portfoliomanager/tests/test_portfolio_schema.py @@ -2,8 +2,8 @@ import polars as pl import pytest -from internal.portfolio import portfolio_schema from pandera.errors import SchemaError +from portfoliomanager.portfolio_schema import portfolio_schema def test_portfolio_schema_valid_data() -> None: diff --git a/applications/portfoliomanager/tests/test_risk_management.py b/applications/portfoliomanager/tests/test_risk_management.py index 26a102162..4a937baf8 100644 --- a/applications/portfoliomanager/tests/test_risk_management.py +++ b/applications/portfoliomanager/tests/test_risk_management.py @@ -4,14 +4,14 @@ import pytest from portfoliomanager.risk_management import ( add_equity_bars_returns_and_realized_volatility_columns, - add_positions_action_column, - add_positions_performance_columns, + add_portfolio_action_column, + add_portfolio_performance_columns, add_predictions_zscore_ranked_columns, create_optimal_portfolio, ) -def test_add_positions_action_column_same_day_positions_locked() -> None: +def test_add_portfolio_action_column_same_day_positions_locked() -> None: current_datetime = datetime(2024, 1, 15, 0, 0, 0, 0, tzinfo=UTC) positions = pl.DataFrame( { @@ -25,13 +25,13 @@ def test_add_positions_action_column_same_day_positions_locked() -> None: } ) - result = add_positions_action_column(positions, current_datetime) + result = add_portfolio_action_column(positions, current_datetime) assert all(action == "PDT_LOCKED" for action in result["action"].to_list()) assert len(result) == 2 # noqa: PLR2004 -def test_add_positions_action_column_previous_day_positions_unlocked() -> None: +def test_add_portfolio_action_column_previous_day_positions_unlocked() -> None: current_datetime = datetime(2024, 1, 15, 0, 0, 0, 0, tzinfo=UTC) positions = pl.DataFrame( { @@ -45,13 +45,13 @@ def test_add_positions_action_column_previous_day_positions_unlocked() -> None: } ) - result = add_positions_action_column(positions, current_datetime) + result = add_portfolio_action_column(positions, current_datetime) assert all(action == "UNSPECIFIED" for action in result["action"].to_list()) assert len(result) == 2 # noqa: PLR2004 -def test_add_positions_action_column_mixed_dates() -> None: +def test_add_portfolio_action_column_mixed_dates() -> None: current_datetime = datetime(2024, 1, 15, 0, 0, 0, 0, tzinfo=UTC) positions = pl.DataFrame( { @@ -66,19 +66,19 @@ def test_add_positions_action_column_mixed_dates() -> None: } ) - result = add_positions_action_column(positions, current_datetime) + result = add_portfolio_action_column(positions, current_datetime) expected_actions = ["PDT_LOCKED", "UNSPECIFIED", "PDT_LOCKED"] assert result["action"].to_list() == expected_actions -def test_add_positions_action_column_empty_dataframe() -> None: +def test_add_portfolio_action_column_empty_dataframe() -> None: current_datetime = datetime(2024, 1, 15, 0, 0, 0, 0, tzinfo=UTC) positions = pl.DataFrame( {"ticker": [], "timestamp": [], "side": [], "dollar_amount": []} ) - result = add_positions_action_column(positions, current_datetime) + result = add_portfolio_action_column(positions, current_datetime) assert len(result) == 0 assert "action" in result.columns @@ -213,7 +213,7 @@ def test_add_equity_bars_returns_and_realized_volatility_columns_null_prices_han assert daily_returns[1] is None # second row should be null -def test_add_positions_performance_columns_long_position_outperforming() -> None: +def test_add_portfolio_performance_columns_long_position_outperforming() -> None: base_timestamp = datetime(2024, 1, 10, tzinfo=UTC).timestamp() positions = pl.DataFrame( @@ -248,14 +248,14 @@ def test_add_positions_performance_columns_long_position_outperforming() -> None ) current_timestamp = datetime.fromtimestamp(base_timestamp + (29 * 86400), tz=UTC) - result = add_positions_performance_columns( + result = add_portfolio_performance_columns( positions, original_predictions, original_equity_bars, current_timestamp ) assert result["action"][0] == "MAINTAIN_POSITION" # 20% > 15% threshold -def test_add_positions_performance_columns_long_position_underperforming() -> None: +def test_add_portfolio_performance_columns_long_position_underperforming() -> None: base_timestamp = datetime(2024, 1, 10, tzinfo=UTC).timestamp() positions = pl.DataFrame( @@ -290,14 +290,14 @@ def test_add_positions_performance_columns_long_position_underperforming() -> No ) current_timestamp = datetime.fromtimestamp(base_timestamp + (29 * 86400), tz=UTC) - result = add_positions_performance_columns( + result = add_portfolio_performance_columns( positions, original_predictions, original_equity_bars, current_timestamp ) assert result["action"][0] == "CLOSE_POSITION" # -10% < -5% threshold -def test_add_positions_performance_columns_short_position_outperforming() -> None: +def test_add_portfolio_performance_columns_short_position_outperforming() -> None: base_timestamp = datetime(2024, 1, 10, tzinfo=UTC).timestamp() positions = pl.DataFrame( @@ -332,7 +332,7 @@ def test_add_positions_performance_columns_short_position_outperforming() -> Non ) current_timestamp = datetime.fromtimestamp(base_timestamp + (29 * 86400), tz=UTC) - result = add_positions_performance_columns( + result = add_portfolio_performance_columns( positions, original_predictions, original_equity_bars, current_timestamp ) @@ -341,7 +341,7 @@ def test_add_positions_performance_columns_short_position_outperforming() -> Non ) # -10% <= -5% threshold (good for short) -def test_add_positions_performance_columns_pdt_locked_position_maintained() -> None: +def test_add_portfolio_performance_columns_pdt_locked_position_maintained() -> None: base_timestamp = datetime(2024, 1, 10, tzinfo=UTC).timestamp() positions = pl.DataFrame( @@ -376,14 +376,14 @@ def test_add_positions_performance_columns_pdt_locked_position_maintained() -> N ) current_timestamp = datetime.fromtimestamp(base_timestamp + (29 * 86400), tz=UTC) - result = add_positions_performance_columns( + result = add_portfolio_performance_columns( positions, original_predictions, original_equity_bars, current_timestamp ) assert result["action"][0] == "PDT_LOCKED" # pdt locked overrides performance -def test_add_positions_performance_columns_multiple_tickers_independent() -> None: +def test_add_portfolio_performance_columns_multiple_tickers_independent() -> None: current_timestamp = datetime(2024, 1, 10, tzinfo=UTC).timestamp() positions = pl.DataFrame( @@ -431,7 +431,7 @@ def test_add_positions_performance_columns_multiple_tickers_independent() -> Non raw_equity_bars ) - out = add_positions_performance_columns( + out = add_portfolio_performance_columns( positions, predictions, equity_bars, @@ -725,7 +725,8 @@ def test_create_optimal_portfolio_mixed_closed_and_maintained_positions() -> Non assert "timestamp" in result.columns assert "side" in result.columns assert "dollar_amount" in result.columns - assert len(result.columns) == 4 # only these 4 columns # noqa: PLR2004 + assert "action" in result.columns + assert len(result.columns) == 5 # noqa: PLR2004 sorted_result = result.sort(["ticker", "side"]) assert sorted_result.equals(result) diff --git a/applications/stack.yml b/applications/stack.yml deleted file mode 100644 index c6f8edb2f..000000000 --- a/applications/stack.yml +++ /dev/null @@ -1,72 +0,0 @@ -version: '3.8' - -services: - datamanager: - image: pocketsizefund/datamanager:latest - ports: - - "8080:8080" - networks: - - app-network - deploy: - replicas: 2 - restart_policy: - condition: on-failure - delay: 5s - max_attempts: 3 - window: 120s - update_config: - parallelism: 1 - delay: 10s - failure_action: rollback - rollback_config: - parallelism: 1 - delay: 10s - placement: - constraints: [] - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8080/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - environment: - - PYTHONPATH=/app/src - - portfoliomanager: - image: pocketsizefund/portfoliomanager:latest - ports: - - "8081:8081" - networks: - - app-network - depends_on: - - datamanager - deploy: - replicas: 2 - restart_policy: - condition: on-failure - delay: 5s - max_attempts: 3 - window: 120s - update_config: - parallelism: 1 - delay: 10s - failure_action: rollback - rollback_config: - parallelism: 1 - delay: 10s - placement: - constraints: [] - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8081/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - environment: - - PYTHONPATH=/app/src - - DATAMANAGER_URL=http://datamanager:8080 - -networks: - app-network: - driver: overlay - attachable: true diff --git a/infrastructure/.claude/settings.local.json b/infrastructure/.claude/settings.local.json deleted file mode 100644 index b9640655b..000000000 --- a/infrastructure/.claude/settings.local.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(pulumi stack output:*)", - "Bash(nu:*)", - "Bash(docker stack ps:*)" - ], - "defaultMode": "acceptEdits", - "additionalDirectories": [ - "/Users/chrisaddy/Library/Application Support/nushell" - ] - } -} \ No newline at end of file diff --git a/infrastructure/.gitignore b/infrastructure/.gitignore deleted file mode 100644 index a3807e5bd..000000000 --- a/infrastructure/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.pyc -venv/ diff --git a/infrastructure/.python-version b/infrastructure/.python-version deleted file mode 100644 index e4fba2183..000000000 --- a/infrastructure/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.12 diff --git a/infrastructure/Pulumi.yaml b/infrastructure/Pulumi.yaml index ad1909c28..35e5309a6 100644 --- a/infrastructure/Pulumi.yaml +++ b/infrastructure/Pulumi.yaml @@ -1,10 +1,6 @@ -name: infrastructure -description: pocketsizefund infra +name: pocketsizefund runtime: name: python options: toolchain: uv -config: - pulumi:tags: - value: - pulumi:template: aws-python +description: Pocket Size Fund application infrastructure diff --git a/infrastructure/__main__.py b/infrastructure/__main__.py index d314bd1b3..2aaa95ce6 100644 --- a/infrastructure/__main__.py +++ b/infrastructure/__main__.py @@ -1,182 +1,796 @@ +import json + import pulumi import pulumi_aws as aws -import pulumi_tls as tls -from pulumi_command import remote - -az = pulumi.Config().get("az") or "us-east-1a" -blueprint_id = pulumi.Config().get("blueprintId") or "ubuntu_24_04" -bundle_mgr = pulumi.Config().get("bundleIdMgr") or "medium_2_0" -bundle_wkr = pulumi.Config().get("bundleIdWkr") or "small_2_0" -allowed_ssh_cidrs = pulumi.Config().get_object("allowedSshCidrs") or ["0.0.0.0/0"] -swarm_manager_allowed_cidrs = pulumi.Config().get_object( - "swarmManagerAllowedCidrs" -) or ["10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"] -swarm_cluster_allowed_cidrs = pulumi.Config().get_object( - "swarmClusterAllowedCidrs" -) or ["10.0.0.0/16"] - -ssh_key = tls.PrivateKey("swarm-key", algorithm="RSA", rsa_bits=4096) -ls_key = aws.lightsail.KeyPair( - "swarm-ls-key", - name="swarm-ls-key", - public_key=ssh_key.public_key_openssh, -) - -cloud_init = """#cloud-config -package_update: true -package_upgrade: true -write_files: - - path: /usr/local/bin/install-docker.sh - permissions: "0755" - content: | - #!/usr/bin/env bash - set -euo pipefail - retry() { for i in {1..10}; do "$@" && break || { sleep 3; echo "retry $i"; }; done; } - - retry apt-get update - retry apt-get install -y ca-certificates curl gnupg - - install -m 0755 -d /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg - chmod a+r /etc/apt/keyrings/docker.gpg - - . /etc/os-release - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list - - retry apt-get update - retry apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin - - usermod -aG docker ubuntu || true - systemctl enable --now docker - -runcmd: - - /usr/local/bin/install-docker.sh - - bash -lc 'for i in {1..60}; do [ -x /usr/bin/docker ] && systemctl is-active --quiet docker && exit 0 || sleep 2; done; exit 1' -""" # noqa: E501 - - -def mk_instance(name: str, bundle_id: str): # noqa: ANN201 - inst = aws.lightsail.Instance( - name, - name=name, - availability_zone=az, - blueprint_id=blueprint_id, - bundle_id=bundle_id, - key_pair_name=ls_key.name, - user_data=cloud_init, - tags={"role": name}, + +current_identity = aws.get_caller_identity() + +account_id = current_identity.account_id + +region = aws.get_region().name + +secret = aws.secretsmanager.get_secret( + name="pocketsizefund/production/environment_variables", +) + +availability_zone_a = f"{region}a" +availability_zone_b = f"{region}b" + +datamanager_image = aws.ecr.get_image( + repository_name="pocketsizefund/datamanager-server", + image_tag="latest", +) + +portfoliomanager_image = aws.ecr.get_image( + repository_name="pocketsizefund/portfoliomanager-server", + image_tag="latest", +) + +equitypricemodel_image = aws.ecr.get_image( + repository_name="pocketsizefund/equitypricemodel-server", + image_tag="latest", +) + +tags = { + "project": "pocketsizefund", + "stack": pulumi.get_stack(), + "manager": "pulumi", +} + +vpc = aws.ec2.Vpc( + "vpc", + cidr_block="10.0.0.0/16", + enable_dns_hostnames=True, + enable_dns_support=True, + tags=tags, +) + +# Internet Gateway for public subnets +igw = aws.ec2.InternetGateway( + "igw", + vpc_id=vpc.id, + tags=tags, +) + +# Public subnets for ALB +public_subnet_1 = aws.ec2.Subnet( + "public_subnet_1", + vpc_id=vpc.id, + cidr_block="10.0.1.0/24", + availability_zone=availability_zone_a, + map_public_ip_on_launch=True, + tags=tags, +) + +public_subnet_2 = aws.ec2.Subnet( + "public_subnet_2", + vpc_id=vpc.id, + cidr_block="10.0.2.0/24", + availability_zone=availability_zone_b, + map_public_ip_on_launch=True, + tags=tags, +) + +# Private subnets for ECS tasks +private_subnet_1 = aws.ec2.Subnet( + "private_subnet_1", + vpc_id=vpc.id, + cidr_block="10.0.3.0/24", + availability_zone=availability_zone_a, + tags=tags, +) + +private_subnet_2 = aws.ec2.Subnet( + "private_subnet_2", + vpc_id=vpc.id, + cidr_block="10.0.4.0/24", + availability_zone=availability_zone_b, + tags=tags, +) + +public_route_table = aws.ec2.RouteTable( + "public_route_table", + vpc_id=vpc.id, + tags=tags, +) + +aws.ec2.Route( + "public_internet_route", + route_table_id=public_route_table.id, + destination_cidr_block="0.0.0.0/0", + gateway_id=igw.id, +) + +aws.ec2.RouteTableAssociation( + "public_subnet_1_rta", + subnet_id=public_subnet_1.id, + route_table_id=public_route_table.id, +) + +aws.ec2.RouteTableAssociation( + "public_subnet_2_rta", + subnet_id=public_subnet_2.id, + route_table_id=public_route_table.id, +) + +# NAT Gateway for private subnets +eip = aws.ec2.Eip( + "nat_elastic_ip", + domain="vpc", + tags=tags, +) + +nat = aws.ec2.NatGateway( + "nat_gateway", + subnet_id=public_subnet_1.id, + allocation_id=eip.id, + tags=tags, +) + +private_route_table = aws.ec2.RouteTable( + "private_route_table", + vpc_id=vpc.id, + tags=tags, +) + +aws.ec2.Route( + "nat_route", + route_table_id=private_route_table.id, + destination_cidr_block="0.0.0.0/0", + nat_gateway_id=nat.id, +) + +aws.ec2.RouteTableAssociation( + "private_subnet_1_rta", + subnet_id=private_subnet_1.id, + route_table_id=private_route_table.id, +) + +aws.ec2.RouteTableAssociation( + "private_subnet_2_rta", + subnet_id=private_subnet_2.id, + route_table_id=private_route_table.id, +) + +alb_security_group = aws.ec2.SecurityGroup( + "alb_sg", + name="pocketsizefund-alb", + vpc_id=vpc.id, + description="Security group for ALB", + ingress=[ + aws.ec2.SecurityGroupIngressArgs( + protocol="tcp", + from_port=80, + to_port=80, + cidr_blocks=["0.0.0.0/0"], + description="Allow HTTP", + ), + aws.ec2.SecurityGroupIngressArgs( + protocol="tcp", + from_port=443, + to_port=443, + cidr_blocks=["0.0.0.0/0"], + description="Allow HTTPS", + ), + ], + egress=[ + aws.ec2.SecurityGroupEgressArgs( + protocol="-1", + from_port=0, + to_port=0, + cidr_blocks=["0.0.0.0/0"], + description="Allow all outbound", + ) + ], + tags=tags, +) + +ecs_security_group = aws.ec2.SecurityGroup( + "ecs_sg", + name="pocketsizefund-ecs-tasks", + vpc_id=vpc.id, + description="Security group for ECS tasks", + tags=tags, +) + +# Allow ALB to reach ECS tasks on port 8080 +aws.ec2.SecurityGroupRule( + "ecs_from_alb", + type="ingress", + security_group_id=ecs_security_group.id, + source_security_group_id=alb_security_group.id, + protocol="tcp", + from_port=8080, + to_port=8080, + description="Allow ALB traffic", +) + +# Allow ECS tasks to communicate with each other +aws.ec2.SecurityGroupRule( + "ecs_self_ingress", + type="ingress", + security_group_id=ecs_security_group.id, + source_security_group_id=ecs_security_group.id, + protocol="tcp", + from_port=8080, + to_port=8080, + description="Allow inter-service communication", +) + +# Allow all outbound traffic from ECS tasks +aws.ec2.SecurityGroupRule( + "ecs_egress", + type="egress", + security_group_id=ecs_security_group.id, + protocol="-1", + from_port=0, + to_port=0, + cidr_blocks=["0.0.0.0/0"], + description="Allow all outbound", +) + +cluster = aws.ecs.Cluster( + "ecs_cluster", + name="pocketsizefund-application", + settings=[aws.ecs.ClusterSettingArgs(name="containerInsights", value="enabled")], + tags=tags, +) + +# Service Discovery Namespace for inter-service communication +service_discovery_namespace = aws.servicediscovery.PrivateDnsNamespace( + "service_discovery", + name="pocketsizefund.local", + vpc=vpc.id, + description="Service discovery for pocketsizefund services", + tags=tags, +) + +alb = aws.lb.LoadBalancer( + "alb", + name="pocketsizefund-alb", + subnets=[public_subnet_1.id, public_subnet_2.id], + security_groups=[alb_security_group.id], + internal=False, + load_balancer_type="application", + tags=tags, +) + +datamanager_tg = aws.lb.TargetGroup( + "datamanager_tg", + name="pocketsizefund-datamanager", + port=8080, + protocol="HTTP", + vpc_id=vpc.id, + target_type="ip", + health_check=aws.lb.TargetGroupHealthCheckArgs( + path="/health", + healthy_threshold=2, + unhealthy_threshold=3, + timeout=5, + interval=30, + ), + tags=tags, +) + +portfoliomanager_tg = aws.lb.TargetGroup( + "portfoliomanager_tg", + name="pocketsizefund-portfoliomanager", + port=8080, + protocol="HTTP", + vpc_id=vpc.id, + target_type="ip", + health_check=aws.lb.TargetGroupHealthCheckArgs( + path="/health", + healthy_threshold=2, + unhealthy_threshold=3, + timeout=5, + interval=30, + ), + tags=tags, +) + +acm_certificate_arn = None # temporary disable HTTPS + +if acm_certificate_arn: + # HTTPS Listener (port 443) + https_listener = aws.lb.Listener( + "https_listener", + load_balancer_arn=alb.arn, + port=443, + protocol="HTTPS", + ssl_policy="ELBSecurityPolicy-TLS13-1-2-2021-06", + certificate_arn=acm_certificate_arn, + default_actions=[ + aws.lb.ListenerDefaultActionArgs( + type="fixed-response", + fixed_response=aws.lb.ListenerDefaultActionFixedResponseArgs( + content_type="text/plain", + message_body="Not Found", + status_code="404", + ), + ) + ], + tags=tags, ) - aws.lightsail.InstancePublicPorts( - f"{name}-ports", - instance_name=inst.name, - port_infos=[ - aws.lightsail.InstancePublicPortsPortInfoArgs( - from_port=22, to_port=22, protocol="tcp", cidrs=["0.0.0.0/0"] - ), - aws.lightsail.InstancePublicPortsPortInfoArgs( - from_port=2377, - to_port=2377, - protocol="tcp", - cidrs=swarm_manager_allowed_cidrs, - ), - aws.lightsail.InstancePublicPortsPortInfoArgs( - from_port=7946, - to_port=7946, - protocol="tcp", - cidrs=swarm_cluster_allowed_cidrs, - ), - aws.lightsail.InstancePublicPortsPortInfoArgs( - from_port=7946, - to_port=7946, - protocol="udp", - cidrs=swarm_cluster_allowed_cidrs, - ), - aws.lightsail.InstancePublicPortsPortInfoArgs( - from_port=4789, - to_port=4789, - protocol="udp", - cidrs=swarm_cluster_allowed_cidrs, - ), - aws.lightsail.InstancePublicPortsPortInfoArgs( - from_port=80, to_port=80, protocol="tcp", cidrs=["0.0.0.0/0"] - ), - aws.lightsail.InstancePublicPortsPortInfoArgs( - from_port=443, to_port=443, protocol="tcp", cidrs=["0.0.0.0/0"] - ), + # HTTP Listener (port 80) - Redirect to HTTPS + http_listener = aws.lb.Listener( + "http_listener", + load_balancer_arn=alb.arn, + port=80, + protocol="HTTP", + default_actions=[ + aws.lb.ListenerDefaultActionArgs( + type="redirect", + redirect=aws.lb.ListenerDefaultActionRedirectArgs( + protocol="HTTPS", + port="443", + status_code="HTTP_301", + ), + ) ], + tags=tags, ) - ip = aws.lightsail.StaticIp(f"{name}-ip", name=f"{name}-ip") - aws.lightsail.StaticIpAttachment( - f"{name}-ip-attach", - instance_name=inst.name, - static_ip_name=ip.name, + alb_listener = https_listener + +else: + # HTTP-only Listener (port 80) + alb_listener = aws.lb.Listener( + "http_listener", + load_balancer_arn=alb.arn, + port=80, + protocol="HTTP", + default_actions=[ + aws.lb.ListenerDefaultActionArgs( + type="fixed-response", + fixed_response=aws.lb.ListenerDefaultActionFixedResponseArgs( + content_type="text/plain", + message_body="Not Found", + status_code="404", + ), + ) + ], + tags=tags, ) - return inst, ip +# Listener Rules for routing attached to primary listener +aws.lb.ListenerRule( + "portfoliomanager_rule", + listener_arn=alb_listener.arn, + priority=200, # Ensures that the more specific data manager paths take precedence + actions=[ + aws.lb.ListenerRuleActionArgs( + type="forward", + target_group_arn=portfoliomanager_tg.arn, + ) + ], + conditions=[ + aws.lb.ListenerRuleConditionArgs( + path_pattern=aws.lb.ListenerRuleConditionPathPatternArgs( + values=["/portfolio*"] + ) + ) + ], + tags=tags, +) +aws.lb.ListenerRule( + "datamanager_rule", + listener_arn=alb_listener.arn, + priority=100, + actions=[ + aws.lb.ListenerRuleActionArgs( + type="forward", + target_group_arn=datamanager_tg.arn, + ) + ], + conditions=[ + aws.lb.ListenerRuleConditionArgs( + path_pattern=aws.lb.ListenerRuleConditionPathPatternArgs( + values=[ + "/predictions*", + "/portfolios*", + "/equity-bars*", + "/equity-details*", + ] + ) + ) + ], + tags=tags, +) -mgr_inst, mgr_ip = mk_instance("swarm-mgr-1", bundle_mgr) -w1_inst, w1_ip = mk_instance("swarm-wkr-1", bundle_wkr) -w2_inst, w2_ip = mk_instance("swarm-wkr-2", bundle_wkr) +# IAM Role for ECS to perform infrastructure tasks +execution_role = aws.iam.Role( + "execution_role", + name="pocketsizefund-ecs-execution-role", + assume_role_policy=json.dumps( + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": {"Service": "ecs-tasks.amazonaws.com"}, + } + ], + } + ), + tags=tags, +) +aws.iam.RolePolicyAttachment( + "execution_role_policy", + role=execution_role.name, + policy_arn="arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy", +) -def conn(host_output: pulumi.Output[str]) -> remote.ConnectionArgs: - return remote.ConnectionArgs( - host=host_output, - user="ubuntu", - private_key=ssh_key.private_key_pem, - ) +# Allow ECS tasks to read secrets from Secrets Manager +aws.iam.RolePolicy( + "execution_role_secrets_policy", + name="pocketsizefund-ecs-execution-role-secrets-policy", + role=execution_role.id, + policy=pulumi.Output.all(secret.arn).apply( + lambda args: json.dumps( + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": ["secretsmanager:GetSecretValue"], + "Resource": args[0], + } + ], + } + ) + ), +) -init_manager = remote.Command( - "init-manager", - connection=conn(mgr_ip.ip_address), - create=" && ".join( # noqa: FLY002 - [ - "bash -lc 'for i in {1..120}; do sudo docker info >/dev/null 2>&1 && break || sleep 3; done'", # noqa: E501 - "bash -lc 'PUBIP=$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4); echo Using-Public-IP:$PUBIP'", # noqa: E501 - 'bash -lc \'STATE=$(sudo docker info --format "{{.Swarm.LocalNodeState}}") || true; ' # noqa: E501 - 'CTRL=$(sudo docker info --format "{{.Swarm.ControlAvailable}}") || true; ' - '[ "$STATE" = active -a "$CTRL" = true ] || ' - "(sudo docker swarm leave --force || true; " - ' sudo docker swarm init --advertise-addr "$PUBIP" --listen-addr "0.0.0.0:2377")\'', # noqa: E501 - "bash -lc 'for i in {1..30}; do sudo ss -ltn | awk \"\\$4 ~ /:2377$/\" && break || sleep 2; done'", # noqa: E501 - "bash -lc 'sudo docker swarm join-token -q worker | sudo tee /home/ubuntu/worker.token >/dev/null'", # noqa: E501 - "bash -lc 'sudo docker swarm join-token -q manager | sudo tee /home/ubuntu/manager.token >/dev/null'", # noqa: E501 - ] +# IAM Role for ECS tasks to access AWS resources +task_role = aws.iam.Role( + "task_role", + name="pocketsizefund-ecs-task-role", + assume_role_policy=json.dumps( + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": {"Service": "ecs-tasks.amazonaws.com"}, + } + ], + } ), + tags=tags, ) +secret_version = aws.secretsmanager.get_secret_version(secret_id=secret.id) +data_bucket_name = pulumi.Output.secret(secret_version.secret_string).apply( + lambda s: json.loads(s)["AWS_S3_DATA_BUCKET_NAME"] +) -get_worker_token = remote.Command( - "get-worker-token", - connection=conn(mgr_ip.ip_address), - create="bash -lc 'sudo docker swarm join-token -q worker'", - opts=pulumi.ResourceOptions(depends_on=[init_manager]), +aws.iam.RolePolicy( + "task_role_s3_policy", + name="pocketsizefund-ecs-task-role-s3-policy", + role=task_role.id, + policy=data_bucket_name.apply( + lambda name: json.dumps( + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": ["s3:GetObject", "s3:PutObject", "s3:ListBucket"], + "Resource": [ + f"arn:aws:s3:::{name}", + f"arn:aws:s3:::{name}/*", + ], + } + ], + } + ) + ), ) -worker_token = pulumi.Output.secret(get_worker_token.stdout).apply(lambda s: s.strip()) +datamanager_log_group = aws.cloudwatch.LogGroup( + "datamanager_logs", + name="/ecs/pocketsizefund/datamanager", + retention_in_days=7, + tags=tags, +) + +portfoliomanager_log_group = aws.cloudwatch.LogGroup( + "portfoliomanager_logs", + name="/ecs/pocketsizefund/portfoliomanager", + retention_in_days=7, + tags=tags, +) + +equitypricemodel_log_group = aws.cloudwatch.LogGroup( + "equitypricemodel_logs", + name="/ecs/pocketsizefund/equitypricemodel", + retention_in_days=7, + tags=tags, +) -def join_worker(res_name: str, worker_ip: pulumi.Output[str]) -> remote.Command: - create_cmd = pulumi.Output.all(mgr_ip.ip_address, worker_token).apply( - lambda vals: ( - "bash -lc 'for i in {1..120}; do sudo docker info >/dev/null 2>&1 && break || sleep 3; done && " # noqa: E501 - f"sudo docker swarm join --token {vals[1]} {vals[0]}:2377'" +datamanager_task_definition = aws.ecs.TaskDefinition( + "datamanager_task", + family="datamanager", + cpu="256", + memory="512", + network_mode="awsvpc", + requires_compatibilities=["FARGATE"], + execution_role_arn=execution_role.arn, + task_role_arn=task_role.arn, + container_definitions=pulumi.Output.all( + datamanager_log_group.name, + datamanager_image.image_uri, + secret.arn, + ).apply( + lambda args: json.dumps( + [ + { + "name": "datamanager", + "image": args[1], + "portMappings": [{"containerPort": 8080, "protocol": "tcp"}], + "secrets": [ + { + "name": "AWS_S3_DATA_BUCKET_NAME", + "valueFrom": f"{args[2]}:AWS_S3_DATA_BUCKET_NAME::", + }, + { + "name": "POLYGON_API_KEY", + "valueFrom": f"{args[2]}:POLYGON_API_KEY::", + }, + ], + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": args[0], + "awslogs-region": region, + "awslogs-stream-prefix": "datamanager", + }, + }, + "essential": True, + } + ] ) - ) - return remote.Command( - res_name, - connection=conn(worker_ip), - create=create_cmd, - opts=pulumi.ResourceOptions(depends_on=[get_worker_token]), - ) + ), + tags=tags, +) + +portfoliomanager_task_definition = aws.ecs.TaskDefinition( + "portfoliomanager_task", + family="portfoliomanager", + cpu="256", + memory="512", + network_mode="awsvpc", + requires_compatibilities=["FARGATE"], + execution_role_arn=execution_role.arn, + container_definitions=pulumi.Output.all( + portfoliomanager_log_group.name, + service_discovery_namespace.name, + portfoliomanager_image.image_uri, + secret.arn, + ).apply( + lambda args: json.dumps( + [ + { + "name": "portfoliomanager", + "image": args[2], + "portMappings": [{"containerPort": 8080, "protocol": "tcp"}], + "environment": [ + { + "name": "PSF_DATAMANAGER_BASE_URL", + "value": f"http://datamanager.{args[1]}:8080", + }, + { + "name": "PSF_EQUITYPRICEMODEL_BASE_URL", + "value": f"http://equitypricemodel.{args[1]}:8080", + }, + ], + "secrets": [ + { + "name": "ALPACA_API_KEY_ID", + "valueFrom": f"{args[3]}:ALPACA_API_KEY_ID::", + }, + { + "name": "ALPACA_API_SECRET", + "valueFrom": f"{args[3]}:ALPACA_API_SECRET::", + }, + { + "name": "ALPACA_IS_PAPER", + "valueFrom": f"{args[3]}:ALPACA_IS_PAPER::", + }, + ], + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": args[0], + "awslogs-region": region, + "awslogs-stream-prefix": "portfoliomanager", + }, + }, + "essential": True, + } + ] + ) + ), + tags=tags, +) + +equitypricemodel_task_definition = aws.ecs.TaskDefinition( + "equitypricemodel_task", + family="equitypricemodel", + cpu="256", + memory="512", + network_mode="awsvpc", + requires_compatibilities=["FARGATE"], + execution_role_arn=execution_role.arn, + container_definitions=pulumi.Output.all( + equitypricemodel_log_group.name, + service_discovery_namespace.name, + equitypricemodel_image.image_uri, + ).apply( + lambda args: json.dumps( + [ + { + "name": "equitypricemodel", + "image": args[2], + "portMappings": [{"containerPort": 8080, "protocol": "tcp"}], + "environment": [ + { + "name": "PSF_DATAMANAGER_BASE_URL", + "value": f"http://datamanager.{args[1]}:8080", + } + ], + "logConfiguration": { + "logDriver": "awslogs", + "options": { + "awslogs-group": args[0], + "awslogs-region": region, + "awslogs-stream-prefix": "equitypricemodel", + }, + }, + "essential": True, + } + ] + ) + ), + tags=tags, +) + +datamanager_sd_service = aws.servicediscovery.Service( + "datamanager_sd", + name="datamanager", + dns_config=aws.servicediscovery.ServiceDnsConfigArgs( + namespace_id=service_discovery_namespace.id, + dns_records=[ + aws.servicediscovery.ServiceDnsConfigDnsRecordArgs(ttl=10, type="A") + ], + ), + tags=tags, +) + +portfoliomanager_sd_service = aws.servicediscovery.Service( + "portfoliomanager_sd", + name="portfoliomanager", + dns_config=aws.servicediscovery.ServiceDnsConfigArgs( + namespace_id=service_discovery_namespace.id, + dns_records=[ + aws.servicediscovery.ServiceDnsConfigDnsRecordArgs(ttl=10, type="A") + ], + ), + tags=tags, +) + +equitypricemodel_sd_service = aws.servicediscovery.Service( + "equitypricemodel_sd", + name="equitypricemodel", + dns_config=aws.servicediscovery.ServiceDnsConfigArgs( + namespace_id=service_discovery_namespace.id, + dns_records=[ + aws.servicediscovery.ServiceDnsConfigDnsRecordArgs(ttl=10, type="A") + ], + ), + tags=tags, +) + +datamanager_service = aws.ecs.Service( + "datamanager_service", + name="pocketsizefund-datamanager", + cluster=cluster.arn, + task_definition=datamanager_task_definition.arn, + desired_count=1, + launch_type="FARGATE", + network_configuration=aws.ecs.ServiceNetworkConfigurationArgs( + subnets=[private_subnet_1.id, private_subnet_2.id], + security_groups=[ecs_security_group.id], + assign_public_ip=False, + ), + load_balancers=[ + aws.ecs.ServiceLoadBalancerArgs( + target_group_arn=datamanager_tg.arn, + container_name="datamanager", + container_port=8080, + ) + ], + service_registries=aws.ecs.ServiceServiceRegistriesArgs( + registry_arn=datamanager_sd_service.arn + ), + opts=pulumi.ResourceOptions(depends_on=[alb_listener]), + tags=tags, +) + +portfoliomanager_service = aws.ecs.Service( + "portfoliomanager_service", + name="pocketsizefund-portfoliomanager", + cluster=cluster.arn, + task_definition=portfoliomanager_task_definition.arn, + desired_count=1, + launch_type="FARGATE", + network_configuration=aws.ecs.ServiceNetworkConfigurationArgs( + subnets=[private_subnet_1.id, private_subnet_2.id], + security_groups=[ecs_security_group.id], + assign_public_ip=False, + ), + load_balancers=[ + aws.ecs.ServiceLoadBalancerArgs( + target_group_arn=portfoliomanager_tg.arn, + container_name="portfoliomanager", + container_port=8080, + ) + ], + service_registries=aws.ecs.ServiceServiceRegistriesArgs( + registry_arn=portfoliomanager_sd_service.arn + ), + opts=pulumi.ResourceOptions(depends_on=[alb_listener, datamanager_service]), + tags=tags, +) + +equitypricemodel_service = aws.ecs.Service( + "equitypricemodel_service", + name="pocketsizefund-equitypricemodel", + cluster=cluster.arn, + task_definition=equitypricemodel_task_definition.arn, + desired_count=1, + launch_type="FARGATE", + network_configuration=aws.ecs.ServiceNetworkConfigurationArgs( + subnets=[private_subnet_1.id, private_subnet_2.id], + security_groups=[ecs_security_group.id], + assign_public_ip=False, + ), + service_registries=aws.ecs.ServiceServiceRegistriesArgs( + registry_arn=equitypricemodel_sd_service.arn + ), + opts=pulumi.ResourceOptions(depends_on=[datamanager_service]), + tags=tags, +) + +protocol = "https://" if acm_certificate_arn else "http://" + +psf_base_url = pulumi.Output.concat(protocol, alb.dns_name) + +readme_content = """ +# infrastructure + +> Application infrastructure resources +## Outputs -join_w1 = join_worker("join-w1", w1_ip.ip_address) -join_w2 = join_worker("join-w2", w2_ip.ip_address) +- base URL: {0} +""" -pulumi.export("managerIp", mgr_ip.ip_address) -pulumi.export("workerIps", pulumi.Output.all(w1_ip.ip_address, w2_ip.ip_address)) -pulumi.export("sshPrivateKeyPem", pulumi.Output.secret(ssh_key.private_key_pem)) +pulumi.export("aws_account_id", account_id) +pulumi.export("aws_vpc_id", vpc.id) +pulumi.export("aws_ecs_cluster_name", cluster.name) +pulumi.export("aws_alb_dns_name", alb.dns_name) +pulumi.export("aws_alb_url", pulumi.Output.concat(protocol, alb.dns_name)) +pulumi.export("aws_service_discovery_namespace", service_discovery_namespace.name) +pulumi.export("aws_ecr_datamanager_image", datamanager_image.image_uri) +pulumi.export("aws_ecr_portfoliomanager_image", portfoliomanager_image.image_uri) +pulumi.export("aws_ecr_equitypricemodel_image", equitypricemodel_image.image_uri) +pulumi.export("psf_base_url", psf_base_url) +pulumi.export("readme", pulumi.Output.format(readme_content, psf_base_url)) diff --git a/infrastructure/docker-compose.yaml b/infrastructure/docker-compose.yaml new file mode 100644 index 000000000..e50d83d47 --- /dev/null +++ b/infrastructure/docker-compose.yaml @@ -0,0 +1,51 @@ +version: "3.9" +services: + datamanager: + image: ${AWS_ECR_DATA_MANAGER_SERVER_IMAGE_ARN} + ports: + - "8080:8080" + networks: + - app-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health"] + interval: 30s + timeout: 5s + retries: 3 + + portfoliomanager: + image: ${AWS_ECR_PORTFOLIO_MANAGER_SERVER_IMAGE_ARN} + ports: + - "8081:8080" + environment: + - DATAMANAGER_BASE_URL=http://datamanager:8080 + - EQUITYPRICEMODEL_BASE_URL=http://equitypricemodel:8080 + networks: + - app-network + depends_on: + - datamanager + - equitypricemodel + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health"] + interval: 30s + timeout: 5s + retries: 3 + + equitypricemodel: + image: ${AWS_ECR_EQUITY_PRICE_MODEL_SERVER_IMAGE_ARN} + ports: + - "8082:8080" + environment: + - DATAMANAGER_BASE_URL=http://datamanager:8080 + networks: + - app-network + depends_on: + - datamanager + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health"] + interval: 30s + timeout: 5s + retries: 3 + +networks: + app-network: + driver: bridge diff --git a/infrastructure/environment_variables.py b/infrastructure/environment_variables.py deleted file mode 100644 index aad13eac0..000000000 --- a/infrastructure/environment_variables.py +++ /dev/null @@ -1,32 +0,0 @@ -import pulumi -import pulumi_aws as aws -from pulumi.config import Config - -configuration = Config() - - -alpaca_api_key_id = configuration.require_secret("ALPACA_API_KEY_ID") -alpaca_api_secret = configuration.require_secret("ALPACA_API_SECRET") -data_bucket_name = configuration.require_secret("DATA_BUCKET_NAME") -polygon_api_key = configuration.require_secret("POLYGON_API_KEY") -duckdb_access_key = configuration.require_secret("DUCKDB_ACCESS_KEY") -duckdb_secret = configuration.require_secret("DUCKDB_SECRET") -aws_region = configuration.get("aws:region") or "us-east-1" - - -def create_environment_variables( - duckdb_user_access_key: aws.iam.AccessKey, -) -> pulumi.Output[dict[str, str]]: - return pulumi.Output.all( - [ - ("ALPACA_API_KEY_ID", alpaca_api_key_id), - ("ALPACA_API_SECRET", alpaca_api_secret), - ("DATA_BUCKET_NAME", data_bucket_name), - ("POLYGON_API_KEY", polygon_api_key), - ("DUCKDB_ACCESS_KEY", duckdb_access_key), - ("DUCKDB_SECRET", duckdb_secret), - ("AWS_REGION", aws_region), - ("DUCKDB_USER_ACCESS_KEY_ID", duckdb_user_access_key.id), - ("DUCKDB_USER_ACCESS_KEY_SECRET", duckdb_user_access_key.secret), - ] - ).apply(lambda secrets: dict(secrets)) diff --git a/infrastructure/images.py b/infrastructure/images.py deleted file mode 100644 index 9bb5e6d2c..000000000 --- a/infrastructure/images.py +++ /dev/null @@ -1,37 +0,0 @@ -from pathlib import Path - -import pulumi -import pulumi_docker_build as docker_build -from pulumi.config import Config - -configuration = Config() - - -def build_image( - service_name: str, - service_version: str, - dockerhub_username: pulumi.Output[str], - dockerhub_password: pulumi.Output[str], -) -> docker_build.Image: - service_directory = Path("../applications") / service_name - if not service_directory.exists(): - message = f"Service directory not found: {service_directory}" - raise FileNotFoundError(message) - - return docker_build.Image( - resource_name=f"pocketsizefund-{service_name}-image", - tags=[f"pocketsizefund/{service_name}:{service_version}"], - context=docker_build.BuildContextArgs(location=str(service_directory)), - platforms=[ - docker_build.Platform.LINUX_AMD64, - docker_build.Platform.LINUX_ARM64, - ], - push=True, - registries=[ - docker_build.RegistryArgs( - address="docker.io", - username=dockerhub_username, - password=dockerhub_password, - ) - ], - ) diff --git a/infrastructure/main.nu b/infrastructure/main.nu deleted file mode 100644 index 8e95ddd86..000000000 --- a/infrastructure/main.nu +++ /dev/null @@ -1,57 +0,0 @@ -def create-contexts [] { - do { - docker context rm -f pocketsizefund - docker context rm -f pocketsizefund-local - } | ignore - docker context create pocketsizefund --docker "host=ssh://pocketsizefund-swarm" - docker context create pocketsizefund-local -} - -def launch-stacks [context: string] { - docker context use $context - docker stack deploy -c stack.yml infrastructure --detach=false -} - -def "infrastructure up" [] { - ^pulumi up --yes - let manager_ip = (^pulumi stack output managerIp | str trim) - let pem = (^pulumi stack output --show-secrets sshPrivateKeyPem) - - $pem | save --raw --force swarm.pem - chmod 600 swarm.pem - - let ssh_cfg = $"($env.HOME)/.ssh/config" - let block = $" -Host pocketsizefund-swarm - HostName ($manager_ip) - User ubuntu - IdentityFile ($env.PWD)/swarm.pem - IdentitiesOnly yes - StrictHostKeyChecking accept-new -" - if (ls $ssh_cfg | is-empty) { - $block | save --raw --force $ssh_cfg -} else { - let cfg = (open --raw $ssh_cfg) - let filtered = ($cfg - | lines - | reduce -f [] { |it, acc| - if ($it | str starts-with "Host pocketsizefund-swarm") { $acc } else { $acc | append $it } - } - | str join (char nl)) - $filtered | save --raw --force $ssh_cfg - $"\n($block)" | save --raw --append $ssh_cfg - } - - ssh-keygen -R $manager_ip | ignore - ssh-keyscan -H $manager_ip | save --append $"($env.HOME)/.ssh/known_hosts" - - ssh pocketsizefund-swarm 'docker info -f "{{.ServerVersion}} {{.Swarm.LocalNodeState}}"' - - create-contexts - - launch-stacks pocketsizefund - launch-stacks pocketsizefund-local - - docker node ls -} diff --git a/infrastructure/prometheus.yml b/infrastructure/prometheus.yml deleted file mode 100644 index 5fa95f88e..000000000 --- a/infrastructure/prometheus.yml +++ /dev/null @@ -1,16 +0,0 @@ -global: - scrape_interval: 15s - evaluation_interval: 15s - -scrape_configs: - - job_name: prometheus - static_configs: - - targets: ['prometheus:9090'] - - - job_name: node-exporter - static_configs: - - targets: ['tasks.node-exporter:9100'] - - - job_name: cadvisor - static_configs: - - targets: ['tasks.cadvisor:8080'] diff --git a/infrastructure/pyproject.toml b/infrastructure/pyproject.toml index 3d0938c99..f39f7174e 100644 --- a/infrastructure/pyproject.toml +++ b/infrastructure/pyproject.toml @@ -2,11 +2,11 @@ name = "infrastructure" version = "0.1.0" description = "Infrastructure management with Pulumi" -readme = "README.md" requires-python = "==3.12.10" dependencies = [ - "pulumi>=3.189.0", - "pulumi-aws>=7.4.0", - "pulumi-command>=1.1.0", - "pulumi-tls>=5.2.1", + "pulumi>=3.189.0", + "pulumi-aws>=7.4.0", + "pulumi-command>=1.1.0", + "pulumi-docker>=4.10.0", + "pulumi-tls>=5.2.1", ] diff --git a/infrastructure/requirements.txt b/infrastructure/requirements.txt deleted file mode 100644 index 9a1b8d0fb..000000000 --- a/infrastructure/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pulumi>=3.0.0,<4.0.0 -pulumi-aws>=7.0.0,<8.0.0 diff --git a/infrastructure/stack.yml b/infrastructure/stack.yml deleted file mode 100644 index 863bae429..000000000 --- a/infrastructure/stack.yml +++ /dev/null @@ -1,143 +0,0 @@ -version: "3.9" - -networks: - public: - driver: overlay - attachable: true - internal: - driver: overlay - attachable: true - -volumes: - traefik_letsencrypt: - portainer_data: - prom_data: - grafana_data: - -secrets: - GRAFANA_ADMIN_PASSWORD: - external: true - -configs: - prometheus.yml: - name: prometheus.yml - file: ./prometheus.yml - -services: - # Network Services - traefik: - image: traefik:v3.1 - command: - - --providers.swarm.endpoint=unix:///var/run/docker.sock - - --providers.swarm.exposedByDefault=false - - --entrypoints.web.address=:80 - - --entrypoints.websecure.address=:443 - - --api.dashboard=true - - --metrics.prometheus=true - - --metrics.prometheus.addEntryPointsLabels=true - - --metrics.prometheus.addServicesLabels=true - ports: - - target: 80 - published: 80 - protocol: tcp - mode: host - - target: 443 - published: 443 - protocol: tcp - mode: host - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - deploy: - placement: - constraints: [node.role == manager] - update_config: - parallelism: 1 - order: start-first - networks: [public] - - portainer: - image: portainer/portainer-ce:latest - ports: - - "9000:9000" - - "9443:9443" - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - portainer_data:/data - networks: - - public - deploy: - placement: - constraints: - - node.role == manager - - # Monitoring Services - prometheus: - image: prom/prometheus:v2.52.0 - command: - - --config.file=/etc/prometheus/prometheus.yml - - --storage.tsdb.path=/prometheus - - --storage.tsdb.retention.time=15d - - --web.enable-lifecycle - volumes: - - prom_data:/prometheus - configs: - - source: prometheus.yml - target: /etc/prometheus/prometheus.yml - deploy: - placement: - constraints: [node.role == manager] - resources: - reservations: { memory: 256M } - limits: { memory: 1G } - networks: [internal] - - node-exporter: - image: prom/node-exporter:v1.8.1 - command: - - --path.rootfs=/host - - --collector.filesystem.mount-points-exclude=^/(dev|proc|run|sys|var/lib/docker/.+|var/lib/kubelet/.+|var/lib/containers/.+)($$|/) - - --no-collector.hwmon - deploy: - mode: global - resources: - reservations: { memory: 64M } - limits: { memory: 256M } - volumes: - - /:/host:ro,rslave - networks: [internal] - - cadvisor: - image: gcr.io/cadvisor/cadvisor:v0.47.2 - deploy: - mode: global - resources: - reservations: { memory: 128M } - limits: { memory: 512M } - volumes: - - /:/rootfs:ro - - /var/run:/var/run:rw - - /sys:/sys:ro - - /var/lib/docker/:/var/lib/docker:ro - networks: [internal] - - grafana: - image: grafana/grafana:10.4.2 - environment: - GF_SECURITY_ADMIN_USER: admin - GF_SECURITY_ADMIN_PASSWORD_FILE: /run/secrets/GRAFANA_ADMIN_PASSWORD - secrets: - - GRAFANA_ADMIN_PASSWORD - volumes: - - grafana_data:/var/lib/grafana - deploy: - placement: - constraints: [node.role == manager] - resources: - reservations: { memory: 128M } - limits: { memory: 512M } - labels: - - traefik.enable=true - - traefik.http.routers.grafana.rule=Host(`grafana.example.com`) - - traefik.http.routers.grafana.entrypoints=web - - traefik.http.services.grafana.loadbalancer.server.port=3000 - networks: [public, internal] diff --git a/infrastructure/uv.lock b/infrastructure/uv.lock deleted file mode 100644 index 6692f07a1..000000000 --- a/infrastructure/uv.lock +++ /dev/null @@ -1,201 +0,0 @@ -version = 1 -revision = 2 -requires-python = "==3.12.10" - -[[package]] -name = "arpeggio" -version = "2.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/c4/516bb54456f85ad1947702ea4cef543a59de66d31a9887dbc3d9df36e3e1/Arpeggio-2.0.2.tar.gz", hash = "sha256:c790b2b06e226d2dd468e4fbfb5b7f506cec66416031fde1441cf1de2a0ba700", size = 766643, upload-time = "2023-07-09T12:30:04.737Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/4f/d28bf30a19d4649b40b501d531b44e73afada99044df100380fd9567e92f/Arpeggio-2.0.2-py2.py3-none-any.whl", hash = "sha256:f7c8ae4f4056a89e020c24c7202ac8df3e2bc84e416746f20b0da35bb1de0250", size = 55287, upload-time = "2023-07-09T12:30:01.87Z" }, -] - -[[package]] -name = "attrs" -version = "25.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, -] - -[[package]] -name = "debugpy" -version = "1.8.16" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/d4/722d0bcc7986172ac2ef3c979ad56a1030e3afd44ced136d45f8142b1f4a/debugpy-1.8.16.tar.gz", hash = "sha256:31e69a1feb1cf6b51efbed3f6c9b0ef03bc46ff050679c4be7ea6d2e23540870", size = 1643809, upload-time = "2025-08-06T18:00:02.647Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/fb/0387c0e108d842c902801bc65ccc53e5b91d8c169702a9bbf4f7efcedf0c/debugpy-1.8.16-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:b202e2843e32e80b3b584bcebfe0e65e0392920dc70df11b2bfe1afcb7a085e4", size = 2511822, upload-time = "2025-08-06T18:00:18.526Z" }, - { url = "https://files.pythonhosted.org/packages/37/44/19e02745cae22bf96440141f94e15a69a1afaa3a64ddfc38004668fcdebf/debugpy-1.8.16-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64473c4a306ba11a99fe0bb14622ba4fbd943eb004847d9b69b107bde45aa9ea", size = 4230135, upload-time = "2025-08-06T18:00:19.997Z" }, - { url = "https://files.pythonhosted.org/packages/f3/0b/19b1ba5ee4412f303475a2c7ad5858efb99c90eae5ec627aa6275c439957/debugpy-1.8.16-cp312-cp312-win32.whl", hash = "sha256:833a61ed446426e38b0dd8be3e9d45ae285d424f5bf6cd5b2b559c8f12305508", size = 5281271, upload-time = "2025-08-06T18:00:21.281Z" }, - { url = "https://files.pythonhosted.org/packages/b1/e0/bc62e2dc141de53bd03e2c7cb9d7011de2e65e8bdcdaa26703e4d28656ba/debugpy-1.8.16-cp312-cp312-win_amd64.whl", hash = "sha256:75f204684581e9ef3dc2f67687c3c8c183fde2d6675ab131d94084baf8084121", size = 5323149, upload-time = "2025-08-06T18:00:23.033Z" }, - { url = "https://files.pythonhosted.org/packages/52/57/ecc9ae29fa5b2d90107cd1d9bf8ed19aacb74b2264d986ae9d44fe9bdf87/debugpy-1.8.16-py2.py3-none-any.whl", hash = "sha256:19c9521962475b87da6f673514f7fd610328757ec993bf7ec0d8c96f9a325f9e", size = 5287700, upload-time = "2025-08-06T18:00:42.333Z" }, -] - -[[package]] -name = "dill" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, -] - -[[package]] -name = "grpcio" -version = "1.74.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/38/b4/35feb8f7cab7239c5b94bd2db71abb3d6adb5f335ad8f131abb6060840b6/grpcio-1.74.0.tar.gz", hash = "sha256:80d1f4fbb35b0742d3e3d3bb654b7381cd5f015f8497279a1e9c21ba623e01b1", size = 12756048, upload-time = "2025-07-24T18:54:23.039Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/5d/e504d5d5c4469823504f65687d6c8fb97b7f7bf0b34873b7598f1df24630/grpcio-1.74.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8533e6e9c5bd630ca98062e3a1326249e6ada07d05acf191a77bc33f8948f3d8", size = 5445551, upload-time = "2025-07-24T18:53:23.641Z" }, - { url = "https://files.pythonhosted.org/packages/43/01/730e37056f96f2f6ce9f17999af1556df62ee8dab7fa48bceeaab5fd3008/grpcio-1.74.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:2918948864fec2a11721d91568effffbe0a02b23ecd57f281391d986847982f6", size = 10979810, upload-time = "2025-07-24T18:53:25.349Z" }, - { url = "https://files.pythonhosted.org/packages/79/3d/09fd100473ea5c47083889ca47ffd356576173ec134312f6aa0e13111dee/grpcio-1.74.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:60d2d48b0580e70d2e1954d0d19fa3c2e60dd7cbed826aca104fff518310d1c5", size = 5941946, upload-time = "2025-07-24T18:53:27.387Z" }, - { url = "https://files.pythonhosted.org/packages/8a/99/12d2cca0a63c874c6d3d195629dcd85cdf5d6f98a30d8db44271f8a97b93/grpcio-1.74.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3601274bc0523f6dc07666c0e01682c94472402ac2fd1226fd96e079863bfa49", size = 6621763, upload-time = "2025-07-24T18:53:29.193Z" }, - { url = "https://files.pythonhosted.org/packages/9d/2c/930b0e7a2f1029bbc193443c7bc4dc2a46fedb0203c8793dcd97081f1520/grpcio-1.74.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:176d60a5168d7948539def20b2a3adcce67d72454d9ae05969a2e73f3a0feee7", size = 6180664, upload-time = "2025-07-24T18:53:30.823Z" }, - { url = "https://files.pythonhosted.org/packages/db/d5/ff8a2442180ad0867717e670f5ec42bfd8d38b92158ad6bcd864e6d4b1ed/grpcio-1.74.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e759f9e8bc908aaae0412642afe5416c9f983a80499448fcc7fab8692ae044c3", size = 6301083, upload-time = "2025-07-24T18:53:32.454Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ba/b361d390451a37ca118e4ec7dccec690422e05bc85fba2ec72b06cefec9f/grpcio-1.74.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9e7c4389771855a92934b2846bd807fc25a3dfa820fd912fe6bd8136026b2707", size = 6994132, upload-time = "2025-07-24T18:53:34.506Z" }, - { url = "https://files.pythonhosted.org/packages/3b/0c/3a5fa47d2437a44ced74141795ac0251bbddeae74bf81df3447edd767d27/grpcio-1.74.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cce634b10aeab37010449124814b05a62fb5f18928ca878f1bf4750d1f0c815b", size = 6489616, upload-time = "2025-07-24T18:53:36.217Z" }, - { url = "https://files.pythonhosted.org/packages/ae/95/ab64703b436d99dc5217228babc76047d60e9ad14df129e307b5fec81fd0/grpcio-1.74.0-cp312-cp312-win32.whl", hash = "sha256:885912559974df35d92219e2dc98f51a16a48395f37b92865ad45186f294096c", size = 3807083, upload-time = "2025-07-24T18:53:37.911Z" }, - { url = "https://files.pythonhosted.org/packages/84/59/900aa2445891fc47a33f7d2f76e00ca5d6ae6584b20d19af9c06fa09bf9a/grpcio-1.74.0-cp312-cp312-win_amd64.whl", hash = "sha256:42f8fee287427b94be63d916c90399ed310ed10aadbf9e2e5538b3e497d269bc", size = 4490123, upload-time = "2025-07-24T18:53:39.528Z" }, -] - -[[package]] -name = "infrastructure" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "pulumi" }, - { name = "pulumi-aws" }, - { name = "pulumi-command" }, - { name = "pulumi-tls" }, -] - -[package.metadata] -requires-dist = [ - { name = "pulumi", specifier = ">=3.189.0" }, - { name = "pulumi-aws", specifier = ">=7.4.0" }, - { name = "pulumi-command", specifier = ">=1.1.0" }, - { name = "pulumi-tls", specifier = ">=5.2.1" }, -] - -[[package]] -name = "parver" -version = "0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "arpeggio" }, - { name = "attrs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cc/e5/1c774688a90f0b76e872e30f6f1ba3f5e14056cd0d96a684047d4a986226/parver-0.5.tar.gz", hash = "sha256:b9fde1e6bb9ce9f07e08e9c4bea8d8825c5e78e18a0052d02e02bf9517eb4777", size = 26908, upload-time = "2023-10-03T21:06:54.506Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/4c/f98024021bef4d44dce3613feebd702c7ad8883f777ff8488384c59e9774/parver-0.5-py3-none-any.whl", hash = "sha256:2281b187276c8e8e3c15634f62287b2fb6fe0efe3010f739a6bd1e45fa2bf2b2", size = 15172, upload-time = "2023-10-03T21:06:52.796Z" }, -] - -[[package]] -name = "pip" -version = "25.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/16/650289cd3f43d5a2fadfd98c68bd1e1e7f2550a1a5326768cddfbcedb2c5/pip-25.2.tar.gz", hash = "sha256:578283f006390f85bb6282dffb876454593d637f5d1be494b5202ce4877e71f2", size = 1840021, upload-time = "2025-07-30T21:50:15.401Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/3f/945ef7ab14dc4f9d7f40288d2df998d1837ee0888ec3659c813487572faa/pip-25.2-py3-none-any.whl", hash = "sha256:6d67a2b4e7f14d8b31b8b52648866fa717f45a1eb70e83002f4331d07e953717", size = 1752557, upload-time = "2025-07-30T21:50:13.323Z" }, -] - -[[package]] -name = "protobuf" -version = "5.29.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/29/d09e70352e4e88c9c7a198d5645d7277811448d76c23b00345670f7c8a38/protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84", size = 425226, upload-time = "2025-05-28T23:51:59.82Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/11/6e40e9fc5bba02988a214c07cf324595789ca7820160bfd1f8be96e48539/protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079", size = 422963, upload-time = "2025-05-28T23:51:41.204Z" }, - { url = "https://files.pythonhosted.org/packages/81/7f/73cefb093e1a2a7c3ffd839e6f9fcafb7a427d300c7f8aef9c64405d8ac6/protobuf-5.29.5-cp310-abi3-win_amd64.whl", hash = "sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc", size = 434818, upload-time = "2025-05-28T23:51:44.297Z" }, - { url = "https://files.pythonhosted.org/packages/dd/73/10e1661c21f139f2c6ad9b23040ff36fee624310dc28fba20d33fdae124c/protobuf-5.29.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671", size = 418091, upload-time = "2025-05-28T23:51:45.907Z" }, - { url = "https://files.pythonhosted.org/packages/6c/04/98f6f8cf5b07ab1294c13f34b4e69b3722bb609c5b701d6c169828f9f8aa/protobuf-5.29.5-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015", size = 319824, upload-time = "2025-05-28T23:51:47.545Z" }, - { url = "https://files.pythonhosted.org/packages/85/e4/07c80521879c2d15f321465ac24c70efe2381378c00bf5e56a0f4fbac8cd/protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61", size = 319942, upload-time = "2025-05-28T23:51:49.11Z" }, - { url = "https://files.pythonhosted.org/packages/7e/cc/7e77861000a0691aeea8f4566e5d3aa716f2b1dece4a24439437e41d3d25/protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5", size = 172823, upload-time = "2025-05-28T23:51:58.157Z" }, -] - -[[package]] -name = "pulumi" -version = "3.190.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "debugpy" }, - { name = "dill" }, - { name = "grpcio" }, - { name = "pip" }, - { name = "protobuf" }, - { name = "pyyaml" }, - { name = "semver" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/c7/25246c8bd05b72986f42d9c2adf561162dbade160a2b52adfa7873b30dc0/pulumi-3.190.0-py3-none-any.whl", hash = "sha256:aff2de5098e7ab24bee0e22b2fde81e0775b65ca03e5f13e9fe9c6cc8a420b63", size = 375069, upload-time = "2025-08-15T17:57:34.315Z" }, -] - -[[package]] -name = "pulumi-aws" -version = "7.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parver" }, - { name = "pulumi" }, - { name = "semver" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d4/20/315ba5d2b9f909dbb5ade876bfdeabad79f1234034afd094be804dd7efdc/pulumi_aws-7.4.0.tar.gz", hash = "sha256:a6d75b04c2a92e33ef2ec22f17ca6ed69040cbbbb655374010b1674ce39382a6", size = 8048045, upload-time = "2025-08-13T18:07:29.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/ba/ba48586cd1b8da9c6ea605bcaeb2d3812fce8ef37391829ea60a77dcd585/pulumi_aws-7.4.0-py3-none-any.whl", hash = "sha256:f478977de19567f96851c7c9ac2555f90f0afdaa2098550d810f303f5f96570e", size = 10933831, upload-time = "2025-08-13T18:07:25.769Z" }, -] - -[[package]] -name = "pulumi-command" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parver" }, - { name = "pulumi" }, - { name = "semver" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/96/b4/03d37a61e49b636b7cd5ba72a28996f07a18d815e6ba2343f6071b77fc51/pulumi_command-1.1.0.tar.gz", hash = "sha256:509b2709938aacfb13717b7b537d728375cd90b409093bf24dacab17d9294a4a", size = 33072, upload-time = "2025-05-27T18:25:11.671Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/f4/c89295ca63e2555cda4b4e16069200cf04262ac87ae263c48562f8297cc8/pulumi_command-1.1.0-py3-none-any.whl", hash = "sha256:d6a62444a1a9a26ded354b668a9cf88c0becd4faacabe4adafbc8dbb65af96c4", size = 36859, upload-time = "2025-05-27T18:25:10.401Z" }, -] - -[[package]] -name = "pulumi-tls" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parver" }, - { name = "pulumi" }, - { name = "semver" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/3a/fca66fb609fa557da5bc7f504c607a4e2be624367e6f7cc6de66aee713f8/pulumi_tls-5.2.1.tar.gz", hash = "sha256:c4eae9d74b40fcc4a50a5b572e53b8564d5cda8172484f4abf273ede7e97147e", size = 26547, upload-time = "2025-07-24T23:30:36.781Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/12/f5035bbfe624279a4838ec824ec8a6d34e9351f6780def8c2ab0ce965a0c/pulumi_tls-5.2.1-py3-none-any.whl", hash = "sha256:021752347ee0381be3183969195d3dbea39696d3d6bad1c19f790b976e2db622", size = 34982, upload-time = "2025-07-24T23:30:35.466Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, -] - -[[package]] -name = "semver" -version = "3.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/d1/d3159231aec234a59dd7d601e9dd9fe96f3afff15efd33c1070019b26132/semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602", size = 269730, upload-time = "2025-01-24T13:19:27.617Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746", size = 17912, upload-time = "2025-01-24T13:19:24.949Z" }, -] diff --git a/libraries/python/pyproject.toml b/libraries/python/pyproject.toml index 2659936e7..4e086c717 100644 --- a/libraries/python/pyproject.toml +++ b/libraries/python/pyproject.toml @@ -3,14 +3,7 @@ name = "internal" version = "0.1.0" description = "Shared Python resources" requires-python = "==3.12.10" -dependencies = [ - "pydantic>=2.8.2", - "cloudevents>=1.12.0", - "tinygrad>=0.10.3", - "numpy>=2.2.6", - "polars>=1.29.0", - "pandera[polars]>=0.26.0", -] +dependencies = ["polars>=1.29.0", "pandera[polars]>=0.26.0"] [tool.uv] package = true diff --git a/libraries/python/src/internal/cloud_event.py b/libraries/python/src/internal/cloud_event.py deleted file mode 100644 index 669ebdeae..000000000 --- a/libraries/python/src/internal/cloud_event.py +++ /dev/null @@ -1,38 +0,0 @@ -from datetime import datetime -from zoneinfo import ZoneInfo - -from cloudevents.pydantic.v2 import CloudEvent - - -def create_cloud_event_success( - application_name: str, - event_metadata: list[str], - data: dict, -) -> CloudEvent: - return CloudEvent( - attributes={ - "source": application_name, - "type": f"application.{application_name}.{'.'.join(event_metadata)}", - }, - data={ - "date": datetime.now(tz=ZoneInfo("America/New_York")).isoformat(), - **data, - }, - ) - - -def create_cloud_event_error( - application_name: str, - event_metadata: list[str], - error_message: str, -) -> CloudEvent: - return CloudEvent( - attributes={ - "source": application_name, - "type": f"application.{application_name}.{'.'.join(event_metadata)}", - }, - data={ - "date": datetime.now(tz=ZoneInfo("America/New_York")).isoformat(), - "error": error_message, - }, - ) diff --git a/libraries/python/src/internal/dates.py b/libraries/python/src/internal/dates.py deleted file mode 100644 index de2e3903b..000000000 --- a/libraries/python/src/internal/dates.py +++ /dev/null @@ -1,55 +0,0 @@ -import datetime -from zoneinfo import ZoneInfo - -from pydantic import BaseModel, Field, field_validator -from pydantic_core import core_schema - - -class Date(BaseModel): - date: datetime.date = Field( - default_factory=lambda: datetime.datetime.now( - ZoneInfo("America/New_York") - ).date(), - ) - - @field_validator("date", mode="before") - def parse_date(cls, value: datetime.date | str) -> datetime.date: # noqa: N805 - if isinstance(value, datetime.date): - return value - for fmt in ("%Y-%m-%d", "%Y/%m/%d"): - try: - return ( - datetime.datetime.strptime(value, fmt) - .replace(tzinfo=ZoneInfo("America/New_York")) - .date() - ) - except ValueError: - continue - msg = "Invalid date format: expected YYYY-MM-DD or YYYY/MM/DD" - raise ValueError(msg) - - model_config = {"json_encoders": {datetime.date: lambda d: d.strftime("%Y/%m/%d")}} - - -class DateRange(BaseModel): - start: datetime.date - end: datetime.date - - @field_validator("end") - @classmethod - def check_end_after_start( - cls, - end_value: datetime.datetime, - info: core_schema.ValidationInfo, - ) -> datetime.datetime: - start_value = info.data.get("start") - if start_value and end_value <= start_value: - msg = "End date must be after start date." - raise ValueError(msg) - return end_value - - def to_object(self) -> dict[str, str]: - return { - "start_date": self.start.isoformat(), - "end_date": self.end.isoformat(), - } diff --git a/libraries/python/src/internal/equity_bar.py b/libraries/python/src/internal/equity_bars_schema.py similarity index 79% rename from libraries/python/src/internal/equity_bar.py rename to libraries/python/src/internal/equity_bars_schema.py index 4e66a262a..14eb33a59 100644 --- a/libraries/python/src/internal/equity_bar.py +++ b/libraries/python/src/internal/equity_bars_schema.py @@ -1,7 +1,7 @@ import pandera.polars as pa import polars as pl -equity_bar_schema = pa.DataFrameSchema( +equity_bars_schema = pa.DataFrameSchema( { "ticker": pa.Column( dtype=str, @@ -19,7 +19,9 @@ ), "open_price": pa.Column( dtype=float, - checks=[pa.Check.greater_than(0)], + checks=[ + pa.Check.greater_than(0) + ], # raw data will not have missing days and therefore no zero values ), "high_price": pa.Column( dtype=float, @@ -42,6 +44,11 @@ nullable=True, checks=[pa.Check.greater_than_or_equal_to(0)], ), + "transactions": pa.Column( + dtype=int, + nullable=True, + checks=[pa.Check.greater_than_or_equal_to(0)], + ), }, unique=["ticker", "timestamp"], strict="filter", # allows DuckDB partion columns diff --git a/libraries/python/src/internal/loss_functions.py b/libraries/python/src/internal/loss_functions.py deleted file mode 100644 index a11559e6d..000000000 --- a/libraries/python/src/internal/loss_functions.py +++ /dev/null @@ -1,28 +0,0 @@ -from tinygrad.tensor import Tensor - - -def quantile_loss( - predictions: Tensor, # shape: (batch_size, output_size, len(quantiles)) - targets: Tensor, # shape: (batch_size, output_size) - quantiles: list[float] | None = None, -) -> Tensor: - if quantiles is None: - quantiles = [0.1, 0.5, 0.9] - - if not all(0 <= q <= 1 for q in quantiles): - message = "All quantiles must be between 0 and 1" - raise ValueError(message) - - errors_total = Tensor.zeros((1,)) - for index, quantile in enumerate(quantiles): - error = targets.sub(predictions[:, :, index]) - quantile_tensor = Tensor([quantile]) - errors_total = errors_total.add( - Tensor.where( - error > 0, - quantile_tensor.mul(error), - (quantile_tensor.sub(1)).mul(error), - ).mean() - ) - - return errors_total.div(len(quantiles)) # shape: (1,) diff --git a/libraries/python/src/internal/lstm_network.py b/libraries/python/src/internal/lstm_network.py deleted file mode 100644 index c00119130..000000000 --- a/libraries/python/src/internal/lstm_network.py +++ /dev/null @@ -1,85 +0,0 @@ -from tinygrad.nn import LSTMCell -from tinygrad.tensor import Tensor - - -class LSTM: - def __init__( - self, - input_size: int, - hidden_size: int, - layer_count: int = 3, - dropout_rate: float = 0.0, - ) -> None: - minimum_layer_count = 3 - if layer_count < minimum_layer_count: - message = f"Layer count must be at least {minimum_layer_count}" - raise ValueError(message) - - self.hidden_size = hidden_size - self.layer_count = layer_count - self.dropout_rate = dropout_rate - - self.layers: list[LSTMCell] = [] - for index in range(layer_count): - input_size = input_size if index == 0 else self.hidden_size - self.layers.append( - LSTMCell( - input_size=input_size, - hidden_size=self.hidden_size, - ) - ) - - def forward( - self, - inputs: Tensor, - state: tuple[list[Tensor], list[Tensor]] | None = None, - ) -> tuple[Tensor, tuple[list[Tensor], list[Tensor]]]: - batch_size, sequence_length, _ = inputs.shape - - if state is None: - hidden_state = [ - Tensor.zeros(batch_size, self.hidden_size) - for _ in range(self.layer_count) - ] - cell_state = [ - Tensor.zeros(batch_size, self.hidden_size) - for _ in range(self.layer_count) - ] - else: - hidden_state, cell_state = state - - outputs = [] - - for t in range(int(sequence_length)): - layer_input = inputs[:, t] - - for index, layer in enumerate(self.layers): - layer_hidden_state, layer_cell_state = layer( - x=layer_input, - hc=( - hidden_state[index], - cell_state[index], - ), - ) - - hidden_state[index] = layer_hidden_state - cell_state[index] = layer_cell_state - - if self.dropout_rate > 0.0 and index < self.layer_count - 1: - hidden_state[index].train() - hidden_state[index] = hidden_state[index].dropout(self.dropout_rate) - - layer_input = layer_hidden_state - - outputs.append(hidden_state[-1]) - - if not outputs: - message = "Cannot stack empty outputs list" - raise ValueError(message) - - if len(outputs) == 1: - output_tensor = outputs[0].unsqueeze(dim=1) - else: - output_tensor = Tensor.stack(outputs[0], *outputs[1:], dim=1) - - return output_tensor, (hidden_state, cell_state) diff --git a/libraries/python/src/internal/mhsa_network.py b/libraries/python/src/internal/mhsa_network.py deleted file mode 100644 index 89e50b97b..000000000 --- a/libraries/python/src/internal/mhsa_network.py +++ /dev/null @@ -1,64 +0,0 @@ -from tinygrad.dtype import dtypes -from tinygrad.nn import Linear -from tinygrad.tensor import Tensor - - -class MultiHeadSelfAttentionNetwork: - def __init__( - self, - heads_count: int, - embedding_size: int, - dropout_rate: float = 0.0, - ) -> None: - if embedding_size % heads_count != 0: - message = "Embedding dimension must be divisible by heads count" - raise ValueError(message) - - self.heads_count = heads_count - self.embedding_size = embedding_size - self.heads_dimension = embedding_size // heads_count - self.dropout_rate = dropout_rate - - self.query_weight = Linear(self.embedding_size, self.embedding_size) - self.key_weight = Linear(self.embedding_size, self.embedding_size) - self.value_weight = Linear(self.embedding_size, self.embedding_size) - - self.fully_connected_out = Linear(self.embedding_size, self.embedding_size) - - self.scale = Tensor(self.heads_dimension**0.5, dtype=dtypes.float32) - - def forward(self, inputs: Tensor) -> tuple[Tensor, Tensor]: - batch_size, sequence_length, _ = inputs.shape - - query_weights = self.query_weight(inputs) - key_weights = self.key_weight(inputs) - value_weights = self.value_weight(inputs) - - shape = (batch_size, sequence_length, self.heads_count, self.heads_dimension) - - # shape: (batch, heads_count, sequence_length, head_dimension) # noqa: ERA001 - query_weights = query_weights.view(shape).transpose(1, 2) - key_weights = key_weights.view(shape).transpose(1, 2) - value_weights = value_weights.view(shape).transpose(1, 2) - - attention_scores = query_weights.matmul(key_weights.transpose(-2, -1)).div( - self.scale - ) - - attention_weights = attention_scores.softmax(axis=-1) - - if self.dropout_rate > 0: - attention_weights = attention_weights.dropout(self.dropout_rate) - - attention_output = attention_weights.matmul(value_weights) - - attention_output = attention_output.transpose(1, 2).reshape( - batch_size, sequence_length, self.embedding_size - ) - - output = self.fully_connected_out(attention_output) - - if self.dropout_rate > 0: - output = output.dropout(self.dropout_rate) - - return output, attention_weights diff --git a/libraries/python/src/internal/money.py b/libraries/python/src/internal/money.py deleted file mode 100644 index 325d0c8f5..000000000 --- a/libraries/python/src/internal/money.py +++ /dev/null @@ -1,33 +0,0 @@ -from decimal import ROUND_HALF_UP, Decimal - -from pydantic import BaseModel, Field, field_validator - - -class Money(BaseModel): - amount: Decimal = Field( - ..., - description="Monetary value in USD with 2 decimal places", - ) - - @field_validator("amount", check_fields=True) - def validate_amount(cls, v: str | Decimal) -> Decimal: # noqa: N805 - if not isinstance(v, Decimal): - v = Decimal(str(v)) - - return v.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP) - - def __float__(self) -> float: - return float(self.amount) - - def __str__(self) -> str: - return f"${self.amount:.2f}" - - def __repr__(self) -> str: - return f"Money(amount=Decimal('{self.amount:.2f}'))" - - @classmethod - def from_float(cls, value: float) -> "Money": - return cls(amount=Decimal(str(value))) - - def to_dict(self) -> dict[str, float]: - return {"amount": float(self.amount)} diff --git a/libraries/python/src/internal/summaries.py b/libraries/python/src/internal/summaries.py deleted file mode 100644 index fc6196467..000000000 --- a/libraries/python/src/internal/summaries.py +++ /dev/null @@ -1,6 +0,0 @@ -from pydantic import BaseModel - - -class BarsSummary(BaseModel): - date: str - count: int diff --git a/libraries/python/src/internal/tft_model.py b/libraries/python/src/internal/tft_model.py deleted file mode 100644 index 3fa10d465..000000000 --- a/libraries/python/src/internal/tft_model.py +++ /dev/null @@ -1,270 +0,0 @@ -from pydantic import BaseModel -from tinygrad.nn import Linear -from tinygrad.nn.optim import Adam -from tinygrad.nn.state import ( - get_parameters, - get_state_dict, - load_state_dict, - safe_load, - safe_save, -) -from tinygrad.tensor import Tensor - -from .loss_functions import quantile_loss -from .lstm_network import LSTM -from .mhsa_network import MultiHeadSelfAttentionNetwork -from .variable_selection_network import VariableSelectionNetwork - - -class Parameters(BaseModel): - hidden_size: int = 64 - output_size: int = 1 # daily return - lstm_layer_count: int = 3 - attention_head_size: int = 4 - dropout_rate: float = 0.1 - quantiles: list[float] = [0.1, 0.5, 0.9] - decoder_categorical_dimension: int - decoder_continuous_dimension: int - encoder_categorical_dimension: int - encoder_continuous_dimension: int - static_categorical_dimension: int - static_continuous_dimension: int - input_length: int = 35 # five weeks - output_length: int = 7 # one week - - -# https://arxiv.org/pdf/1912.09363 -class TFTModel: - def __init__(self, parameters: Parameters) -> None: - self.hidden_size = parameters.hidden_size - self.batch_size = parameters.input_length - self.input_length = parameters.input_length - self.output_length = parameters.output_length - self.output_size = parameters.output_size - self.quantiles = parameters.quantiles - - encoder_dimension = ( - parameters.encoder_categorical_dimension - + parameters.encoder_continuous_dimension - ) - - decoder_dimension = ( - parameters.decoder_categorical_dimension - + parameters.decoder_continuous_dimension - ) - - self.encoder_variable_selection_network = VariableSelectionNetwork( - input_dimension=encoder_dimension, - hidden_size=parameters.hidden_size, - ) - - self.decoder_variable_selection_network = VariableSelectionNetwork( - input_dimension=decoder_dimension, - hidden_size=parameters.hidden_size, - ) - - self.static_context_linear = Linear( - in_features=parameters.static_categorical_dimension - + parameters.static_continuous_dimension, - out_features=parameters.hidden_size, - ) - - self.lstm_encoder = LSTM( - input_size=encoder_dimension, - hidden_size=parameters.hidden_size, - layer_count=parameters.lstm_layer_count, - dropout_rate=parameters.dropout_rate, - ) - - self.lstm_decoder = LSTM( - input_size=decoder_dimension, - hidden_size=parameters.hidden_size, - layer_count=parameters.lstm_layer_count, - dropout_rate=parameters.dropout_rate, - ) - - self.self_attention = MultiHeadSelfAttentionNetwork( - heads_count=parameters.attention_head_size, - embedding_size=parameters.hidden_size, - dropout_rate=parameters.dropout_rate, - ) - - self.pre_output_layer = Linear( - in_features=parameters.hidden_size, - out_features=parameters.output_size * len(parameters.quantiles), - ) - - self.output_layer = Linear( - in_features=parameters.hidden_size, - out_features=parameters.output_size, - ) - - self.parameters = get_parameters(self) - - def forward(self, inputs: dict[str, Tensor]) -> dict[str, Tensor]: - encoder_categorical_features = inputs["encoder_categorical_features"] - encoder_continuous_features = inputs["encoder_continuous_features"] - - encoder_input = encoder_categorical_features.cat( - encoder_continuous_features, - dim=2, - ) - - decoder_categorical_features = inputs["decoder_categorical_features"] - decoder_continuous_features = Tensor.zeros( - self.batch_size, decoder_categorical_features.shape[1], 0 - ) # not currently used - - decoder_input = decoder_categorical_features.cat( - decoder_continuous_features, - dim=2, - ) - - static_categorical_features = inputs["static_categorical_features"] - - static_context = None # NOTE: maybe remove - - static_input = static_categorical_features.to( - device=self.static_context_linear.weight.device - ) - - static_context = self.static_context_linear(static_input) - - static_context = static_context.view((self.batch_size, self.hidden_size)) - - encoder_weights = self.encoder_variable_selection_network.forward(encoder_input) - - encoder_input = Tensor(encoder_input * encoder_weights) - - decoder_weights = self.decoder_variable_selection_network.forward(decoder_input) - - decoder_input = Tensor(decoder_input * decoder_weights) - - encoder_static_context = static_context.unsqueeze(1).expand( - -1, self.input_length, -1 - ) - - decoder_static_context = static_context.unsqueeze(1).expand( - -1, self.output_length, -1 - ) - - encoder_output, (h_n, c_n) = self.lstm_encoder.forward(encoder_input) - - encoder_output = Tensor(encoder_output + encoder_static_context) - - decoder_output, _ = self.lstm_decoder.forward(decoder_input, (h_n, c_n)) - - decoder_output = Tensor(decoder_output + decoder_static_context) - - sequence = Tensor.cat(encoder_output, decoder_output, dim=1) - - expanded_static_context = static_context.unsqueeze(1).expand( - -1, sequence.size(1), -1 - ) - - attended_output, _ = self.self_attention.forward( - Tensor(sequence + expanded_static_context), - ) - - decoder_attended = attended_output[:, -self.output_length :, :] - - output = self.pre_output_layer(decoder_attended).relu() - - predictions = self.output_layer(output) - - quantiles = predictions.reshape( - self.batch_size, - self.output_length, - self.output_size, - len(self.quantiles), - ) - - return { - "predictions": quantiles[ - :, :, :, len(self.quantiles) // 2 - ], # shape: (batch_size, output_length, output_size) - "quantiles": quantiles, # shape: (batch_size, output_length, output_size, len(quantiles)) # noqa: E501 - } - - def train( - self, - inputs_list: list[dict[str, Tensor]], - epoch_count: int, - learning_rate: float = 1e-3, - ) -> dict[str, list[float]]: - optimizer = Adam(params=self.parameters, lr=learning_rate) - - losses: list[float] = [] - - for _ in range(epoch_count): - epoch_loss: float = 0.0 - - for inputs in inputs_list: - outputs = self.forward(inputs) - - loss = quantile_loss( - outputs["quantiles"].reshape( - -1, self.output_size, len(self.quantiles) - ), - inputs["targets"].reshape(-1, self.output_size), - self.quantiles, - ) - - optimizer.zero_grad() - _ = loss.backward() - optimizer.step() - - epoch_loss += loss.numpy().item() - - average_epoch_loss: float = epoch_loss / len(inputs_list) - losses.append(average_epoch_loss) - - return { - "losses": losses, - } - - def validate( - self, - inputs_list: list[dict[str, Tensor]], - ) -> float: - total_loss = 0.0 - batch_count = 0 - - for inputs in inputs_list: - outputs = self.forward(inputs) - - loss = quantile_loss( - outputs["predictions"], - inputs["targets"], - self.quantiles, - ) - - total_loss += loss.numpy().item() - batch_count += 1 - - return total_loss / batch_count - - def save( - self, - path_and_file: str = "tft_model.safetensor", - ) -> None: - states = get_state_dict(self) - safe_save(states, path_and_file) - - def load( - self, - path_and_file: str = "tft_model.safetensor", - ) -> None: - states = safe_load(path_and_file) - load_state_dict(self, states) - - def predict( - self, - inputs: dict[str, Tensor], - ) -> dict[str, Tensor]: - outputs = self.forward(inputs) - - return { - "predictions": outputs["predictions"], - "quantiles": outputs["quantiles"], - } diff --git a/libraries/python/src/internal/variable_selection_network.py b/libraries/python/src/internal/variable_selection_network.py deleted file mode 100644 index 13035c00f..000000000 --- a/libraries/python/src/internal/variable_selection_network.py +++ /dev/null @@ -1,21 +0,0 @@ -from tinygrad import nn -from tinygrad.tensor import Tensor - - -class VariableSelectionNetwork: - def __init__(self, input_dimension: int, hidden_size: int) -> None: - self.input_layer = nn.Linear( - in_features=input_dimension, - out_features=hidden_size, - ) - - self.output_layer = nn.Linear( - in_features=hidden_size, - out_features=input_dimension, - ) - - def forward(self, inputs: Tensor) -> Tensor: - inputs = self.input_layer(inputs) - inputs = inputs.relu() - inputs = self.output_layer(inputs) - return inputs.sigmoid() diff --git a/libraries/python/tests/test_dates.py b/libraries/python/tests/test_dates.py deleted file mode 100644 index b1a4bc21c..000000000 --- a/libraries/python/tests/test_dates.py +++ /dev/null @@ -1,109 +0,0 @@ -import datetime -from unittest.mock import patch -from zoneinfo import ZoneInfo - -import pytest -from internal.dates import Date, DateRange -from pydantic import ValidationError - - -def test_date_default() -> None: - with patch("internal.dates.datetime") as mock_datetime: - mock_datetime.datetime.now.return_value = datetime.datetime( - 2023, 5, 15, 10, 30, 0, tzinfo=ZoneInfo("America/New_York") - ) - mock_datetime.date = datetime.date - - date_instance = Date() - - assert date_instance.date == datetime.date(2023, 5, 15) - - -def test_date_explicit_date() -> None: - test_date = datetime.date(2023, 1, 1) - date_instance = Date(date=test_date) - - assert date_instance.date == test_date - - -def test_date_string_dash_format() -> None: - date_instance = Date(date=datetime.date.fromisoformat("2023-03-15")) - - assert date_instance.date == datetime.date(2023, 3, 15) - - -def test_date_json_encoder() -> None: - test_date = datetime.date(2023, 6, 10) - date_instance = Date(date=test_date) - - json_dict = date_instance.model_dump(mode="json") - assert json_dict["date"] == "2023/06/10" - - -def test_date_range_valid() -> None: - start = datetime.date(2023, 1, 1) - end = datetime.date(2023, 12, 31) - - date_range = DateRange(start=start, end=end) - - assert date_range.start == start - assert date_range.end == end - - -def test_date_range_end_before_start() -> None: - start = datetime.date(2023, 12, 31) - end = datetime.date(2023, 1, 1) - - with pytest.raises(ValidationError) as exc_info: - DateRange(start=start, end=end) - - assert "End date must be after start date" in str(exc_info.value) - - -def test_date_range_same_dates() -> None: - same_date = datetime.date(2023, 6, 15) - - with pytest.raises(ValidationError) as exc_info: - DateRange(start=same_date, end=same_date) - - assert "End date must be after start date" in str(exc_info.value) - - -def test_date_range_one_day_apart() -> None: - start = datetime.date(2023, 6, 15) - end = datetime.date(2023, 6, 16) - - date_range = DateRange(start=start, end=end) - - assert date_range.start == start - assert date_range.end == end - - -def test_date_range_to_object() -> None: - start = datetime.date(2023, 3, 1) - end = datetime.date(2023, 3, 31) - - date_range = DateRange(start=start, end=end) - result = date_range.to_object() - - expected = { - "start_date": "2023-03-01", - "end_date": "2023-03-31", - } - - assert result == expected - - -def test_date_range_to_object_leap_year() -> None: - start = datetime.date(2024, 2, 28) - end = datetime.date(2024, 2, 29) - - date_range = DateRange(start=start, end=end) - result = date_range.to_object() - - expected = { - "start_date": "2024-02-28", - "end_date": "2024-02-29", - } - - assert result == expected diff --git a/libraries/python/tests/test_equity_bar.py b/libraries/python/tests/test_equity_bars_schema.py similarity index 75% rename from libraries/python/tests/test_equity_bar.py rename to libraries/python/tests/test_equity_bars_schema.py index 2c9eb6829..a9d3d9f8c 100644 --- a/libraries/python/tests/test_equity_bar.py +++ b/libraries/python/tests/test_equity_bars_schema.py @@ -1,10 +1,10 @@ import polars as pl import pytest -from internal.equity_bar import equity_bar_schema +from internal.equity_bars_schema import equity_bars_schema from pandera.errors import SchemaError -def test_equity_bar_schema_valid_data() -> None: +def test_equity_bars_schema_valid_data() -> None: valid_data = pl.DataFrame( { "ticker": ["AAPL"], @@ -15,14 +15,15 @@ def test_equity_bar_schema_valid_data() -> None: "close_price": [153.0], "volume": [1000000], "volume_weighted_average_price": [152.5], + "transactions": [100], } ) - validated_df = equity_bar_schema.validate(valid_data) - assert validated_df.shape == (1, 8) + validated_df = equity_bars_schema.validate(valid_data) + assert validated_df.shape == (1, 9) -def test_equity_bar_schema_ticker_lowercase_fails() -> None: +def test_equity_bars_schema_ticker_lowercase_fails() -> None: data = pl.DataFrame( { "ticker": ["aapl"], @@ -33,14 +34,15 @@ def test_equity_bar_schema_ticker_lowercase_fails() -> None: "close_price": [153.0], "volume": [1000000], "volume_weighted_average_price": [152.5], + "transactions": [100], } ) with pytest.raises(SchemaError): - equity_bar_schema.validate(data) + equity_bars_schema.validate(data) -def test_equity_bar_schema_ticker_uppercase_passes() -> None: +def test_equity_bars_schema_ticker_uppercase_passes() -> None: data = pl.DataFrame( { "ticker": ["AAPL"], @@ -51,14 +53,15 @@ def test_equity_bar_schema_ticker_uppercase_passes() -> None: "close_price": [153.0], "volume": [1000000], "volume_weighted_average_price": [152.5], + "transactions": [100], } ) - validated_df = equity_bar_schema.validate(data) + validated_df = equity_bars_schema.validate(data) assert validated_df["ticker"][0] == "AAPL" -def test_equity_bar_schema_negative_timestamp() -> None: +def test_equity_bars_schema_negative_timestamp() -> None: data = pl.DataFrame( { "ticker": ["AAPL"], @@ -69,14 +72,15 @@ def test_equity_bar_schema_negative_timestamp() -> None: "close_price": [153.0], "volume": [1000000], "volume_weighted_average_price": [152.5], + "transactions": [100], } ) with pytest.raises(SchemaError): - equity_bar_schema.validate(data) + equity_bars_schema.validate(data) -def test_equity_bar_schema_zero_timestamp() -> None: +def test_equity_bars_schema_zero_timestamp() -> None: data = pl.DataFrame( { "ticker": ["AAPL"], @@ -87,14 +91,15 @@ def test_equity_bar_schema_zero_timestamp() -> None: "close_price": [153.0], "volume": [1000000], "volume_weighted_average_price": [152.5], + "transactions": [100], } ) with pytest.raises(SchemaError): - equity_bar_schema.validate(data) + equity_bars_schema.validate(data) -def test_equity_bar_schema_negative_prices() -> None: +def test_equity_bars_schema_negative_prices() -> None: price_fields = [ "open_price", "high_price", @@ -114,16 +119,17 @@ def test_equity_bar_schema_negative_prices() -> None: "close_price": [153.0], "volume": [1000000], "volume_weighted_average_price": [152.5], + "transactions": [100], } ) data = data.with_columns(pl.lit(-1.0).alias(field)) with pytest.raises(SchemaError): - equity_bar_schema.validate(data) + equity_bars_schema.validate(data) -def test_equity_bar_schema_zero_prices_not_allowed() -> None: +def test_equity_bars_schema_zero_prices_not_allowed() -> None: data = pl.DataFrame( { "ticker": ["AAPL"], @@ -134,14 +140,15 @@ def test_equity_bar_schema_zero_prices_not_allowed() -> None: "close_price": [153.0], "volume": [1000000], "volume_weighted_average_price": [152.5], + "transactions": [100], } ) with pytest.raises(SchemaError): - equity_bar_schema.validate(data) + equity_bars_schema.validate(data) -def test_equity_bar_schema_negative_volume() -> None: +def test_equity_bars_schema_negative_volume() -> None: data = pl.DataFrame( { "ticker": ["AAPL"], @@ -152,14 +159,15 @@ def test_equity_bar_schema_negative_volume() -> None: "close_price": [153.0], "volume": [-1000000], "volume_weighted_average_price": [152.5], + "transactions": [100], } ) with pytest.raises(SchemaError): - equity_bar_schema.validate(data) + equity_bars_schema.validate(data) -def test_equity_bar_schema_type_coercion() -> None: +def test_equity_bars_schema_type_coercion() -> None: data = pl.DataFrame( { "ticker": ["AAPL"], @@ -170,17 +178,18 @@ def test_equity_bar_schema_type_coercion() -> None: "close_price": [153.0], "volume": ["1000000"], # string that can be coerced to int "volume_weighted_average_price": [152.5], + "transactions": [100], } ) - validated_df = equity_bar_schema.validate(data) + validated_df = equity_bars_schema.validate(data) assert validated_df["timestamp"].dtype == pl.Float64 assert validated_df["open_price"].dtype == pl.Float64 assert validated_df["high_price"].dtype == pl.Float64 assert validated_df["volume"].dtype == pl.Int64 -def test_equity_bar_schema_missing_required_column() -> None: +def test_equity_bars_schema_missing_required_column() -> None: data = pl.DataFrame( { "ticker": ["AAPL"], @@ -191,14 +200,15 @@ def test_equity_bar_schema_missing_required_column() -> None: "close_price": [153.0], "volume": [1000000], "volume_weighted_average_price": [152.5], + "transactions": [100], } ) with pytest.raises((SchemaError, pl.exceptions.ColumnNotFoundError)): - equity_bar_schema.validate(data) + equity_bars_schema.validate(data) -def test_equity_bar_schema_null_values() -> None: +def test_equity_bars_schema_null_values() -> None: data = pl.DataFrame( { "ticker": [None], @@ -209,14 +219,15 @@ def test_equity_bar_schema_null_values() -> None: "close_price": [153.0], "volume": [1000000], "volume_weighted_average_price": [152.5], + "transactions": [100], } ) with pytest.raises(SchemaError): - equity_bar_schema.validate(data) + equity_bars_schema.validate(data) -def test_equity_bar_schema_multiple_rows() -> None: +def test_equity_bars_schema_multiple_rows() -> None: data = pl.DataFrame( { "ticker": ["AAPL", "GOOGL", "NVDA"], @@ -227,9 +238,10 @@ def test_equity_bar_schema_multiple_rows() -> None: "close_price": [153.0, 103.0, 303.0], "volume": [1000000, 500000, 750000], "volume_weighted_average_price": [152.5, 102.0, 302.0], + "transactions": [100, 50, 75], } ) - validated_df = equity_bar_schema.validate(data) - assert validated_df.shape == (3, 8) + validated_df = equity_bars_schema.validate(data) + assert validated_df.shape == (3, 9) assert validated_df["ticker"].to_list() == ["AAPL", "GOOGL", "NVDA"] diff --git a/libraries/python/tests/test_loss_functions.py b/libraries/python/tests/test_loss_functions.py deleted file mode 100644 index f618fb9e9..000000000 --- a/libraries/python/tests/test_loss_functions.py +++ /dev/null @@ -1,69 +0,0 @@ -import numpy as np -import pytest -from internal.loss_functions import quantile_loss -from numpy.random import PCG64, Generator -from tinygrad.tensor import Tensor - -rng = Generator(PCG64()) - - -def test_quantile_loss_basic() -> None: - predictions = Tensor([[[1.0, 1.2, 1.5]], [[2.0, 2.1, 2.3]], [[3.0, 2.8, 2.9]]]) - targets = Tensor([[2.0], [2.5], [1.8]]) - quantiles = [0.25, 0.5, 0.75] - - loss = quantile_loss(predictions, targets, quantiles) - - assert isinstance(loss, Tensor) - assert len(loss.shape) == 0 or loss.shape in [(), (0,), (1,)] - - -def test_quantile_loss_multiple_samples() -> None: - predictions = Tensor([[[1.0, 1.1, 1.3]], [[2.0, 2.2, 2.4]]]) - targets = Tensor([[2.5], [5.5]]) - quantiles = [0.25, 0.5, 0.75] - - loss: Tensor = quantile_loss(predictions, targets, quantiles) - - assert isinstance(loss, Tensor) - assert len(loss.shape) == 0 or loss.shape in [(), (0,), (1,)] - - -def test_quantile_loss_perfect_prediction() -> None: - predictions = Tensor([[[2.0, 2.0, 2.0]]]) - targets = Tensor([[2.0]]) - quantiles = [0.25, 0.5, 0.75] - - loss = quantile_loss(predictions, targets, quantiles) - - assert loss.numpy() >= 0.0 - - -def test_quantile_loss_different_quantiles() -> None: - predictions = Tensor([[[3.0, 3.1, 3.0, 2.9, 3.0]]]) - targets = Tensor([[3.0]]) - quantiles = [0.1, 0.25, 0.5, 0.75, 0.9] - - loss = quantile_loss(predictions, targets, quantiles) - - assert isinstance(loss, Tensor) - assert loss.numpy() >= 0.0 - - -def test_quantile_loss_shapes() -> None: - for batch_size in [1, 2, 4, 8]: - predictions = Tensor(rng.standard_normal((batch_size, 1, 3)).astype(np.float32)) - targets = Tensor(rng.standard_normal((batch_size, 1)).astype(np.float32)) - quantiles = [0.25, 0.5, 0.75] - - loss = quantile_loss(predictions, targets, quantiles) - assert isinstance(loss, Tensor) - - -def test_quantile_loss_invalid_quantiles() -> None: - predictions = Tensor([[[1.0, 1.2, 1.3]]]) - targets = Tensor([[2.0]]) - quantiles = [0.25, 1.5, 0.75] # Invalid quantile > 1 - - with pytest.raises(ValueError, match="All quantiles must be between 0 and 1"): - quantile_loss(predictions, targets, quantiles) diff --git a/libraries/python/tests/test_lstm_network.py b/libraries/python/tests/test_lstm_network.py deleted file mode 100644 index 3378b4e50..000000000 --- a/libraries/python/tests/test_lstm_network.py +++ /dev/null @@ -1,107 +0,0 @@ -from typing import NamedTuple - -import numpy as np -from internal.lstm_network import LSTM -from numpy.random import PCG64, Generator -from tinygrad.tensor import Tensor - -rng = Generator(PCG64()) - - -def test_lstm_initialization() -> None: - lstm = LSTM( - input_size=32, - hidden_size=64, - layer_count=3, - dropout_rate=0.1, - ) - - class Expected(NamedTuple): - hidden_state: int = 64 - layer_count: int = 3 - dropout_rate: float = 0.1 - - expected = Expected(hidden_state=64, layer_count=3, dropout_rate=0.1) - - assert lstm.hidden_size == expected.hidden_state - assert lstm.layer_count == expected.layer_count - assert lstm.dropout_rate == expected.dropout_rate - - -def test_lstm_forward() -> None: - lstm = LSTM( - input_size=16, - hidden_size=32, - layer_count=3, - dropout_rate=0.0, - ) - - input_tensor = Tensor(rng.standard_normal((4, 10, 16))) - output, hidden_state = lstm.forward(input_tensor) - - expected_hidden_state = 2 - - assert output.shape == (4, 10, 32) - assert isinstance(hidden_state, tuple) - assert len(hidden_state) == expected_hidden_state - - -def test_lstm_different_sequence_lengths() -> None: - lstm = LSTM( - input_size=8, - hidden_size=16, - layer_count=3, - dropout_rate=0.0, - ) - - for sequence_length in [5, 10, 20]: - input_tensor = Tensor(rng.standard_normal((2, sequence_length, 8))) - output, hidden_state = lstm.forward(input_tensor) - - assert output.shape == (2, sequence_length, 16) - - -def test_lstm_multiple_layers() -> None: - lstm = LSTM( - input_size=10, - hidden_size=20, - layer_count=3, - dropout_rate=0.0, - ) - - input_tensor = Tensor(rng.standard_normal((2, 5, 10))) - output, hidden_state = lstm.forward(input_tensor) - - assert output.shape == (2, 5, 20) - assert isinstance(hidden_state, tuple) - - -def test_lstm_single_timestep() -> None: - lstm = LSTM( - input_size=12, - hidden_size=24, - layer_count=3, - dropout_rate=0.0, - ) - - input_tensor = Tensor(rng.standard_normal((3, 1, 12))) - output, _ = lstm.forward(input_tensor) - - assert output.shape == (3, 1, 24) - - -def test_lstm_consistency() -> None: - lstm = LSTM( - input_size=6, - hidden_size=12, - layer_count=3, - dropout_rate=0.0, - ) - - input_tensor = Tensor(rng.standard_normal((1, 3, 6))) - - first_output, _ = lstm.forward(input_tensor) - second_output, _ = lstm.forward(input_tensor) - - assert first_output.shape == second_output.shape - assert np.allclose(first_output.numpy(), second_output.numpy(), rtol=1e-5) diff --git a/libraries/python/tests/test_mhsa_network.py b/libraries/python/tests/test_mhsa_network.py deleted file mode 100644 index 05a03292d..000000000 --- a/libraries/python/tests/test_mhsa_network.py +++ /dev/null @@ -1,72 +0,0 @@ -from internal.mhsa_network import MultiHeadSelfAttentionNetwork -from numpy.random import PCG64, Generator -from tinygrad.tensor import Tensor - -rng = Generator(PCG64()) - - -def test_multi_head_attention_initialization() -> None: - heads_count = 8 - embedding_size = 64 - attention = MultiHeadSelfAttentionNetwork(heads_count=8, embedding_size=64) - - assert attention.heads_count == heads_count - assert attention.embedding_size == embedding_size - - -def test_multi_head_attention_forward() -> None: - attention = MultiHeadSelfAttentionNetwork(heads_count=4, embedding_size=32) - - input_tensor = Tensor(rng.standard_normal((2, 10, 32))) - output, attention_weights = attention.forward(input_tensor) - - batch_size = 2 - heads_count = 4 - - assert output.shape == (batch_size, 10, 32) - assert attention_weights.shape[0] == batch_size - assert attention_weights.shape[1] == heads_count - - -def test_multi_head_attention_different_heads() -> None: - for heads_count in [1, 2, 4, 8]: - embedding_size = 32 - attention = MultiHeadSelfAttentionNetwork( - heads_count=heads_count, embedding_size=embedding_size - ) - - input_tensor = Tensor(rng.standard_normal((1, 5, embedding_size))) - output, attention_weights = attention.forward(input_tensor) - - assert output.shape == (1, 5, embedding_size) - assert attention_weights.shape[1] == heads_count - - -def test_multi_head_attention_single_sequence() -> None: - attention = MultiHeadSelfAttentionNetwork(heads_count=2, embedding_size=16) - - input_tensor = Tensor(rng.standard_normal((1, 1, 16))) - output, _ = attention.forward(input_tensor) - - assert output.shape == (1, 1, 16) - - -def test_multi_head_attention_longer_sequences() -> None: - attention = MultiHeadSelfAttentionNetwork(heads_count=4, embedding_size=64) - - for sequence_length in [10, 20, 50]: - input_tensor = Tensor(rng.standard_normal((1, sequence_length, 64))) - output, _ = attention.forward(input_tensor) - - assert output.shape == (1, sequence_length, 64) - - -def test_multi_head_attention_batch_processing() -> None: - attention = MultiHeadSelfAttentionNetwork(heads_count=2, embedding_size=32) - - for batch_size in [1, 2, 4, 8]: - input_tensor = Tensor(rng.standard_normal((batch_size, 5, 32))) - output, attention_weights = attention.forward(input_tensor) - - assert output.shape == (batch_size, 5, 32) - assert attention_weights.shape[0] == batch_size diff --git a/libraries/python/tests/test_tft_dataset.py b/libraries/python/tests/test_tft_dataset.py deleted file mode 100644 index 6c720d64e..000000000 --- a/libraries/python/tests/test_tft_dataset.py +++ /dev/null @@ -1,244 +0,0 @@ -import math - -import polars as pl -from internal.tft_dataset import TFTDataset - - -def test_tft_dataset_load_data() -> None: - data = pl.DataFrame( - { - "timestamp": [ - 1672531200000, # 2023-01-01 - 1672617600000, # 2023-01-02 - 1672704000000, # 2023-01-03 - 1672531200000, # 2023-01-01 - 1672617600000, # 2023-01-02 - 1672704000000, # 2023-01-03 - ], - "open_price": [100.0, 101.0, 102.0, 50.0, 51.0, 52.0], - "high_price": [110.0, 111.0, 112.0, 60.0, 61.0, 62.0], - "low_price": [90.0, 91.0, 92.0, 40.0, 41.0, 42.0], - "close_price": [105.0, 106.0, 107.0, 55.0, 56.0, 57.0], - "volume": [1000, 1100, 1200, 500, 600, 700], - "volume_weighted_average_price": [105.0, 106.0, 107.0, 55.0, 56.0, 57.0], - "ticker": ["AAPL", "AAPL", "AAPL", "GOOGL", "GOOGL", "GOOGL"], - "sector": [ - "Technology", - "Technology", - "Technology", - "Technology", - "Technology", - "Technology", - ], - "industry": [ - "Consumer Electronics", - "Consumer Electronics", - "Consumer Electronics", - "Internet Services", - "Internet Services", - "Internet Services", - ], - } - ) - - dataset = TFTDataset() - - dataset.preprocess_and_set_data(data) - - assert hasattr(dataset, "data") - assert hasattr(dataset, "mappings") - - -def test_tft_dataset_get_dimensions() -> None: - data = pl.DataFrame( - { - "timestamp": [ - 1672531200000, # 2023-01-01 - 1672617600000, # 2023-01-02 - ], - "open_price": [100.0, 101.0], - "high_price": [110.0, 111.0], - "low_price": [90.0, 91.0], - "close_price": [105.0, 106.0], - "volume": [1000, 1100], - "volume_weighted_average_price": [105.0, 106.0], - "ticker": ["AAPL", "AAPL"], - "sector": ["Technology", "Technology"], - "industry": ["Consumer Electronics", "Consumer Electronics"], - } - ) - - dataset = TFTDataset() - - dataset.preprocess_and_set_data(data) - - dimensions = dataset.get_dimensions() - - assert "encoder_categorical_features" in dimensions - assert "encoder_continuous_features" in dimensions - assert "decoder_categorical_features" in dimensions - assert "decoder_continuous_features" in dimensions - assert "static_categorical_features" in dimensions - assert "static_continuous_features" in dimensions - - -def test_tft_dataset_batches() -> None: - data = pl.DataFrame( - { - "timestamp": [ - 1672531200000, # 2023-01-01 - 1672617600000, # 2023-01-02 - 1672704000000, # 2023-01-03 - 1672790400000, # 2023-01-04 - ], - "open_price": [100.0, 101.0, 102.0, 103.0], - "high_price": [110.0, 111.0, 112.0, 113.0], - "low_price": [90.0, 91.0, 92.0, 93.0], - "close_price": [105.0, 106.0, 107.0, 108.0], - "volume": [1000, 1100, 1200, 1300], - "volume_weighted_average_price": [105.0, 106.0, 107.0, 108.0], - "ticker": ["AAPL", "AAPL", "AAPL", "AAPL"], - "sector": ["Technology", "Technology", "Technology", "Technology"], - "industry": [ - "Consumer Electronics", - "Consumer Electronics", - "Consumer Electronics", - "Consumer Electronics", - ], - } - ) - - dataset = TFTDataset() - - dataset.preprocess_and_set_data(data) - - expected_input_length = 2 - expected_output_length = 1 - - batches = dataset.get_batches( - data_type="predict", - input_length=expected_input_length, - output_length=expected_output_length, - ) - - assert isinstance(batches, list) - assert len(batches) == 1 - - for batch in batches: - assert "encoder_categorical_features" in batch - assert "encoder_continuous_features" in batch - assert "decoder_categorical_features" in batch - assert "static_categorical_features" in batch - - encoder_categorical_features = batch["encoder_categorical_features"] - encoder_continuous_features = batch["encoder_continuous_features"] - decoder_categorical_features = batch["decoder_categorical_features"] - static_categorical_features = batch["static_categorical_features"] - - assert encoder_categorical_features.shape[0] == expected_input_length - assert encoder_continuous_features.shape[0] == expected_input_length - assert decoder_categorical_features.shape[0] == expected_output_length - assert static_categorical_features.shape[0] == 1 - - -def test_tft_dataset_daily_return_calculation() -> None: - data = pl.DataFrame( - { - "timestamp": [ - 1672531200000, # 2023-01-01 - 1672617600000, # 2023-01-02 - 1672704000000, # 2023-01-03 - 1672790400000, # 2023-01-04 - ], - "open_price": [100.0, 101.0, 102.0, 103.0], - "high_price": [110.0, 111.0, 112.0, 113.0], - "low_price": [90.0, 91.0, 92.0, 93.0], - "close_price": [100.0, 105.0, 102.0, 108.0], # returns: +5%, -2.86%, +5.88% - "volume": [1000, 1100, 1200, 1300], - "volume_weighted_average_price": [100.0, 105.0, 102.0, 108.0], - "ticker": ["AAPL", "AAPL", "AAPL", "AAPL"], - "sector": ["Technology", "Technology", "Technology", "Technology"], - "industry": [ - "Consumer Electronics", - "Consumer Electronics", - "Consumer Electronics", - "Consumer Electronics", - ], - } - ) - - dataset = TFTDataset() - - dataset.preprocess_and_set_data(data) - - assert "daily_return" in dataset.data.columns - - expected_rows_after_filter = 3 - assert len(dataset.data) == expected_rows_after_filter - - assert "daily_return" in dataset.continuous_columns - - daily_returns = dataset.data["daily_return"].to_list() - - expected_daily_return_count = 3 - assert len(daily_returns) == expected_daily_return_count - assert all(isinstance(val, float) and math.isfinite(val) for val in daily_returns) - - -def test_tft_dataset_daily_return_targets() -> None: - data = pl.DataFrame( - { - "timestamp": [ - 1672531200000, # 2023-01-01 - 1672617600000, # 2023-01-02 - 1672704000000, # 2023-01-03 - 1672790400000, # 2023-01-04 - 1672876800000, # 2023-01-05 - 1672963200000, # 2023-01-06 - ], - "open_price": [100.0, 101.0, 102.0, 103.0, 104.0, 105.0], - "high_price": [110.0, 111.0, 112.0, 113.0, 114.0, 115.0], - "low_price": [90.0, 91.0, 92.0, 93.0, 94.0, 95.0], - "close_price": [100.0, 105.0, 102.0, 108.0, 106.0, 110.0], - "volume": [1000, 1100, 1200, 1300, 1400, 1500], - "volume_weighted_average_price": [100.0, 105.0, 102.0, 108.0, 106.0, 110.0], - "ticker": ["AAPL", "AAPL", "AAPL", "AAPL", "AAPL", "AAPL"], - "sector": [ - "Technology", - "Technology", - "Technology", - "Technology", - "Technology", - "Technology", - ], - "industry": [ - "Consumer Electronics", - "Consumer Electronics", - "Consumer Electronics", - "Consumer Electronics", - "Consumer Electronics", - "Consumer Electronics", - ], - } - ) - - dataset = TFTDataset() - - dataset.preprocess_and_set_data(data) - - batches = dataset.get_batches( - data_type="train", - input_length=2, - output_length=1, - ) - - assert len(batches) > 0 - - for batch in batches: - if "targets" in batch: - targets = batch["targets"] - assert targets.shape[1] == 1 - expected_tensor_dimensions = 2 - assert len(targets.shape) == expected_tensor_dimensions - assert targets.shape[0] > 0 - assert targets.shape[1] == 1 diff --git a/libraries/python/tests/test_variable_selection_network.py b/libraries/python/tests/test_variable_selection_network.py deleted file mode 100644 index 262078b32..000000000 --- a/libraries/python/tests/test_variable_selection_network.py +++ /dev/null @@ -1,193 +0,0 @@ -import numpy as np -from internal.variable_selection_network import VariableSelectionNetwork -from numpy.random import PCG64, Generator -from tinygrad.tensor import Tensor - -rng = Generator(PCG64()) - - -def test_variable_selection_network_initialization() -> None: - input_dimension = 32 - hidden_size = 64 - - vsn = VariableSelectionNetwork( - input_dimension=input_dimension, - hidden_size=hidden_size, - ) - - assert hasattr(vsn, "input_layer") - assert hasattr(vsn, "output_layer") - assert vsn.input_layer.weight.shape[0] == hidden_size - assert vsn.input_layer.weight.shape[1] == input_dimension - assert vsn.output_layer.weight.shape[0] == input_dimension - assert vsn.output_layer.weight.shape[1] == hidden_size - - -def test_variable_selection_network_forward_basic() -> None: - input_dimension = 16 - hidden_size = 32 - batch_size = 4 - - vsn = VariableSelectionNetwork( - input_dimension=input_dimension, - hidden_size=hidden_size, - ) - - input_tensor = Tensor( - rng.standard_normal((batch_size, input_dimension)).astype(np.float32) - ) - output = vsn.forward(input_tensor) - - assert output.shape == (batch_size, input_dimension) - - -def test_variable_selection_network_output_range() -> None: - input_dimension = 8 - hidden_size = 16 - - vsn = VariableSelectionNetwork( - input_dimension=input_dimension, - hidden_size=hidden_size, - ) - - input_tensor = Tensor(rng.standard_normal((2, input_dimension)).astype(np.float32)) - output = vsn.forward(input_tensor) - - output_numpy = output.numpy() - assert np.all(output_numpy >= 0.0) - assert np.all(output_numpy <= 1.0) - - -def test_variable_selection_network_different_batch_sizes() -> None: - input_dimension = 12 - hidden_size = 24 - - vsn = VariableSelectionNetwork( - input_dimension=input_dimension, - hidden_size=hidden_size, - ) - - for batch_size in [1, 2, 8, 16]: - input_tensor = Tensor( - rng.standard_normal((batch_size, input_dimension)).astype(np.float32) - ) - output = vsn.forward(input_tensor) - - assert output.shape == (batch_size, input_dimension) - - -def test_variable_selection_network_different_dimensions() -> None: - test_configs = [ - (4, 8), - (10, 20), - (32, 64), - (64, 32), - (100, 50), - ] - - for input_dimension, hidden_size in test_configs: - vsn = VariableSelectionNetwork( - input_dimension=input_dimension, - hidden_size=hidden_size, - ) - - input_tensor = Tensor( - rng.standard_normal((2, input_dimension)).astype(np.float32) - ) - output = vsn.forward(input_tensor) - - assert output.shape == (2, input_dimension) - - -def test_variable_selection_network_zero_input() -> None: - input_dimension = 16 - hidden_size = 32 - - vsn = VariableSelectionNetwork( - input_dimension=input_dimension, - hidden_size=hidden_size, - ) - - input_tensor = Tensor(np.zeros((3, input_dimension)).astype(np.float32)) - output = vsn.forward(input_tensor) - - assert output.shape == (3, input_dimension) - output_numpy = output.numpy() - assert np.all(output_numpy >= 0.0) - assert np.all(output_numpy <= 1.0) - - -def test_variable_selection_network_positive_input() -> None: - input_dimension = 20 - hidden_size = 40 - - vsn = VariableSelectionNetwork( - input_dimension=input_dimension, - hidden_size=hidden_size, - ) - - input_tensor = Tensor( - np.abs(rng.standard_normal((4, input_dimension))).astype(np.float32) - ) - output = vsn.forward(input_tensor) - - assert output.shape == (4, input_dimension) - output_numpy = output.numpy() - assert np.all(output_numpy >= 0.0) - assert np.all(output_numpy <= 1.0) - - -def test_variable_selection_network_negative_input() -> None: - input_dimension = 24 - hidden_size = 48 - - vsn = VariableSelectionNetwork( - input_dimension=input_dimension, - hidden_size=hidden_size, - ) - - input_tensor = Tensor( - -np.abs(rng.standard_normal((3, input_dimension))).astype(np.float32) - ) - output = vsn.forward(input_tensor) - - assert output.shape == (3, input_dimension) - output_numpy = output.numpy() - assert np.all(output_numpy >= 0.0) - assert np.all(output_numpy <= 1.0) - - -def test_variable_selection_network_consistency() -> None: - input_dimension = 16 - hidden_size = 32 - - vsn = VariableSelectionNetwork( - input_dimension=input_dimension, - hidden_size=hidden_size, - ) - - input_tensor = Tensor(rng.standard_normal((2, input_dimension)).astype(np.float32)) - - first_output = vsn.forward(input_tensor) - second_output = vsn.forward(input_tensor) - - assert first_output.shape == second_output.shape - assert np.allclose(first_output.numpy(), second_output.numpy(), rtol=1e-5) - - -def test_variable_selection_network_single_dimension() -> None: - input_dimension = 1 - hidden_size = 2 - - vsn = VariableSelectionNetwork( - input_dimension=input_dimension, - hidden_size=hidden_size, - ) - - input_tensor = Tensor([[1.5], [2.0], [-0.5]]) - output = vsn.forward(input_tensor) - - assert output.shape == (3, 1) - output_numpy = output.numpy() - assert np.all(output_numpy >= 0.0) - assert np.all(output_numpy <= 1.0) diff --git a/maskfile.md b/maskfile.md index 63a7d2d07..12764c2e5 100644 --- a/maskfile.md +++ b/maskfile.md @@ -1,7 +1,9 @@ # Pocket Size Fund Task Manager ## setup + > Initial system setup and prerequisite configuration + ```bash set -euo pipefail @@ -14,10 +16,6 @@ if ! command -v docker >/dev/null >&1; then missing_deps+=("Docker") fi -if ! command -v pulumi >/dev/null >&1; then - missing_deps+=("Pulumi CLI") -fi - if [[ ${#missing_deps[@]} -gt 0 ]]; then echo "Missing prerequisites: ${missing_deps[*]}" echo "Please install the following:" @@ -26,679 +24,313 @@ if [[ ${#missing_deps[@]} -gt 0 ]]; then "Docker") echo " - Docker: https://docs.docker.com/get-docker/" ;; - "Pulumi CLI") - echo " - Pulumi CLI: https://www.pulumi.com/docs/get-started/install/" - ;; esac done exit 1 fi -echo "Checking DockerHub authentication" -if ! docker info >/dev/null >&1; then - echo "Docker daemon not running" - exit 1 -fi - -if ! docker system info --format '{{.Username}}' 2>/dev/null | grep -q .; then - echo "️Not logged into DockerHub. Run 'docker login' first" - exit 1 -fi - echo "Prerequisites check completed" -``` - -## continuous_integration -> Continuous integration workflow -```bash -set -euo pipefail - -echo "Running continuous integration workflow" - -echo "Testing" -mask development python test - -echo "Building applications" -mask infrastructure applications build - -echo "Continuous integration workflow completed successfully" -``` -## infrastructure -> Manage infrastructure deployments -### base -> Base infrastructure deployment -#### up -> Deploy complete infrastructure stack (Pulumi + Docker) to local and production environments. -```bash -set -euo pipefail +echo "Configuring GitHub CLI" -echo "Starting infrastructure deployment" - -cd infrastructure - -echo "Deploying infrastructure with Pulumi" -if ! pulumi up --yes; then - echo "Pulumi deployment failed" +if ! gh auth status >/dev/null 2>&1; then + echo "GitHub CLI not authenticated" + echo "Run 'gh auth login' before setup" exit 1 fi -echo "Getting infrastructure outputs" -MANAGER_IP=$(pulumi stack output managerIp | tr -d '\r\n') -if [[ -z "$MANAGER_IP" ]]; then - echo "Failed to get manager IP from Pulumi" - exit 1 -fi - -echo "Setting up SSH configuration" -pulumi stack output --show-secrets sshPrivateKeyPem | tr -d '\r' > swarm.pem -chmod 600 swarm.pem -trap 'rm -f "$PWD/swarm.pem"' EXIT +echo "GitHub CLI configuration completed" -if ! ssh-keygen -l -f swarm.pem >/dev/null >&1; then - echo "Invalid SSH key format" - exit 1 -fi - -SSH_CONFIG="$HOME/.ssh/config" -mkdir -p "$(dirname "$SSH_CONFIG")" +echo "Development environment setup completed successfully" +``` -if [[ -f "$SSH_CONFIG" ]]; then - sed -i.bak '/^Host pocketsizefund-production$/,/^Host /{ /^Host pocketsizefund-production$/d; /^Host /!d; }' "$SSH_CONFIG" || true - sed -i.bak '${ /^Host /!d; }' "$SSH_CONFIG" || true -fi +## infrastructure -cat >> "$SSH_CONFIG" << EOF - -Host pocketsizefund-production - HostName $MANAGER_IP - User ubuntu - IdentityFile $PWD/swarm.pem - IdentitiesOnly yes - StrictHostKeyChecking accept-new - ServerAliveInterval 60 - ServerAliveCountMax 3 -EOF - -echo "Updating SSH known hosts" -ssh-keygen -R "$MANAGER_IP" >/dev/null >&1 || true -ssh-keyscan -H "$MANAGER_IP" 2>/dev/null >> "$HOME/.ssh/known_hosts" - -echo "Testing SSH connection" -MAX_RETRIES=5 -RETRY_COUNT=0 - -while [[ $RETRY_COUNT -lt $MAX_RETRIES ]]; do - if ssh -o ConnectTimeout=10 pocketsizefund-production 'docker info -f "{{.ServerVersion}} {{.Swarm.LocalNodeState}}"' 2>/dev/null; then - echo "SSH connection successful" - break - else - ((RETRY_COUNT++)) - echo "SSH connection attempt $RETRY_COUNT/$MAX_RETRIES failed, retrying in 5 seconds" - sleep 5 - fi -done - -if [[ $RETRY_COUNT -eq $MAX_RETRIES ]]; then - echo "Failed to establish SSH connection after $MAX_RETRIES attempts" - exit 1 -fi +> Manage infrastructure resources -echo "Setting up Docker contexts" +### images -for context in pocketsizefund-production pocketsizefund-local; do - if docker context ls --format '{{.Name}}' | grep -q "^${context}$"; then - docker context use default >/dev/null >&1 || true - docker context rm -f "$context" >/dev/null >&1 || true - fi -done +> Manage Docker images for applications -if ! docker context create pocketsizefund-production --docker "host=ssh://pocketsizefund-production"; then - echo "Failed to create production Docker context" - exit 1 -fi +#### build (application_name) (stage_name) -if ! docker context create pocketsizefund-local --docker "host=unix:///var/run/docker.sock"; then - echo "Failed to create local Docker context" - exit 1 -fi +> Build application Docker images -echo "Ensuring local Docker swarm is initialized" -docker context use pocketsizefund-local -if ! docker info --format '{{.Swarm.LocalNodeState}}' | grep -q active; then - docker swarm init --advertise-addr 127.0.0.1 >/dev/null 2>&1 || true -fi - -echo "Deploying infrastructure stack to production" -docker context use pocketsizefund-production -if ! docker stack deploy -c stack.yml infrastructure --with-registry-auth; then - echo "Failed to deploy infrastructure stack to production" - exit 1 -fi - -echo "Deploying infrastructure stack to local" -docker context use pocketsizefund-local -if ! docker stack deploy -c stack.yml infrastructure --with-registry-auth; then - echo "Failed to deploy infrastructure stack to local" - exit 1 -fi +```bash +set -euo pipefail -echo "Deploying application services" -cd ../applications -echo "Deploying applications to production" -docker context use pocketsizefund-production -if ! docker stack deploy -c stack.yml applications --with-registry-auth; then - echo "Failed to deploy applications to production" - exit 1 -fi +echo "Building application image locally" -echo "Deploying applications to local" -docker context use pocketsizefund-local -if ! docker stack deploy -c stack.yml applications --with-registry-auth; then - echo "Failed to deploy applications to local" - exit 1 -fi +aws_account_id=$(aws sts get-caller-identity --query Account --output text) -echo "Cluster status:" -docker context use pocketsizefund-production -echo "Production cluster:" -docker node ls >/dev/null || echo " Unable to list production nodes" - -docker context use pocketsizefund-local -echo "Local cluster:" -docker node ls >/dev/null || echo " Unable to list local nodes" +docker build \ + --platform linux/amd64 \ + --target ${stage_name} \ + --file applications/${application_name}/Dockerfile \ + --tag pocketsizefund/${application_name}-${stage_name}:latest \ + --tag ${aws_account_id}.dkr.ecr.us-east-1.amazonaws.com/pocketsizefund/${application_name}-${stage_name}:latest \ + . -echo "Infrastructure deployment completed successfully" +echo "Application image built: ${application_name} ${stage_name}" ``` -#### down +#### push (application_name) (stage_name) -> Completely tear down infrastructure and services. +> Push application Docker image to ECR ```bash set -euo pipefail -echo "Taking down infrastructure" - -cd infrastructure - -echo "Removing application stacks" -for context in pocketsizefund-production pocketsizefund-local; do - echo "Removing from $context" - if docker context ls --format '{{.Name}}' | grep -q "^${context}$"; then - docker context use "$context" - docker stack rm applications >/dev/null || echo " applications not found in $context" - docker stack rm infrastructure >/dev/null || echo " infrastructure stack not found in $context" - else - echo "Context $context not found" - fi -done - -echo "Waiting for services to stop" -sleep 10 - -echo "️Destroying cloud infrastructure" -if ! pulumi destroy --yes; then - echo "Pulumi destroy failed" - exit 1 -fi +echo "Pushing application image to ECR" -echo "Cleaning up SSH configuration" -SSH_CONFIG="$HOME/.ssh/config" -if [[ -f "$SSH_CONFIG" ]]; then - sed -i.bak '/^Host pocketsizefund-production$/,/^Host /{ /^Host pocketsizefund-production$/d; /^Host /!d; }' "$SSH_CONFIG" || true - sed -i.bak '${ /^Host /!d; }' "$SSH_CONFIG" || true -fi +aws_account_id=$(aws sts get-caller-identity --query Account --output text) -rm -f swarm.pem +aws ecr get-login-password \ + --region us-east-1 | docker login \ + --username AWS \ + --password-stdin ${aws_account_id}.dkr.ecr.us-east-1.amazonaws.com -echo "Removing Docker contexts" -docker context use default >/dev/null >&1 || true -for context in pocketsizefund-production pocketsizefund-local; do - docker context rm -f "$context" >/dev/null >&1 || true -done +docker push ${aws_account_id}.dkr.ecr.us-east-1.amazonaws.com/pocketsizefund/${application_name}-${stage_name}:latest -echo "Infrastructure taken down successfully" +echo "Application image pushed: ${application_name} ${stage_name}" ``` -### applications -> Build and deploy application containers -#### build -> Build and push application Docker images to DockerHub -```bash -set -euo pipefail - -echo "️Building and pushing application images" - -for app_dir in applications/*/; do - app_name=$(basename "$app_dir") - if [[ -f "$app_dir/Dockerfile" ]]; then - echo "Building $app_name..." - cd "$app_dir" - - version=$(uv version --short 2>/dev/null || echo "latest") +### stack - docker build -t "pocketsizefund/$app_name:latest" -t "pocketsizefund/$app_name:$version" . +> Manage infrastructure stack - docker push "pocketsizefund/$app_name:latest" - docker push "pocketsizefund/$app_name:$version" +#### up - cd .. - echo "$app_name built and pushed" - else - echo "️Skipping $app_name (no Dockerfile found)" - fi -done +> Launch or update infrastructure stack -echo "All application images built and pushed successfully" -``` - -#### deploy -> Deploy applications to both local and production Docker swarm ```bash set -euo pipefail -echo "Deploying applications" +cd infrastructure/ -if docker context ls --format '{{.Name}}' | grep -q "^pocketsizefund-production$"; then - echo "Deploying to production" - docker context use pocketsizefund-production - docker stack deploy -c applications/stack.yml applications --with-registry-auth -else - echo "️Production context not found, skipping production deployment" -fi +echo "Launching infrastructure" -if docker context ls --format '{{.Name}}' | grep -q "^pocketsizefund-local$"; then - echo "Deploying to local" - docker context use pocketsizefund-local - docker stack deploy -c applications/stack.yml applications --with-registry-auth -else - echo "️Local context not found, skipping local deployment" -fi - -docker context use default >/dev/null >&1 || true +pulumi up --diff --yes --stack production -echo "Application deployment completed" -``` - -## test -> Test application endpoints and service health across environments +echo "Forcing ECS service deployments to pull latest images" -### endpoints -> Test HTTP endpoints for DataManager and PortfolioManager services -```bash -set -euo pipefail +CLUSTER=$(pulumi stack output aws_ecs_cluster_name --stack production 2>/dev/null || echo "") -echo "Testing application endpoints" - -test_endpoint() { - local name="1$" - local url="2$" - local context="3$" - - printf "%-25s %-15s " "$name" "[$context]" - - if timeout 10 curl -sf "$url" >/dev/null 2>&1; then - echo " OK" - return 0 - elif timeout 10 curl -s "$url" >/dev/null 2>&1; then - echo " RESPONDING (non-200)" - return 1 - else - echo " FAILED" - return 1 - fi -} - -cd infrastructure -MANAGER_IP="" -if pulumi stack --show-name >/dev/null 2>&1; then - MANAGER_IP=$(pulumi stack output managerIp 2>/dev/null || echo "") -fi -cd .. - -echo "Local endpoints:" -test_endpoint "DataManager" "http://localhost:8080/health" "local" -test_endpoint "DataManager (root)" "http://localhost:8080/" "local" -test_endpoint "PortfolioManager" "http://localhost:8081/health" "local" -test_endpoint "PortfolioManager (root)" "http://localhost:8081/" "local" - -if [[ -n "$MANAGER_IP" ]]; then - echo "" - echo "Production endpoints (IP: $MANAGER_IP):" - test_endpoint "DataManager" "http://$MANAGER_IP:8080/health" "production" - test_endpoint "DataManager (root)" "http://$MANAGER_IP:8080/" "production" - test_endpoint "PortfolioManager" "http://$MANAGER_IP:8081/health" "production" - test_endpoint "PortfolioManager (root)" "http://$MANAGER_IP:8081/" "production" +if [ -z "$CLUSTER" ]; then + echo "Cluster not found - skipping service deployments (initial setup)" else - echo "️Production manager IP not available - skipping production tests" -fi - -docker context use default >/dev/null >&1 || true -echo " Endpoint testing completed" -``` - -### health -> Check Docker service health across all contexts -```bash -set -euo pipefail - -test_service_health() { - local context="$1" - echo "Docker Services in $context:" - - if docker context ls --format '{{.Name}}' | grep -q "^${context}$"; then - docker context use "$context" >/dev/null >&1 + for SERVICE in pocketsizefund-datamanager pocketsizefund-portfoliomanager pocketsizefund-equitypricemodel; do + echo "Checking if $SERVICE exists and is ready" + + # Wait up to 60 seconds for service to be active + RETRY_COUNT=0 + MAX_RETRIES=12 + RETRY_WAIT_SECONDS=5 + SERVICE_READY=false + + while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do + SERVICE_STATUS=$(aws ecs describe-services \ + --cluster "$CLUSTER" \ + --services "$SERVICE" \ + --query 'services[0].status' \ + --output text 2>/dev/null || echo "NONE") + + if [ "$SERVICE_STATUS" = "ACTIVE" ]; then + SERVICE_READY=true + echo "Service $SERVICE is ACTIVE" + break + elif [ "$SERVICE_STATUS" = "NONE" ]; then + echo "Service not found, waiting ($((RETRY_COUNT + 1))/$MAX_RETRIES)" + else + echo "Service status: $SERVICE_STATUS, waiting ($((RETRY_COUNT + 1))/$MAX_RETRIES)" + fi - if docker service ls --format "table {{.Name}}\t{{.Replicas}}\t{{.Image}}" >/dev/null; then - echo "Services listed successfully" + sleep $RETRY_WAIT_SECONDS + RETRY_COUNT=$((RETRY_COUNT + 1)) + done + + if [ "$SERVICE_READY" = true ]; then + echo "Forcing new deployment for $SERVICE" + aws ecs update-service \ + --cluster "$CLUSTER" \ + --service "$SERVICE" \ + --force-new-deployment \ + --no-cli-pager \ + --output text > /dev/null 2>&1 && echo "Deployment initiated" || echo "Failed to force deployment" else - echo "No services found or connection error" + echo "Skipping $SERVICE (not ready after 60s - may be initial deployment)" fi - else - echo "Context $context not available" - fi -} + done -echo "Service health check" -test_service_health "pocketsizefund-local" -test_service_health "pocketsizefund-production" + echo "Stack update complete - ECS is performing rolling deployments" + echo "Monitor progress: aws ecs describe-services --cluster $CLUSTER --services pocketsizefund-portfoliomanager" +fi -docker context use default >/dev/null >&1 || true +echo "Infrastructure launched successfully" ``` -### all -> Run complete test suite (endpoints + health checks) -```bash -set -euo pipefail +#### down -echo "Running complete test suite" +> Teardown infrastructure stack -mask test endpoints -mask test health +```bash +set -euo pipefail -echo "Complete test suite finished" -``` +echo "Tearing down infrastructure" -## docker -> Docker context and service management commands +cd infrastructure/ -### context -> Switch Docker context between local and production environments -#### local -> Switch to local Docker swarm context -```bash -docker context use pocketsizefund-local -echo "Switched to local context" -docker context ls | grep "\*" -``` +pulumi down --yes --stack production -#### production -> Switch to production Docker swarm context -```bash -docker context use pocketsizefund-production -echo "Switched to production context" -docker context ls | grep "\*" -``` - -#### default -> Switch back to default Docker context -```bash -docker context use default -echo "Switched to default context" +echo "Infrastructure torn down successfully" ``` ### services -> Docker swarm service management -#### ls -> List all Docker services with health status -```bash -echo "Docker services status:" -docker service ls -echo "Service health details:" -docker service ls --format "table {{.Name}}\t{{.Replicas}}\t{{.Image}}\t{{.Ports}}" | \ - while IFS=$'\t' read -r name replicas image ports; do - if [[ "$name" != "NAME" ]]; then - printf "%-30s %s\n" "$name" "$replicas" - fi - done -``` -#### logs -> View logs for a specific service (interactive selection) -```bash -echo "Available services:" -services=($(docker service ls --format '{{.Name}}')) +> Manage infrastructure services -if [[ ${#services[@]} -eq 0 ]]; then - echo "No services found" - exit 1 -fi +#### invoke (application_name) [date_range] -echo "Select a service:" -select service in "${services[@]}"; do - if [[ -n "$service" ]]; then - echo "Showing logs for $service (press Ctrl+C to exit):" - docker service logs -f "$service" - break - else - echo "Invalid selection. Please try again." - fi -done -``` +> Invoke service REST endpoint -#### inspect -> Inspect service configuration and status ```bash -echo "Available services:" -services=($(docker service ls --format '{{.Name}}')) - -if [[ ${#services[@]} -eq 0 ]]; then - echo "No services found" - exit 1 -fi +set -euo pipefail -echo "Select a service to inspect:" -select service in "${services[@]}"; do - if [[ -n "$service" ]]; then - echo "Inspecting $service:" - echo "Service tasks" - docker service ps "$service" - echo "Service details" - docker service inspect "$service" --pretty - break - else - echo "Invalid selection. Please try again." - fi -done -``` +echo "Invoking ${application_name} service" -### stack -> Docker stack operations for infrastructure and applications -#### ls -> List all deployed stacks -```bash -echo "Deployed Docker stacks:" -docker stack ls -``` +cd infrastructure/ -#### ps -> Show tasks for infrastructure and application stacks -```bash -echo "️Infrastructure stack:" -docker stack ps infrastructure >/dev/null || echo "Infrastructure stack not deployed" -echo "Applications stack:" -docker stack ps applications >/dev/null || echo "Applications stack not deployed" -``` +BASE_URL=$(pulumi stack output psf_base_url --stack production 2>/dev/null || echo "") -#### rm -> Remove infrastructure and application stacks -```bash -echo "Removing Docker stacks" -docker stack rm applications >/dev/null && echo "Applications stack removed" || echo "Applications stack not found" -docker stack rm infrastructure >/dev/null && echo "Infrastructure stack removed" || echo "Infrastructure stack not found" -echo "Waiting for cleanup" -sleep 5 -echo "Stack removal completed" -``` +if [ -z "$BASE_URL" ]; then + echo "Error: psf_base_url not found - infrastructure might not be deployed" + exit 1 +fi -## status -> Show comprehensive system status across all environments -```bash -set -euo pipefail +case "$application_name" in + portfoliomanager) + FULL_URL="${BASE_URL}/portfolio" + echo "Creating portfolio: $FULL_URL" + + curl -X POST "$FULL_URL" \ + -H "Content-Type: application/json" \ + -w "\nHTTP Status: %{http_code}\n" \ + -s + ;; + + datamanager) + if [ -n "${date_range:-}" ]; then + cd "${MASKFILE_DIR}" + uv run python tools/sync_equity_bars_data.py "$BASE_URL" "$date_range" + else + CURRENT_DATE=$(date -u +"%Y-%m-%dT00:00:00Z") + FULL_URL="${BASE_URL}/equity-bars" + echo "Syncing equity bars: $FULL_URL" + + curl -X POST "$FULL_URL" \ + -H "Content-Type: application/json" \ + -d "{\"date\": \"$CURRENT_DATE\"}" \ + -w "\nHTTP Status: %{http_code}\n" \ + -s + fi + ;; -echo "System status" + *) + echo "Unknown application name: ${application_name}" + echo "Valid options: portfoliomanager, datamanager" + exit 1 + ;; +esac +``` -echo "Docker contexts:" -docker context ls +## development -echo "️Infrastructure status:" -cd infrastructure -if pulumi stack --show-name >/dev/null; then - echo "Current stack: $(pulumi stack --show-name)" - if MANAGER_IP=$(pulumi stack output managerIp 2>/dev/null); then - echo "Manager IP: $MANAGER_IP" - else - echo "Manager IP: Not available (stack may be down)" - fi -else - echo "No active Pulumi stack found" -fi -cd .. +> Python development tools and code quality checks -echo "Docker stacks:" -if docker context use pocketsizefund-local >/dev/null >&1; then - echo "Local stacks:" - docker stack ls >/dev/null || echo " No stacks deployed locally" -fi -echo "" -if docker context use pocketsizefund-production >/dev/null >&1; then - echo "Production stacks:" - docker stack ls >/dev/null || echo " No stacks deployed in production" -fi +### rust -docker context use default >/dev/null >&1 || true -echo "Status check completed" -``` +> Rust development workflow commands -## secrets -> Manage Docker Swarm secrets for application configuration +#### update -### list -> List all Docker secrets (requires active swarm context) -```bash -echo "Docker secrets:" -if docker info --format '{{.Swarm.LocalNodeState}}' 2>/dev/null | grep -q active; then - docker secret ls -else - echo "Not connected to Docker swarm - switch context first:" - echo "mask docker context local" - echo "mask docker context production" -fi -``` +> Update Rust dependencies -### create -> Interactively create required Docker secrets ```bash set -euo pipefail -if ! docker info --format '{{.Swarm.LocalNodeState}}' 2>/dev/null | grep -q active; then - echo "Not connected to Docker swarm - switch context first:" - echo "mask docker context local" - echo "mask docker context production" - exit 1 -fi - -echo "Creating Docker secrets" -echo "Leave blank to skip a secret" - -secrets=( - "GRAFANA_ADMIN_PASSWORD:Grafana admin password" - "ALPACA_API_KEY:Alpaca API key" - "ALPACA_API_SECRET:Alpaca API secret" - "ALPACA_BASE_URL:Alpaca base URL" - "EDGAR_USER_AGENT:EDGAR user agent string" - "DATA_BUCKET:Data storage bucket name" - "POLYGON_API_KEY:Polygon API key" - "DUCKDB_ACCESS_KEY:DuckDB access key" - "DUCKDB_SECRET:DuckDB secret" - "WEIGHTS_AND_BIASES_API_KEY:Weights & Biases API key" -) - -for secret_info in "${secrets[@]}"; do - secret_name="${secret_info%%:*}" - secret_desc="${secret_info#*:}" +echo "Updating Rust dependencies" - echo -n "Enter $secret_desc ($secret_name): " - read -r secret_value - - if [[ -n "$secret_value" ]]; then - if echo "$secret_value" | docker secret create "$secret_name" - >/dev/null; then - echo "Created $secret_name" - else - echo "️ $secret_name already exists or creation failed" - fi - else - echo "️Skipped $secret_name" - fi -done +cargo update -echo "Secret creation completed" +echo "Rust dependencies updated successfully" ``` -## development -> Python development tools and code quality checks - -### rust -> Rust development workflow commands - #### check + > Check Rust compilation + ```bash set -euo pipefail echo "Check Rust compilation" + cargo check + echo "Rust compiled successfully" ``` #### format + > Format Rust code + ```bash set -euo pipefail echo "Formatting Rust code" + cargo fmt --all + echo "Rust code formatted successfully" ``` #### lint + > Run Rust code quality checks + ```bash set -euo pipefail echo "Running Rust lint checks" + cargo clippy + echo "Rust linting completed successfully" ``` - #### test + > Run Rust tests + ```bash set -euo pipefail echo "Running Rust tests" + cargo test --workspace --verbose + echo "Rust tests completed successfully" ``` #### all + > Full Rust development checks + ```bash set -euo pipefail echo "Running Rust development checks" +mask development rust update + mask development rust check mask development rust format @@ -707,40 +339,50 @@ mask development rust lint mask development rust test -echo "Rust development workflow completed successfully" +echo "Rust development checks completed successfully" ``` ### python + > Python development workflow commands + #### install + > Install Python dependencies + ```bash set -euo pipefail echo "Installing Python dependencies" -export COMPOSE_BAKE=true + uv sync --all-packages --all-groups echo "Python dependencies installed successfully" ``` #### format + > Format Python code + ```bash set -euo pipefail echo "Formatting Python code" + ruff format echo "Python code formatted successfully" ``` #### dead-code + > Check for dead Python code + ```bash set -euo pipefail -echo "Running vulture dead code analysis" +echo "Running dead code analysis" + uvx vulture \ --min-confidence 80 \ --exclude '.flox,.venv,target' \ @@ -750,13 +392,14 @@ echo "Dead code check completed" ``` #### lint + > Run comprehensive Python code quality checks + ```bash set -euo pipefail echo "Running Python lint checks" -echo "Running ruff linting" ruff check \ --output-format=github \ . @@ -765,31 +408,23 @@ echo "Python linting completed successfully" ``` #### test + > Run Python tests using Docker Compose with coverage reporting + ```bash set -euo pipefail echo "Running Python tests" -mkdir -p coverage_output - -echo "Cleaning up previous test runs" -docker compose --file tests.yaml down --volumes --remove-orphans - -echo "️Building test containers" -docker compose --file tests.yaml build tests - -echo "Running tests with coverage" -docker compose --file tests.yaml run --rm --no-TTY tests - -echo "Cleaning up test containers" -docker compose --file tests.yaml down --volumes --remove-orphans +uv run coverage run --parallel-mode -m pytest && uv run coverage combine && uv run coverage report && uv run coverage xml -o coverage/.python.xml echo "Python tests completed successfully" ``` #### all + > Full Python development checks + ```bash set -euo pipefail @@ -805,76 +440,51 @@ mask development python dead-code mask development python test -echo "Development workflow completed successfully" +echo "Python development checks completed successfully" ``` -## logs -> Quick access to service logs across environments +## models + +> Model management commands + +### train (application_name) + +> Train machine learning model -### infrastructure -> View logs for infrastructure services (Grafana, Prometheus, Traefik) ```bash -echo "Infrastructure service logs" -echo "Select environment:" -select env in "local" "production"; do - case $env in - local|production) - context="pocketsizefund-$env" - docker context use "$context" - echo "Infrastructure services in $env:" - services=($(docker service ls --filter "name=infrastructure_" --format '{{.Name}}')) - if [[ ${#services[@]} -eq 0 ]]; then - echo "No infrastructure services found" - exit 1 - fi - echo "Select service:" - select service in "${services[@]}"; do - if [[ -n "$service" ]]; then - echo "Logs for $service (press Ctrl+C to exit):" - docker service logs -f "$service" - break - fi - done - break - ;; - *) - echo "Invalid selection" - ;; - esac -done -docker context use default >/dev/null >&1 || true +set -euo pipefail + +# Load environment variables in isolated subshell +( + set -a + source "${MASKFILE_DIR}/.env" + set +a + + export APPLICATION_NAME="${application_name}" + + uv run python tools/run_training_job.py +) ``` -### applications -> View logs for application services (DataManager, PortfolioManager) +### artifacts + +#### download (application_name) + +> Manage model artifacts + ```bash -echo "Application service logs" -echo "Select environment:" -select env in "local" "production"; do - case $env in - local|production) - context="pocketsizefund-$env" - docker context use "$context" - echo "Application services in $env:" - services=($(docker service ls --filter "name=applications_" --format '{{.Name}}')) - if [[ ${#services[@]} -eq 0 ]]; then - echo "No application services found" - exit 1 - fi - echo "Select service:" - select service in "${services[@]}"; do - if [[ -n "$service" ]]; then - echo " Logs for $service (press Ctrl+C to exit):" - docker service logs -f "$service" - break - fi - done - break - ;; - *) - echo "Invalid selection" - ;; - esac -done -docker context use default >/dev/null >&1 || true +set -euo pipefail + +# Load environment variables in isolated subshell +( + set -a + source "${MASKFILE_DIR}/.env" + set +a + + export APPLICATION_NAME="${application_name}" + + uv run python tools/download_model_artifacts.py +) ``` + + diff --git a/pyproject.toml b/pyproject.toml index dbbb6f76d..eda4eca81 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,13 +3,28 @@ name = "pocketsizefund" version = "20250602.4" description = "Open source quantitative hedge fund 🍊" requires-python = "==3.12.10" -dependencies = ["internal"] +dependencies = [ + "internal", + "fastapi>=0.121.0", + "uvicorn>=0.35.0", + "structlog>=25.5.0", + "sagemaker>=2.252.0", + "numpy>=1.26.4", + "tinygrad>=0.10.3", + "requests>=2.32.5", +] [tool.uv.sources] internal = { workspace = true } [tool.uv.workspace] -members = ["applications/*", "libraries/python"] +members = [ + "applications/portfoliomanager", + "applications/equitypricemodel", + "libraries/python", + "infrastructure", + "tools", +] [dependency-groups] dev = ["coverage>=7.8.0", "pytest>=8.3.5", "behave>=1.2.6"] @@ -40,7 +55,7 @@ show_missing = true skip_covered = true [tool.coverage.xml] -output = "coverage_output/.python_coverage.xml" +output = "coverage/.python.xml" [tool.ruff.lint] select = [ @@ -76,6 +91,7 @@ select = [ "PERF", # performance "PIE", # misc lints "PL", # pylint + "PLR", # pylint refactor "PT", # pytest style "PTH", # use pathlib "PYI", # type hints diff --git a/tests.yaml b/tests.yaml deleted file mode 100644 index 55d8243fd..000000000 --- a/tests.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: pocketsizefund-tests -services: - tests: - image: pocketsizefund-tests:latest - build: - context: . - dockerfile: Dockerfile.tests - tags: - - pocketsizefund-tests:latest - volumes: - - ./coverage_output:/tests/coverage_output # mounted for coverage output - command: - - /bin/sh - - -euxc - - | - uv run coverage run --parallel-mode -m pytest && \ - uv run coverage combine && \ - uv run coverage report && \ - uv run coverage xml -o /tests/coverage_output/.python_coverage.xml diff --git a/tools/download_model_artifacts.py b/tools/download_model_artifacts.py new file mode 100644 index 000000000..d04138125 --- /dev/null +++ b/tools/download_model_artifacts.py @@ -0,0 +1,122 @@ +import os +import sys +import tarfile + +import boto3 +import structlog + +logger = structlog.get_logger() + + +def download_model_artifacts( + application_name: str, + aws_profile: str, + artifacts_bucket: str, +) -> None: + logger.info("Downloading model artifact", application_name=application_name) + + session = boto3.Session(profile_name=aws_profile) + s3_client = session.client("s3") + + try: + file_objects = s3_client.list_objects_v2( + Bucket=artifacts_bucket, + Prefix=f"artifacts/{application_name}", + ) + except Exception as e: + logger.exception("Error listing objects", bucket=artifacts_bucket, error=f"{e}") + raise RuntimeError from e + + options = set() + + for file_object in file_objects.get("Contents", []): + file_object_name = file_object["Key"] + + file_object_name_parts = file_object_name.split("/") + + if len(file_object_name_parts) < 2: # noqa: PLR2004 + logger.warning("Skipping malformed path", path=file_object_name) + continue + + options.add(file_object_name_parts[1]) + + if not options: + logger.error("No artifacts found", application_name=application_name) + raise RuntimeError + + logger.info("Available artifacts", options=options) + + selected_option = input("Select an artifact to download: ") + + if selected_option not in options: + logger.error( + "Invalid selection", + selected_option=selected_option, + valid_options=options, + ) + raise RuntimeError + + logger.info("Selected artifact", selected_option=selected_option) + + target_path = f"artifacts/{selected_option}/output/model.tar.gz" + destination_directory = f"applications/{application_name}/src/{application_name}/" + destination_path = os.path.join(destination_directory, "model.tar.gz") # noqa: PTH118 + + os.makedirs(destination_directory, exist_ok=True) # noqa: PTH103 + + try: + s3_client.download_file( + Bucket=artifacts_bucket, + Key=target_path, + Filename=destination_path, + ) + except Exception as e: + logger.exception( + "Error downloading file", + bucket=artifacts_bucket, + key=target_path, + error=f"{e}", + ) + raise RuntimeError from e + + try: + with tarfile.open(destination_path, "r:gz") as tar: + tar.extractall(path=destination_directory, filter="data") + except Exception as e: + logger.exception( + "Error extracting tar file", + path=destination_path, + error=f"{e}", + ) + raise RuntimeError from e + + logger.info("Artifact downloaded and extracted successfully") + + +if __name__ == "__main__": + application_name = os.getenv("APPLICATION_NAME", "") + aws_profile = os.getenv("AWS_PROFILE", "") + artifacts_bucket = os.getenv("AWS_S3_ARTIFACTS_BUCKET_NAME", "") + + environment_variables = { + "APPLICATION_NAME": application_name, + "AWS_PROFILE": aws_profile, + "AWS_S3_ARTIFACTS_BUCKET_NAME": artifacts_bucket, + } + for environment_variable in [application_name, aws_profile, artifacts_bucket]: + if not environment_variable: + logger.error( + "Missing required environment variable(s)", + **environment_variables, + ) + sys.exit(1) + + try: + download_model_artifacts( + application_name=application_name, + aws_profile=aws_profile, + artifacts_bucket=artifacts_bucket, + ) + except Exception as e: + logger.exception("Failed to download model artifacts", error=f"{e}") + sys.exit(1) diff --git a/tools/pyproject.toml b/tools/pyproject.toml new file mode 100644 index 000000000..26c68dbf0 --- /dev/null +++ b/tools/pyproject.toml @@ -0,0 +1,6 @@ +[project] +name = "tools" +version = "0.1.0" +description = "Project tools and scripts" +requires-python = "==3.12.10" +dependencies = ["boto3>=1.40.74", "massive>=2.0.2"] diff --git a/tools/run_training_job.py b/tools/run_training_job.py new file mode 100644 index 000000000..221ea41d9 --- /dev/null +++ b/tools/run_training_job.py @@ -0,0 +1,103 @@ +import os +import sys + +import boto3 +import structlog +from sagemaker.estimator import Estimator +from sagemaker.inputs import TrainingInput +from sagemaker.session import Session + +logger = structlog.get_logger() + + +def run_training_job( # noqa: PLR0913 + application_name: str, + aws_profile: str, + image_uri: str, + s3_data_path: str, + sagemaker_role: str, + output_path: str, +) -> None: + logger.info("Starting training job", application_name=application_name) + + try: + session = boto3.Session(profile_name=aws_profile) + sagemaker_session = Session(boto_session=session) + except Exception as e: + logger.exception( + "Error creating SageMaker session", + error=f"{e}", + application_name=application_name, + ) + raise RuntimeError from e + + estimator = Estimator( + image_uri=image_uri, + role=sagemaker_role, + instance_count=1, + instance_type="ml.t3.xlarge", + sagemaker_session=sagemaker_session, + output_path=output_path, + ) + + training_data_input = TrainingInput( + s3_data=s3_data_path, + content_type="application/x-parquet", + input_mode="File", + ) + + try: + estimator.fit({"train": training_data_input}) + except Exception as e: + logger.exception( + "Error during training job", + error=f"{e}", + application_name=application_name, + ) + raise RuntimeError from e + + +if __name__ == "__main__": + application_name = os.getenv("APPLICATION_NAME", "") + aws_profile = os.getenv("AWS_PROFILE", "") + image_uri = os.getenv("AWS_ECR_EQUITY_PRICE_MODEL_TRAINER_IMAGE_ARN", "") + s3_data_path = os.getenv("AWS_S3_EQUITY_PRICE_MODEL_TRAINING_DATA_PATH", "") + sagemaker_role = os.getenv("AWS_SAGEMAKER_ROLE_ARN", "") + output_path = os.getenv("AWS_S3_EQUITY_PRICE_MODEL_ARTIFACT_OUTPUT_PATH", "") + + environment_variables = { + "APPLICATION_NAME": application_name, + "AWS_PROFILE": aws_profile, + "AWS_ECR_EQUITY_PRICE_MODEL_TRAINER_IMAGE_ARN": image_uri, + "AWS_S3_EQUITY_PRICE_MODEL_TRAINING_DATA_PATH": s3_data_path, + "AWS_SAGEMAKER_ROLE_ARN": sagemaker_role, + "AWS_S3_EQUITY_PRICE_MODEL_ARTIFACT_OUTPUT_PATH": output_path, + } + + missing_environment_variables = [ + key for key, value in environment_variables.items() if not value + ] + if missing_environment_variables: + logger.error( + "Missing required environment variables", + missing_environment_variables=missing_environment_variables, + **environment_variables, + ) + sys.exit(1) + + try: + run_training_job( + application_name=application_name, + aws_profile=aws_profile, + image_uri=image_uri, + s3_data_path=s3_data_path, + sagemaker_role=sagemaker_role, + output_path=output_path, + ) + except Exception as e: + logger.exception( + "Training job failed", + error=f"{e}", + application_name=application_name, + ) + sys.exit(1) diff --git a/tools/sync_equity_bars_data.py b/tools/sync_equity_bars_data.py new file mode 100644 index 000000000..e6deb07b6 --- /dev/null +++ b/tools/sync_equity_bars_data.py @@ -0,0 +1,153 @@ +import json +import sys +import time +from datetime import UTC, datetime, timedelta + +import requests +import structlog + +logger = structlog.get_logger() + + +def validate_and_parse_dates(date_range_json: str) -> tuple[datetime, datetime]: + try: + date_range = json.loads(date_range_json) + except json.JSONDecodeError as e: + logger.exception("JSON decoding error", error=f"{e}") + raise RuntimeError from e + + if "start_date" not in date_range or "end_date" not in date_range: + logger.error("Missing required date fields", date_range=date_range) + raise RuntimeError + + try: + start_date = datetime.strptime(date_range["start_date"], "%Y-%m-%d").replace( + tzinfo=UTC + ) + end_date = datetime.strptime(date_range["end_date"], "%Y-%m-%d").replace( + tzinfo=UTC + ) + except ValueError as e: + logger.exception( + "Date parsing error", + error=f"{e}", + required_format="YYYY-MM-DD", + ) + raise RuntimeError from e + + current_date = datetime.now(tz=UTC).replace( + hour=0, minute=0, second=0, microsecond=0 + ) + maximum_lookback_days = 365 * 2 # two year limit + + minimum_allowed_date = current_date - timedelta(days=maximum_lookback_days) + + start_date = max(start_date, minimum_allowed_date) + end_date = min(end_date, current_date) + + if start_date > end_date: + logger.error( + "Invalid date range after clamping", + start_date=start_date.strftime("%Y-%m-%d"), + end_date=end_date.strftime("%Y-%m-%d"), + ) + raise RuntimeError + + return start_date, end_date + + +def sync_equity_bars_for_date(base_url: str, date: datetime) -> int: + url = f"{base_url}/equity-bars" + date_string = date.strftime("%Y-%m-%dT00:00:00Z") + + response = requests.post( + url, + json={"date": date_string}, + headers={"Content-Type": "application/json"}, + timeout=60, + ) + + return response.status_code + + +def sync_equity_bars_data( + base_url: str, + date_range: tuple[datetime, datetime], +) -> None: + start_date, end_date = date_range + + logger.info( + "Backfilling equity bars", + start_date=start_date.strftime("%Y-%m-%d"), + end_date=end_date.strftime("%Y-%m-%d"), + ) + logger.info("Data manager URL", base_url=f"{base_url}/equity-bars") + + current_date = start_date + request_count = 0 + + while current_date <= end_date: + request_count += 1 + + logger.info( + "Syncing data started", + request_count=request_count, + date=current_date.strftime("%Y-%m-%d"), + ) + + try: + status_code = sync_equity_bars_for_date(base_url, current_date) + logger.info("Syncing data completed", status_code=status_code) + + if status_code >= 400: # noqa: PLR2004 + logger.error("Syncing data failed", status_code=status_code) + except requests.RequestException as e: + logger.exception("HTTP request failed", error=f"{e}") + + current_date += timedelta(days=1) + + if current_date <= end_date: + logger.info("Waiting 15 seconds before next request") + time.sleep(15) # Polygon rate limit + + logger.info("All dates processed", total_requests=request_count) + + +if __name__ == "__main__": + if len(sys.argv) != 3: # noqa: PLR2004 + logger.error( + "Usage: python sync_equity_bars_data.py ", + args_received=len(sys.argv) - 1, + ) + sys.exit(1) + + base_url = sys.argv[1] + raw_date_range = sys.argv[2] + + arguments = { + "base_url": base_url, + "raw_date_range": raw_date_range, + } + + for argument in [base_url, raw_date_range]: + if not argument: + logger.error( + "Missing required positional argument(s)", + **arguments, + ) + sys.exit(1) + + try: + date_range = validate_and_parse_dates(raw_date_range) + except Exception as e: + logger.exception("Failed to parse date range", error=f"{e}") + sys.exit(1) + + try: + sync_equity_bars_data( + base_url=base_url, + date_range=date_range, + ) + except Exception as e: + logger.exception("Failed to sync equity bars data", error=f"{e}") + sys.exit(1) diff --git a/uv.lock b/uv.lock index 8e5c6a6b3..4a3349f73 100644 --- a/uv.lock +++ b/uv.lock @@ -8,111 +8,12 @@ resolution-markers = [ [manifest] members = [ - "datamanager", + "equitypricemodel", + "infrastructure", "internal", - "models", "pocketsizefund", "portfoliomanager", -] - -[[package]] -name = "adlfs" -version = "2024.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "azure-core" }, - { name = "azure-datalake-store" }, - { name = "azure-identity" }, - { name = "azure-storage-blob" }, - { name = "fsspec" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/76/82/e30891af574fb358449fb9436aac53569814452cb88b0cba4f488171b8dc/adlfs-2024.12.0.tar.gz", hash = "sha256:04582bf7461a57365766d01a295a0a88b2b8c42c4fea06e2d673f62675cac5c6", size = 49189, upload-time = "2024-12-15T19:06:30.939Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/ed/d1bf75c089857d38332cf45416e419b47382b345ba5dfc4fae69397830d9/adlfs-2024.12.0-py3-none-any.whl", hash = "sha256:00aab061ddec0413b2039487e656b62e01ece8ef1ca0493f76034a596cf069e3", size = 41792, upload-time = "2024-12-15T19:06:27.718Z" }, -] - -[[package]] -name = "aiobotocore" -version = "2.24.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "aioitertools" }, - { name = "botocore" }, - { name = "jmespath" }, - { name = "multidict" }, - { name = "python-dateutil" }, - { name = "wrapt" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/02/b4ed1af4b3437c2fc6e6111e7fdee011b34cf1c0cc8f314474f843e10019/aiobotocore-2.24.1.tar.gz", hash = "sha256:59237f1b2d4ff619f9a9e78360b691d59b92fdd4d03d054dbd2eeff8ada5667e", size = 119754, upload-time = "2025-08-15T15:49:53.209Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/26/c3c93209084e24990ad1b4214f67dce1c0183454cec9cd2cad9433f493bb/aiobotocore-2.24.1-py3-none-any.whl", hash = "sha256:557922823455ca65bbd065b363b54846f16b9c4b6bd0b61ecdfa01ca13a04531", size = 85216, upload-time = "2025-08-15T15:49:51.442Z" }, -] - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, -] - -[[package]] -name = "aiohttp" -version = "3.12.15" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9b/e7/d92a237d8802ca88483906c388f7c201bbe96cd80a165ffd0ac2f6a8d59f/aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2", size = 7823716, upload-time = "2025-07-29T05:52:32.215Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/63/97/77cb2450d9b35f517d6cf506256bf4f5bda3f93a66b4ad64ba7fc917899c/aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7", size = 702333, upload-time = "2025-07-29T05:50:46.507Z" }, - { url = "https://files.pythonhosted.org/packages/83/6d/0544e6b08b748682c30b9f65640d006e51f90763b41d7c546693bc22900d/aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444", size = 476948, upload-time = "2025-07-29T05:50:48.067Z" }, - { url = "https://files.pythonhosted.org/packages/3a/1d/c8c40e611e5094330284b1aea8a4b02ca0858f8458614fa35754cab42b9c/aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d", size = 469787, upload-time = "2025-07-29T05:50:49.669Z" }, - { url = "https://files.pythonhosted.org/packages/38/7d/b76438e70319796bfff717f325d97ce2e9310f752a267bfdf5192ac6082b/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c", size = 1716590, upload-time = "2025-07-29T05:50:51.368Z" }, - { url = "https://files.pythonhosted.org/packages/79/b1/60370d70cdf8b269ee1444b390cbd72ce514f0d1cd1a715821c784d272c9/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0", size = 1699241, upload-time = "2025-07-29T05:50:53.628Z" }, - { url = "https://files.pythonhosted.org/packages/a3/2b/4968a7b8792437ebc12186db31523f541943e99bda8f30335c482bea6879/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab", size = 1754335, upload-time = "2025-07-29T05:50:55.394Z" }, - { url = "https://files.pythonhosted.org/packages/fb/c1/49524ed553f9a0bec1a11fac09e790f49ff669bcd14164f9fab608831c4d/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb", size = 1800491, upload-time = "2025-07-29T05:50:57.202Z" }, - { url = "https://files.pythonhosted.org/packages/de/5e/3bf5acea47a96a28c121b167f5ef659cf71208b19e52a88cdfa5c37f1fcc/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545", size = 1719929, upload-time = "2025-07-29T05:50:59.192Z" }, - { url = "https://files.pythonhosted.org/packages/39/94/8ae30b806835bcd1cba799ba35347dee6961a11bd507db634516210e91d8/aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c", size = 1635733, upload-time = "2025-07-29T05:51:01.394Z" }, - { url = "https://files.pythonhosted.org/packages/7a/46/06cdef71dd03acd9da7f51ab3a9107318aee12ad38d273f654e4f981583a/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd", size = 1696790, upload-time = "2025-07-29T05:51:03.657Z" }, - { url = "https://files.pythonhosted.org/packages/02/90/6b4cfaaf92ed98d0ec4d173e78b99b4b1a7551250be8937d9d67ecb356b4/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f", size = 1718245, upload-time = "2025-07-29T05:51:05.911Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e6/2593751670fa06f080a846f37f112cbe6f873ba510d070136a6ed46117c6/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d", size = 1658899, upload-time = "2025-07-29T05:51:07.753Z" }, - { url = "https://files.pythonhosted.org/packages/8f/28/c15bacbdb8b8eb5bf39b10680d129ea7410b859e379b03190f02fa104ffd/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519", size = 1738459, upload-time = "2025-07-29T05:51:09.56Z" }, - { url = "https://files.pythonhosted.org/packages/00/de/c269cbc4faa01fb10f143b1670633a8ddd5b2e1ffd0548f7aa49cb5c70e2/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea", size = 1766434, upload-time = "2025-07-29T05:51:11.423Z" }, - { url = "https://files.pythonhosted.org/packages/52/b0/4ff3abd81aa7d929b27d2e1403722a65fc87b763e3a97b3a2a494bfc63bc/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3", size = 1726045, upload-time = "2025-07-29T05:51:13.689Z" }, - { url = "https://files.pythonhosted.org/packages/71/16/949225a6a2dd6efcbd855fbd90cf476052e648fb011aa538e3b15b89a57a/aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1", size = 423591, upload-time = "2025-07-29T05:51:15.452Z" }, - { url = "https://files.pythonhosted.org/packages/2b/d8/fa65d2a349fe938b76d309db1a56a75c4fb8cc7b17a398b698488a939903/aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34", size = 450266, upload-time = "2025-07-29T05:51:17.239Z" }, -] - -[[package]] -name = "aioitertools" -version = "0.12.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/de/38491a84ab323b47c7f86e94d2830e748780525f7a10c8600b67ead7e9ea/aioitertools-0.12.0.tar.gz", hash = "sha256:c2a9055b4fbb7705f561b9d86053e8af5d10cc845d22c32008c43490b2d8dd6b", size = 19369, upload-time = "2024-09-02T03:33:40.349Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/13/58b70a580de00893223d61de8fea167877a3aed97d4a5e1405c9159ef925/aioitertools-0.12.0-py3-none-any.whl", hash = "sha256:fc1f5fac3d737354de8831cbba3eb04f79dd649d8f3afb4c5b114925e662a796", size = 24345, upload-time = "2024-09-02T03:34:59.454Z" }, -] - -[[package]] -name = "aiosignal" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, + "tools", ] [[package]] @@ -132,6 +33,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/b5/efdf8d3d206632b0dfaad07193dd396413235f9d9a96c1843d83594851d4/alpaca_py-0.42.1-py3-none-any.whl", hash = "sha256:234fea37151d4d5995de6d4f2fff24d584120214eb9f39198c399d1000004efa", size = 122157, upload-time = "2025-08-29T18:40:50.9Z" }, ] +[[package]] +name = "annotated-doc" +version = "0.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/a6/dc46877b911e40c00d395771ea710d5e77b6de7bacd5fdcd78d70cc5a48f/annotated_doc-0.0.3.tar.gz", hash = "sha256:e18370014c70187422c33e945053ff4c286f453a984eba84d0dbfa0c935adeda", size = 5535, upload-time = "2025-10-24T14:57:10.718Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/b7/cf592cb5de5cb3bade3357f8d2cf42bf103bbe39f459824b4939fd212911/annotated_doc-0.0.3-py3-none-any.whl", hash = "sha256:348ec6664a76f1fd3be81f43dffbee4c7e8ce931ba71ec67cc7f4ade7fbbb580", size = 5488, upload-time = "2025-10-24T14:57:09.462Z" }, +] + [[package]] name = "annotated-types" version = "0.7.0" @@ -141,6 +51,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] +[[package]] +name = "antlr4-python3-runtime" +version = "4.9.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3e/38/7859ff46355f76f8d19459005ca000b6e7012f2f1ca597746cbcd1fbfe5e/antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b", size = 117034, upload-time = "2021-11-06T17:52:23.524Z" } + [[package]] name = "anyio" version = "4.10.0" @@ -156,71 +72,21 @@ wheels = [ ] [[package]] -name = "attrs" -version = "25.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, -] - -[[package]] -name = "azure-core" -version = "1.35.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "requests" }, - { name = "six" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/89/f53968635b1b2e53e4aad2dd641488929fef4ca9dfb0b97927fa7697ddf3/azure_core-1.35.0.tar.gz", hash = "sha256:c0be528489485e9ede59b6971eb63c1eaacf83ef53001bfe3904e475e972be5c", size = 339689, upload-time = "2025-07-03T00:55:23.496Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/78/bf94897361fdd650850f0f2e405b2293e2f12808239046232bdedf554301/azure_core-1.35.0-py3-none-any.whl", hash = "sha256:8db78c72868a58f3de8991eb4d22c4d368fae226dac1002998d6c50437e7dad1", size = 210708, upload-time = "2025-07-03T00:55:25.238Z" }, -] - -[[package]] -name = "azure-datalake-store" -version = "0.0.53" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi" }, - { name = "msal" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/22/ff/61369d06422b5ac48067215ff404841342651b14a89b46c8d8e1507c8f17/azure-datalake-store-0.0.53.tar.gz", hash = "sha256:05b6de62ee3f2a0a6e6941e6933b792b800c3e7f6ffce2fc324bc19875757393", size = 71430, upload-time = "2023-05-10T21:17:05.665Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/2a/75f56b14f115189155cf12e46b366ad1fe3357af5a1a7c09f7446662d617/azure_datalake_store-0.0.53-py2.py3-none-any.whl", hash = "sha256:a30c902a6e360aa47d7f69f086b426729784e71c536f330b691647a51dc42b2b", size = 55308, upload-time = "2023-05-10T21:17:02.629Z" }, -] - -[[package]] -name = "azure-identity" -version = "1.24.0" +name = "arpeggio" +version = "2.0.3" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "azure-core" }, - { name = "cryptography" }, - { name = "msal" }, - { name = "msal-extensions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b5/44/f3ee20bacb220b6b4a2b0a6cf7e742eecb383a5ccf604dd79ec27c286b7e/azure_identity-1.24.0.tar.gz", hash = "sha256:6c3a40b2a70af831e920b89e6421e8dcd4af78a0cb38b9642d86c67643d4930c", size = 271630, upload-time = "2025-08-07T22:27:36.258Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/58/ba011f3cf8291804ce80f9d81289ac15f0319a27f9d7e3c124aa5e4981cc/Arpeggio-2.0.3.tar.gz", hash = "sha256:9e85ad35cfc6c938676817c7ae9a1000a7c72a34c71db0c687136c460d12b85e", size = 766566, upload-time = "2025-09-12T12:45:20.594Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/74/17428cb429e8d52f6d0d69ed685f4760a545cb0156594963a9337b53b6c9/azure_identity-1.24.0-py3-none-any.whl", hash = "sha256:9e04997cde0ab02ed66422c74748548e620b7b29361c72ce622acab0267ff7c4", size = 187890, upload-time = "2025-08-07T22:27:38.033Z" }, + { url = "https://files.pythonhosted.org/packages/84/4d/53b8186b41842f7a5e971b1d1c28e678364dcf841e4170f5d14d38ac1e2a/Arpeggio-2.0.3-py2.py3-none-any.whl", hash = "sha256:9374d9c531b62018b787635f37fd81c9a6ee69ef2d28c5db3cd18791b1f7db2f", size = 54656, upload-time = "2025-09-12T12:45:17.971Z" }, ] [[package]] -name = "azure-storage-blob" -version = "12.26.0" +name = "attrs" +version = "25.3.0" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "azure-core" }, - { name = "cryptography" }, - { name = "isodate" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/96/95/3e3414491ce45025a1cde107b6ae72bf72049e6021597c201cd6a3029b9a/azure_storage_blob-12.26.0.tar.gz", hash = "sha256:5dd7d7824224f7de00bfeb032753601c982655173061e242f13be6e26d78d71f", size = 583332, upload-time = "2025-07-16T21:34:07.644Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/64/63dbfdd83b31200ac58820a7951ddfdeed1fbee9285b0f3eae12d1357155/azure_storage_blob-12.26.0-py3-none-any.whl", hash = "sha256:8c5631b8b22b4f53ec5fff2f3bededf34cfef111e2af613ad42c9e6de00a77fe", size = 412907, upload-time = "2025-07-16T21:34:09.367Z" }, + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, ] [[package]] @@ -242,39 +108,30 @@ wheels = [ [[package]] name = "boto3" -version = "1.39.11" +version = "1.40.74" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b6/2e/ed75ea3ee0fd1afacc3379bc2b7457c67a6b0f0e554e1f7ccbdbaed2351b/boto3-1.39.11.tar.gz", hash = "sha256:3027edf20642fe1d5f9dc50a420d0fe2733073ed6a9f0f047b60fe08c3682132", size = 111869, upload-time = "2025-07-22T19:26:50.867Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/37/0db5fc46548b347255310893f1a47971a1d8eb0dbc46dfb5ace8a1e7d45e/boto3-1.40.74.tar.gz", hash = "sha256:484e46bf394b03a7c31b34f90945ebe1390cb1e2ac61980d128a9079beac87d4", size = 111592, upload-time = "2025-11-14T20:29:10.991Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/66/88566a6484e746c0b075f7c9bb248e8548eda0a486de4460d150a41e2d57/boto3-1.39.11-py3-none-any.whl", hash = "sha256:af8f1dad35eceff7658fab43b39b0f55892b6e3dd12308733521cc24dd2c9a02", size = 139900, upload-time = "2025-07-22T19:26:48.706Z" }, + { url = "https://files.pythonhosted.org/packages/d2/08/c52751748762901c0ca3c3019e3aa950010217f0fdf9940ebe68e6bb2f5a/boto3-1.40.74-py3-none-any.whl", hash = "sha256:41fc8844b37ae27b24bcabf8369769df246cc12c09453988d0696ad06d6aa9ef", size = 139360, upload-time = "2025-11-14T20:29:09.477Z" }, ] [[package]] name = "botocore" -version = "1.39.11" +version = "1.40.74" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6d/d0/9d64261186cff650fe63168441edb4f4cd33f085a74c0c54455630a71f91/botocore-1.39.11.tar.gz", hash = "sha256:953b12909d6799350e346ab038e55b6efe622c616f80aef74d7a6683ffdd972c", size = 14217749, upload-time = "2025-07-22T19:26:40.723Z" } +sdist = { url = "https://files.pythonhosted.org/packages/81/dc/0412505f05286f282a75bb0c650e525ddcfaf3f6f1a05cd8e99d32a2db06/botocore-1.40.74.tar.gz", hash = "sha256:57de0b9ffeada06015b3c7e5186c77d0692b210d9e5efa294f3214df97e2f8ee", size = 14452479, upload-time = "2025-11-14T20:29:00.949Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1c/2c/8a0b02d60a1dbbae7faa5af30484b016aa3023f9833dfc0d19b0b770dd6a/botocore-1.39.11-py3-none-any.whl", hash = "sha256:1545352931a8a186f3e977b1e1a4542d7d434796e274c3c62efd0210b5ea76dc", size = 13876276, upload-time = "2025-07-22T19:26:35.164Z" }, -] - -[[package]] -name = "cachetools" -version = "5.5.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380, upload-time = "2025-02-20T21:01:19.524Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080, upload-time = "2025-02-20T21:01:16.647Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a2/306dec16e3c84f3ca7aaead0084358c1c7fbe6501f6160844cbc93bc871e/botocore-1.40.74-py3-none-any.whl", hash = "sha256:f39f5763e35e75f0bd91212b7b36120b1536203e8003cd952ef527db79702b15", size = 14117911, upload-time = "2025-11-14T20:28:58.153Z" }, ] [[package]] @@ -286,28 +143,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, ] -[[package]] -name = "cffi" -version = "1.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, -] - [[package]] name = "charset-normalizer" version = "3.4.3" @@ -340,18 +175,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, ] -[[package]] -name = "cloudevents" -version = "1.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "deprecation" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7a/aa/804bdb5f2f021fcc887eeabfa24bad0ffd4b150f60850ae88faa51d393a5/cloudevents-1.12.0.tar.gz", hash = "sha256:ebd5544ceb58c8378a0787b657a2ae895e929b80a82d6675cba63f0e8c5539e0", size = 34494, upload-time = "2025-06-02T18:58:45.104Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/b6/4e29b74bb40daa7580310a5ff0df5f121a08ce98340e01a960b668468aab/cloudevents-1.12.0-py3-none-any.whl", hash = "sha256:49196267f5f963d87ae156f93fc0fa32f4af69485f2c8e62e0db8b0b4b8b8921", size = 55762, upload-time = "2025-06-02T18:58:44.013Z" }, -] - [[package]] name = "cloudpickle" version = "3.1.1" @@ -390,54 +213,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bb/78/983efd23200921d9edb6bd40512e1aa04af553d7d5a171e50f9b2b45d109/coverage-7.10.4-py3-none-any.whl", hash = "sha256:065d75447228d05121e5c938ca8f0e91eed60a1eb2d1258d42d5084fecfc3302", size = 208365, upload-time = "2025-08-17T00:26:41.479Z" }, ] -[[package]] -name = "croniter" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "python-dateutil" }, - { name = "pytz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ad/2f/44d1ae153a0e27be56be43465e5cb39b9650c781e001e7864389deb25090/croniter-6.0.0.tar.gz", hash = "sha256:37c504b313956114a983ece2c2b07790b1f1094fe9d81cc94739214748255577", size = 64481, upload-time = "2024-12-17T17:17:47.32Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/4b/290b4c3efd6417a8b0c284896de19b1d5855e6dbdb97d2a35e68fa42de85/croniter-6.0.0-py2.py3-none-any.whl", hash = "sha256:2f878c3856f17896979b2a4379ba1f09c83e374931ea15cc835c5dd2eee9b368", size = 25468, upload-time = "2024-12-17T17:17:45.359Z" }, -] - -[[package]] -name = "cryptography" -version = "45.0.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d6/0d/d13399c94234ee8f3df384819dc67e0c5ce215fb751d567a55a1f4b028c7/cryptography-45.0.6.tar.gz", hash = "sha256:5c966c732cf6e4a276ce83b6e4c729edda2df6929083a952cc7da973c539c719", size = 744949, upload-time = "2025-08-05T23:59:27.93Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/29/2793d178d0eda1ca4a09a7c4e09a5185e75738cc6d526433e8663b460ea6/cryptography-45.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:048e7ad9e08cf4c0ab07ff7f36cc3115924e22e2266e034450a890d9e312dd74", size = 7042702, upload-time = "2025-08-05T23:58:23.464Z" }, - { url = "https://files.pythonhosted.org/packages/b3/b6/cabd07410f222f32c8d55486c464f432808abaa1f12af9afcbe8f2f19030/cryptography-45.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44647c5d796f5fc042bbc6d61307d04bf29bccb74d188f18051b635f20a9c75f", size = 4206483, upload-time = "2025-08-05T23:58:27.132Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9e/f9c7d36a38b1cfeb1cc74849aabe9bf817990f7603ff6eb485e0d70e0b27/cryptography-45.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e40b80ecf35ec265c452eea0ba94c9587ca763e739b8e559c128d23bff7ebbbf", size = 4429679, upload-time = "2025-08-05T23:58:29.152Z" }, - { url = "https://files.pythonhosted.org/packages/9c/2a/4434c17eb32ef30b254b9e8b9830cee4e516f08b47fdd291c5b1255b8101/cryptography-45.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:00e8724bdad672d75e6f069b27970883179bd472cd24a63f6e620ca7e41cc0c5", size = 4210553, upload-time = "2025-08-05T23:58:30.596Z" }, - { url = "https://files.pythonhosted.org/packages/ef/1d/09a5df8e0c4b7970f5d1f3aff1b640df6d4be28a64cae970d56c6cf1c772/cryptography-45.0.6-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a3085d1b319d35296176af31c90338eeb2ddac8104661df79f80e1d9787b8b2", size = 3894499, upload-time = "2025-08-05T23:58:32.03Z" }, - { url = "https://files.pythonhosted.org/packages/79/62/120842ab20d9150a9d3a6bdc07fe2870384e82f5266d41c53b08a3a96b34/cryptography-45.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1b7fa6a1c1188c7ee32e47590d16a5a0646270921f8020efc9a511648e1b2e08", size = 4458484, upload-time = "2025-08-05T23:58:33.526Z" }, - { url = "https://files.pythonhosted.org/packages/fd/80/1bc3634d45ddfed0871bfba52cf8f1ad724761662a0c792b97a951fb1b30/cryptography-45.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:275ba5cc0d9e320cd70f8e7b96d9e59903c815ca579ab96c1e37278d231fc402", size = 4210281, upload-time = "2025-08-05T23:58:35.445Z" }, - { url = "https://files.pythonhosted.org/packages/7d/fe/ffb12c2d83d0ee625f124880a1f023b5878f79da92e64c37962bbbe35f3f/cryptography-45.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f4028f29a9f38a2025abedb2e409973709c660d44319c61762202206ed577c42", size = 4456890, upload-time = "2025-08-05T23:58:36.923Z" }, - { url = "https://files.pythonhosted.org/packages/8c/8e/b3f3fe0dc82c77a0deb5f493b23311e09193f2268b77196ec0f7a36e3f3e/cryptography-45.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ee411a1b977f40bd075392c80c10b58025ee5c6b47a822a33c1198598a7a5f05", size = 4333247, upload-time = "2025-08-05T23:58:38.781Z" }, - { url = "https://files.pythonhosted.org/packages/b3/a6/c3ef2ab9e334da27a1d7b56af4a2417d77e7806b2e0f90d6267ce120d2e4/cryptography-45.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e2a21a8eda2d86bb604934b6b37691585bd095c1f788530c1fcefc53a82b3453", size = 4565045, upload-time = "2025-08-05T23:58:40.415Z" }, - { url = "https://files.pythonhosted.org/packages/31/c3/77722446b13fa71dddd820a5faab4ce6db49e7e0bf8312ef4192a3f78e2f/cryptography-45.0.6-cp311-abi3-win32.whl", hash = "sha256:d063341378d7ee9c91f9d23b431a3502fc8bfacd54ef0a27baa72a0843b29159", size = 2928923, upload-time = "2025-08-05T23:58:41.919Z" }, - { url = "https://files.pythonhosted.org/packages/38/63/a025c3225188a811b82932a4dcc8457a26c3729d81578ccecbcce2cb784e/cryptography-45.0.6-cp311-abi3-win_amd64.whl", hash = "sha256:833dc32dfc1e39b7376a87b9a6a4288a10aae234631268486558920029b086ec", size = 3403805, upload-time = "2025-08-05T23:58:43.792Z" }, - { url = "https://files.pythonhosted.org/packages/5b/af/bcfbea93a30809f126d51c074ee0fac5bd9d57d068edf56c2a73abedbea4/cryptography-45.0.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:3436128a60a5e5490603ab2adbabc8763613f638513ffa7d311c900a8349a2a0", size = 7020111, upload-time = "2025-08-05T23:58:45.316Z" }, - { url = "https://files.pythonhosted.org/packages/98/c6/ea5173689e014f1a8470899cd5beeb358e22bb3cf5a876060f9d1ca78af4/cryptography-45.0.6-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0d9ef57b6768d9fa58e92f4947cea96ade1233c0e236db22ba44748ffedca394", size = 4198169, upload-time = "2025-08-05T23:58:47.121Z" }, - { url = "https://files.pythonhosted.org/packages/ba/73/b12995edc0c7e2311ffb57ebd3b351f6b268fed37d93bfc6f9856e01c473/cryptography-45.0.6-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea3c42f2016a5bbf71825537c2ad753f2870191134933196bee408aac397b3d9", size = 4421273, upload-time = "2025-08-05T23:58:48.557Z" }, - { url = "https://files.pythonhosted.org/packages/f7/6e/286894f6f71926bc0da67408c853dd9ba953f662dcb70993a59fd499f111/cryptography-45.0.6-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:20ae4906a13716139d6d762ceb3e0e7e110f7955f3bc3876e3a07f5daadec5f3", size = 4199211, upload-time = "2025-08-05T23:58:50.139Z" }, - { url = "https://files.pythonhosted.org/packages/de/34/a7f55e39b9623c5cb571d77a6a90387fe557908ffc44f6872f26ca8ae270/cryptography-45.0.6-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dac5ec199038b8e131365e2324c03d20e97fe214af051d20c49db129844e8b3", size = 3883732, upload-time = "2025-08-05T23:58:52.253Z" }, - { url = "https://files.pythonhosted.org/packages/f9/b9/c6d32edbcba0cd9f5df90f29ed46a65c4631c4fbe11187feb9169c6ff506/cryptography-45.0.6-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:18f878a34b90d688982e43f4b700408b478102dd58b3e39de21b5ebf6509c301", size = 4450655, upload-time = "2025-08-05T23:58:53.848Z" }, - { url = "https://files.pythonhosted.org/packages/77/2d/09b097adfdee0227cfd4c699b3375a842080f065bab9014248933497c3f9/cryptography-45.0.6-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5bd6020c80c5b2b2242d6c48487d7b85700f5e0038e67b29d706f98440d66eb5", size = 4198956, upload-time = "2025-08-05T23:58:55.209Z" }, - { url = "https://files.pythonhosted.org/packages/55/66/061ec6689207d54effdff535bbdf85cc380d32dd5377173085812565cf38/cryptography-45.0.6-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:eccddbd986e43014263eda489abbddfbc287af5cddfd690477993dbb31e31016", size = 4449859, upload-time = "2025-08-05T23:58:56.639Z" }, - { url = "https://files.pythonhosted.org/packages/41/ff/e7d5a2ad2d035e5a2af116e1a3adb4d8fcd0be92a18032917a089c6e5028/cryptography-45.0.6-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:550ae02148206beb722cfe4ef0933f9352bab26b087af00e48fdfb9ade35c5b3", size = 4320254, upload-time = "2025-08-05T23:58:58.833Z" }, - { url = "https://files.pythonhosted.org/packages/82/27/092d311af22095d288f4db89fcaebadfb2f28944f3d790a4cf51fe5ddaeb/cryptography-45.0.6-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5b64e668fc3528e77efa51ca70fadcd6610e8ab231e3e06ae2bab3b31c2b8ed9", size = 4554815, upload-time = "2025-08-05T23:59:00.283Z" }, - { url = "https://files.pythonhosted.org/packages/7e/01/aa2f4940262d588a8fdf4edabe4cda45854d00ebc6eaac12568b3a491a16/cryptography-45.0.6-cp37-abi3-win32.whl", hash = "sha256:780c40fb751c7d2b0c6786ceee6b6f871e86e8718a8ff4bc35073ac353c7cd02", size = 2912147, upload-time = "2025-08-05T23:59:01.716Z" }, - { url = "https://files.pythonhosted.org/packages/0a/bc/16e0276078c2de3ceef6b5a34b965f4436215efac45313df90d55f0ba2d2/cryptography-45.0.6-cp37-abi3-win_amd64.whl", hash = "sha256:20d15aed3ee522faac1a39fbfdfee25d17b1284bafd808e1640a74846d7c4d1b", size = 3390459, upload-time = "2025-08-05T23:59:03.358Z" }, -] - [[package]] name = "cucumber-expressions" version = "18.0.1" @@ -457,66 +232,25 @@ wheels = [ ] [[package]] -name = "dataclasses-json" -version = "0.5.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "marshmallow" }, - { name = "marshmallow-enum" }, - { name = "typing-inspect" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/86/c2/db1972ba8fda56d1c3317d8cca1c06af4b5df7e3c94345048d10cf4c7bf4/dataclasses-json-0.5.9.tar.gz", hash = "sha256:e9ac87b73edc0141aafbce02b44e93553c3123ad574958f0fe52a534b6707e8e", size = 43145, upload-time = "2023-06-30T20:12:09.506Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/04/2851f9fe4b01b5b752c16e41d581f6b9d0ca82e388d7bd58357d758fc6ce/dataclasses_json-0.5.9-py3-none-any.whl", hash = "sha256:1280542631df1c375b7bc92e5b86d39e06c44760d7e3571a537b3b8acabf2f0c", size = 26306, upload-time = "2023-06-30T20:12:08.092Z" }, -] - -[[package]] -name = "datamanager" -version = "0.1.0" -source = { editable = "applications/datamanager" } -dependencies = [ - { name = "duckdb" }, - { name = "fastapi" }, - { name = "structlog" }, - { name = "uvicorn" }, -] - -[package.metadata] -requires-dist = [ - { name = "duckdb", specifier = ">=1.4.0" }, - { name = "fastapi", specifier = ">=0.116.1" }, - { name = "structlog", specifier = ">=25.4.0" }, - { name = "uvicorn", specifier = ">=0.35.0" }, -] - -[[package]] -name = "decorator" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, -] - -[[package]] -name = "deprecation" -version = "2.1.0" +name = "debugpy" +version = "1.8.17" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5a/d3/8ae2869247df154b64c1884d7346d412fed0c49df84db635aab2d1c40e62/deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff", size = 173788, upload-time = "2020-04-20T14:23:38.738Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/ad/71e708ff4ca377c4230530d6a7aa7992592648c122a2cd2b321cf8b35a76/debugpy-1.8.17.tar.gz", hash = "sha256:fd723b47a8c08892b1a16b2c6239a8b96637c62a59b94bb5dab4bac592a58a8e", size = 1644129, upload-time = "2025-09-17T16:33:20.633Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/02/c3/253a89ee03fc9b9682f1541728eb66db7db22148cd94f89ab22528cd1e1b/deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a", size = 11178, upload-time = "2020-04-20T14:23:36.581Z" }, + { url = "https://files.pythonhosted.org/packages/08/2b/9d8e65beb2751876c82e1aceb32f328c43ec872711fa80257c7674f45650/debugpy-1.8.17-cp312-cp312-macosx_15_0_universal2.whl", hash = "sha256:f14467edef672195c6f6b8e27ce5005313cb5d03c9239059bc7182b60c176e2d", size = 2549522, upload-time = "2025-09-17T16:33:38.466Z" }, + { url = "https://files.pythonhosted.org/packages/b4/78/eb0d77f02971c05fca0eb7465b18058ba84bd957062f5eec82f941ac792a/debugpy-1.8.17-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:24693179ef9dfa20dca8605905a42b392be56d410c333af82f1c5dff807a64cc", size = 4309417, upload-time = "2025-09-17T16:33:41.299Z" }, + { url = "https://files.pythonhosted.org/packages/37/42/c40f1d8cc1fed1e75ea54298a382395b8b937d923fcf41ab0797a554f555/debugpy-1.8.17-cp312-cp312-win32.whl", hash = "sha256:6a4e9dacf2cbb60d2514ff7b04b4534b0139facbf2abdffe0639ddb6088e59cf", size = 5277130, upload-time = "2025-09-17T16:33:43.554Z" }, + { url = "https://files.pythonhosted.org/packages/72/22/84263b205baad32b81b36eac076de0cdbe09fe2d0637f5b32243dc7c925b/debugpy-1.8.17-cp312-cp312-win_amd64.whl", hash = "sha256:e8f8f61c518952fb15f74a302e068b48d9c4691768ade433e4adeea961993464", size = 5319053, upload-time = "2025-09-17T16:33:53.033Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d0/89247ec250369fc76db477720a26b2fce7ba079ff1380e4ab4529d2fe233/debugpy-1.8.17-py2.py3-none-any.whl", hash = "sha256:60c7dca6571efe660ccb7a9508d73ca14b8796c4ed484c2002abba714226cfef", size = 5283210, upload-time = "2025-09-17T16:34:25.835Z" }, ] [[package]] -name = "diskcache" -version = "5.6.3" +name = "dill" +version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916, upload-time = "2023-08-31T06:12:00.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550, upload-time = "2023-08-31T06:11:58.822Z" }, + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, ] [[package]] @@ -534,320 +268,102 @@ wheels = [ ] [[package]] -name = "docstring-parser" -version = "0.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/9d/c3b43da9515bd270df0f80548d9944e389870713cc1fe2b8fb35fe2bcefd/docstring_parser-0.17.0.tar.gz", hash = "sha256:583de4a309722b3315439bb31d64ba3eebada841f2e2cee23b99df001434c912", size = 27442, upload-time = "2025-07-21T07:35:01.868Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" }, +name = "equitypricemodel" +version = "0.1.0" +source = { editable = "applications/equitypricemodel" } +dependencies = [ + { name = "internal" }, + { name = "python-dotenv" }, ] -[[package]] -name = "duckdb" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/93/adc0d183642fc9a602ca9b97cb16754c84b8c1d92e5b99aec412e0c419a8/duckdb-1.4.0.tar.gz", hash = "sha256:bd5edee8bd5a73b5822f2b390668597b5fcdc2d3292c244d8d933bb87ad6ac4c", size = 18453175, upload-time = "2025-09-16T10:22:41.509Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/6d/0c774d6af1aed82dbe855d266cb000a1c09ea31ed7d6c3a79e2167a38e7a/duckdb-1.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:18b3a048fca6cc7bafe08b10e1b0ab1509d7a0381ffb2c70359e7dc56d8a705d", size = 31307425, upload-time = "2025-09-16T10:21:57.83Z" }, - { url = "https://files.pythonhosted.org/packages/d3/c0/1fd7b7b2c0c53d8d748d2f28ea9096df5ee9dc39fa736cca68acabe69656/duckdb-1.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c1271cb85aeacccfd0b1284e816280a7450df1dd4dd85ccb2848563cfdf90e9", size = 17295727, upload-time = "2025-09-16T10:22:02.242Z" }, - { url = "https://files.pythonhosted.org/packages/98/d3/4d4c4bd667b7ada5f6c207c2f127591ebb8468333f207f8f10ff0532578e/duckdb-1.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55064dd2e25711eeaa6a72c25405bdd7994c81a3221657e94309a2faf65d25a6", size = 14826879, upload-time = "2025-09-16T10:22:05.162Z" }, - { url = "https://files.pythonhosted.org/packages/b0/48/e0c1b97d76fb7567c53db5739931323238fad54a642707008104f501db37/duckdb-1.4.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0536d7c81bc506532daccf373ddbc8c6add46aeb70ef3cd5ee70ad5c2b3165ea", size = 18417856, upload-time = "2025-09-16T10:22:07.919Z" }, - { url = "https://files.pythonhosted.org/packages/12/78/297b838f3b9511589badc8f472f70b31cf3bbf9eb99fa0a4d6e911d3114a/duckdb-1.4.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:784554e3ddfcfc5c5c7b1aa1f9925fedb7938f6628729adba48f7ea37554598f", size = 20427154, upload-time = "2025-09-16T10:22:10.216Z" }, - { url = "https://files.pythonhosted.org/packages/ea/57/500d251b886494f6c52d56eeab8a1860572ee62aed05d7d50c71ba2320f3/duckdb-1.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:c5d2aa4d6981f525ada95e6db41bb929403632bb5ff24bd6d6dd551662b1b613", size = 12290108, upload-time = "2025-09-16T10:22:12.668Z" }, +[package.metadata] +requires-dist = [ + { name = "internal", editable = "libraries/python" }, + { name = "python-dotenv", specifier = ">=1.2.1" }, ] [[package]] name = "fastapi" -version = "0.116.1" +version = "0.121.0" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "annotated-doc" }, { name = "pydantic" }, { name = "starlette" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/78/d7/6c8b3bfe33eeffa208183ec037fee0cce9f7f024089ab1c5d12ef04bd27c/fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143", size = 296485, upload-time = "2025-07-11T16:22:32.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/e3/77a2df0946703973b9905fd0cde6172c15e0781984320123b4f5079e7113/fastapi-0.121.0.tar.gz", hash = "sha256:06663356a0b1ee93e875bbf05a31fb22314f5bed455afaaad2b2dad7f26e98fa", size = 342412, upload-time = "2025-11-03T10:25:54.818Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" }, + { url = "https://files.pythonhosted.org/packages/dd/2c/42277afc1ba1a18f8358561eee40785d27becab8f80a1f945c0a3051c6eb/fastapi-0.121.0-py3-none-any.whl", hash = "sha256:8bdf1b15a55f4e4b0d6201033da9109ea15632cb76cf156e7b8b4019f2172106", size = 109183, upload-time = "2025-11-03T10:25:53.27Z" }, ] [[package]] -name = "flyteidl" -version = "1.16.0" +name = "google-pasta" +version = "0.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "googleapis-common-protos" }, - { name = "protobuf" }, - { name = "protoc-gen-openapiv2" }, + { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bb/29/0c0b0e4debbe47ebe1968bf50f1b05b6e729684507d77e96b34c781abc83/flyteidl-1.16.0.tar.gz", hash = "sha256:21aa4a729be8f91d9a5d3dc8ad07a8ece8a29bb5c5a5adc2b84f355a4aabd798", size = 130124, upload-time = "2025-07-17T21:11:32.268Z" } +sdist = { url = "https://files.pythonhosted.org/packages/35/4a/0bd53b36ff0323d10d5f24ebd67af2de10a1117f5cf4d7add90df92756f1/google-pasta-0.2.0.tar.gz", hash = "sha256:c9f2c8dfc8f96d0d5808299920721be30c9eec37f2389f28904f454565c8a16e", size = 40430, upload-time = "2020-03-13T18:57:50.34Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/65/37/b420b175c474b9e8bf9e00c4d4038dc1cf27dadaf94e0e1c87d595d30f28/flyteidl-1.16.0-py3-none-any.whl", hash = "sha256:b7e87de3e5034baf46f469790a5951bbcfc6a7540bd3057e4c8308de30a961ba", size = 221389, upload-time = "2025-07-17T21:11:30.456Z" }, + { url = "https://files.pythonhosted.org/packages/a3/de/c648ef6835192e6e2cc03f40b19eeda4382c49b5bafb43d88b931c4c74ac/google_pasta-0.2.0-py3-none-any.whl", hash = "sha256:b32482794a366b5366a32c92a9a9201b107821889935a02b3e51f6b432ea84ed", size = 57471, upload-time = "2020-03-13T18:57:48.872Z" }, ] [[package]] -name = "flytekit" -version = "1.16.3" +name = "graphene" +version = "3.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "adlfs" }, - { name = "click" }, - { name = "cloudpickle" }, - { name = "croniter" }, - { name = "dataclasses-json" }, - { name = "diskcache" }, - { name = "docker" }, - { name = "docstring-parser" }, - { name = "flyteidl" }, - { name = "fsspec" }, - { name = "gcsfs" }, - { name = "googleapis-common-protos" }, - { name = "grpcio" }, - { name = "grpcio-status" }, - { name = "importlib-metadata" }, - { name = "joblib" }, - { name = "jsonlines" }, - { name = "jsonpickle" }, - { name = "keyring" }, - { name = "markdown-it-py" }, - { name = "marshmallow-enum" }, - { name = "marshmallow-jsonschema" }, - { name = "mashumaro" }, - { name = "msgpack" }, - { name = "protobuf" }, - { name = "pygments" }, - { name = "python-json-logger" }, - { name = "pytimeparse" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "rich" }, - { name = "rich-click" }, - { name = "s3fs" }, - { name = "statsd" }, + { name = "graphql-core" }, + { name = "graphql-relay" }, + { name = "python-dateutil" }, { name = "typing-extensions" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ed/ac/c73902513ba7a8f206c3b8f419f36a2abed7760783dcf06615e6db42e3da/flytekit-1.16.3.tar.gz", hash = "sha256:16533e1375eedccecfca673970a3cb7bda9eac3f6b9b094a81edac9c2388d09f", size = 564641, upload-time = "2025-07-17T18:56:15.241Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/9c/ae4f566977dcfcf20f935ac5906b53106aa16c7e98751646dc3c837f1513/flytekit-1.16.3-py3-none-any.whl", hash = "sha256:466848f9e44ee9ab4c56e7b47ffa2ded79f2bc74585139983ad4815a6bfe0336", size = 666231, upload-time = "2025-07-17T18:56:12.677Z" }, -] - -[[package]] -name = "frozenlist" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, - { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, - { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, - { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, - { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, - { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, - { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, - { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, - { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, - { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, ] - -[[package]] -name = "fsspec" -version = "2025.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8b/02/0835e6ab9cfc03916fe3f78c0956cfcdb6ff2669ffa6651065d5ebf7fc98/fsspec-2025.7.0.tar.gz", hash = "sha256:786120687ffa54b8283d942929540d8bc5ccfa820deb555a2b5d0ed2b737bf58", size = 304432, upload-time = "2025-07-15T16:05:21.19Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/f6/bf62ff950c317ed03e77f3f6ddd7e34aaa98fe89d79ebd660c55343d8054/graphene-3.4.3.tar.gz", hash = "sha256:2a3786948ce75fe7e078443d37f609cbe5bb36ad8d6b828740ad3b95ed1a0aaa", size = 44739, upload-time = "2024-11-09T20:44:25.757Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/e0/014d5d9d7a4564cf1c40b5039bc882db69fd881111e03ab3657ac0b218e2/fsspec-2025.7.0-py3-none-any.whl", hash = "sha256:8b012e39f63c7d5f10474de957f3ab793b47b45ae7d39f2fb735f8bbe25c0e21", size = 199597, upload-time = "2025-07-15T16:05:19.529Z" }, + { url = "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl", hash = "sha256:820db6289754c181007a150db1f7fff544b94142b556d12e3ebc777a7bf36c71", size = 114894, upload-time = "2024-11-09T20:44:23.851Z" }, ] [[package]] -name = "gcsfs" -version = "2025.7.0" +name = "graphql-core" +version = "3.2.6" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "decorator" }, - { name = "fsspec" }, - { name = "google-auth" }, - { name = "google-auth-oauthlib" }, - { name = "google-cloud-storage" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/d7/5eafe9f09f1bb09433a473cef7984cd52c398592c8fd09974e0ad87cfea4/gcsfs-2025.7.0.tar.gz", hash = "sha256:ad3ff66cf189ae8fc375ac8a2af409003dbca02357621cb94a66e457e02ba420", size = 82659, upload-time = "2025-07-15T16:49:21.647Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/21/f5/54bccbee01efbc25581db6aafefb6f6c277d880930f7a083b10052382463/gcsfs-2025.7.0-py2.py3-none-any.whl", hash = "sha256:653503331d58cb02bb34e725d4595d166e93f7f2f3ff88e4c66ef535ae66eae5", size = 36815, upload-time = "2025-07-15T16:49:20.333Z" }, -] - -[[package]] -name = "gitdb" -version = "4.0.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "smmap" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, -] - -[[package]] -name = "gitpython" -version = "3.1.45" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "gitdb" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9a/c8/dd58967d119baab745caec2f9d853297cec1989ec1d63f677d3880632b88/gitpython-3.1.45.tar.gz", hash = "sha256:85b0ee964ceddf211c41b9f27a49086010a190fd8132a24e21f362a4b36a791c", size = 215076, upload-time = "2025-07-24T03:45:54.871Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/61/d4b89fec821f72385526e1b9d9a3a0385dda4a72b206d28049e2c7cd39b8/gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77", size = 208168, upload-time = "2025-07-24T03:45:52.517Z" }, -] - -[[package]] -name = "google-api-core" -version = "2.25.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-auth" }, - { name = "googleapis-common-protos" }, - { name = "proto-plus" }, - { name = "protobuf" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dc/21/e9d043e88222317afdbdb567165fdbc3b0aad90064c7e0c9eb0ad9955ad8/google_api_core-2.25.1.tar.gz", hash = "sha256:d2aaa0b13c78c61cb3f4282c464c046e45fbd75755683c9c525e6e8f7ed0a5e8", size = 165443, upload-time = "2025-06-12T20:52:20.439Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/14/4b/ead00905132820b623732b175d66354e9d3e69fcf2a5dcdab780664e7896/google_api_core-2.25.1-py3-none-any.whl", hash = "sha256:8a2a56c1fef82987a524371f99f3bd0143702fecc670c72e600c1cda6bf8dbb7", size = 160807, upload-time = "2025-06-12T20:52:19.334Z" }, -] - -[[package]] -name = "google-auth" -version = "2.40.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cachetools" }, - { name = "pyasn1-modules" }, - { name = "rsa" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9e/9b/e92ef23b84fa10a64ce4831390b7a4c2e53c0132568d99d4ae61d04c8855/google_auth-2.40.3.tar.gz", hash = "sha256:500c3a29adedeb36ea9cf24b8d10858e152f2412e3ca37829b3fa18e33d63b77", size = 281029, upload-time = "2025-06-04T18:04:57.577Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/16/7574029da84834349b60ed71614d66ca3afe46e9bf9c7b9562102acb7d4f/graphql_core-3.2.6.tar.gz", hash = "sha256:c08eec22f9e40f0bd61d805907e3b3b1b9a320bc606e23dc145eebca07c8fbab", size = 505353, upload-time = "2025-01-26T16:36:27.374Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/63/b19553b658a1692443c62bd07e5868adaa0ad746a0751ba62c59568cd45b/google_auth-2.40.3-py2.py3-none-any.whl", hash = "sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca", size = 216137, upload-time = "2025-06-04T18:04:55.573Z" }, + { url = "https://files.pythonhosted.org/packages/ae/4f/7297663840621022bc73c22d7d9d80dbc78b4db6297f764b545cd5dd462d/graphql_core-3.2.6-py3-none-any.whl", hash = "sha256:78b016718c161a6fb20a7d97bbf107f331cd1afe53e45566c59f776ed7f0b45f", size = 203416, upload-time = "2025-01-26T16:36:24.868Z" }, ] [[package]] -name = "google-auth-oauthlib" -version = "1.2.2" +name = "graphql-relay" +version = "3.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "google-auth" }, - { name = "requests-oauthlib" }, + { name = "graphql-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/87/e10bf24f7bcffc1421b84d6f9c3377c30ec305d082cd737ddaa6d8f77f7c/google_auth_oauthlib-1.2.2.tar.gz", hash = "sha256:11046fb8d3348b296302dd939ace8af0a724042e8029c1b872d87fabc9f41684", size = 20955, upload-time = "2025-04-22T16:40:29.172Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/13/98fbf8d67552f102488ffc16c6f559ce71ea15f6294728d33928ab5ff14d/graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c", size = 50027, upload-time = "2022-04-16T11:03:45.447Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/84/40ee070be95771acd2f4418981edb834979424565c3eec3cd88b6aa09d24/google_auth_oauthlib-1.2.2-py3-none-any.whl", hash = "sha256:fd619506f4b3908b5df17b65f39ca8d66ea56986e5472eb5978fd8f3786f00a2", size = 19072, upload-time = "2025-04-22T16:40:28.174Z" }, -] - -[[package]] -name = "google-cloud-core" -version = "2.4.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core" }, - { name = "google-auth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d6/b8/2b53838d2acd6ec6168fd284a990c76695e84c65deee79c9f3a4276f6b4f/google_cloud_core-2.4.3.tar.gz", hash = "sha256:1fab62d7102844b278fe6dead3af32408b1df3eb06f5c7e8634cbd40edc4da53", size = 35861, upload-time = "2025-03-10T21:05:38.948Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/86/bda7241a8da2d28a754aad2ba0f6776e35b67e37c36ae0c45d49370f1014/google_cloud_core-2.4.3-py2.py3-none-any.whl", hash = "sha256:5130f9f4c14b4fafdff75c79448f9495cfade0d8775facf1b09c3bf67e027f6e", size = 29348, upload-time = "2025-03-10T21:05:37.785Z" }, -] - -[[package]] -name = "google-cloud-storage" -version = "3.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core" }, - { name = "google-auth" }, - { name = "google-cloud-core" }, - { name = "google-crc32c" }, - { name = "google-resumable-media" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1e/91/10b9ddd5baacde375dcd7e6716b5024b3f65a22366f74c26926b6aa84e4e/google_cloud_storage-3.3.0.tar.gz", hash = "sha256:ae9d891d53e17d9681d7c4ef1ffeea0cde9bdc53d5b64fa6ff6bf30d1911cf61", size = 7781974, upload-time = "2025-08-12T09:10:36.245Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/41/9d/2814a2c47429dc2e197e176de25a946d4538422b081ade8638e585e4006f/google_cloud_storage-3.3.0-py3-none-any.whl", hash = "sha256:0338ecd6621b3ecacb108f1cf7513ff0d1bca7f1ff4d58e0220b59f3a725ff23", size = 274270, upload-time = "2025-08-12T09:10:34.793Z" }, -] - -[[package]] -name = "google-crc32c" -version = "1.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/ae/87802e6d9f9d69adfaedfcfd599266bf386a54d0be058b532d04c794f76d/google_crc32c-1.7.1.tar.gz", hash = "sha256:2bff2305f98846f3e825dbeec9ee406f89da7962accdb29356e4eadc251bd472", size = 14495, upload-time = "2025-03-26T14:29:13.32Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/b7/787e2453cf8639c94b3d06c9d61f512234a82e1d12d13d18584bd3049904/google_crc32c-1.7.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2d73a68a653c57281401871dd4aeebbb6af3191dcac751a76ce430df4d403194", size = 30470, upload-time = "2025-03-26T14:34:31.655Z" }, - { url = "https://files.pythonhosted.org/packages/ed/b4/6042c2b0cbac3ec3a69bb4c49b28d2f517b7a0f4a0232603c42c58e22b44/google_crc32c-1.7.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:22beacf83baaf59f9d3ab2bbb4db0fb018da8e5aebdce07ef9f09fce8220285e", size = 30315, upload-time = "2025-03-26T15:01:54.634Z" }, - { url = "https://files.pythonhosted.org/packages/29/ad/01e7a61a5d059bc57b702d9ff6a18b2585ad97f720bd0a0dbe215df1ab0e/google_crc32c-1.7.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19eafa0e4af11b0a4eb3974483d55d2d77ad1911e6cf6f832e1574f6781fd337", size = 33180, upload-time = "2025-03-26T14:41:32.168Z" }, - { url = "https://files.pythonhosted.org/packages/3b/a5/7279055cf004561894ed3a7bfdf5bf90a53f28fadd01af7cd166e88ddf16/google_crc32c-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6d86616faaea68101195c6bdc40c494e4d76f41e07a37ffdef270879c15fb65", size = 32794, upload-time = "2025-03-26T14:41:33.264Z" }, - { url = "https://files.pythonhosted.org/packages/0f/d6/77060dbd140c624e42ae3ece3df53b9d811000729a5c821b9fd671ceaac6/google_crc32c-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:b7491bdc0c7564fcf48c0179d2048ab2f7c7ba36b84ccd3a3e1c3f7a72d3bba6", size = 33477, upload-time = "2025-03-26T14:29:10.94Z" }, -] - -[[package]] -name = "google-resumable-media" -version = "2.7.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-crc32c" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/5a/0efdc02665dca14e0837b62c8a1a93132c264bd02054a15abb2218afe0ae/google_resumable_media-2.7.2.tar.gz", hash = "sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0", size = 2163099, upload-time = "2024-08-07T22:20:38.555Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/35/b8d3baf8c46695858cb9d8835a53baa1eeb9906ddaf2f728a5f5b640fd1e/google_resumable_media-2.7.2-py2.py3-none-any.whl", hash = "sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa", size = 81251, upload-time = "2024-08-07T22:20:36.409Z" }, -] - -[[package]] -name = "googleapis-common-protos" -version = "1.70.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/39/24/33db22342cf4a2ea27c9955e6713140fedd51e8b141b5ce5260897020f1a/googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257", size = 145903, upload-time = "2025-04-14T10:17:02.924Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/f1/62a193f0227cf15a920390abe675f386dec35f7ae3ffe6da582d3ade42c7/googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8", size = 294530, upload-time = "2025-04-14T10:17:01.271Z" }, + { url = "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl", hash = "sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5", size = 16940, upload-time = "2022-04-16T11:03:43.895Z" }, ] [[package]] name = "grpcio" -version = "1.74.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/38/b4/35feb8f7cab7239c5b94bd2db71abb3d6adb5f335ad8f131abb6060840b6/grpcio-1.74.0.tar.gz", hash = "sha256:80d1f4fbb35b0742d3e3d3bb654b7381cd5f015f8497279a1e9c21ba623e01b1", size = 12756048, upload-time = "2025-07-24T18:54:23.039Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/5d/e504d5d5c4469823504f65687d6c8fb97b7f7bf0b34873b7598f1df24630/grpcio-1.74.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8533e6e9c5bd630ca98062e3a1326249e6ada07d05acf191a77bc33f8948f3d8", size = 5445551, upload-time = "2025-07-24T18:53:23.641Z" }, - { url = "https://files.pythonhosted.org/packages/43/01/730e37056f96f2f6ce9f17999af1556df62ee8dab7fa48bceeaab5fd3008/grpcio-1.74.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:2918948864fec2a11721d91568effffbe0a02b23ecd57f281391d986847982f6", size = 10979810, upload-time = "2025-07-24T18:53:25.349Z" }, - { url = "https://files.pythonhosted.org/packages/79/3d/09fd100473ea5c47083889ca47ffd356576173ec134312f6aa0e13111dee/grpcio-1.74.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:60d2d48b0580e70d2e1954d0d19fa3c2e60dd7cbed826aca104fff518310d1c5", size = 5941946, upload-time = "2025-07-24T18:53:27.387Z" }, - { url = "https://files.pythonhosted.org/packages/8a/99/12d2cca0a63c874c6d3d195629dcd85cdf5d6f98a30d8db44271f8a97b93/grpcio-1.74.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3601274bc0523f6dc07666c0e01682c94472402ac2fd1226fd96e079863bfa49", size = 6621763, upload-time = "2025-07-24T18:53:29.193Z" }, - { url = "https://files.pythonhosted.org/packages/9d/2c/930b0e7a2f1029bbc193443c7bc4dc2a46fedb0203c8793dcd97081f1520/grpcio-1.74.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:176d60a5168d7948539def20b2a3adcce67d72454d9ae05969a2e73f3a0feee7", size = 6180664, upload-time = "2025-07-24T18:53:30.823Z" }, - { url = "https://files.pythonhosted.org/packages/db/d5/ff8a2442180ad0867717e670f5ec42bfd8d38b92158ad6bcd864e6d4b1ed/grpcio-1.74.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e759f9e8bc908aaae0412642afe5416c9f983a80499448fcc7fab8692ae044c3", size = 6301083, upload-time = "2025-07-24T18:53:32.454Z" }, - { url = "https://files.pythonhosted.org/packages/b0/ba/b361d390451a37ca118e4ec7dccec690422e05bc85fba2ec72b06cefec9f/grpcio-1.74.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9e7c4389771855a92934b2846bd807fc25a3dfa820fd912fe6bd8136026b2707", size = 6994132, upload-time = "2025-07-24T18:53:34.506Z" }, - { url = "https://files.pythonhosted.org/packages/3b/0c/3a5fa47d2437a44ced74141795ac0251bbddeae74bf81df3447edd767d27/grpcio-1.74.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cce634b10aeab37010449124814b05a62fb5f18928ca878f1bf4750d1f0c815b", size = 6489616, upload-time = "2025-07-24T18:53:36.217Z" }, - { url = "https://files.pythonhosted.org/packages/ae/95/ab64703b436d99dc5217228babc76047d60e9ad14df129e307b5fec81fd0/grpcio-1.74.0-cp312-cp312-win32.whl", hash = "sha256:885912559974df35d92219e2dc98f51a16a48395f37b92865ad45186f294096c", size = 3807083, upload-time = "2025-07-24T18:53:37.911Z" }, - { url = "https://files.pythonhosted.org/packages/84/59/900aa2445891fc47a33f7d2f76e00ca5d6ae6584b20d19af9c06fa09bf9a/grpcio-1.74.0-cp312-cp312-win_amd64.whl", hash = "sha256:42f8fee287427b94be63d916c90399ed310ed10aadbf9e2e5538b3e497d269bc", size = 4490123, upload-time = "2025-07-24T18:53:39.528Z" }, -] - -[[package]] -name = "grpcio-status" -version = "1.74.0" +version = "1.76.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "googleapis-common-protos" }, - { name = "grpcio" }, - { name = "protobuf" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/93/22/238c5f01e6837df54494deb08d5c772bc3f5bf5fb80a15dce254892d1a81/grpcio_status-1.74.0.tar.gz", hash = "sha256:c58c1b24aa454e30f1fc6a7e0dbbc194c54a408143971a94b5f4e40bb5831432", size = 13662, upload-time = "2025-07-24T19:01:56.874Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/e0/318c1ce3ae5a17894d5791e87aea147587c9e702f24122cc7a5c8bbaeeb1/grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73", size = 12785182, upload-time = "2025-10-21T16:23:12.106Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/aa/1b1fe7d8ab699e1ec26d3a36b91d3df9f83a30abc07d4c881d0296b17b67/grpcio_status-1.74.0-py3-none-any.whl", hash = "sha256:52cdbd759a6760fc8f668098a03f208f493dd5c76bf8e02598bbbaf1f6fc2876", size = 14425, upload-time = "2025-07-24T19:01:19.963Z" }, + { url = "https://files.pythonhosted.org/packages/bf/05/8e29121994b8d959ffa0afd28996d452f291b48cfc0875619de0bde2c50c/grpcio-1.76.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:81fd9652b37b36f16138611c7e884eb82e0cec137c40d3ef7c3f9b3ed00f6ed8", size = 5799718, upload-time = "2025-10-21T16:21:17.939Z" }, + { url = "https://files.pythonhosted.org/packages/d9/75/11d0e66b3cdf998c996489581bdad8900db79ebd83513e45c19548f1cba4/grpcio-1.76.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:04bbe1bfe3a68bbfd4e52402ab7d4eb59d72d02647ae2042204326cf4bbad280", size = 11825627, upload-time = "2025-10-21T16:21:20.466Z" }, + { url = "https://files.pythonhosted.org/packages/28/50/2f0aa0498bc188048f5d9504dcc5c2c24f2eb1a9337cd0fa09a61a2e75f0/grpcio-1.76.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d388087771c837cdb6515539f43b9d4bf0b0f23593a24054ac16f7a960be16f4", size = 6359167, upload-time = "2025-10-21T16:21:23.122Z" }, + { url = "https://files.pythonhosted.org/packages/66/e5/bbf0bb97d29ede1d59d6588af40018cfc345b17ce979b7b45424628dc8bb/grpcio-1.76.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f8f757bebaaea112c00dba718fc0d3260052ce714e25804a03f93f5d1c6cc11", size = 7044267, upload-time = "2025-10-21T16:21:25.995Z" }, + { url = "https://files.pythonhosted.org/packages/f5/86/f6ec2164f743d9609691115ae8ece098c76b894ebe4f7c94a655c6b03e98/grpcio-1.76.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:980a846182ce88c4f2f7e2c22c56aefd515daeb36149d1c897f83cf57999e0b6", size = 6573963, upload-time = "2025-10-21T16:21:28.631Z" }, + { url = "https://files.pythonhosted.org/packages/60/bc/8d9d0d8505feccfdf38a766d262c71e73639c165b311c9457208b56d92ae/grpcio-1.76.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f92f88e6c033db65a5ae3d97905c8fea9c725b63e28d5a75cb73b49bda5024d8", size = 7164484, upload-time = "2025-10-21T16:21:30.837Z" }, + { url = "https://files.pythonhosted.org/packages/67/e6/5d6c2fc10b95edf6df9b8f19cf10a34263b7fd48493936fffd5085521292/grpcio-1.76.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4baf3cbe2f0be3289eb68ac8ae771156971848bb8aaff60bad42005539431980", size = 8127777, upload-time = "2025-10-21T16:21:33.577Z" }, + { url = "https://files.pythonhosted.org/packages/3f/c8/dce8ff21c86abe025efe304d9e31fdb0deaaa3b502b6a78141080f206da0/grpcio-1.76.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:615ba64c208aaceb5ec83bfdce7728b80bfeb8be97562944836a7a0a9647d882", size = 7594014, upload-time = "2025-10-21T16:21:41.882Z" }, + { url = "https://files.pythonhosted.org/packages/e0/42/ad28191ebf983a5d0ecef90bab66baa5a6b18f2bfdef9d0a63b1973d9f75/grpcio-1.76.0-cp312-cp312-win32.whl", hash = "sha256:45d59a649a82df5718fd9527ce775fd66d1af35e6d31abdcdc906a49c6822958", size = 3984750, upload-time = "2025-10-21T16:21:44.006Z" }, + { url = "https://files.pythonhosted.org/packages/9e/00/7bd478cbb851c04a48baccaa49b75abaa8e4122f7d86da797500cccdd771/grpcio-1.76.0-cp312-cp312-win_amd64.whl", hash = "sha256:c088e7a90b6017307f423efbb9d1ba97a22aa2170876223f9709e9d1de0b5347", size = 4704003, upload-time = "2025-10-21T16:21:46.244Z" }, ] [[package]] @@ -898,14 +414,35 @@ wheels = [ [[package]] name = "importlib-metadata" -version = "8.7.0" +version = "6.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/eb/58c2ab27ee628ad801f56d4017fe62afab0293116f6d0b08f1d5bd46e06f/importlib_metadata-6.11.0.tar.gz", hash = "sha256:1231cf92d825c9e03cfc4da076a16de6422c863558229ea0b22b675657463443", size = 54593, upload-time = "2023-12-03T17:33:10.693Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, + { url = "https://files.pythonhosted.org/packages/59/9b/ecce94952ab5ea74c31dcf9ccf78ccd484eebebef06019bf8cb579ab4519/importlib_metadata-6.11.0-py3-none-any.whl", hash = "sha256:f0afba6205ad8f8947c7d338b5342d5db2afbfd82f9cbef7879a9539cc12eb9b", size = 23427, upload-time = "2023-12-03T17:33:08.965Z" }, +] + +[[package]] +name = "infrastructure" +version = "0.1.0" +source = { virtual = "infrastructure" } +dependencies = [ + { name = "pulumi" }, + { name = "pulumi-aws" }, + { name = "pulumi-command" }, + { name = "pulumi-docker" }, + { name = "pulumi-tls" }, +] + +[package.metadata] +requires-dist = [ + { name = "pulumi", specifier = ">=3.189.0" }, + { name = "pulumi-aws", specifier = ">=7.4.0" }, + { name = "pulumi-command", specifier = ">=1.1.0" }, + { name = "pulumi-docker", specifier = ">=4.10.0" }, + { name = "pulumi-tls", specifier = ">=5.2.1" }, ] [[package]] @@ -922,202 +459,76 @@ name = "internal" version = "0.1.0" source = { editable = "libraries/python" } dependencies = [ - { name = "cloudevents" }, - { name = "numpy" }, { name = "pandera", extra = ["polars"] }, { name = "polars" }, - { name = "pydantic" }, - { name = "tinygrad" }, ] [package.metadata] -requires-dist = [ - { name = "cloudevents", specifier = ">=1.12.0" }, - { name = "numpy", specifier = ">=2.2.6" }, - { name = "pandera", extras = ["polars"], specifier = ">=0.26.0" }, - { name = "polars", specifier = ">=1.29.0" }, - { name = "pydantic", specifier = ">=2.8.2" }, - { name = "tinygrad", specifier = ">=0.10.3" }, -] - -[[package]] -name = "isodate" -version = "0.7.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/4d/e940025e2ce31a8ce1202635910747e5a87cc3a6a6bb2d00973375014749/isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6", size = 29705, upload-time = "2024-10-08T23:04:11.5Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320, upload-time = "2024-10-08T23:04:09.501Z" }, -] - -[[package]] -name = "jaraco-classes" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "more-itertools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777, upload-time = "2024-03-31T07:27:34.792Z" }, -] - -[[package]] -name = "jaraco-context" -version = "6.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", size = 13912, upload-time = "2024-08-20T03:39:27.358Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4", size = 6825, upload-time = "2024-08-20T03:39:25.966Z" }, -] - -[[package]] -name = "jaraco-functools" -version = "4.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "more-itertools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f7/ed/1aa2d585304ec07262e1a83a9889880701079dde796ac7b1d1826f40c63d/jaraco_functools-4.3.0.tar.gz", hash = "sha256:cfd13ad0dd2c47a3600b439ef72d8615d482cedcff1632930d6f28924d92f294", size = 19755, upload-time = "2025-08-18T20:05:09.91Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/09/726f168acad366b11e420df31bf1c702a54d373a83f968d94141a8c3fde0/jaraco_functools-4.3.0-py3-none-any.whl", hash = "sha256:227ff8ed6f7b8f62c56deff101545fa7543cf2c8e7b82a7c2116e672f29c26e8", size = 10408, upload-time = "2025-08-18T20:05:08.69Z" }, -] - -[[package]] -name = "jeepney" -version = "0.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" }, -] - -[[package]] -name = "jmespath" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, -] - -[[package]] -name = "joblib" -version = "1.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/fe/0f5a938c54105553436dbff7a61dc4fed4b1b2c98852f8833beaf4d5968f/joblib-1.5.1.tar.gz", hash = "sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444", size = 330475, upload-time = "2025-05-23T12:04:37.097Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl", hash = "sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a", size = 307746, upload-time = "2025-05-23T12:04:35.124Z" }, -] - -[[package]] -name = "jsonlines" -version = "4.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/87/bcda8e46c88d0e34cad2f09ee2d0c7f5957bccdb9791b0b934ec84d84be4/jsonlines-4.0.0.tar.gz", hash = "sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74", size = 11359, upload-time = "2023-09-01T12:34:44.187Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701, upload-time = "2023-09-01T12:34:42.563Z" }, -] - -[[package]] -name = "jsonpickle" -version = "4.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/a6/d07afcfdef402900229bcca795f80506b207af13a838d4d99ad45abf530c/jsonpickle-4.1.1.tar.gz", hash = "sha256:f86e18f13e2b96c1c1eede0b7b90095bbb61d99fedc14813c44dc2f361dbbae1", size = 316885, upload-time = "2025-06-02T20:36:11.57Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/73/04df8a6fa66d43a9fd45c30f283cc4afff17da671886e451d52af60bdc7e/jsonpickle-4.1.1-py3-none-any.whl", hash = "sha256:bb141da6057898aa2438ff268362b126826c812a1721e31cf08a6e142910dc91", size = 47125, upload-time = "2025-06-02T20:36:08.647Z" }, -] - -[[package]] -name = "keyring" -version = "25.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jaraco-classes" }, - { name = "jaraco-context" }, - { name = "jaraco-functools" }, - { name = "jeepney", marker = "sys_platform == 'linux'" }, - { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" }, - { name = "secretstorage", marker = "sys_platform == 'linux'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/70/09/d904a6e96f76ff214be59e7aa6ef7190008f52a0ab6689760a98de0bf37d/keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66", size = 62750, upload-time = "2024-12-25T15:26:45.782Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd", size = 39085, upload-time = "2024-12-25T15:26:44.377Z" }, -] - -[[package]] -name = "loguru" -version = "0.7.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "win32-setctime", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" }, +requires-dist = [ + { name = "pandera", extras = ["polars"], specifier = ">=0.26.0" }, + { name = "polars", specifier = ">=1.29.0" }, ] [[package]] -name = "markdown-it-py" -version = "4.0.0" +name = "jmespath" +version = "1.0.1" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, + { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, ] [[package]] -name = "marshmallow" -version = "3.26.1" +name = "jsonschema" +version = "4.25.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "packaging" }, + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/5e/5e53d26b42ab75491cda89b871dab9e97c840bf12c63ec58a1919710cd06/marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6", size = 221825, upload-time = "2025-02-03T15:32:25.093Z" } +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/75/51952c7b2d3873b44a0028b1bd26a25078c18f92f256608e8d1dc61b39fd/marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c", size = 50878, upload-time = "2025-02-03T15:32:22.295Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, ] [[package]] -name = "marshmallow-enum" -version = "1.5.1" +name = "jsonschema-specifications" +version = "2025.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "marshmallow" }, + { name = "referencing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8e/8c/ceecdce57dfd37913143087fffd15f38562a94f0d22823e3c66eac0dca31/marshmallow-enum-1.5.1.tar.gz", hash = "sha256:38e697e11f45a8e64b4a1e664000897c659b60aa57bfa18d44e226a9920b6e58", size = 4013, upload-time = "2019-08-21T01:07:46.254Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/59/ef3a3dc499be447098d4a89399beb869f813fee1b5a57d5d79dee2c1bf51/marshmallow_enum-1.5.1-py2.py3-none-any.whl", hash = "sha256:57161ab3dbfde4f57adeb12090f39592e992b9c86d206d02f6bd03ebec60f072", size = 4186, upload-time = "2019-08-21T01:07:44.814Z" }, + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, ] [[package]] -name = "marshmallow-jsonschema" -version = "0.13.0" +name = "markdown-it-py" +version = "4.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "marshmallow" }, + { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2f/53/109d80013b70b6140d05e521ad31e3014680007b51c3dfac72ad20a2d6ee/marshmallow-jsonschema-0.13.0.tar.gz", hash = "sha256:f8ce19cfc0edd909e81f141d7420c33544b849bc5ebbfae8f6a3deea5a3b1f47", size = 12703, upload-time = "2021-10-21T18:02:40.923Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/cf/a620a7b0a5ba2aaa52e70f95795e0cf3a7f6332a7cb432a1223b61ac654e/marshmallow_jsonschema-0.13.0-py3-none-any.whl", hash = "sha256:2814f2afb94a6e01b3c0a5795b3dfb142b628763655f20378400af5c0a2307fb", size = 11812, upload-time = "2021-10-21T18:02:39.392Z" }, + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, ] [[package]] -name = "mashumaro" -version = "3.16" +name = "massive" +version = "2.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "certifi" }, + { name = "urllib3" }, + { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d7/92/4c1ac8d819fba3d6988876cadd922803818905a50d22d2027581366e8142/mashumaro-3.16.tar.gz", hash = "sha256:3844137cf053bbac30c4cbd0ee9984e839a5731a0ef96fd3dd9388359af3f2e1", size = 189804, upload-time = "2025-05-20T18:50:50.407Z" } +sdist = { url = "https://files.pythonhosted.org/packages/89/60/5a387e96e834b662b4dde53c061e15cf060a6c3a32553fda679e435bfcbc/massive-2.0.2.tar.gz", hash = "sha256:1d64b7fcf20678cc231cfd2cd5365e4e9f16cc3ee617fa056344987e5adcc1e4", size = 44798, upload-time = "2025-11-19T15:36:30.799Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/25/2142964380b25340d52f6ba5db771625f36ea54118deb94267eecf6e45f1/mashumaro-3.16-py3-none-any.whl", hash = "sha256:d72782cdad5e164748ca883023bc5a214a80835cdca75826bf0bcbff827e0bd3", size = 93990, upload-time = "2025-05-20T18:50:48.494Z" }, + { url = "https://files.pythonhosted.org/packages/42/21/7f50902ef5e19e22628d225428599fdb7819756bf8720f94d39327f760cd/massive-2.0.2-py3-none-any.whl", hash = "sha256:6c6dd3d628dd68f036f49640426976aa6495904c68ee0fa01b4024ff9d900ddd", size = 62611, upload-time = "2025-11-19T15:36:29.689Z" }, ] [[package]] @@ -1130,73 +541,12 @@ wheels = [ ] [[package]] -name = "models" -version = "0.1.0" -source = { virtual = "applications/models" } -dependencies = [ - { name = "alpaca-py" }, - { name = "boto3" }, - { name = "botocore" }, - { name = "flytekit" }, - { name = "internal" }, - { name = "loguru" }, - { name = "polars" }, - { name = "polygon-api-client" }, - { name = "pyarrow" }, - { name = "pydantic" }, - { name = "requests" }, - { name = "wandb" }, -] - -[package.metadata] -requires-dist = [ - { name = "alpaca-py", specifier = ">=0.42.0" }, - { name = "boto3", specifier = ">=1.38.23" }, - { name = "botocore", specifier = ">=1.38.23" }, - { name = "flytekit", specifier = ">=1.16.1" }, - { name = "internal", editable = "libraries/python" }, - { name = "loguru", specifier = ">=0.7.3" }, - { name = "polars", specifier = ">=1.29.0" }, - { name = "polygon-api-client", specifier = ">=1.14.6" }, - { name = "pyarrow", specifier = ">=20.0.0" }, - { name = "pydantic", specifier = ">=2.8.2" }, - { name = "requests", specifier = ">=2.31.0" }, - { name = "wandb", specifier = ">=0.21.1" }, -] - -[[package]] -name = "more-itertools" -version = "10.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ce/a0/834b0cebabbfc7e311f30b46c8188790a37f89fc8d756660346fe5abfd09/more_itertools-10.7.0.tar.gz", hash = "sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3", size = 127671, upload-time = "2025-04-22T14:17:41.838Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/9f/7ba6f94fc1e9ac3d2b853fdff3035fb2fa5afbed898c4a72b8a020610594/more_itertools-10.7.0-py3-none-any.whl", hash = "sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e", size = 65278, upload-time = "2025-04-22T14:17:40.49Z" }, -] - -[[package]] -name = "msal" -version = "1.33.0" +name = "mock" +version = "4.0.3" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cryptography" }, - { name = "pyjwt", extra = ["crypto"] }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d5/da/81acbe0c1fd7e9e4ec35f55dadeba9833a847b9a6ba2e2d1e4432da901dd/msal-1.33.0.tar.gz", hash = "sha256:836ad80faa3e25a7d71015c990ce61f704a87328b1e73bcbb0623a18cbf17510", size = 153801, upload-time = "2025-07-22T19:36:33.693Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/5b/fbc73e91f7727ae1e79b21ed833308e99dc11cc1cd3d4717f579775de5e9/msal-1.33.0-py3-none-any.whl", hash = "sha256:c0cd41cecf8eaed733ee7e3be9e040291eba53b0f262d3ae9c58f38b04244273", size = 116853, upload-time = "2025-07-22T19:36:32.403Z" }, -] - -[[package]] -name = "msal-extensions" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "msal" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/01/99/5d239b6156eddf761a636bded1118414d161bd6b7b37a9335549ed159396/msal_extensions-1.3.1.tar.gz", hash = "sha256:c5b0fd10f65ef62b5f1d62f4251d51cbcaf003fcedae8c91b040a488614be1a4", size = 23315, upload-time = "2025-03-14T23:51:03.902Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e2/be/3ea39a8fd4ed3f9a25aae18a1bff2df7a610bca93c8ede7475e32d8b73a0/mock-4.0.3.tar.gz", hash = "sha256:7d3fbbde18228f4ff2f1f119a45cdffa458b4c0dee32eb4d2bb2f82554bac7bc", size = 72316, upload-time = "2020-12-10T07:33:13.043Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/75/bd9b7bb966668920f06b200e84454c8f3566b102183bc55c5473d96cb2b9/msal_extensions-1.3.1-py3-none-any.whl", hash = "sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca", size = 20583, upload-time = "2025-03-14T23:51:03.016Z" }, + { url = "https://files.pythonhosted.org/packages/5c/03/b7e605db4a57c0f6fba744b11ef3ddf4ddebcada35022927a2b5fc623fdf/mock-4.0.3-py3-none-any.whl", hash = "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62", size = 28536, upload-time = "2020-12-10T07:33:11.564Z" }, ] [[package]] @@ -1218,30 +568,19 @@ wheels = [ ] [[package]] -name = "multidict" -version = "6.6.4" +name = "multiprocess" +version = "0.70.18" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/7f/0652e6ed47ab288e3756ea9c0df8b14950781184d4bd7883f4d87dd41245/multidict-6.6.4.tar.gz", hash = "sha256:d2d4e4787672911b48350df02ed3fa3fffdc2f2e8ca06dd6afdf34189b76a9dd", size = 101843, upload-time = "2025-08-11T12:08:48.217Z" } +dependencies = [ + { name = "dill" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503, upload-time = "2025-04-17T03:11:27.742Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/f6/512ffd8fd8b37fb2680e5ac35d788f1d71bbaf37789d21a820bdc441e565/multidict-6.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0ffb87be160942d56d7b87b0fdf098e81ed565add09eaa1294268c7f3caac4c8", size = 76516, upload-time = "2025-08-11T12:06:53.393Z" }, - { url = "https://files.pythonhosted.org/packages/99/58/45c3e75deb8855c36bd66cc1658007589662ba584dbf423d01df478dd1c5/multidict-6.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d191de6cbab2aff5de6c5723101705fd044b3e4c7cfd587a1929b5028b9714b3", size = 45394, upload-time = "2025-08-11T12:06:54.555Z" }, - { url = "https://files.pythonhosted.org/packages/fd/ca/e8c4472a93a26e4507c0b8e1f0762c0d8a32de1328ef72fd704ef9cc5447/multidict-6.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38a0956dd92d918ad5feff3db8fcb4a5eb7dba114da917e1a88475619781b57b", size = 43591, upload-time = "2025-08-11T12:06:55.672Z" }, - { url = "https://files.pythonhosted.org/packages/05/51/edf414f4df058574a7265034d04c935aa84a89e79ce90fcf4df211f47b16/multidict-6.6.4-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:6865f6d3b7900ae020b495d599fcf3765653bc927951c1abb959017f81ae8287", size = 237215, upload-time = "2025-08-11T12:06:57.213Z" }, - { url = "https://files.pythonhosted.org/packages/c8/45/8b3d6dbad8cf3252553cc41abea09ad527b33ce47a5e199072620b296902/multidict-6.6.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a2088c126b6f72db6c9212ad827d0ba088c01d951cee25e758c450da732c138", size = 258299, upload-time = "2025-08-11T12:06:58.946Z" }, - { url = "https://files.pythonhosted.org/packages/3c/e8/8ca2e9a9f5a435fc6db40438a55730a4bf4956b554e487fa1b9ae920f825/multidict-6.6.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0f37bed7319b848097085d7d48116f545985db988e2256b2e6f00563a3416ee6", size = 242357, upload-time = "2025-08-11T12:07:00.301Z" }, - { url = "https://files.pythonhosted.org/packages/0f/84/80c77c99df05a75c28490b2af8f7cba2a12621186e0a8b0865d8e745c104/multidict-6.6.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:01368e3c94032ba6ca0b78e7ccb099643466cf24f8dc8eefcfdc0571d56e58f9", size = 268369, upload-time = "2025-08-11T12:07:01.638Z" }, - { url = "https://files.pythonhosted.org/packages/0d/e9/920bfa46c27b05fb3e1ad85121fd49f441492dca2449c5bcfe42e4565d8a/multidict-6.6.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fe323540c255db0bffee79ad7f048c909f2ab0edb87a597e1c17da6a54e493c", size = 269341, upload-time = "2025-08-11T12:07:02.943Z" }, - { url = "https://files.pythonhosted.org/packages/af/65/753a2d8b05daf496f4a9c367fe844e90a1b2cac78e2be2c844200d10cc4c/multidict-6.6.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8eb3025f17b0a4c3cd08cda49acf312a19ad6e8a4edd9dbd591e6506d999402", size = 256100, upload-time = "2025-08-11T12:07:04.564Z" }, - { url = "https://files.pythonhosted.org/packages/09/54/655be13ae324212bf0bc15d665a4e34844f34c206f78801be42f7a0a8aaa/multidict-6.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bbc14f0365534d35a06970d6a83478b249752e922d662dc24d489af1aa0d1be7", size = 253584, upload-time = "2025-08-11T12:07:05.914Z" }, - { url = "https://files.pythonhosted.org/packages/5c/74/ab2039ecc05264b5cec73eb018ce417af3ebb384ae9c0e9ed42cb33f8151/multidict-6.6.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:75aa52fba2d96bf972e85451b99d8e19cc37ce26fd016f6d4aa60da9ab2b005f", size = 251018, upload-time = "2025-08-11T12:07:08.301Z" }, - { url = "https://files.pythonhosted.org/packages/af/0a/ccbb244ac848e56c6427f2392741c06302bbfba49c0042f1eb3c5b606497/multidict-6.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fefd4a815e362d4f011919d97d7b4a1e566f1dde83dc4ad8cfb5b41de1df68d", size = 251477, upload-time = "2025-08-11T12:07:10.248Z" }, - { url = "https://files.pythonhosted.org/packages/0e/b0/0ed49bba775b135937f52fe13922bc64a7eaf0a3ead84a36e8e4e446e096/multidict-6.6.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:db9801fe021f59a5b375ab778973127ca0ac52429a26e2fd86aa9508f4d26eb7", size = 263575, upload-time = "2025-08-11T12:07:11.928Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d9/7fb85a85e14de2e44dfb6a24f03c41e2af8697a6df83daddb0e9b7569f73/multidict-6.6.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a650629970fa21ac1fb06ba25dabfc5b8a2054fcbf6ae97c758aa956b8dba802", size = 259649, upload-time = "2025-08-11T12:07:13.244Z" }, - { url = "https://files.pythonhosted.org/packages/03/9e/b3a459bcf9b6e74fa461a5222a10ff9b544cb1cd52fd482fb1b75ecda2a2/multidict-6.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:452ff5da78d4720d7516a3a2abd804957532dd69296cb77319c193e3ffb87e24", size = 251505, upload-time = "2025-08-11T12:07:14.57Z" }, - { url = "https://files.pythonhosted.org/packages/86/a2/8022f78f041dfe6d71e364001a5cf987c30edfc83c8a5fb7a3f0974cff39/multidict-6.6.4-cp312-cp312-win32.whl", hash = "sha256:8c2fcb12136530ed19572bbba61b407f655e3953ba669b96a35036a11a485793", size = 41888, upload-time = "2025-08-11T12:07:15.904Z" }, - { url = "https://files.pythonhosted.org/packages/c7/eb/d88b1780d43a56db2cba24289fa744a9d216c1a8546a0dc3956563fd53ea/multidict-6.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:047d9425860a8c9544fed1b9584f0c8bcd31bcde9568b047c5e567a1025ecd6e", size = 46072, upload-time = "2025-08-11T12:07:17.045Z" }, - { url = "https://files.pythonhosted.org/packages/9f/16/b929320bf5750e2d9d4931835a4c638a19d2494a5b519caaaa7492ebe105/multidict-6.6.4-cp312-cp312-win_arm64.whl", hash = "sha256:14754eb72feaa1e8ae528468f24250dd997b8e2188c3d2f593f9eba259e4b364", size = 43222, upload-time = "2025-08-11T12:07:18.328Z" }, - { url = "https://files.pythonhosted.org/packages/fd/69/b547032297c7e63ba2af494edba695d781af8a0c6e89e4d06cf848b21d80/multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c", size = 12313, upload-time = "2025-08-11T12:08:46.891Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948, upload-time = "2025-04-17T03:11:20.223Z" }, + { url = "https://files.pythonhosted.org/packages/4b/88/9039f2fed1012ef584751d4ceff9ab4a51e5ae264898f0b7cbf44340a859/multiprocess-0.70.18-py311-none-any.whl", hash = "sha256:5aa6eef98e691281b3ad923be2832bf1c55dd2c859acd73e5ec53a66aae06a1d", size = 144462, upload-time = "2025-04-17T03:11:21.657Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b6/5f922792be93b82ec6b5f270bbb1ef031fd0622847070bbcf9da816502cc/multiprocess-0.70.18-py312-none-any.whl", hash = "sha256:9b78f8e5024b573730bfb654783a13800c2c0f2dfc0c25e70b40d184d64adaa2", size = 150287, upload-time = "2025-04-17T03:11:22.69Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636, upload-time = "2025-04-17T03:11:24.936Z" }, + { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478, upload-time = "2025-04-17T03:11:26.253Z" }, ] [[package]] @@ -1255,39 +594,40 @@ wheels = [ [[package]] name = "numpy" -version = "2.3.2" +version = "1.26.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/7d/3fec4199c5ffb892bed55cff901e4f39a58c81df9c44c280499e92cad264/numpy-2.3.2.tar.gz", hash = "sha256:e0486a11ec30cdecb53f184d496d1c6a20786c81e55e41640270130056f8ee48", size = 20489306, upload-time = "2025-07-24T21:32:07.553Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/6d/745dd1c1c5c284d17725e5c802ca4d45cfc6803519d777f087b71c9f4069/numpy-2.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bc3186bea41fae9d8e90c2b4fb5f0a1f5a690682da79b92574d63f56b529080b", size = 20956420, upload-time = "2025-07-24T20:28:18.002Z" }, - { url = "https://files.pythonhosted.org/packages/bc/96/e7b533ea5740641dd62b07a790af5d9d8fec36000b8e2d0472bd7574105f/numpy-2.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f4f0215edb189048a3c03bd5b19345bdfa7b45a7a6f72ae5945d2a28272727f", size = 14184660, upload-time = "2025-07-24T20:28:39.522Z" }, - { url = "https://files.pythonhosted.org/packages/2b/53/102c6122db45a62aa20d1b18c9986f67e6b97e0d6fbc1ae13e3e4c84430c/numpy-2.3.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b1224a734cd509f70816455c3cffe13a4f599b1bf7130f913ba0e2c0b2006c0", size = 5113382, upload-time = "2025-07-24T20:28:48.544Z" }, - { url = "https://files.pythonhosted.org/packages/2b/21/376257efcbf63e624250717e82b4fae93d60178f09eb03ed766dbb48ec9c/numpy-2.3.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3dcf02866b977a38ba3ec10215220609ab9667378a9e2150615673f3ffd6c73b", size = 6647258, upload-time = "2025-07-24T20:28:59.104Z" }, - { url = "https://files.pythonhosted.org/packages/91/ba/f4ebf257f08affa464fe6036e13f2bf9d4642a40228781dc1235da81be9f/numpy-2.3.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:572d5512df5470f50ada8d1972c5f1082d9a0b7aa5944db8084077570cf98370", size = 14281409, upload-time = "2025-07-24T20:40:30.298Z" }, - { url = "https://files.pythonhosted.org/packages/59/ef/f96536f1df42c668cbacb727a8c6da7afc9c05ece6d558927fb1722693e1/numpy-2.3.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8145dd6d10df13c559d1e4314df29695613575183fa2e2d11fac4c208c8a1f73", size = 16641317, upload-time = "2025-07-24T20:40:56.625Z" }, - { url = "https://files.pythonhosted.org/packages/f6/a7/af813a7b4f9a42f498dde8a4c6fcbff8100eed00182cc91dbaf095645f38/numpy-2.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:103ea7063fa624af04a791c39f97070bf93b96d7af7eb23530cd087dc8dbe9dc", size = 16056262, upload-time = "2025-07-24T20:41:20.797Z" }, - { url = "https://files.pythonhosted.org/packages/8b/5d/41c4ef8404caaa7f05ed1cfb06afe16a25895260eacbd29b4d84dff2920b/numpy-2.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc927d7f289d14f5e037be917539620603294454130b6de200091e23d27dc9be", size = 18579342, upload-time = "2025-07-24T20:41:50.753Z" }, - { url = "https://files.pythonhosted.org/packages/a1/4f/9950e44c5a11636f4a3af6e825ec23003475cc9a466edb7a759ed3ea63bd/numpy-2.3.2-cp312-cp312-win32.whl", hash = "sha256:d95f59afe7f808c103be692175008bab926b59309ade3e6d25009e9a171f7036", size = 6320610, upload-time = "2025-07-24T20:42:01.551Z" }, - { url = "https://files.pythonhosted.org/packages/7c/2f/244643a5ce54a94f0a9a2ab578189c061e4a87c002e037b0829dd77293b6/numpy-2.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:9e196ade2400c0c737d93465327d1ae7c06c7cb8a1756121ebf54b06ca183c7f", size = 12786292, upload-time = "2025-07-24T20:42:20.738Z" }, - { url = "https://files.pythonhosted.org/packages/54/cd/7b5f49d5d78db7badab22d8323c1b6ae458fbf86c4fdfa194ab3cd4eb39b/numpy-2.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:ee807923782faaf60d0d7331f5e86da7d5e3079e28b291973c545476c2b00d07", size = 10194071, upload-time = "2025-07-24T20:42:36.657Z" }, + { url = "https://files.pythonhosted.org/packages/95/12/8f2020a8e8b8383ac0177dc9570aad031a3beb12e38847f7129bacd96228/numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", size = 20335901, upload-time = "2024-02-05T23:55:32.801Z" }, + { url = "https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", size = 13685868, upload-time = "2024-02-05T23:55:56.28Z" }, + { url = "https://files.pythonhosted.org/packages/79/f8/97f10e6755e2a7d027ca783f63044d5b1bc1ae7acb12afe6a9b4286eac17/numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", size = 13925109, upload-time = "2024-02-05T23:56:20.368Z" }, + { url = "https://files.pythonhosted.org/packages/0f/50/de23fde84e45f5c4fda2488c759b69990fd4512387a8632860f3ac9cd225/numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", size = 17950613, upload-time = "2024-02-05T23:56:56.054Z" }, + { url = "https://files.pythonhosted.org/packages/4c/0c/9c603826b6465e82591e05ca230dfc13376da512b25ccd0894709b054ed0/numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", size = 13572172, upload-time = "2024-02-05T23:57:21.56Z" }, + { url = "https://files.pythonhosted.org/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", size = 17786643, upload-time = "2024-02-05T23:57:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/28/4a/46d9e65106879492374999e76eb85f87b15328e06bd1550668f79f7b18c6/numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", size = 5677803, upload-time = "2024-02-05T23:58:08.963Z" }, + { url = "https://files.pythonhosted.org/packages/16/2e/86f24451c2d530c88daf997cb8d6ac622c1d40d19f5a031ed68a4b73a374/numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", size = 15517754, upload-time = "2024-02-05T23:58:36.364Z" }, ] [[package]] -name = "oauthlib" -version = "3.3.1" +name = "omegaconf" +version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" } +dependencies = [ + { name = "antlr4-python3-runtime" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/48/6388f1bb9da707110532cb70ec4d2822858ddfb44f1cdf1233c20a80ea4b/omegaconf-2.3.0.tar.gz", hash = "sha256:d5d4b6d29955cc50ad50c46dc269bcd92c6e00f5f90d23ab5fee7bfca4ba4cc7", size = 3298120, upload-time = "2022-12-08T20:59:22.753Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, + { url = "https://files.pythonhosted.org/packages/e3/94/1843518e420fa3ed6919835845df698c7e27e183cb997394e4a670973a65/omegaconf-2.3.0-py3-none-any.whl", hash = "sha256:7b4df175cdb08ba400f45cae3bdcae7ba8365db4d165fc65fd04b050ab63b46b", size = 79500, upload-time = "2022-12-08T20:59:19.686Z" }, ] [[package]] name = "packaging" -version = "25.0" +version = "24.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950, upload-time = "2024-11-08T09:47:47.202Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451, upload-time = "2024-11-08T09:47:44.722Z" }, ] [[package]] @@ -1358,6 +698,43 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/85/8d/eef3d8cdccc32abdd91b1286884c99b8c3a6d3b135affcc2a7a0f383bb32/parse_type-0.6.6-py2.py3-none-any.whl", hash = "sha256:3ca79bbe71e170dfccc8ec6c341edfd1c2a0fc1e5cfd18330f93af938de2348c", size = 27085, upload-time = "2025-08-11T22:53:46.396Z" }, ] +[[package]] +name = "parver" +version = "0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "arpeggio" }, + { name = "attrs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cc/e5/1c774688a90f0b76e872e30f6f1ba3f5e14056cd0d96a684047d4a986226/parver-0.5.tar.gz", hash = "sha256:b9fde1e6bb9ce9f07e08e9c4bea8d8825c5e78e18a0052d02e02bf9517eb4777", size = 26908, upload-time = "2023-10-03T21:06:54.506Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/4c/f98024021bef4d44dce3613feebd702c7ad8883f777ff8488384c59e9774/parver-0.5-py3-none-any.whl", hash = "sha256:2281b187276c8e8e3c15634f62287b2fb6fe0efe3010f739a6bd1e45fa2bf2b2", size = 15172, upload-time = "2023-10-03T21:06:52.796Z" }, +] + +[[package]] +name = "pathos" +version = "0.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dill" }, + { name = "multiprocess" }, + { name = "pox" }, + { name = "ppft" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/90/fdbe3bbfe79933db439e1844083cb6e9d5a9d3b686738549b3d22d06eae7/pathos-0.3.4.tar.gz", hash = "sha256:bad4912d0ef865654a7cc478da65f2e1d5b69f3d92c4a7d9c9845657783c0754", size = 167076, upload-time = "2025-04-17T03:37:08.234Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/0a/daece46e65c821d153746566a1604ac90338f0279b1fb858a3617eb60472/pathos-0.3.4-py3-none-any.whl", hash = "sha256:fe44883448c05c80d518b61df491b496f6190bb6860253f3254d8c9afb53c340", size = 82261, upload-time = "2025-04-17T03:37:06.936Z" }, +] + +[[package]] +name = "pip" +version = "25.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014, upload-time = "2025-10-25T00:55:41.394Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622, upload-time = "2025-10-25T00:55:39.247Z" }, +] + [[package]] name = "platformdirs" version = "4.3.8" @@ -1381,25 +758,39 @@ name = "pocketsizefund" version = "20250602.4" source = { virtual = "." } dependencies = [ + { name = "fastapi" }, { name = "internal" }, + { name = "numpy" }, + { name = "requests" }, + { name = "sagemaker" }, + { name = "structlog" }, + { name = "tinygrad" }, + { name = "uvicorn" }, ] [package.dev-dependencies] dev = [ { name = "behave" }, { name = "coverage" }, - { name = "pyproject-fmt" }, { name = "pytest" }, ] [package.metadata] -requires-dist = [{ name = "internal", editable = "libraries/python" }] +requires-dist = [ + { name = "fastapi", specifier = ">=0.121.0" }, + { name = "internal", editable = "libraries/python" }, + { name = "numpy", specifier = ">=1.26.4" }, + { name = "requests", specifier = ">=2.32.5" }, + { name = "sagemaker", specifier = ">=2.252.0" }, + { name = "structlog", specifier = ">=25.5.0" }, + { name = "tinygrad", specifier = ">=0.10.3" }, + { name = "uvicorn", specifier = ">=0.35.0" }, +] [package.metadata.requires-dev] dev = [ { name = "behave", specifier = ">=1.2.6" }, { name = "coverage", specifier = ">=7.8.0" }, - { name = "pyproject-fmt", specifier = ">=2.6.0" }, { name = "pytest", specifier = ">=8.3.5" }, ] @@ -1417,155 +808,149 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/99/6b93c854e602927a778eabd7550204f700cc4e6c07be73372371583dda3e/polars-1.32.3-cp39-abi3-win_arm64.whl", hash = "sha256:a2e3f87c60f54eefe67b1bebd3105918d84df0fd6d59cc6b870c2f16d2d26ca1", size = 34198919, upload-time = "2025-08-14T17:27:21.423Z" }, ] -[[package]] -name = "polygon-api-client" -version = "1.15.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "urllib3" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0f/87/da00179018cbbe5201e835b1b08b1006bccbac23d29c07db77fd93832447/polygon_api_client-1.15.3.tar.gz", hash = "sha256:6f802bf845cce6004fc2f7921b6fe2e7941caf6539216033415cbea2194f8a48", size = 37976, upload-time = "2025-07-17T15:55:27.344Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/b2/4a51232a3017dce2a74cd3e9bda16d118a95cc20e7c75969710ca9839dc0/polygon_api_client-1.15.3-py3-none-any.whl", hash = "sha256:a6a3b36cfb4a021c4fd89d782e5950d2e6b20554afb463c1217f3cc138c0d2d3", size = 54553, upload-time = "2025-07-17T15:55:25.958Z" }, -] - [[package]] name = "portfoliomanager" version = "0.1.0" source = { editable = "applications/portfoliomanager" } dependencies = [ { name = "alpaca-py" }, - { name = "fastapi" }, { name = "httpx" }, { name = "internal" }, { name = "pandera", extra = ["pandas", "polars"] }, - { name = "uvicorn" }, ] [package.metadata] requires-dist = [ { name = "alpaca-py", specifier = ">=0.42.1" }, - { name = "fastapi", specifier = ">=0.116.1" }, { name = "httpx", specifier = ">=0.27.0" }, { name = "internal", editable = "libraries/python" }, { name = "pandera", extras = ["polars", "pandas"], specifier = ">=0.26.0" }, - { name = "uvicorn", specifier = ">=0.35.0" }, ] [[package]] -name = "propcache" -version = "0.3.2" +name = "pox" +version = "0.3.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } +sdist = { url = "https://files.pythonhosted.org/packages/56/99/42670d273fd598a6fe98c8b2f593ee425b29e44f2d1a61ff622031204ccd/pox-0.3.6.tar.gz", hash = "sha256:84eeed39600159a62804aacfc00e353edeaae67d8c647ccaaab73a6efed3f605", size = 119393, upload-time = "2025-04-16T00:05:49.811Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, - { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, - { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, - { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, - { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, - { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, - { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, - { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c2/6435789c26661bef699868ee54d2763aea636a1ed21ec8e350b1f9f65888/pox-0.3.6-py3-none-any.whl", hash = "sha256:d48654d0a3dca0c9c02dccae54a53c3870286a5217ad306b2bd94f84e008bc1b", size = 29495, upload-time = "2025-04-16T00:05:48.319Z" }, ] [[package]] -name = "proto-plus" -version = "1.26.1" +name = "ppft" +version = "1.7.7" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/ac/87285f15f7cce6d4a008f33f1757fb5a13611ea8914eb58c3d0d26243468/proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012", size = 56142, upload-time = "2025-03-10T15:54:38.843Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/46/9e9f2ae7e8e284acbde6ab36f7f4a35b273519a60c0ed419af2da780d49f/ppft-1.7.7.tar.gz", hash = "sha256:f3f77448cfe24c2b8d2296b6d8732280b25041a3f3e1f551856c6451d3e01b96", size = 136272, upload-time = "2025-04-16T01:47:40.925Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/6d/280c4c2ce28b1593a19ad5239c8b826871fc6ec275c21afc8e1820108039/proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66", size = 50163, upload-time = "2025-03-10T15:54:37.335Z" }, + { url = "https://files.pythonhosted.org/packages/5b/23/6aef7c24f4ee6f765aeaaaa3bf24cfdb0730a20336a02b1a061d227d84be/ppft-1.7.7-py3-none-any.whl", hash = "sha256:fb7524db110682de886b4bb5b08f7bf6a38940566074ef2f62521cbbd3864676", size = 56764, upload-time = "2025-04-16T01:47:39.453Z" }, ] [[package]] name = "protobuf" -version = "6.32.0" +version = "5.29.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c0/df/fb4a8eeea482eca989b51cffd274aac2ee24e825f0bf3cbce5281fa1567b/protobuf-6.32.0.tar.gz", hash = "sha256:a81439049127067fc49ec1d36e25c6ee1d1a2b7be930675f919258d03c04e7d2", size = 440614, upload-time = "2025-08-14T21:21:25.015Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/29/d09e70352e4e88c9c7a198d5645d7277811448d76c23b00345670f7c8a38/protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84", size = 425226, upload-time = "2025-05-28T23:51:59.82Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/18/df8c87da2e47f4f1dcc5153a81cd6bca4e429803f4069a299e236e4dd510/protobuf-6.32.0-cp310-abi3-win32.whl", hash = "sha256:84f9e3c1ff6fb0308dbacb0950d8aa90694b0d0ee68e75719cb044b7078fe741", size = 424409, upload-time = "2025-08-14T21:21:12.366Z" }, - { url = "https://files.pythonhosted.org/packages/e1/59/0a820b7310f8139bd8d5a9388e6a38e1786d179d6f33998448609296c229/protobuf-6.32.0-cp310-abi3-win_amd64.whl", hash = "sha256:a8bdbb2f009cfc22a36d031f22a625a38b615b5e19e558a7b756b3279723e68e", size = 435735, upload-time = "2025-08-14T21:21:15.046Z" }, - { url = "https://files.pythonhosted.org/packages/cc/5b/0d421533c59c789e9c9894683efac582c06246bf24bb26b753b149bd88e4/protobuf-6.32.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d52691e5bee6c860fff9a1c86ad26a13afbeb4b168cd4445c922b7e2cf85aaf0", size = 426449, upload-time = "2025-08-14T21:21:16.687Z" }, - { url = "https://files.pythonhosted.org/packages/ec/7b/607764ebe6c7a23dcee06e054fd1de3d5841b7648a90fd6def9a3bb58c5e/protobuf-6.32.0-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:501fe6372fd1c8ea2a30b4d9be8f87955a64d6be9c88a973996cef5ef6f0abf1", size = 322869, upload-time = "2025-08-14T21:21:18.282Z" }, - { url = "https://files.pythonhosted.org/packages/40/01/2e730bd1c25392fc32e3268e02446f0d77cb51a2c3a8486b1798e34d5805/protobuf-6.32.0-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:75a2aab2bd1aeb1f5dc7c5f33bcb11d82ea8c055c9becbb41c26a8c43fd7092c", size = 322009, upload-time = "2025-08-14T21:21:19.893Z" }, - { url = "https://files.pythonhosted.org/packages/9c/f2/80ffc4677aac1bc3519b26bc7f7f5de7fce0ee2f7e36e59e27d8beb32dd1/protobuf-6.32.0-py3-none-any.whl", hash = "sha256:ba377e5b67b908c8f3072a57b63e2c6a4cbd18aea4ed98d2584350dbf46f2783", size = 169287, upload-time = "2025-08-14T21:21:23.515Z" }, + { url = "https://files.pythonhosted.org/packages/5f/11/6e40e9fc5bba02988a214c07cf324595789ca7820160bfd1f8be96e48539/protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079", size = 422963, upload-time = "2025-05-28T23:51:41.204Z" }, + { url = "https://files.pythonhosted.org/packages/81/7f/73cefb093e1a2a7c3ffd839e6f9fcafb7a427d300c7f8aef9c64405d8ac6/protobuf-5.29.5-cp310-abi3-win_amd64.whl", hash = "sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc", size = 434818, upload-time = "2025-05-28T23:51:44.297Z" }, + { url = "https://files.pythonhosted.org/packages/dd/73/10e1661c21f139f2c6ad9b23040ff36fee624310dc28fba20d33fdae124c/protobuf-5.29.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671", size = 418091, upload-time = "2025-05-28T23:51:45.907Z" }, + { url = "https://files.pythonhosted.org/packages/6c/04/98f6f8cf5b07ab1294c13f34b4e69b3722bb609c5b701d6c169828f9f8aa/protobuf-5.29.5-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015", size = 319824, upload-time = "2025-05-28T23:51:47.545Z" }, + { url = "https://files.pythonhosted.org/packages/85/e4/07c80521879c2d15f321465ac24c70efe2381378c00bf5e56a0f4fbac8cd/protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61", size = 319942, upload-time = "2025-05-28T23:51:49.11Z" }, + { url = "https://files.pythonhosted.org/packages/7e/cc/7e77861000a0691aeea8f4566e5d3aa716f2b1dece4a24439437e41d3d25/protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5", size = 172823, upload-time = "2025-05-28T23:51:58.157Z" }, ] [[package]] -name = "protoc-gen-openapiv2" -version = "0.0.1" +name = "psutil" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/31/4723d756b59344b643542936e37a31d1d3204bcdc42a7daa8ee9eb06fb50/psutil-7.1.0.tar.gz", hash = "sha256:655708b3c069387c8b77b072fc429a57d0e214221d01c0a772df7dfedcb3bcd2", size = 497660, upload-time = "2025-09-17T20:14:52.902Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/62/ce4051019ee20ce0ed74432dd73a5bb087a6704284a470bb8adff69a0932/psutil-7.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76168cef4397494250e9f4e73eb3752b146de1dd950040b29186d0cce1d5ca13", size = 245242, upload-time = "2025-09-17T20:14:56.126Z" }, + { url = "https://files.pythonhosted.org/packages/38/61/f76959fba841bf5b61123fbf4b650886dc4094c6858008b5bf73d9057216/psutil-7.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:5d007560c8c372efdff9e4579c2846d71de737e4605f611437255e81efcca2c5", size = 246682, upload-time = "2025-09-17T20:14:58.25Z" }, + { url = "https://files.pythonhosted.org/packages/88/7a/37c99d2e77ec30d63398ffa6a660450b8a62517cabe44b3e9bae97696e8d/psutil-7.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22e4454970b32472ce7deaa45d045b34d3648ce478e26a04c7e858a0a6e75ff3", size = 287994, upload-time = "2025-09-17T20:14:59.901Z" }, + { url = "https://files.pythonhosted.org/packages/9d/de/04c8c61232f7244aa0a4b9a9fbd63a89d5aeaf94b2fc9d1d16e2faa5cbb0/psutil-7.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c70e113920d51e89f212dd7be06219a9b88014e63a4cec69b684c327bc474e3", size = 291163, upload-time = "2025-09-17T20:15:01.481Z" }, + { url = "https://files.pythonhosted.org/packages/f4/58/c4f976234bf6d4737bc8c02a81192f045c307b72cf39c9e5c5a2d78927f6/psutil-7.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d4a113425c037300de3ac8b331637293da9be9713855c4fc9d2d97436d7259d", size = 293625, upload-time = "2025-09-17T20:15:04.492Z" }, + { url = "https://files.pythonhosted.org/packages/79/87/157c8e7959ec39ced1b11cc93c730c4fb7f9d408569a6c59dbd92ceb35db/psutil-7.1.0-cp37-abi3-win32.whl", hash = "sha256:09ad740870c8d219ed8daae0ad3b726d3bf9a028a198e7f3080f6a1888b99bca", size = 244812, upload-time = "2025-09-17T20:15:07.462Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e9/b44c4f697276a7a95b8e94d0e320a7bf7f3318521b23de69035540b39838/psutil-7.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:57f5e987c36d3146c0dd2528cd42151cf96cd359b9d67cfff836995cc5df9a3d", size = 247965, upload-time = "2025-09-17T20:15:09.673Z" }, + { url = "https://files.pythonhosted.org/packages/26/65/1070a6e3c036f39142c2820c4b52e9243246fcfc3f96239ac84472ba361e/psutil-7.1.0-cp37-abi3-win_arm64.whl", hash = "sha256:6937cb68133e7c97b6cc9649a570c9a18ba0efebed46d8c5dae4c07fa1b67a07", size = 244971, upload-time = "2025-09-17T20:15:12.262Z" }, +] + +[[package]] +name = "pulumi" +version = "3.207.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "googleapis-common-protos" }, + { name = "debugpy" }, + { name = "dill" }, + { name = "grpcio" }, + { name = "pip" }, { name = "protobuf" }, + { name = "pyyaml" }, + { name = "semver" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d8/d2/84fecd8df61640226c726c12ad7ddd2a7666a7cd7f898b9a5b72e3a66d44/protoc-gen-openapiv2-0.0.1.tar.gz", hash = "sha256:6f79188d842c13177c9c0558845442c340b43011bf67dfef1dfc3bc067506409", size = 7323, upload-time = "2022-12-02T01:40:57.306Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/ac/bd8961859d8f3f81530465d2ce9b165627e961c00348939009bac2700cc6/protoc_gen_openapiv2-0.0.1-py3-none-any.whl", hash = "sha256:18090c8be3877c438e7da0f7eb7cace45a9a210306bca4707708dbad367857be", size = 7883, upload-time = "2022-12-02T01:40:55.244Z" }, + { url = "https://files.pythonhosted.org/packages/cf/b0/c3e5a44e192d32bcf30c39aa54321aae85e8e0ea5ca310945e34b23761e5/pulumi-3.207.0-py3-none-any.whl", hash = "sha256:8a5a211d155f7c60fb8333005b53490c7e1eb882bbd5f7afbccc267fe8c2478c", size = 389892, upload-time = "2025-11-12T16:14:05.829Z" }, ] [[package]] -name = "pyarrow" -version = "21.0.0" +name = "pulumi-aws" +version = "7.11.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ef/c2/ea068b8f00905c06329a3dfcd40d0fcc2b7d0f2e355bdb25b65e0a0e4cd4/pyarrow-21.0.0.tar.gz", hash = "sha256:5051f2dccf0e283ff56335760cbc8622cf52264d67e359d5569541ac11b6d5bc", size = 1133487, upload-time = "2025-07-18T00:57:31.761Z" } +dependencies = [ + { name = "parver" }, + { name = "pulumi" }, + { name = "semver" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/dc/eea8e5147dc69ca59006b566e3ce606e4a4c416d5dc598ea2ceb89745624/pulumi_aws-7.11.1.tar.gz", hash = "sha256:74f05f31495f89d22ac40f7a0bb07fb063d950ad6097ed30fec02bb369d1d876", size = 8346790, upload-time = "2025-11-11T13:01:15.784Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/d4/d4f817b21aacc30195cf6a46ba041dd1be827efa4a623cc8bf39a1c2a0c0/pyarrow-21.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:3a302f0e0963db37e0a24a70c56cf91a4faa0bca51c23812279ca2e23481fccd", size = 31160305, upload-time = "2025-07-18T00:55:35.373Z" }, - { url = "https://files.pythonhosted.org/packages/a2/9c/dcd38ce6e4b4d9a19e1d36914cb8e2b1da4e6003dd075474c4cfcdfe0601/pyarrow-21.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:b6b27cf01e243871390474a211a7922bfbe3bda21e39bc9160daf0da3fe48876", size = 32684264, upload-time = "2025-07-18T00:55:39.303Z" }, - { url = "https://files.pythonhosted.org/packages/4f/74/2a2d9f8d7a59b639523454bec12dba35ae3d0a07d8ab529dc0809f74b23c/pyarrow-21.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e72a8ec6b868e258a2cd2672d91f2860ad532d590ce94cdf7d5e7ec674ccf03d", size = 41108099, upload-time = "2025-07-18T00:55:42.889Z" }, - { url = "https://files.pythonhosted.org/packages/ad/90/2660332eeb31303c13b653ea566a9918484b6e4d6b9d2d46879a33ab0622/pyarrow-21.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b7ae0bbdc8c6674259b25bef5d2a1d6af5d39d7200c819cf99e07f7dfef1c51e", size = 42829529, upload-time = "2025-07-18T00:55:47.069Z" }, - { url = "https://files.pythonhosted.org/packages/33/27/1a93a25c92717f6aa0fca06eb4700860577d016cd3ae51aad0e0488ac899/pyarrow-21.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:58c30a1729f82d201627c173d91bd431db88ea74dcaa3885855bc6203e433b82", size = 43367883, upload-time = "2025-07-18T00:55:53.069Z" }, - { url = "https://files.pythonhosted.org/packages/05/d9/4d09d919f35d599bc05c6950095e358c3e15148ead26292dfca1fb659b0c/pyarrow-21.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:072116f65604b822a7f22945a7a6e581cfa28e3454fdcc6939d4ff6090126623", size = 45133802, upload-time = "2025-07-18T00:55:57.714Z" }, - { url = "https://files.pythonhosted.org/packages/71/30/f3795b6e192c3ab881325ffe172e526499eb3780e306a15103a2764916a2/pyarrow-21.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf56ec8b0a5c8c9d7021d6fd754e688104f9ebebf1bf4449613c9531f5346a18", size = 26203175, upload-time = "2025-07-18T00:56:01.364Z" }, + { url = "https://files.pythonhosted.org/packages/5c/a4/fbbbff9b5227debd24266e71c2dc570385b2a96169b93ee6333edd792db3/pulumi_aws-7.11.1-py3-none-any.whl", hash = "sha256:c8463ed7b5a0584285b86ad7dff7a48b36fe0aa0c37e3c9f3f30380cf6820ee9", size = 11317237, upload-time = "2025-11-11T13:01:11.784Z" }, ] [[package]] -name = "pyasn1" -version = "0.6.1" +name = "pulumi-command" +version = "1.1.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } +dependencies = [ + { name = "parver" }, + { name = "pulumi" }, + { name = "semver" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/b3/195cac7358abfe93d56f3e2a8d35a73747fc3d66fdfa1193a564fd700603/pulumi_command-1.1.3.tar.gz", hash = "sha256:6cd18d0270cdcb9fd4db66fca9403c3d2855483959730332dd15f97bc088670f", size = 33054, upload-time = "2025-10-01T17:17:43.044Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, + { url = "https://files.pythonhosted.org/packages/18/5c/fad8af4c8355c8893ca075c94c99a4119d201737e63491d1a7553d55054a/pulumi_command-1.1.3-py3-none-any.whl", hash = "sha256:0708a009079470dfe76fed401ba00bc3c8bfa355ebad0e1a3a70c0ccce20e209", size = 36880, upload-time = "2025-10-01T17:17:40.69Z" }, ] [[package]] -name = "pyasn1-modules" -version = "0.4.2" +name = "pulumi-docker" +version = "4.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyasn1" }, + { name = "parver" }, + { name = "pulumi" }, + { name = "semver" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/bd/79e56ec5ab69cb2d3d03718c54e2b71adc384c3aa0cc6c09cc7e6e3f9bdd/pulumi_docker-4.10.0.tar.gz", hash = "sha256:2f1e97842189e7e26dfc7eff0bd22e86690c57a67c1635afae9feaee56072538", size = 115579, upload-time = "2025-11-13T20:40:37.279Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, + { url = "https://files.pythonhosted.org/packages/fc/09/09f511246822d27440e5fd2e146a8fba9089c536936d9230becdf11f3968/pulumi_docker-4.10.0-py3-none-any.whl", hash = "sha256:6c9ebde223aa1b49a8c4447c742bc7e7f0abafeadc9e9f80b4f461a57c5e2b17", size = 137182, upload-time = "2025-11-13T20:40:35.436Z" }, ] [[package]] -name = "pycparser" -version = "2.22" +name = "pulumi-tls" +version = "5.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } +dependencies = [ + { name = "parver" }, + { name = "pulumi" }, + { name = "semver" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/4a/eda9909797bb898fbe97101ed1daeed31629f53bce24cf956e609ff55c9a/pulumi_tls-5.2.3.tar.gz", hash = "sha256:0a8c398d4daac34477d21d42f97a98c816f2d187775d0541b8b718464d9821cd", size = 26523, upload-time = "2025-11-13T22:46:09.338Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, + { url = "https://files.pythonhosted.org/packages/8b/10/1a492d796ebec9182a3f8b8ec684f4eb53e663cca6e08eab7c97f7804968/pulumi_tls-5.2.3-py3-none-any.whl", hash = "sha256:74602f072312081966b92f51cce35f2b725f0fcd536e27382ea54b96406c47f5", size = 34983, upload-time = "2025-11-13T22:46:07.764Z" }, ] [[package]] name = "pydantic" -version = "2.11.7" +version = "2.12.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, @@ -1573,34 +958,38 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/ad/a17bc283d7d81837c061c49e3eaa27a45991759a1b7eae1031921c6bd924/pydantic-2.12.4.tar.gz", hash = "sha256:0f8cb9555000a4b5b617f66bfd2566264c4984b27589d3b845685983e8ea85ac", size = 821038, upload-time = "2025-11-05T10:50:08.59Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, + { url = "https://files.pythonhosted.org/packages/82/2f/e68750da9b04856e2a7ec56fc6f034a5a79775e9b9a81882252789873798/pydantic-2.12.4-py3-none-any.whl", hash = "sha256:92d3d202a745d46f9be6df459ac5a064fdaa3c1c4cd8adcfa332ccf3c05f871e", size = 463400, upload-time = "2025-11-05T10:50:06.732Z" }, ] [[package]] name = "pydantic-core" -version = "2.33.2" +version = "2.41.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, - { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, - { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, - { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, - { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, - { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, - { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, - { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, - { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, - { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, - { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/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]] @@ -1612,43 +1001,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] -[[package]] -name = "pyjwt" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, -] - -[package.optional-dependencies] -crypto = [ - { name = "cryptography" }, -] - -[[package]] -name = "pyproject-fmt" -version = "2.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "toml-fmt-common" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/01/d6/f3f39f474bf50d3add1210549ecc193480c7f5a48031cfa2ae9036849c53/pyproject_fmt-2.6.0.tar.gz", hash = "sha256:6640830f59f65d26aa953f5ce887d23b9359856a5d0e10d33c756b9676b229df", size = 43484, upload-time = "2025-05-19T22:07:55.444Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/c2/2e32756ecbeffa47ce302c3ac76920111e6cee7290cdf4754c00ab139c4f/pyproject_fmt-2.6.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:27bd6d64a983309a1f70a166daf6936b549aea4212837f9e25e4b708532dd2eb", size = 1407476, upload-time = "2025-05-19T22:07:28.163Z" }, - { url = "https://files.pythonhosted.org/packages/58/4e/8cd51c8fc3b80bb01a4ef2e15cec0750c1799a96efca1ae1555754831a21/pyproject_fmt-2.6.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ab34015c68dcca4d4ca8f309fe7b5fef548344d07f3231fa3dcae706e6a021d4", size = 1323184, upload-time = "2025-05-19T22:07:30.095Z" }, - { url = "https://files.pythonhosted.org/packages/42/93/29292c95f30d69ee3b91bfdfc93bf95756219ac66f1c35e01d963f73f02d/pyproject_fmt-2.6.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa0767d1a3b9c8b7f1aa024219b557e243f9d0bf24c5aa5276892a306882f364", size = 1393126, upload-time = "2025-05-19T22:07:31.694Z" }, - { url = "https://files.pythonhosted.org/packages/32/5d/a9b6dededb12d0f6987ca239fcb1489d8f58fc8a95377a5cbcb5094f0fbc/pyproject_fmt-2.6.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37a25b891dc2028b879899dde537c208c571251e7b69842fc2023becde0bc198", size = 1351902, upload-time = "2025-05-19T22:07:33.323Z" }, - { url = "https://files.pythonhosted.org/packages/b2/8d/104f7da273d619759227b2cfe88f65c5ed4d82d440a328068be1298115ce/pyproject_fmt-2.6.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae21ae42bf364542a2d2c3b7aa278fe74fefb7f16a25de198a4d11274fe6113d", size = 1676973, upload-time = "2025-05-19T22:07:34.939Z" }, - { url = "https://files.pythonhosted.org/packages/cf/df/08f19eb3c617ac63335b56a2ba415145092bd8dff649bf38181e64698835/pyproject_fmt-2.6.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43917582b5c43ef99866731d9adfa412cd19a5a0ef0ce318619f824dfabb1eae", size = 1553054, upload-time = "2025-05-19T22:07:36.121Z" }, - { url = "https://files.pythonhosted.org/packages/b6/d1/1ce362f0b8a5730f0c611db67ecd475b0d742a85e7c1d8937597987b6b0c/pyproject_fmt-2.6.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8919e055255297971c12cf02bce7d12b95fd02151901054df524b2e80bad4948", size = 1501535, upload-time = "2025-05-19T22:07:37.756Z" }, - { url = "https://files.pythonhosted.org/packages/c1/cc/b4f38f5539c7f868a53acbcd67136f3e8fa1841a3a5254a01dbfb5485276/pyproject_fmt-2.6.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e5c363fd47eedd1796c044e95e7354c2e77448424031b4816e0b500cbf05cc", size = 1508770, upload-time = "2025-05-19T22:07:38.964Z" }, - { url = "https://files.pythonhosted.org/packages/44/22/d5ab722135215f3fa09494aa21fb0c47fefc083c3c525d65292d585ee22b/pyproject_fmt-2.6.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:ec8abed5f0aec8d72c8341242c4c898b4baf3005d42aa0542433e27c81582d65", size = 1630762, upload-time = "2025-05-19T22:07:40.322Z" }, - { url = "https://files.pythonhosted.org/packages/a4/9a/5c0fe5390e82458c784aad8b70462c4f5a66faa54c56ce9899db5b0df536/pyproject_fmt-2.6.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9989ea221f760043224152ac32cfccf2a30712d18b5bdb189db0c8cee0fbf5ce", size = 1673003, upload-time = "2025-05-19T22:07:41.871Z" }, - { url = "https://files.pythonhosted.org/packages/12/8c/651067e3f62b41280ef84e3968960f2a2c7bfb89a2969840766341cabeeb/pyproject_fmt-2.6.0-cp39-abi3-win32.whl", hash = "sha256:0639fed0b4fe849f01949f2c7baf5e377d10b6374cff8da7c6da83ac207986e1", size = 1248635, upload-time = "2025-05-19T22:07:43.483Z" }, - { url = "https://files.pythonhosted.org/packages/07/9c/186f03ebe8efc6dfe4c886c2d5e369234bc301076b79aa66f2b3bebf61f0/pyproject_fmt-2.6.0-cp39-abi3-win_amd64.whl", hash = "sha256:3402dd5982d09a9baee7243cef8b2b5154f14b683bc23e207bf75599101526fa", size = 1366895, upload-time = "2025-05-19T22:07:44.808Z" }, -] - [[package]] name = "pytest" version = "8.4.1" @@ -1678,21 +1030,12 @@ wheels = [ ] [[package]] -name = "python-json-logger" -version = "3.3.0" +name = "python-dotenv" +version = "1.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/de/d3144a0bceede957f961e975f3752760fbe390d57fbe194baf709d8f1f7b/python_json_logger-3.3.0.tar.gz", hash = "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84", size = 16642, upload-time = "2025-03-07T07:08:27.301Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7", size = 15163, upload-time = "2025-03-07T07:08:25.627Z" }, -] - -[[package]] -name = "pytimeparse" -version = "1.1.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/5d/231f5f33c81e09682708fb323f9e4041408d8223e2f0fb9742843328778f/pytimeparse-1.1.8.tar.gz", hash = "sha256:e86136477be924d7e670646a98561957e8ca7308d44841e21f5ddea757556a0a", size = 9403, upload-time = "2018-05-18T17:40:42.76Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/b4/afd75551a3b910abd1d922dbd45e49e5deeb4d47dc50209ce489ba9844dd/pytimeparse-1.1.8-py2.py3-none-any.whl", hash = "sha256:04b7be6cc8bd9f5647a6325444926c3ac34ee6bc7e69da4367ba282f076036bd", size = 9969, upload-time = "2018-05-18T17:40:41.28Z" }, + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, ] [[package]] @@ -1714,15 +1057,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, ] -[[package]] -name = "pywin32-ctypes" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" }, -] - [[package]] name = "pyyaml" version = "6.0.2" @@ -1740,6 +1074,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, ] +[[package]] +name = "referencing" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, +] + [[package]] name = "requests" version = "2.32.5" @@ -1755,19 +1103,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] -[[package]] -name = "requests-oauthlib" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "oauthlib" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650, upload-time = "2024-03-22T20:32:29.939Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" }, -] - [[package]] name = "rich" version = "14.1.0" @@ -1782,81 +1117,112 @@ wheels = [ ] [[package]] -name = "rich-click" -version = "1.8.9" +name = "rpds-py" +version = "0.27.1" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b7/a8/dcc0a8ec9e91d76ecad9413a84b6d3a3310c6111cfe012d75ed385c78d96/rich_click-1.8.9.tar.gz", hash = "sha256:fd98c0ab9ddc1cf9c0b7463f68daf28b4d0033a74214ceb02f761b3ff2af3136", size = 39378, upload-time = "2025-05-19T21:33:05.569Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/dd/2c0cbe774744272b0ae725f44032c77bdcab6e8bcf544bffa3b6e70c8dba/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8", size = 27479, upload-time = "2025-08-27T12:16:36.024Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/c2/9fce4c8a9587c4e90500114d742fe8ef0fd92d7bad29d136bb9941add271/rich_click-1.8.9-py3-none-any.whl", hash = "sha256:c3fa81ed8a671a10de65a9e20abf642cfdac6fdb882db1ef465ee33919fbcfe2", size = 36082, upload-time = "2025-05-19T21:33:04.195Z" }, + { url = "https://files.pythonhosted.org/packages/bd/fe/38de28dee5df58b8198c743fe2bea0c785c6d40941b9950bac4cdb71a014/rpds_py-0.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ae2775c1973e3c30316892737b91f9283f9908e3cc7625b9331271eaaed7dc90", size = 361887, upload-time = "2025-08-27T12:13:10.233Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/4b6c7eedc7dd90986bf0fab6ea2a091ec11c01b15f8ba0a14d3f80450468/rpds_py-0.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2643400120f55c8a96f7c9d858f7be0c88d383cd4653ae2cf0d0c88f668073e5", size = 345795, upload-time = "2025-08-27T12:13:11.65Z" }, + { url = "https://files.pythonhosted.org/packages/6f/0e/e650e1b81922847a09cca820237b0edee69416a01268b7754d506ade11ad/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16323f674c089b0360674a4abd28d5042947d54ba620f72514d69be4ff64845e", size = 385121, upload-time = "2025-08-27T12:13:13.008Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ea/b306067a712988e2bff00dcc7c8f31d26c29b6d5931b461aa4b60a013e33/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a1f4814b65eacac94a00fc9a526e3fdafd78e439469644032032d0d63de4881", size = 398976, upload-time = "2025-08-27T12:13:14.368Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0a/26dc43c8840cb8fe239fe12dbc8d8de40f2365e838f3d395835dde72f0e5/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba32c16b064267b22f1850a34051121d423b6f7338a12b9459550eb2096e7ec", size = 525953, upload-time = "2025-08-27T12:13:15.774Z" }, + { url = "https://files.pythonhosted.org/packages/22/14/c85e8127b573aaf3a0cbd7fbb8c9c99e735a4a02180c84da2a463b766e9e/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5c20f33fd10485b80f65e800bbe5f6785af510b9f4056c5a3c612ebc83ba6cb", size = 407915, upload-time = "2025-08-27T12:13:17.379Z" }, + { url = "https://files.pythonhosted.org/packages/ed/7b/8f4fee9ba1fb5ec856eb22d725a4efa3deb47f769597c809e03578b0f9d9/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:466bfe65bd932da36ff279ddd92de56b042f2266d752719beb97b08526268ec5", size = 386883, upload-time = "2025-08-27T12:13:18.704Z" }, + { url = "https://files.pythonhosted.org/packages/86/47/28fa6d60f8b74fcdceba81b272f8d9836ac0340570f68f5df6b41838547b/rpds_py-0.27.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:41e532bbdcb57c92ba3be62c42e9f096431b4cf478da9bc3bc6ce5c38ab7ba7a", size = 405699, upload-time = "2025-08-27T12:13:20.089Z" }, + { url = "https://files.pythonhosted.org/packages/d0/fd/c5987b5e054548df56953a21fe2ebed51fc1ec7c8f24fd41c067b68c4a0a/rpds_py-0.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f149826d742b406579466283769a8ea448eed82a789af0ed17b0cd5770433444", size = 423713, upload-time = "2025-08-27T12:13:21.436Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ba/3c4978b54a73ed19a7d74531be37a8bcc542d917c770e14d372b8daea186/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80c60cfb5310677bd67cb1e85a1e8eb52e12529545441b43e6f14d90b878775a", size = 562324, upload-time = "2025-08-27T12:13:22.789Z" }, + { url = "https://files.pythonhosted.org/packages/b5/6c/6943a91768fec16db09a42b08644b960cff540c66aab89b74be6d4a144ba/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7ee6521b9baf06085f62ba9c7a3e5becffbc32480d2f1b351559c001c38ce4c1", size = 593646, upload-time = "2025-08-27T12:13:24.122Z" }, + { url = "https://files.pythonhosted.org/packages/11/73/9d7a8f4be5f4396f011a6bb7a19fe26303a0dac9064462f5651ced2f572f/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a512c8263249a9d68cac08b05dd59d2b3f2061d99b322813cbcc14c3c7421998", size = 558137, upload-time = "2025-08-27T12:13:25.557Z" }, + { url = "https://files.pythonhosted.org/packages/6e/96/6772cbfa0e2485bcceef8071de7821f81aeac8bb45fbfd5542a3e8108165/rpds_py-0.27.1-cp312-cp312-win32.whl", hash = "sha256:819064fa048ba01b6dadc5116f3ac48610435ac9a0058bbde98e569f9e785c39", size = 221343, upload-time = "2025-08-27T12:13:26.967Z" }, + { url = "https://files.pythonhosted.org/packages/67/b6/c82f0faa9af1c6a64669f73a17ee0eeef25aff30bb9a1c318509efe45d84/rpds_py-0.27.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9199717881f13c32c4046a15f024971a3b78ad4ea029e8da6b86e5aa9cf4594", size = 232497, upload-time = "2025-08-27T12:13:28.326Z" }, + { url = "https://files.pythonhosted.org/packages/e1/96/2817b44bd2ed11aebacc9251da03689d56109b9aba5e311297b6902136e2/rpds_py-0.27.1-cp312-cp312-win_arm64.whl", hash = "sha256:33aa65b97826a0e885ef6e278fbd934e98cdcfed80b63946025f01e2f5b29502", size = 222790, upload-time = "2025-08-27T12:13:29.71Z" }, ] [[package]] -name = "rsa" -version = "4.9.1" +name = "s3transfer" +version = "0.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyasn1" }, + { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +sdist = { url = "https://files.pythonhosted.org/packages/62/74/8d69dcb7a9efe8baa2046891735e5dfe433ad558ae23d9e3c14c633d1d58/s3transfer-0.14.0.tar.gz", hash = "sha256:eff12264e7c8b4985074ccce27a3b38a485bb7f7422cc8046fee9be4983e4125", size = 151547, upload-time = "2025-09-09T19:23:31.089Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, + { url = "https://files.pythonhosted.org/packages/48/f0/ae7ca09223a81a1d890b2557186ea015f6e0502e9b8cb8e1813f1d8cfa4e/s3transfer-0.14.0-py3-none-any.whl", hash = "sha256:ea3b790c7077558ed1f02a3072fb3cb992bbbd253392f4b6e9e8976941c7d456", size = 85712, upload-time = "2025-09-09T19:23:30.041Z" }, ] [[package]] -name = "s3fs" -version = "2025.7.0" +name = "sagemaker" +version = "2.252.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aiobotocore" }, - { name = "aiohttp" }, - { name = "fsspec" }, + { name = "attrs" }, + { name = "boto3" }, + { name = "cloudpickle" }, + { name = "docker" }, + { name = "fastapi" }, + { name = "google-pasta" }, + { name = "graphene" }, + { name = "importlib-metadata" }, + { name = "jsonschema" }, + { name = "numpy" }, + { name = "omegaconf" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "pathos" }, + { name = "platformdirs" }, + { name = "protobuf" }, + { name = "psutil" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "sagemaker-core" }, + { name = "schema" }, + { name = "smdebug-rulesconfig" }, + { name = "tblib" }, + { name = "tqdm" }, + { name = "urllib3" }, + { name = "uvicorn" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bf/13/37438c4672ba1d23ec46df0e4b57e98469e5c5f4f98313cf6842b631652b/s3fs-2025.7.0.tar.gz", hash = "sha256:5e7f9ec0cad7745155e3eb86fae15b1481fa29946bf5b3a4ce3a60701ce6022d", size = 77795, upload-time = "2025-07-15T16:35:22.177Z" } +sdist = { url = "https://files.pythonhosted.org/packages/de/b4/9a507d3d5bfe684cabd9c34d099f8b600d890cb0ae9b5356f9a62a3625f6/sagemaker-2.252.0.tar.gz", hash = "sha256:bb0d2ee2541f02c6771d9bf47bd3a58a4b28872f1f1df672ce584271290ef10f", size = 1229142, upload-time = "2025-09-29T18:40:00.381Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/c7/30d13b7fd4f866ca3f30e9a6e7ae038f0c45226f6e26b3cc98d6d197f93b/s3fs-2025.7.0-py3-none-any.whl", hash = "sha256:b6b2d3f84b6aa1c2ba5e62e39dd9410cf54f10a2cce1ea6db1ba0d1a6bcce685", size = 30315, upload-time = "2025-07-15T16:35:20.734Z" }, + { url = "https://files.pythonhosted.org/packages/31/a6/3617655deeeab9cacdcd3c5a87caa47f70bff26d0cf9fef970af8f77be80/sagemaker-2.252.0-py3-none-any.whl", hash = "sha256:097653ea870c77376e4a6607d05fbe8732cdbbc320eadba5208f5a0604bc58bb", size = 1690676, upload-time = "2025-09-29T18:39:58.048Z" }, ] [[package]] -name = "s3transfer" -version = "0.13.1" +name = "sagemaker-core" +version = "1.0.59" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "botocore" }, + { name = "boto3" }, + { name = "importlib-metadata" }, + { name = "jsonschema" }, + { name = "mock" }, + { name = "platformdirs" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "rich" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6d/05/d52bf1e65044b4e5e27d4e63e8d1579dbdec54fce685908ae09bc3720030/s3transfer-0.13.1.tar.gz", hash = "sha256:c3fdba22ba1bd367922f27ec8032d6a1cf5f10c934fb5d68cf60fd5a23d936cf", size = 150589, upload-time = "2025-07-18T19:22:42.31Z" } +sdist = { url = "https://files.pythonhosted.org/packages/53/76/4db845f8b9e363107873099ff35b182acad7982c3e62deb9ab0f081ed114/sagemaker_core-1.0.59.tar.gz", hash = "sha256:6b363b0a107fea53cb9ac3d917644069b158b7b08d824ebe539f3a8e26d79995", size = 413156, upload-time = "2025-09-10T10:24:36.935Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/4f/d073e09df851cfa251ef7840007d04db3293a0482ce607d2b993926089be/s3transfer-0.13.1-py3-none-any.whl", hash = "sha256:a981aa7429be23fe6dfc13e80e4020057cbab622b08c0315288758d67cabc724", size = 85308, upload-time = "2025-07-18T19:22:40.947Z" }, + { url = "https://files.pythonhosted.org/packages/b6/a7/d9fe23faa34cc8cf2eaf93692a2b349142b490822982a5275784470ecbb8/sagemaker_core-1.0.59-py3-none-any.whl", hash = "sha256:d524daada4a5911c4e0ac84c8f6ac9e4de0abdf5a13dd6f4faa511b9f12e452f", size = 427887, upload-time = "2025-09-10T10:24:35.175Z" }, ] [[package]] -name = "secretstorage" -version = "3.3.3" +name = "schema" +version = "0.7.7" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cryptography", marker = "sys_platform == 'linux'" }, - { name = "jeepney", marker = "sys_platform == 'linux'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", size = 19739, upload-time = "2022-08-13T16:22:46.976Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/01/0ea2e66bad2f13271e93b729c653747614784d3ebde219679e41ccdceecd/schema-0.7.7.tar.gz", hash = "sha256:7da553abd2958a19dc2547c388cde53398b39196175a9be59ea1caf5ab0a1807", size = 44245, upload-time = "2024-05-04T10:56:17.318Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99", size = 15221, upload-time = "2022-08-13T16:22:44.457Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1b/81855a88c6db2b114d5b2e9f96339190d5ee4d1b981d217fa32127bb00e0/schema-0.7.7-py2.py3-none-any.whl", hash = "sha256:5d976a5b50f36e74e2157b47097b60002bd4d42e65425fcc9c9befadb4255dde", size = 18632, upload-time = "2024-05-04T10:56:13.86Z" }, ] [[package]] -name = "sentry-sdk" -version = "2.35.0" +name = "semver" +version = "3.0.4" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/31/83/055dc157b719651ef13db569bb8cf2103df11174478649735c1b2bf3f6bc/sentry_sdk-2.35.0.tar.gz", hash = "sha256:5ea58d352779ce45d17bc2fa71ec7185205295b83a9dbb5707273deb64720092", size = 343014, upload-time = "2025-08-14T17:11:20.223Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/d1/d3159231aec234a59dd7d601e9dd9fe96f3afff15efd33c1070019b26132/semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602", size = 269730, upload-time = "2025-01-24T13:19:27.617Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/3d/742617a7c644deb0c1628dcf6bb2d2165ab7c6aab56fe5222758994007f8/sentry_sdk-2.35.0-py2.py3-none-any.whl", hash = "sha256:6e0c29b9a5d34de8575ffb04d289a987ff3053cf2c98ede445bea995e3830263", size = 363806, upload-time = "2025-08-14T17:11:18.29Z" }, + { url = "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746", size = 17912, upload-time = "2025-01-24T13:19:24.949Z" }, ] [[package]] @@ -1869,12 +1235,12 @@ wheels = [ ] [[package]] -name = "smmap" -version = "5.0.2" +name = "smdebug-rulesconfig" +version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/7d/8ad6a2098e03c1f811d1277a2cedb81265828f144f6d323b83a2392e8bb9/smdebug_rulesconfig-1.0.1.tar.gz", hash = "sha256:7a19e6eb2e6bcfefbc07e4a86ef7a88f32495001a038bf28c7d8e77ab793fcd6", size = 12060, upload-time = "2020-12-18T23:54:52.357Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, + { url = "https://files.pythonhosted.org/packages/26/a1/45a13a05198bbe9527bab2c5e5daa8bd02678aa825eec14783e767bfa7d1/smdebug_rulesconfig-1.0.1-py2.py3-none-any.whl", hash = "sha256:104da3e6931ecf879dfc687ca4bbb3bee5ea2bc27f4478e9dbb3ee3655f1ae61", size = 20282, upload-time = "2020-12-18T23:54:51.267Z" }, ] [[package]] @@ -1909,21 +1275,21 @@ wheels = [ ] [[package]] -name = "statsd" -version = "4.0.1" +name = "structlog" +version = "25.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/27/29/05e9f50946f4cf2ed182726c60d9c0ae523bb3f180588c574dd9746de557/statsd-4.0.1.tar.gz", hash = "sha256:99763da81bfea8daf6b3d22d11aaccb01a8d0f52ea521daab37e758a4ca7d128", size = 27814, upload-time = "2022-11-06T14:17:36.194Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/52/9ba0f43b686e7f3ddfeaa78ac3af750292662284b3661e91ad5494f21dbc/structlog-25.5.0.tar.gz", hash = "sha256:098522a3bebed9153d4570c6d0288abf80a031dfdb2048d59a49e9dc2190fc98", size = 1460830, upload-time = "2025-10-27T08:28:23.028Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/d0/c9543b52c067a390ae6ae632d7fd1b97a35cdc8d69d40c0b7d334b326410/statsd-4.0.1-py2.py3-none-any.whl", hash = "sha256:c2676519927f7afade3723aca9ca8ea986ef5b059556a980a867721ca69df093", size = 13118, upload-time = "2022-11-06T14:17:34.258Z" }, + { url = "https://files.pythonhosted.org/packages/a8/45/a132b9074aa18e799b891b91ad72133c98d8042c70f6240e4c5f9dabee2f/structlog-25.5.0-py3-none-any.whl", hash = "sha256:a8453e9b9e636ec59bd9e79bbd4a72f025981b3ba0f5837aebf48f02f37a7f9f", size = 72510, upload-time = "2025-10-27T08:28:21.535Z" }, ] [[package]] -name = "structlog" -version = "25.4.0" +name = "tblib" +version = "3.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/b9/6e672db4fec07349e7a8a8172c1a6ae235c58679ca29c3f86a61b5e59ff3/structlog-25.4.0.tar.gz", hash = "sha256:186cd1b0a8ae762e29417095664adf1d6a31702160a46dacb7796ea82f7409e4", size = 1369138, upload-time = "2025-06-02T08:21:12.971Z" } +sdist = { url = "https://files.pythonhosted.org/packages/54/95/4b3044ec4bf248186769629bbfb495a458deb6e4c1f9eff7f298ae1e336e/tblib-3.1.0.tar.gz", hash = "sha256:06404c2c9f07f66fee2d7d6ad43accc46f9c3361714d9b8426e7f47e595cd652", size = 30766, upload-time = "2025-03-31T12:58:27.473Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/4a/97ee6973e3a73c74c8120d59829c3861ea52210667ec3e7a16045c62b64d/structlog-25.4.0-py3-none-any.whl", hash = "sha256:fe809ff5c27e557d14e613f45ca441aabda051d119ee5a0102aaba6ce40eed2c", size = 68720, upload-time = "2025-06-02T08:21:11.43Z" }, + { url = "https://files.pythonhosted.org/packages/27/44/aa5c8b10b2cce7a053018e0d132bd58e27527a0243c4985383d5b6fd93e9/tblib-3.1.0-py3-none-any.whl", hash = "sha256:670bb4582578134b3d81a84afa1b016128b429f3d48e6cbbaecc9d15675e984e", size = 12552, upload-time = "2025-03-31T12:58:26.142Z" }, ] [[package]] @@ -1936,12 +1302,30 @@ wheels = [ ] [[package]] -name = "toml-fmt-common" -version = "1.0.1" +name = "tools" +version = "0.1.0" +source = { virtual = "tools" } +dependencies = [ + { name = "boto3" }, + { name = "massive" }, +] + +[package.metadata] +requires-dist = [ + { name = "boto3", specifier = ">=1.40.74" }, + { name = "massive", specifier = ">=2.0.2" }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3a/7a/fca432020e0b2134f7bb8fa4bf4714f6f0d1c72a08100c96b582c22098bc/toml_fmt_common-1.0.1.tar.gz", hash = "sha256:7a29e99e527ffac456043296a0f1d8c03aaa1b06167bd39ad5e3cc5041f31c17", size = 9626, upload-time = "2024-10-20T05:01:31.278Z" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/7f/094a5d096adaf2a51de24c8650530625a262bef0c654fc981165ad45821f/toml_fmt_common-1.0.1-py3-none-any.whl", hash = "sha256:7a6542e36a7167fa94b8b997d3f8debadbb4ab757c7d78a77304579bd7a0cc7d", size = 5666, upload-time = "2024-10-20T05:01:29.468Z" }, + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, ] [[package]] @@ -1980,14 +1364,14 @@ wheels = [ [[package]] name = "typing-inspection" -version = "0.4.1" +version = "0.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, ] [[package]] @@ -2021,35 +1405,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/e2/dc81b1bd1dcfe91735810265e9d26bc8ec5da45b4c0f6237e286819194c3/uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a", size = 66406, upload-time = "2025-06-28T16:15:44.816Z" }, ] -[[package]] -name = "wandb" -version = "0.21.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "gitpython" }, - { name = "packaging" }, - { name = "platformdirs" }, - { name = "protobuf" }, - { name = "pydantic" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "sentry-sdk" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/26/69/217598886af89350e36bc05c092a67c9c469cff1fd6446edd4c879027e36/wandb-0.21.1.tar.gz", hash = "sha256:753bbdaa3a7703344056e019425b39c17a3d31d8ca0c4d13c4efc046935b08b9", size = 40131395, upload-time = "2025-08-07T18:52:48.85Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/d0/589f970741f3ead9ad28d4cbb668d1e6a39848df767f004ac9c7bed8f4b5/wandb-0.21.1-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:96f9eedeae428de0d88f9751fb81f1b730ae7902f35c2f5a7a904d7733f124f3", size = 21701698, upload-time = "2025-08-07T18:52:22.399Z" }, - { url = "https://files.pythonhosted.org/packages/41/6c/a6140a0f395a99902aafdfe63088b7aff509e4f14cd7dd084d47eab36f27/wandb-0.21.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:41a1ec1b98d9d7e1bcafc483bce82e184b6cbae7531328a0fe8dd0f56d96a92e", size = 21221046, upload-time = "2025-08-07T18:52:26.134Z" }, - { url = "https://files.pythonhosted.org/packages/e9/d8/dacbb30ed35141d48a387d84f2e792d4b61b5bcdbf5ffdbd3f0b57beb346/wandb-0.21.1-py3-none-macosx_11_0_x86_64.whl", hash = "sha256:f74d4691c38318ed8611e00ca3246b4152a03ff390fdce41816bea5705452a73", size = 21885803, upload-time = "2025-08-07T18:52:28.489Z" }, - { url = "https://files.pythonhosted.org/packages/b0/48/3a7290a33b1f64e29ac8779dab4d4cdef31a9ed3c3d9ea656a4507d64332/wandb-0.21.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c8fbd60b9abf4b9bec201f311602f61394d41a3503c801750b03975a5e36d1b", size = 20825318, upload-time = "2025-08-07T18:52:31.282Z" }, - { url = "https://files.pythonhosted.org/packages/a9/54/c0a087114ff1bb6c32e64aaa58aea4342cebc0ad58b1378c0a5a831d2508/wandb-0.21.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ded9313672630c0630f5b13c598ce9aa0e932e811ebc18823fcc4d73acfb6bb", size = 22362500, upload-time = "2025-08-07T18:52:33.889Z" }, - { url = "https://files.pythonhosted.org/packages/65/68/3aae277ea9fb5d91eec066cf256755bed3a740d92b539888a7ce36cf3f6c/wandb-0.21.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:44f3194d697b409f91708c50c5f9d56e282434a0d60ac380b64f0fb6991cd630", size = 20830372, upload-time = "2025-08-07T18:52:36.76Z" }, - { url = "https://files.pythonhosted.org/packages/d2/bb/58d206e79be1f279ef06cb934ae1e208bcacd2cd73b7a7652236575010d6/wandb-0.21.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e0b68bb6dbe94f1910c665c755f438292df40c272feb1a8b42208c1df52cce26", size = 22438521, upload-time = "2025-08-07T18:52:39.672Z" }, - { url = "https://files.pythonhosted.org/packages/e7/b8/dfe01f8e4c40d5dda820fd839c39431608a3453670f79404fa28915972d2/wandb-0.21.1-py3-none-win32.whl", hash = "sha256:98306c3fb369dfafb7194270b938b000ea2bb08dbddff10c19b5a805fd5cab80", size = 21569814, upload-time = "2025-08-07T18:52:42.58Z" }, - { url = "https://files.pythonhosted.org/packages/51/ba/81c77d5d831fcddb89661c85175fcbb91d2ffecf6b0591972829da3eb42f/wandb-0.21.1-py3-none-win_amd64.whl", hash = "sha256:8be92a7e92b5cb5ce00ec0961f9dbaad7757ffdbc5b5a8f2cc7188e23f653f0a", size = 21569817, upload-time = "2025-08-07T18:52:45.559Z" }, -] - [[package]] name = "websockets" version = "14.2" @@ -2070,65 +1425,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/c8/d529f8a32ce40d98309f4470780631e971a5a842b60aec864833b3615786/websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b", size = 157416, upload-time = "2025-01-19T21:00:54.843Z" }, ] -[[package]] -name = "win32-setctime" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" }, -] - -[[package]] -name = "wrapt" -version = "1.17.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998, upload-time = "2025-08-12T05:51:47.138Z" }, - { url = "https://files.pythonhosted.org/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020, upload-time = "2025-08-12T05:51:35.906Z" }, - { url = "https://files.pythonhosted.org/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098, upload-time = "2025-08-12T05:51:57.474Z" }, - { url = "https://files.pythonhosted.org/packages/9f/81/5d931d78d0eb732b95dc3ddaeeb71c8bb572fb01356e9133916cd729ecdd/wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828", size = 88036, upload-time = "2025-08-12T05:52:34.784Z" }, - { url = "https://files.pythonhosted.org/packages/ca/38/2e1785df03b3d72d34fc6252d91d9d12dc27a5c89caef3335a1bbb8908ca/wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9", size = 88156, upload-time = "2025-08-12T05:52:13.599Z" }, - { url = "https://files.pythonhosted.org/packages/b3/8b/48cdb60fe0603e34e05cffda0b2a4adab81fd43718e11111a4b0100fd7c1/wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396", size = 87102, upload-time = "2025-08-12T05:52:14.56Z" }, - { url = "https://files.pythonhosted.org/packages/3c/51/d81abca783b58f40a154f1b2c56db1d2d9e0d04fa2d4224e357529f57a57/wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc", size = 87732, upload-time = "2025-08-12T05:52:36.165Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" }, - { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" }, - { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, -] - -[[package]] -name = "yarl" -version = "1.20.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, - { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, - { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, - { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, - { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, - { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, - { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, - { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, - { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, - { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, -] - [[package]] name = "zipp" version = "3.23.0"