diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 9928d9f8e..76c4521b6 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -11,7 +11,7 @@ "Bash(rm:*)", "WebFetch(domain:docs.github.com)", "Bash(git add:*)", - "Bash(python -m pytest application/datamanager/tests -v)", + "Bash(python -m pytest:*)", "Bash(uv pip:*)", "Bash(cat:*)", "Bash(mise run:*)", diff --git a/.flox/env/manifest.lock b/.flox/env/manifest.lock index 466a5645f..833f05d04 100644 --- a/.flox/env/manifest.lock +++ b/.flox/env/manifest.lock @@ -173,27 +173,27 @@ { "attr_path": "fselect", "broken": false, - "derivation": "/nix/store/wdm7paaq0jmq205qd3ydxiil2r41l5xf-fselect-0.8.12.drv", + "derivation": "/nix/store/15zp329ir3k3j1isp0r59dy8pcg5w9cg-fselect-0.9.0.drv", "description": "Find files with SQL-like queries", "install_id": "fselect", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "fselect-0.8.12", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "fselect-0.9.0", "pname": "fselect", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:22:55.085824Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T00:26:12.620192Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.8.12", + "version": "0.9.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/xwh5qyb1ly63xj7vq9j0k703vkngdgx7-fselect-0.8.12" + "out": "/nix/store/8ra6ngn7x18niiimxbvam6zhk8ivyarq-fselect-0.9.0" }, "system": "aarch64-darwin", "group": "toplevel", @@ -202,27 +202,27 @@ { "attr_path": "fselect", "broken": false, - "derivation": "/nix/store/06fp8lhy8yl12j0cqz0q3gysk232v329-fselect-0.8.12.drv", + "derivation": "/nix/store/p558m5i7yh38qhikyqkx8g31kxzmbcvr-fselect-0.9.0.drv", "description": "Find files with SQL-like queries", "install_id": "fselect", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "fselect-0.8.12", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "fselect-0.9.0", "pname": "fselect", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:41:02.201870Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T01:59:39.053607Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.8.12", + "version": "0.9.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/wzjd8qhdqvy9i5yqbmnilq34g3qk5lrd-fselect-0.8.12" + "out": "/nix/store/0vcyyybxaw5v089gh62367whlnn980n7-fselect-0.9.0" }, "system": "aarch64-linux", "group": "toplevel", @@ -231,27 +231,27 @@ { "attr_path": "fselect", "broken": false, - "derivation": "/nix/store/cnqjlv8m2kmvb3p20br2j99hq27nlsi5-fselect-0.8.12.drv", + "derivation": "/nix/store/6d3h9hc6zi13b0vyjckkkns0xsyd54vp-fselect-0.9.0.drv", "description": "Find files with SQL-like queries", "install_id": "fselect", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "fselect-0.8.12", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "fselect-0.9.0", "pname": "fselect", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:56:59.481087Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:32:16.673494Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.8.12", + "version": "0.9.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/jhsq1fky0wb43xjkkckdkzdz4wf5ybby-fselect-0.8.12" + "out": "/nix/store/gs5xwmjad2nn51j45afqp8q84ib4nq7x-fselect-0.9.0" }, "system": "x86_64-darwin", "group": "toplevel", @@ -260,27 +260,27 @@ { "attr_path": "fselect", "broken": false, - "derivation": "/nix/store/hp1d6rfahlivn5gp54p42mqwq8mlxrm7-fselect-0.8.12.drv", + "derivation": "/nix/store/znc4cjf72cgdi9zzgrx9c8slplw1clxj-fselect-0.9.0.drv", "description": "Find files with SQL-like queries", "install_id": "fselect", "license": "[ Apache-2.0, MIT ]", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "fselect-0.8.12", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "fselect-0.9.0", "pname": "fselect", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T05:15:56.715716Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T03:13:25.966552Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.8.12", + "version": "0.9.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/0lsljh99jcvxvc3lzfcxmm0ka615hwxg-fselect-0.8.12" + "out": "/nix/store/b6nnfmz69br2fa6879xjhbba5y754870-fselect-0.9.0" }, "system": "x86_64-linux", "group": "toplevel", @@ -289,27 +289,27 @@ { "attr_path": "google-cloud-sdk", "broken": false, - "derivation": "/nix/store/74dn4bx76qm4gdihagvkvb1wi0kdq7w3-google-cloud-sdk-519.0.0.drv", + "derivation": "/nix/store/rrcl7gvilcj449k0fg563jifz4wcmd11-google-cloud-sdk-529.0.0.drv", "description": "Tools for the google cloud platform", "install_id": "google-cloud-sdk", "license": "Unspecified free software license", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "google-cloud-sdk-519.0.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "google-cloud-sdk-529.0.0", "pname": "google-cloud-sdk", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:22:55.314939Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T00:26:12.870512Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "519.0.0", + "version": "529.0.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/4xcvvzj8l7yqyy6y5jqz3b4hjdfkmcdn-google-cloud-sdk-519.0.0" + "out": "/nix/store/9v8y10z0y9lkhjsaf728nhhbc4jbp83q-google-cloud-sdk-529.0.0" }, "system": "aarch64-darwin", "group": "toplevel", @@ -318,27 +318,27 @@ { "attr_path": "google-cloud-sdk", "broken": false, - "derivation": "/nix/store/w9sc3aj2b3bicgz5qi74b4xqilcw7aqf-google-cloud-sdk-519.0.0.drv", + "derivation": "/nix/store/ia40bmxnm5yrahgdzmv29jv7j8858c7l-google-cloud-sdk-529.0.0.drv", "description": "Tools for the google cloud platform", "install_id": "google-cloud-sdk", "license": "Unspecified free software license", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "google-cloud-sdk-519.0.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "google-cloud-sdk-529.0.0", "pname": "google-cloud-sdk", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:41:02.865688Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T01:59:39.864067Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "519.0.0", + "version": "529.0.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/n8sw91d27fn44rpqghclsdkz5hhlnap8-google-cloud-sdk-519.0.0" + "out": "/nix/store/5kz4dghm4lc2rmjy85xz813irlpyglhl-google-cloud-sdk-529.0.0" }, "system": "aarch64-linux", "group": "toplevel", @@ -347,27 +347,27 @@ { "attr_path": "google-cloud-sdk", "broken": false, - "derivation": "/nix/store/j8g5mdx60ccfyhrfa7z06zzgw5vb5hqh-google-cloud-sdk-519.0.0.drv", + "derivation": "/nix/store/6hx4k3dfvj1n7ny5jq7v5abfy9vhvrb7-google-cloud-sdk-529.0.0.drv", "description": "Tools for the google cloud platform", "install_id": "google-cloud-sdk", "license": "Unspecified free software license", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "google-cloud-sdk-519.0.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "google-cloud-sdk-529.0.0", "pname": "google-cloud-sdk", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:56:59.752175Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:32:17.016315Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "519.0.0", + "version": "529.0.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/g0xihzc90kaymzxj07yrwpj05xkq1p4k-google-cloud-sdk-519.0.0" + "out": "/nix/store/arw4kq8hig5v2n3gq3pzw521qb3rc736-google-cloud-sdk-529.0.0" }, "system": "x86_64-darwin", "group": "toplevel", @@ -376,27 +376,27 @@ { "attr_path": "google-cloud-sdk", "broken": false, - "derivation": "/nix/store/6mqpbcy2msiqgfidl4601kjnybn8q2b2-google-cloud-sdk-519.0.0.drv", + "derivation": "/nix/store/3s4zjlxpndjdjx6p16ak137hhp2i1d7q-google-cloud-sdk-529.0.0.drv", "description": "Tools for the google cloud platform", "install_id": "google-cloud-sdk", "license": "Unspecified free software license", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "google-cloud-sdk-519.0.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "google-cloud-sdk-529.0.0", "pname": "google-cloud-sdk", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T05:15:57.436179Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T03:13:26.878159Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "519.0.0", + "version": "529.0.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/kd9329md95zg07y6b5q82lxrbnzlywkn-google-cloud-sdk-519.0.0" + "out": "/nix/store/aw6lxd787x16w8d2ll2afnjjz3kqi0m4-google-cloud-sdk-529.0.0" }, "system": "x86_64-linux", "group": "toplevel", @@ -405,27 +405,27 @@ { "attr_path": "mise", "broken": false, - "derivation": "/nix/store/b4c0kwl8f21cr9p79n06f4kzkgwkmfya-mise-2025.5.10.drv", + "derivation": "/nix/store/wvkjklbcrwqc1zb3z1l99saalqmmrbgx-mise-2025.8.6.drv", "description": "Front-end to your dev env", "install_id": "mise", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "mise-2025.5.10", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "mise-2025.8.6", "pname": "mise", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:22:57.243849Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T00:26:15.081436Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2025.5.10", + "version": "2025.8.6", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/al559nmr0nsmxjdmx9hvhdr3g0gmig8i-mise-2025.5.10" + "out": "/nix/store/nnhr9arv6p3whvdzc7xvkifi9zvkj2d8-mise-2025.8.6" }, "system": "aarch64-darwin", "group": "toplevel", @@ -434,27 +434,27 @@ { "attr_path": "mise", "broken": false, - "derivation": "/nix/store/gwlrsrv4n953w6nyvczcqzn9xd3jdny7-mise-2025.5.10.drv", + "derivation": "/nix/store/dqlas8pkisrd49k59qsa3riz9skq14rj-mise-2025.8.6.drv", "description": "Front-end to your dev env", "install_id": "mise", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "mise-2025.5.10", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "mise-2025.8.6", "pname": "mise", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:41:11.477233Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T01:59:49.801432Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2025.5.10", + "version": "2025.8.6", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/x43wl521m6bcd20qd44qqfdbxj1k4vd8-mise-2025.5.10" + "out": "/nix/store/szp56d7i8360b8r0s64fskb052vkr6wm-mise-2025.8.6" }, "system": "aarch64-linux", "group": "toplevel", @@ -463,27 +463,27 @@ { "attr_path": "mise", "broken": false, - "derivation": "/nix/store/hqd37qsqai4zs4hw5g494lcypp7l8z15-mise-2025.5.10.drv", + "derivation": "/nix/store/q7n6h077wd3xqh8m9ylvz69jr41rcmvy-mise-2025.8.6.drv", "description": "Front-end to your dev env", "install_id": "mise", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "mise-2025.5.10", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "mise-2025.8.6", "pname": "mise", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:57:01.791877Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:32:19.614307Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2025.5.10", + "version": "2025.8.6", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/cq4a3vbpn1b3c50sacxairljmpihwb26-mise-2025.5.10" + "out": "/nix/store/skik69gqc1kadavrd3hkhja8qmwl6n2f-mise-2025.8.6" }, "system": "x86_64-darwin", "group": "toplevel", @@ -492,27 +492,27 @@ { "attr_path": "mise", "broken": false, - "derivation": "/nix/store/57k62gr9r4jjk1lhbhq5wkg4xpscsxh6-mise-2025.5.10.drv", + "derivation": "/nix/store/1cyg8v3wskbkg2xwjgh9dy3c27772qh6-mise-2025.8.6.drv", "description": "Front-end to your dev env", "install_id": "mise", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "mise-2025.5.10", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "mise-2025.8.6", "pname": "mise", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T05:16:07.617332Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T03:13:39.000824Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "2025.5.10", + "version": "2025.8.6", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/mqrw2sbdc3ynw4h3dqi76l6r77zvzwva-mise-2025.5.10" + "out": "/nix/store/7kxwlzg2dn4pa6ngif1hl7lcxsjpvibq-mise-2025.8.6" }, "system": "x86_64-linux", "group": "toplevel", @@ -521,27 +521,27 @@ { "attr_path": "nushell", "broken": false, - "derivation": "/nix/store/zdh83ygmcrmwlh6rz4rnh9y4iswy287m-nushell-0.104.0.drv", + "derivation": "/nix/store/fv47rlnv4ic5spp5bay5g0w78ik43din-nushell-0.106.1.drv", "description": "Modern shell written in Rust", "install_id": "nushell", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "nushell-0.104.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "nushell-0.106.1", "pname": "nushell", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:22:57.823745Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T00:26:15.733915Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.104.0", + "version": "0.106.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/4n5adksh17xrf5p4knpslv9004njzxgh-nushell-0.104.0" + "out": "/nix/store/vs83xcd5w2fp4zbiph6cv2pbdck8q5xr-nushell-0.106.1" }, "system": "aarch64-darwin", "group": "toplevel", @@ -550,27 +550,27 @@ { "attr_path": "nushell", "broken": false, - "derivation": "/nix/store/r0pvy2lgpk3xzszph5z114nrjli0mlx7-nushell-0.104.0.drv", + "derivation": "/nix/store/w1ws1m4kmb83avs264ibhmh6d3pxi1gi-nushell-0.106.1.drv", "description": "Modern shell written in Rust", "install_id": "nushell", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "nushell-0.104.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "nushell-0.106.1", "pname": "nushell", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:41:12.853996Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T01:59:51.473137Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.104.0", + "version": "0.106.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/f1q5bvlgv5si530fpz9mky4sdmmcm9vl-nushell-0.104.0" + "out": "/nix/store/cq6x30n4i319wxzjxa9smz64i8hr6q0w-nushell-0.106.1" }, "system": "aarch64-linux", "group": "toplevel", @@ -579,27 +579,27 @@ { "attr_path": "nushell", "broken": false, - "derivation": "/nix/store/7ixlmy71jdldly382hlb99hrch615gy4-nushell-0.104.0.drv", + "derivation": "/nix/store/lq9hr2jclji1nbpqy8663mvs2z3s3rvg-nushell-0.106.1.drv", "description": "Modern shell written in Rust", "install_id": "nushell", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "nushell-0.104.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "nushell-0.106.1", "pname": "nushell", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:57:02.397353Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:32:20.392232Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.104.0", + "version": "0.106.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/29sngawmfygz9vvgbmrch8kfiip753yx-nushell-0.104.0" + "out": "/nix/store/jqy13fjyrih2x9jfp0hcd2f47c7pfys1-nushell-0.106.1" }, "system": "x86_64-darwin", "group": "toplevel", @@ -608,27 +608,27 @@ { "attr_path": "nushell", "broken": false, - "derivation": "/nix/store/vagdi6gg8hif7cgnq9kfawa54xzvikl0-nushell-0.104.0.drv", + "derivation": "/nix/store/cr3gwnpbgndd62asprqs3gvcq17a6qq2-nushell-0.106.1.drv", "description": "Modern shell written in Rust", "install_id": "nushell", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "nushell-0.104.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "nushell-0.106.1", "pname": "nushell", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T05:16:09.134007Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T03:13:40.953445Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.104.0", + "version": "0.106.1", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/ywp33ksgp2v32g0dwril2ds1rlri1kp8-nushell-0.104.0" + "out": "/nix/store/pikr2lds8w3shnsq0l1f7aamlmvsi0i3-nushell-0.106.1" }, "system": "x86_64-linux", "group": "toplevel", @@ -637,27 +637,27 @@ { "attr_path": "pulumi", "broken": false, - "derivation": "/nix/store/7bsq24dm1v6wb49ydb0k6yn6nmm0pxss-pulumi-3.162.0.drv", - "description": "Pulumi is a cloud development platform that makes creating cloud programs easy and productive", + "derivation": "/nix/store/n2v4csjg0gjc8prng395za379qsxy9fh-pulumi-3.185.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "pulumi-3.162.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "pulumi-3.185.0", "pname": "pulumi", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:23:03.637131Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T00:26:22.054956Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.162.0", + "version": "3.185.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/7c0zvx95gdjw4l7i204dx7p8qy53xl5b-pulumi-3.162.0" + "out": "/nix/store/4bvrwnls681x5yi6z0dk4i6sdci19dmv-pulumi-3.185.0" }, "system": "aarch64-darwin", "group": "toplevel", @@ -666,27 +666,27 @@ { "attr_path": "pulumi", "broken": false, - "derivation": "/nix/store/nvi31ab26wbfdmqgasy0aiw0lwv20kp1-pulumi-3.162.0.drv", - "description": "Pulumi is a cloud development platform that makes creating cloud programs easy and productive", + "derivation": "/nix/store/2hd1cwgm0n44fvbkqkbk24wpmd7kv6d4-pulumi-3.185.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "pulumi-3.162.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "pulumi-3.185.0", "pname": "pulumi", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:41:24.080748Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:00:06.056158Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.162.0", + "version": "3.185.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/7hywb6nj3ncb4vxgajy5rx08585gimnm-pulumi-3.162.0" + "out": "/nix/store/rql14n80fhs6r73qj0qp0hgayr062j7n-pulumi-3.185.0" }, "system": "aarch64-linux", "group": "toplevel", @@ -695,27 +695,27 @@ { "attr_path": "pulumi", "broken": false, - "derivation": "/nix/store/p0gh9rbadhy7yznwgd451kf34kq8vaxc-pulumi-3.162.0.drv", - "description": "Pulumi is a cloud development platform that makes creating cloud programs easy and productive", + "derivation": "/nix/store/c3qaa7c053xnza3p2wl446jqpgz23f7n-pulumi-3.185.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "pulumi-3.162.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "pulumi-3.185.0", "pname": "pulumi", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:57:08.445800Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:32:27.943149Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.162.0", + "version": "3.185.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/mnv181ligy9sa1kcnm2dlwxvvd20b0q2-pulumi-3.162.0" + "out": "/nix/store/arbn3yc7wzirimvcr5qjcbfzdh2j5j45-pulumi-3.185.0" }, "system": "x86_64-darwin", "group": "toplevel", @@ -724,27 +724,27 @@ { "attr_path": "pulumi", "broken": false, - "derivation": "/nix/store/588r6hkkv00sa5fafjss5c177ax06gqf-pulumi-3.162.0.drv", - "description": "Pulumi is a cloud development platform that makes creating cloud programs easy and productive", + "derivation": "/nix/store/j07b2n10mvs5wgcsm94w643rdf149x5v-pulumi-3.185.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "pulumi-3.162.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "pulumi-3.185.0", "pname": "pulumi", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T05:16:21.078364Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T03:13:56.426861Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.162.0", + "version": "3.185.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/vf5wwsm7xf2xwq9763k4xwgr0k8w9j3n-pulumi-3.162.0" + "out": "/nix/store/yapplr29i2zp6gbdc7xwl6ji09qd6vn8-pulumi-3.185.0" }, "system": "x86_64-linux", "group": "toplevel", @@ -753,27 +753,27 @@ { "attr_path": "pulumiPackages.pulumi-python", "broken": false, - "derivation": "/nix/store/x6zr25662d3schi6yyhz4c5q3ssjy367-pulumi-python-3.162.0.drv", + "derivation": "/nix/store/md4dhgi1lwvk2qzhx97drnl72g1k7zv7-pulumi-python-3.185.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "pulumi-python-3.162.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "pulumi-python-3.185.0", "pname": "pulumi-python", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:23:03.646283Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T00:26:22.064739Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.162.0", + "version": "3.185.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/76qjbggbyh89icvc8hsv18fnl3h4s4lp-pulumi-python-3.162.0" + "out": "/nix/store/dqim7ygm70iqskxby9l2sllbvhinr69l-pulumi-python-3.185.0" }, "system": "aarch64-darwin", "group": "toplevel", @@ -782,27 +782,27 @@ { "attr_path": "pulumiPackages.pulumi-python", "broken": false, - "derivation": "/nix/store/cdzifga3f64iy408v801m881k4ckfkxn-pulumi-python-3.162.0.drv", + "derivation": "/nix/store/k021h47dcna0k7laaimrl112i1n120in-pulumi-python-3.185.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "pulumi-python-3.162.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "pulumi-python-3.185.0", "pname": "pulumi-python", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:41:24.095263Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:00:06.075355Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.162.0", + "version": "3.185.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/lyixr9jxs4liaawa4rqi8s07gwmc4xw4-pulumi-python-3.162.0" + "out": "/nix/store/b926n9vq0904paavsy53jfdp38cvj1x4-pulumi-python-3.185.0" }, "system": "aarch64-linux", "group": "toplevel", @@ -811,27 +811,27 @@ { "attr_path": "pulumiPackages.pulumi-python", "broken": false, - "derivation": "/nix/store/cg8v4vwi9h91ih6zk1yhychkvlh6r6x4-pulumi-python-3.162.0.drv", + "derivation": "/nix/store/g39a61xzjnx7gmj2il5aqs7c6h0nv528-pulumi-python-3.185.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "pulumi-python-3.162.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "pulumi-python-3.185.0", "pname": "pulumi-python", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:57:08.455236Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:32:27.954954Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.162.0", + "version": "3.185.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/wn6lhy96v6qn3lwhxnnlrm5sp5h5q716-pulumi-python-3.162.0" + "out": "/nix/store/i3rgdzf7xdii3d86hg4bpsf83dnyd7zq-pulumi-python-3.185.0" }, "system": "x86_64-darwin", "group": "toplevel", @@ -840,27 +840,27 @@ { "attr_path": "pulumiPackages.pulumi-python", "broken": false, - "derivation": "/nix/store/i49j5z46n8lf048961hj9yglmqj7vx82-pulumi-python-3.162.0.drv", + "derivation": "/nix/store/infns5gs04xx8zgz8y6nfff440bpilzj-pulumi-python-3.185.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "pulumi-python-3.162.0", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "pulumi-python-3.185.0", "pname": "pulumi-python", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T05:16:21.093444Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T03:13:56.452524Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "3.162.0", + "version": "3.185.0", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/9why6bwbrg9wjs9wv1cw7vqd3srg1npf-pulumi-python-3.162.0" + "out": "/nix/store/a6l2g4f1z2i9gc314bjkw7xklkqmkdmg-pulumi-python-3.185.0" }, "system": "x86_64-linux", "group": "toplevel", @@ -869,27 +869,27 @@ { "attr_path": "ruff", "broken": false, - "derivation": "/nix/store/8h26kjdg3izsnvym7hlyr64dybcbik17-ruff-0.11.11.drv", + "derivation": "/nix/store/vp9j1bdmdvxhwg32ql5v10437lmsz7nf-ruff-0.12.4.drv", "description": "Extremely fast Python linter and code formatter", "install_id": "ruff", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "ruff-0.11.11", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "ruff-0.12.4", "pname": "ruff", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:23:27.312019Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T00:26:48.523662Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.11.11", + "version": "0.12.4", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/k0k8m644ynbr1zck96ckcagzzlv4qqgb-ruff-0.11.11" + "out": "/nix/store/rwxgbgfx5m3ln4d2wv0vx194wy7j4v3j-ruff-0.12.4" }, "system": "aarch64-darwin", "group": "toplevel", @@ -898,27 +898,27 @@ { "attr_path": "ruff", "broken": false, - "derivation": "/nix/store/xxd3ypn1hfyv4j8ssq8rlpd3r3dxmf2d-ruff-0.11.11.drv", + "derivation": "/nix/store/8ayki0a0lg9kw7pjsgyh77a036y8pymp-ruff-0.12.4.drv", "description": "Extremely fast Python linter and code formatter", "install_id": "ruff", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "ruff-0.11.11", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "ruff-0.12.4", "pname": "ruff", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:41:59.883315Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:00:55.335510Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.11.11", + "version": "0.12.4", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/axlcjs1wwzmjgm46hs590vlf72wwwq61-ruff-0.11.11" + "out": "/nix/store/cqslzqas3rb1qzdx9gfkp9piz8awz1l4-ruff-0.12.4" }, "system": "aarch64-linux", "group": "toplevel", @@ -927,27 +927,27 @@ { "attr_path": "ruff", "broken": false, - "derivation": "/nix/store/x1kw71hahh8d8663yn1wc9m08gkdcdlx-ruff-0.11.11.drv", + "derivation": "/nix/store/ydm14pzd102b2zvxd7rf1plwj8vjz0yq-ruff-0.12.4.drv", "description": "Extremely fast Python linter and code formatter", "install_id": "ruff", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "ruff-0.11.11", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "ruff-0.12.4", "pname": "ruff", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:57:32.798449Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:33:00.323658Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.11.11", + "version": "0.12.4", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/ldi9qdqx4pmdzqaypsk07wrc7xcry6vc-ruff-0.11.11" + "out": "/nix/store/jipra52bjpjsmqsmy6w5w7z07m3ivw7z-ruff-0.12.4" }, "system": "x86_64-darwin", "group": "toplevel", @@ -956,27 +956,27 @@ { "attr_path": "ruff", "broken": false, - "derivation": "/nix/store/h501fb8q4j37n5wxk1v0lpb6g3hfpziq-ruff-0.11.11.drv", + "derivation": "/nix/store/s95ap8bq6hqh0w421d0yr4zji0rd30jg-ruff-0.12.4.drv", "description": "Extremely fast Python linter and code formatter", "install_id": "ruff", "license": "MIT", - "locked_url": "https://github.com/flox/nixpkgs?rev=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "ruff-0.11.11", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "ruff-0.12.4", "pname": "ruff", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T05:16:58.378619Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T03:14:48.280945Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.11.11", + "version": "0.12.4", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/v7s30nbh27pvn626q4wmhwmw910rkjxs-ruff-0.11.11" + "out": "/nix/store/yr42i3idp27hhsxhakws9nm42f6c6gqm-ruff-0.12.4" }, "system": "x86_64-linux", "group": "toplevel", @@ -985,27 +985,27 @@ { "attr_path": "uv", "broken": false, - "derivation": "/nix/store/dsahw3040avihwrkl5n5bqp7ak39qb68-uv-0.7.8.drv", + "derivation": "/nix/store/r73cws9f03q1bb6yiynf7cydq620r7hw-uv-0.8.2.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "uv-0.7.8", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "uv-0.8.2", "pname": "uv", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:23:51.617532Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T00:27:16.729256Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.7.8", + "version": "0.8.2", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/14fx9ajm7isc8rkr4jgf98pm9y1nmv2v-uv-0.7.8" + "out": "/nix/store/db9y1b002zlnyjgpsnbl9hvlwsiqajl4-uv-0.8.2" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1014,27 +1014,27 @@ { "attr_path": "uv", "broken": false, - "derivation": "/nix/store/cjmf8sgmbmiid4x0in5pw1d3jfsa9r01-uv-0.7.8.drv", + "derivation": "/nix/store/h31r5jskn5fjad9xffsagc30kb0pxxar-uv-0.8.2.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "uv-0.7.8", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "uv-0.8.2", "pname": "uv", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:42:34.059324Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:01:44.564146Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.7.8", + "version": "0.8.2", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/qqwziiwldw73d4cj82pc9gi1zc594m89-uv-0.7.8" + "out": "/nix/store/bdps6h2gn2rysavc3cq2slqnjlsyyk03-uv-0.8.2" }, "system": "aarch64-linux", "group": "toplevel", @@ -1043,27 +1043,27 @@ { "attr_path": "uv", "broken": false, - "derivation": "/nix/store/4n45k4c8plhbwmqa1pqkxry2gi3hnbvl-uv-0.7.8.drv", + "derivation": "/nix/store/9fc1gmai85rmaiaj91kj348pgapv6fzy-uv-0.8.2.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "uv-0.7.8", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "uv-0.8.2", "pname": "uv", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:57:57.865093Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:33:35.880116Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.7.8", + "version": "0.8.2", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/1bwfrca14w02rzq8bl72xffn9vsdshnm-uv-0.7.8" + "out": "/nix/store/91g6383zq1wbiik2an7g6yfrj294c19v-uv-0.8.2" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1072,27 +1072,27 @@ { "attr_path": "uv", "broken": false, - "derivation": "/nix/store/fxwyayd2ikwl4a2zkpknqffdlg4sw3x5-uv-0.7.8.drv", + "derivation": "/nix/store/yjph3bdnhgzkbnr0a2qhzz3wbspiimpw-uv-0.8.2.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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "uv-0.7.8", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "uv-0.8.2", "pname": "uv", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T05:17:33.641841Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T03:15:39.576767Z", "stabilities": [ "unstable" ], "unfree": false, - "version": "0.7.8", + "version": "0.8.2", "outputs_to_install": [ "out" ], "outputs": { - "out": "/nix/store/7nmrwl4kz78cjgwykrngkj68sx3ry79i-uv-0.7.8" + "out": "/nix/store/swq8qrr7n5gkc1b4940q62a3ll52prgl-uv-0.8.2" }, "system": "x86_64-linux", "group": "toplevel", @@ -1101,17 +1101,17 @@ { "attr_path": "python313Packages.vulture", "broken": false, - "derivation": "/nix/store/aqfdil6kh8vdzr1hrrdb0p0iwzakn5hm-python3.13-vulture-2.14.drv", + "derivation": "/nix/store/32nihzi1nx446pk383g78d6mw6xc734s-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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", "name": "python3.13-vulture-2.14", "pname": "vulture", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:23:22.696174Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T00:26:43.523561Z", "stabilities": [ "unstable" ], @@ -1121,8 +1121,8 @@ "out" ], "outputs": { - "dist": "/nix/store/wss3crp2ddy9z5n79ppjbz51n22ahs25-python3.13-vulture-2.14-dist", - "out": "/nix/store/hfq41abbvsnpkk2nan1wsmqxgiiwnf6d-python3.13-vulture-2.14" + "dist": "/nix/store/g4w4vfh1hgm5vfxqxxy7a0rlc1hybixh-python3.13-vulture-2.14-dist", + "out": "/nix/store/cjpzb97gl8giy0awwhzs2fxrzbldjdw7-python3.13-vulture-2.14" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1131,17 +1131,17 @@ { "attr_path": "python313Packages.vulture", "broken": false, - "derivation": "/nix/store/5d6drcxwb8grwssxnlgf5krsqrqghnxf-python3.13-vulture-2.14.drv", + "derivation": "/nix/store/45pjsi9x9x3lk7d8gv2yl8749gfdbh6x-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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", "name": "python3.13-vulture-2.14", "pname": "vulture", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:41:52.942356Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:00:45.953676Z", "stabilities": [ "unstable" ], @@ -1151,8 +1151,8 @@ "out" ], "outputs": { - "dist": "/nix/store/dm8qyyxibv1vaf10svxqgc84lshdcjyw-python3.13-vulture-2.14-dist", - "out": "/nix/store/q7m41nfx7xzxf93rz28wccxak93xv4hp-python3.13-vulture-2.14" + "dist": "/nix/store/4c6lq83d3q593vrs8x22fmv052i9gfb7-python3.13-vulture-2.14-dist", + "out": "/nix/store/nk1cwmm3n2zwmhv1134sq5yh8mpkgc2b-python3.13-vulture-2.14" }, "system": "aarch64-linux", "group": "toplevel", @@ -1161,17 +1161,17 @@ { "attr_path": "python313Packages.vulture", "broken": false, - "derivation": "/nix/store/kwvncdy339ghk2mfv4xnk2yd1fl55w5d-python3.13-vulture-2.14.drv", + "derivation": "/nix/store/ndpdvvqw75hnr9p4gq0sa0q1sanjf3rn-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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", "name": "python3.13-vulture-2.14", "pname": "vulture", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:57:28.041441Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:32:54.078468Z", "stabilities": [ "unstable" ], @@ -1181,8 +1181,8 @@ "out" ], "outputs": { - "dist": "/nix/store/3cv1gdzaqa40b7vzcyasj7x01r4p458p-python3.13-vulture-2.14-dist", - "out": "/nix/store/3i5g4gnnzzdf0zl3fjri6mcsvf3gb0vy-python3.13-vulture-2.14" + "dist": "/nix/store/9q4vnqp0rpggp04c5w9pjk7sp21d0xsy-python3.13-vulture-2.14-dist", + "out": "/nix/store/6bhr50lfglxdmpv9n3jhmi98hbzacggj-python3.13-vulture-2.14" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1191,17 +1191,17 @@ { "attr_path": "python313Packages.vulture", "broken": false, - "derivation": "/nix/store/mz50y50gavk58x56z45qhzkl13xw2n9y-python3.13-vulture-2.14.drv", + "derivation": "/nix/store/4sgflvdh30xvfd2a55025afj6v97m664-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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", "name": "python3.13-vulture-2.14", "pname": "vulture", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T05:16:50.905097Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T03:14:38.091751Z", "stabilities": [ "unstable" ], @@ -1211,8 +1211,8 @@ "out" ], "outputs": { - "dist": "/nix/store/dq6kv57djil8falgbgkgagrwagqsfh30-python3.13-vulture-2.14-dist", - "out": "/nix/store/l6dml5y8hplj1rnkzsy1q3yli4pls9cr-python3.13-vulture-2.14" + "dist": "/nix/store/b4hhs9y36f2b96l505bpp54hp7lifpwm-python3.13-vulture-2.14-dist", + "out": "/nix/store/gnffvcxchixrzy552h98v2jccav27bnf-python3.13-vulture-2.14" }, "system": "x86_64-linux", "group": "toplevel", @@ -1221,17 +1221,17 @@ { "attr_path": "yamllint", "broken": false, - "derivation": "/nix/store/p8hkyk4gw3dacajrw96rwhhpxdryn2g4-python3.12-yamllint-1.37.1.drv", + "derivation": "/nix/store/cxvrl8j9fprl8hr8n0gv1pm1xd1vglwr-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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "python3.12-yamllint-1.37.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "python3.13-yamllint-1.37.1", "pname": "yamllint", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:23:58.892389Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T00:27:24.798276Z", "stabilities": [ "unstable" ], @@ -1241,8 +1241,8 @@ "out" ], "outputs": { - "dist": "/nix/store/cabqrzcssd4jz420wqnkf2ail19dhbd5-python3.12-yamllint-1.37.1-dist", - "out": "/nix/store/zpx2h1p689s0sq15pnm8hrwb1r8qiq2g-python3.12-yamllint-1.37.1" + "dist": "/nix/store/5787d9236p07pwd04gj00k6rli35wp84-python3.13-yamllint-1.37.1-dist", + "out": "/nix/store/lm8hla11svn8glcgc5yhg1990gdrw5qq-python3.13-yamllint-1.37.1" }, "system": "aarch64-darwin", "group": "toplevel", @@ -1251,17 +1251,17 @@ { "attr_path": "yamllint", "broken": false, - "derivation": "/nix/store/hdmz4s1aqgss4hz07xwc5934nacjggzw-python3.12-yamllint-1.37.1.drv", + "derivation": "/nix/store/rzgf4z5m9hwfxzr689mln0c2gdr8cf60-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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "python3.12-yamllint-1.37.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "python3.13-yamllint-1.37.1", "pname": "yamllint", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:42:45.037826Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:01:59.340541Z", "stabilities": [ "unstable" ], @@ -1271,8 +1271,8 @@ "out" ], "outputs": { - "dist": "/nix/store/7pr088lzbsq3n0pwnx5mz906asffwm09-python3.12-yamllint-1.37.1-dist", - "out": "/nix/store/61rk661yf0an0kfpbmng1baqzdlpvxim-python3.12-yamllint-1.37.1" + "dist": "/nix/store/1p8xbkrqhm0mqacghfgfdp1q9ggxrirq-python3.13-yamllint-1.37.1-dist", + "out": "/nix/store/8h5vdqrx7b2hzlhqy2rcniq5nf0i0j7f-python3.13-yamllint-1.37.1" }, "system": "aarch64-linux", "group": "toplevel", @@ -1281,17 +1281,17 @@ { "attr_path": "yamllint", "broken": false, - "derivation": "/nix/store/x3lk9vrrrpn341mdw0nswqljx87l7gxy-python3.12-yamllint-1.37.1.drv", + "derivation": "/nix/store/jyn77m4ng8p61xdmppjpq68x5j8jrk7v-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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "python3.12-yamllint-1.37.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "python3.13-yamllint-1.37.1", "pname": "yamllint", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T04:58:05.443100Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T02:33:46.012406Z", "stabilities": [ "unstable" ], @@ -1301,8 +1301,8 @@ "out" ], "outputs": { - "dist": "/nix/store/87msznav6i4car58rjbpxz99p5q7zxas-python3.12-yamllint-1.37.1-dist", - "out": "/nix/store/x8hq6b2bxxw6iq3nisvz4vq3x8rg8nw6-python3.12-yamllint-1.37.1" + "dist": "/nix/store/ig2y0prb5vi6ky2fbg245439dl0w076w-python3.13-yamllint-1.37.1-dist", + "out": "/nix/store/53vl9m6b594yf85093gbhlw8lv4ivndq-python3.13-yamllint-1.37.1" }, "system": "x86_64-darwin", "group": "toplevel", @@ -1311,17 +1311,17 @@ { "attr_path": "yamllint", "broken": false, - "derivation": "/nix/store/fp461qwy8l4f97wqvnxfdxyp6599s1kf-python3.12-yamllint-1.37.1.drv", + "derivation": "/nix/store/ckjzi23qkjgm1nyyfcq3d4aaqgw2nqs6-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=96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "name": "python3.12-yamllint-1.37.1", + "locked_url": "https://github.com/flox/nixpkgs?rev=005433b926e16227259a1843015b5b2b7f7d1fc3", + "name": "python3.13-yamllint-1.37.1", "pname": "yamllint", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", - "rev_count": 807377, - "rev_date": "2025-05-28T19:24:49Z", - "scrape_date": "2025-05-31T05:17:45.185126Z", + "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev_count": 843472, + "rev_date": "2025-08-12T19:39:21Z", + "scrape_date": "2025-08-14T03:15:55.394937Z", "stabilities": [ "unstable" ], @@ -1331,8 +1331,8 @@ "out" ], "outputs": { - "dist": "/nix/store/armnb0mkgb4bi4bx01xhhzv5xlra8gh5-python3.12-yamllint-1.37.1-dist", - "out": "/nix/store/r46xh5mckk2m9maai0bc2dx63jj84w5l-python3.12-yamllint-1.37.1" + "dist": "/nix/store/jxjhi5yqq6d1f54x74j9d0c3s4v9imsd-python3.13-yamllint-1.37.1-dist", + "out": "/nix/store/fhvbnxy08wqk8gvwpgyi55n6zrmgv951-python3.13-yamllint-1.37.1" }, "system": "x86_64-linux", "group": "toplevel", diff --git a/.github/workflows/launch_application.yaml b/.github/workflows/launch_infrastructure.yaml similarity index 82% rename from .github/workflows/launch_application.yaml rename to .github/workflows/launch_infrastructure.yaml index 7813c7367..a43e238e5 100644 --- a/.github/workflows/launch_application.yaml +++ b/.github/workflows/launch_infrastructure.yaml @@ -1,11 +1,11 @@ --- -name: Launch application +name: Launch infrastructure on: schedule: - cron: '0 13 * * 1,2,3,4,5' # launch at 8:00 AM EST jobs: - launch_application: - name: Launch application on weekday schedule + launch_infrastructure: + name: Launch infrastructure on weekday schedule runs-on: ubuntu-latest environment: pulumi steps: diff --git a/.github/workflows/teardown_application.yaml b/.github/workflows/teardown_infrastructure.yaml similarity index 76% rename from .github/workflows/teardown_application.yaml rename to .github/workflows/teardown_infrastructure.yaml index 5f128cd07..412be254f 100644 --- a/.github/workflows/teardown_application.yaml +++ b/.github/workflows/teardown_infrastructure.yaml @@ -1,12 +1,11 @@ --- -name: Teardown application +name: Teardown infrastructure on: schedule: - cron: '0 23 * * 1,2,3,4,5' # teardown at 6:00 PM EST jobs: - teardown_application: - name: Teardown application on weekday schedule - if: github.event.schedule == '0 23 * * 1,2,3,4,5' + teardown_infrastructure: + name: Teardown infrastructure on weekday schedule runs-on: ubuntu-latest environment: pulumi steps: diff --git a/.gitignore b/.gitignore index 9819ac08b..ddc5257ee 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,11 @@ .flox/log/ .flox/run/ .env +.ruff_cache/ +.pytest_cache/ +.venv/ .python_coverage.* +coverage_output/ __pycache__/ infrastructure/Pulumi.infrastructure.yaml infrastructure/Pulumi.production.yaml @@ -12,3 +16,6 @@ infrastructure/Pulumi.production.yaml .coverage/ coverage.xml infrastructure/kubeconfig.json +*.egg-info +wandb/ +*.csv diff --git a/.mise.toml b/.mise.toml index d38ffb55b..5d0e7a8e9 100644 --- a/.mise.toml +++ b/.mise.toml @@ -40,32 +40,6 @@ docker compose --file tests.yaml run --rm --no-TTY tests docker compose --file tests.yaml down --volumes --remove-orphans """ -[tasks."application:service:run"] -description = "Run the application service locally with hot reloading" -run = """ -cd application/{{option(name="service")}} -uv run uvicorn src.{{option(name="service")}}.main:application --reload -""" - -[tasks."application:service:test:integration"] -description = "Run integration tests" -run = """ -cd application/{{option(name="service")}} -docker compose up --build --abort-on-container-exit --remove-orphans -""" - -[tasks."application:service:test:behavioral"] -description = "Run behavioral tests" -run = """ -cd application/{{option(name="service")}} -if [ {{flag(name="cleanup")}} == true ] -then - docker compose down -v -else - docker compose up --build --abort-on-container-exit -fi -""" - [tasks."lint"] depends = ["python:lint"] description = "Run code quality checks" @@ -93,16 +67,3 @@ set -e cd infrastructure uv run pulumi down --yes --stack pocketsizefund/pocketsizefund/production """ - -[tasks."cli:datamanager:authorize"] -description = "Authorize the CLI with AWS credentials" -run = """ -aws iam attach-user-policy --user-name {{option(user-name="user-name")}} --policy-arn ${{pulumi stack output DATAMANAGER_API_ACCESS_POLICY_ARN}} -""" - -[tasks."dashboard:upload"] -description = "Upload Grafana dashboard" -run = """ -cd infrastructure -nu upload_grafana_dashboard.nu -""" diff --git a/Dockerfile.tests b/Dockerfile.tests index 0c47ddfbb..baefe4946 100644 --- a/Dockerfile.tests +++ b/Dockerfile.tests @@ -17,18 +17,20 @@ WORKDIR /tests COPY pyproject.toml uv.lock ./ -COPY application/datamanager/pyproject.toml ./application/datamanager/ +COPY applications/datamanager/pyproject.toml ./applications/datamanager/ -COPY application/positionmanager/pyproject.toml ./application/positionmanager/ +COPY applications/portfoliomanager/pyproject.toml ./applications/portfoliomanager/ -COPY application/predictionengine/pyproject.toml ./application/predictionengine/ +COPY applications/models/pyproject.toml ./applications/models/ COPY infrastructure/pyproject.toml ./infrastructure/ -COPY workflows/pyproject.toml ./workflows/ +COPY libraries/python/pyproject.toml ./libraries/python/ RUN uv sync --all-packages --dev -COPY application/ ./application/ +COPY applications/ ./applications/ + +COPY libraries/ ./libraries/ RUN mkdir -p /tests/coverage_output diff --git a/README.md b/README.md index 6466e05f3..29da49252 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,6 @@ An unordered and non-exhaustive list we work towards: > No code is good code > Never write documentation > Git is truth -> Communicate without speaking -> Make everything liquid ### Links diff --git a/application/datamanager/.dockerignore b/application/datamanager/.dockerignore deleted file mode 100644 index 6ed040e7f..000000000 --- a/application/datamanager/.dockerignore +++ /dev/null @@ -1,8 +0,0 @@ -__pycache__/ -*.py[cod] -*$py.class -.venv/ -.pytest_cache/ -.coverage -htmlcov/ -.git/ \ No newline at end of file diff --git a/application/datamanager/Dockerfile b/application/datamanager/Dockerfile deleted file mode 100644 index a5a65dbe7..000000000 --- a/application/datamanager/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM python:3.12.10 - -COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv - -ENV PYTHONPATH=/app/src - -WORKDIR /app - -COPY pyproject.toml ./ - -RUN uv sync --no-dev - -COPY ./src ./src - -EXPOSE 8080 - -ENTRYPOINT ["uv", "run", "uvicorn", "datamanager.main:application", "--host", "0.0.0.0", "--port", "8080", "--app-dir", "src"] diff --git a/application/datamanager/Dockerfile.test b/application/datamanager/Dockerfile.test deleted file mode 100644 index c03f06455..000000000 --- a/application/datamanager/Dockerfile.test +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.13-slim -COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv - -WORKDIR /tests - -COPY pyproject.toml . -RUN uv sync --only-group dev - -COPY features /tests - -CMD ["uv", "run", "behave", "features/"] diff --git a/application/datamanager/compose.yaml b/application/datamanager/compose.yaml deleted file mode 100644 index 1be7ecb99..000000000 --- a/application/datamanager/compose.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: Data manager integration tests - -services: - datamanager: - build: - context: . - dockerfile: Dockerfile - ports: - - 8080:8080 - environment: - - POLYGON_API_KEY=${POLYGON_API_KEY} - - AWS_S3_DATA_BUCKET_NAME=${AWS_S3_DATA_BUCKET_NAME} - volumes: - - ./:/app/datamanager - healthcheck: - test: ["CMD", "curl", "-f", "http://0.0.0.0:8080/health"] - interval: 10s - timeout: 5s - retries: 3 - start_period: 1s - - tests: - build: - context: . - dockerfile: Dockerfile.test - volumes: - - ./:/app/datamanager - depends_on: - datamanager: - condition: service_healthy - environment: - - BASE_URL=http://datamanager:8080 - command: ["uv", "run", "behave"] diff --git a/application/datamanager/features/environment.py b/application/datamanager/features/environment.py deleted file mode 100644 index 796fe865c..000000000 --- a/application/datamanager/features/environment.py +++ /dev/null @@ -1,7 +0,0 @@ -import os - -from behave.runner import Context - - -def before_all(context: Context) -> None: - context.base_url = os.environ.get("BASE_URL", "http://datamanager:8080") diff --git a/application/datamanager/features/equity_bars.feature b/application/datamanager/features/equity_bars.feature deleted file mode 100644 index 9bbe4080f..000000000 --- a/application/datamanager/features/equity_bars.feature +++ /dev/null @@ -1,24 +0,0 @@ -Feature: Equity Bars Data Management - As a datamanager application - I want to fetch, store, retrieve, and delete equity bars data - So that I can manage market data efficiently - - Background: - Given the datamanager API is running - - Scenario Outline: Manage bucket data for to - Given I have date ranges: - | start_date | end_date | - | | | - When I send a POST request to "/equity-bars" for date range - Then the response status code should be 200 - When I send a GET request to "/equity-bars" for date range - Then the response status code should be 200 - When I send a DELETE request to "/equity-bars" for date "" - Then the response status code should be 204 - - Examples: dates - | start_date | end_date | - | 2025-05-20 | 2025-05-20 | - - Scenario Outline: Skip weekends diff --git a/application/datamanager/features/health.feature b/application/datamanager/features/health.feature deleted file mode 100644 index 8a63f0aba..000000000 --- a/application/datamanager/features/health.feature +++ /dev/null @@ -1,11 +0,0 @@ -Feature: Health Check Endpoint - As a client - I want to check the health of the datamanager API - So that I can ensure the service is running - - Background: - Given the datamanager API is running - - Scenario: Health endpoint responds successfully - When I send a GET request to "/health" - Then the response status code should be 200 \ No newline at end of file diff --git a/application/datamanager/features/steps/equity_bars_steps.py b/application/datamanager/features/steps/equity_bars_steps.py deleted file mode 100644 index fb16ddef7..000000000 --- a/application/datamanager/features/steps/equity_bars_steps.py +++ /dev/null @@ -1,62 +0,0 @@ -import os -from pathlib import Path - -import requests -from behave import given, then, when # type: ignore -from behave.runner import Context - - -@given("I have date ranges") -def step_impl_date_ranges(context: Context) -> None: - for row in context.table: # type: ignore - context.start_date = row["start_date"] - context.end_date = row["end_date"] - - -@given("the datamanager API is running") -def step_impl_api_url(context: Context) -> None: - context.api_url = context.base_url - - -@when('I send a POST request to "{endpoint}" for date range') -def step_impl_post_request(context: Context, endpoint: str) -> None: - url = f"{context.api_url}{endpoint}" - response = requests.post(url, json={"date": context.start_date}, timeout=30) - context.response = response - - -@when('I send a GET request to "{endpoint}" for date range') -def step_imp_get_request(context: Context, endpoint: str) -> None: - url = f"{context.api_url}{endpoint}" - response = requests.get( - url, - params={"start_date": context.start_date, "end_date": context.end_date}, - timeout=30, - ) - context.response = response - - -@then("the response status code should be {status_code}") -def step_impl_response_status_code(context: Context, status_code: str) -> None: - assert context.response.status_code == int(status_code), ( - f"Expected status code {status_code}, got {context.response.status_code}" - ) - - -@when('I send a DELETE request to "{endpoint}" for date "{date_str}"') -def step_impl(context: Context, endpoint: str, date_str: str) -> None: - url = f"{context.api_url}{endpoint}" - response = requests.delete(url, json={"date": date_str}, timeout=30) - context.response = response - context.test_date = date_str - - -@then('the equity bars data for "{date_str}" should be deleted') -def step_impl_equity_bars(context: Context, date_str: str) -> None: # noqa: ARG001 - if os.environ.get("GCP_GCS_BUCKET"): - assert True, "GCS bucket deletion check would go here" - else: - expected_file = Path(f"equity_bars_{date_str}.parquet") - assert not expected_file.exists(), ( - f"Parquet file {expected_file} still exists after deletion" - ) diff --git a/application/datamanager/features/steps/health_steps.py b/application/datamanager/features/steps/health_steps.py deleted file mode 100644 index f9c0addf9..000000000 --- a/application/datamanager/features/steps/health_steps.py +++ /dev/null @@ -1,9 +0,0 @@ -import requests -from behave import when # type: ignore -from behave.runner import Context - - -@when('I send a GET request to "{endpoint}"') -def step_impl(context: Context, endpoint: str) -> None: - url = f"{context.api_url}{endpoint}" - context.response = requests.get(url, timeout=30) diff --git a/application/datamanager/mise.toml b/application/datamanager/mise.toml deleted file mode 100644 index 6e7cf7378..000000000 --- a/application/datamanager/mise.toml +++ /dev/null @@ -1,11 +0,0 @@ -[tasks."test:docker:behave"] -description = "Run behave tests with Docker Compose" -run = """ -docker-compose up --build --abort-on-container-exit -""" - -[tasks."test:docker:behave:cleanup"] -description = "Clean up after Docker Compose tests" -run = """ -docker-compose down -v -""" \ No newline at end of file diff --git a/application/datamanager/pyproject.toml b/application/datamanager/pyproject.toml deleted file mode 100644 index 8c877b256..000000000 --- a/application/datamanager/pyproject.toml +++ /dev/null @@ -1,28 +0,0 @@ -[project] -name = "datamanager" -version = "0.1.0" -description = "Data management service" -requires-python = "==3.12.10" -dependencies = [ - "fastapi>=0.115.12", - "uvicorn>=0.34.2", - "duckdb>=1.2.2", - "polars>=1.29.0", - "pyarrow>=20.0.0", - "loguru>=0.7.3", - "requests>=2.31.0", - "prometheus-fastapi-instrumentator>=7.1.0", - "cloudevents>=1.12.0", - "polygon-api-client>=1.14.6", - "boto3>=1.38.23", -] - -[tool.hatch.build.targets.wheel] -packages = ["datamanager"] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[dependency-groups] -dev = ["behave>=1.2.6"] diff --git a/application/datamanager/src/datamanager/clients.py b/application/datamanager/src/datamanager/clients.py deleted file mode 100644 index 701420f2b..000000000 --- a/application/datamanager/src/datamanager/clients.py +++ /dev/null @@ -1,45 +0,0 @@ -from typing import cast - -import boto3 -from polygon import RESTClient -from polygon.rest.models.aggs import GroupedDailyAgg - - -class PolygonClient: - def __init__(self, polygon_api_key: str) -> None: - self.polygon_client = RESTClient(api_key=polygon_api_key) - - def get_all_equity_bars(self, date: str) -> list[GroupedDailyAgg]: - grouped = self.polygon_client.get_grouped_daily_aggs( - date=date, - adjusted=True, - ) - - return cast("list[GroupedDailyAgg]", grouped) - - -class S3Client: - def __init__(self, data_bucket_name: str) -> None: - self.s3_client = boto3.client("s3") - self.data_bucket_name = data_bucket_name - self.daily_equity_bars_path = f"s3://{self.data_bucket_name}/equity/bars/" - - def list_objects(self, prefix: str = "") -> list[str]: - objects = [] - paginator = self.s3_client.get_paginator("list_objects_v2") - - for page in paginator.paginate(Bucket=self.data_bucket_name, Prefix=prefix): - if "Contents" in page: - objects.extend([obj["Key"] for obj in page["Contents"]]) - - return objects - - def delete_objects(self, object_names: list[str]) -> None: - if not object_names: - return - - delete_requests = [{"Key": obj} for obj in object_names] - self.s3_client.delete_objects( - Bucket=self.data_bucket_name, - Delete={"Objects": delete_requests}, - ) diff --git a/application/datamanager/src/datamanager/main.py b/application/datamanager/src/datamanager/main.py deleted file mode 100644 index 63ca97015..000000000 --- a/application/datamanager/src/datamanager/main.py +++ /dev/null @@ -1,297 +0,0 @@ -import json -import os -import traceback -from collections.abc import AsyncGenerator -from contextlib import asynccontextmanager -from datetime import date, datetime -from zoneinfo import ZoneInfo - -import duckdb -import polars as pl -import pyarrow as pa -import pyarrow.lib -import requests -from cloudevents.pydantic.v2 import CloudEvent -from duckdb import IOException -from fastapi import FastAPI, Request, Response, status -from google.api_core import exceptions -from google.api_core.exceptions import GoogleAPIError -from loguru import logger -from polars.exceptions import ComputeError -from prometheus_client import Gauge -from prometheus_fastapi_instrumentator import Instrumentator - -from .clients import PolygonClient, S3Client -from .models import SummaryDate - - -def bars_query(*, bucket: str, start_date: date, end_date: date) -> str: - path_pattern = f"s3://{bucket}/equity/bars/*/*/*/*" - - return f""" - SELECT * - FROM read_parquet( - '{path_pattern}', - HIVE_PARTITIONING=1 - ) - WHERE - (year > {start_date.year} OR - (year = {start_date.year} AND month > {start_date.month}) OR - (year = {start_date.year} AND month = {start_date.month} - AND day >= {start_date.day})) - AND - (year < {end_date.year} OR - (year = {end_date.year} AND month < {end_date.month}) OR - (year = {end_date.year} - AND month = {end_date.month} - AND day <= {end_date.day})) - """ # noqa: S608 - - -@asynccontextmanager -async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: - app.state.polygon_client = PolygonClient( - polygon_api_key=os.getenv("POLYGON_API_KEY", ""), - ) - - app.state.s3_client = S3Client( - data_bucket_name=os.getenv("AWS_S3_DATA_BUCKET_NAME", "") - ) - - duckdb_user_access_key_id = os.getenv("AWS_IAM_DUCKDB_USER_ACCESS_KEY_ID") - duckdb_user_access_key_secret = os.getenv("AWS_IAM_DUCKDB_USER_ACCESS_KEY_SECRET") - aws_region = os.getenv("AWS_REGION", "us-east-1") - - app.state.connection = duckdb.connect() - app.state.connection.execute(f""" - INSTALL httpfs; - LOAD httpfs; - SET http_keep_alive=true; - SET http_timeout=30000; - CREATE SECRET ( - TYPE S3, - PROVIDER config, - KEY_ID '{duckdb_user_access_key_id}', - SECRET '{duckdb_user_access_key_secret}', - REGION '{aws_region}' - ); - """) - - yield - - if hasattr(app.state, "connection"): - app.state.connection.close() - - -application = FastAPI(lifespan=lifespan) -Instrumentator().instrument(application).expose(application) - -equity_bars_total_rows = Gauge( - "equity_bars_total_rows", - "Total number of rows in equity bars bucket", -) - - -@application.get("/health") -def get_health() -> Response: - return Response(status_code=status.HTTP_200_OK) - - -@application.get("/metrics") -def get_metrics(request: Request) -> Response: - try: - count_query = f""" - SELECT COUNT(*) as total_rows - FROM read_parquet( - 's3://{request.app.state.s3_client.data_bucket_name}/equity/bars/*/*/*/*', - HIVE_PARTITIONING=1 - ) - """ # noqa: S608 - - result = request.app.state.connection.execute(count_query).fetchone() - - total_rows = result[0] if result else 0 - - equity_bars_total_rows.set(total_rows) - - logger.info(f"Updated equity_bars_total_rows metric: {total_rows}") - - return Response( - status_code=status.HTTP_200_OK, - content=json.dumps({"total_rows": total_rows}), - media_type="application/json", - ) - - except ( - duckdb.Error, - IOException, - ComputeError, - GoogleAPIError, - ) as e: - logger.error(f"Error updating metrics: {e}") - - return Response( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - content=json.dumps({"error": "Failed to fetch metrics"}), - media_type="application/json", - ) - - except requests.RequestException as e: # TEMP - logger.error(f"Request error while fetching metrics: {e}") - return Response( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - content=json.dumps({"error": "Failed to fetch metrics"}), - media_type="application/json", - ) - - -@application.get("/equity-bars") -def get_equity_bars( - request: Request, - start_date: date, - end_date: date, -) -> Response: - query = bars_query( - bucket=request.app.state.s3_client.data_bucket_name, - start_date=start_date, - end_date=end_date, - ) - - try: - data = request.app.state.connection.execute(query).arrow() - - if data.num_rows == 0: - return Response( - status_code=status.HTTP_404_NOT_FOUND, - content=json.dumps({"error": "No data found for the given date range"}), - media_type="application/json", - ) - - logger.info(f"Query returned rows count: {data.num_rows}") - sink = pa.BufferOutputStream() - with pa.ipc.RecordBatchStreamWriter(sink, data.schema) as writer: - writer.write_table(data) - - filename = f"equity_bars_{start_date}_{end_date}.arrow" - content_disposition = f"attachment; {filename=}" - - return Response( - content=sink.getvalue().to_pybytes(), - media_type="application/vnd.apache.arrow.file", - headers={ - "Content-Disposition": content_disposition, - "X-Row-Count": str(data.num_rows), - "X-Start-Date": str(start_date), - "X-End-Date": str(end_date), - }, - ) - - except ( - requests.RequestException, - ComputeError, - IOException, - GoogleAPIError, - pyarrow.lib.ArrowIOError, - ) as e: - logger.error(f"Error querying data: {e}") - logger.error(traceback.format_exc()) - return Response( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - content=json.dumps({"error": f"Failed to query data: {e!s}"}), - media_type="application/json", - ) - - -@application.post("/equity-bars/fetch") -def fetch_equity_bars( - request: Request, - summary_date: SummaryDate | None, -) -> CloudEvent: - polygon_client = request.app.state.polygon_client - daily_equity_bars_path = request.app.state.s3_client.daily_equity_bars_path - - if summary_date is None: - summary_date = SummaryDate( - date=datetime.now(tz=ZoneInfo("America/New_York")).date() - ) - - request_summary_date: str = summary_date.date.strftime("%Y-%m-%d") - - all_equity_bars_response = polygon_client.get_all_equity_bars( - date=request_summary_date, - ) - - all_equity_bars = pl.DataFrame(all_equity_bars_response) - count = len(all_equity_bars) - if count > 0: - try: - all_equity_bars.with_columns( - [ - pl.from_epoch("t", time_unit="ms").alias("datetime"), - pl.from_epoch("t", time_unit="ms").dt.year().alias("year"), - pl.from_epoch("t", time_unit="ms").dt.month().alias("month"), - pl.from_epoch("t", time_unit="ms").dt.day().alias("day"), - ], - ).write_parquet( - file=daily_equity_bars_path, - partition_by=["year", "month", "day"], - ) - except ( - requests.RequestException, - ComputeError, - IOException, - GoogleAPIError, - pyarrow.lib.ArrowIOError, - ) as e: - logger.error(f"Error writing parquet file: {e}") - logger.error(traceback.format_exc()) - - return CloudEvent( - attributes={ - "source": "datamanager", - "type": "application.datamanager.equity.bars.errored", - }, - data={ - "date": request_summary_date, - "error": str(e), - }, - ) - - return CloudEvent( - attributes={ - "source": "datamanager", - "type": "application.datamanager.equity.bars.created", - }, - data={ - "date": request_summary_date, - "count": count, - }, - ) - - -@application.delete("/equity-bars") -def delete_equity_bars(request: Request, summary_date: SummaryDate) -> Response: - s3_client = request.app.state.s3_client - year = summary_date.date.year - month = summary_date.date.month - day = summary_date.date.day - prefix = f"equity/bars/{year=}/{month=}/{day=}" - - try: - blobs = list(s3_client.list_objects(prefix=prefix)) - except exceptions.NotFound: - return Response( - status_code=status.HTTP_404_NOT_FOUND, - content=json.dumps({"error": "No equity bars found"}), - media_type="application/json", - ) - if not blobs: - return Response( - status_code=status.HTTP_404_NOT_FOUND, - content=json.dumps({"error": "No equity bars found for the given date"}), - media_type="application/json", - ) - - logger.info(f"Deleting prefix: {prefix=}") - s3_client.delete_objects(blobs) - return Response(status_code=status.HTTP_204_NO_CONTENT) diff --git a/application/datamanager/tests/test_datamanager_main.py b/application/datamanager/tests/test_datamanager_main.py deleted file mode 100644 index d1faf9f34..000000000 --- a/application/datamanager/tests/test_datamanager_main.py +++ /dev/null @@ -1,265 +0,0 @@ -import unittest -from datetime import date -from unittest.mock import MagicMock, patch - -from duckdb import IOException -from fastapi import FastAPI, status -from fastapi.testclient import TestClient - -from application.datamanager.src.datamanager.main import application, get_metrics -from application.datamanager.src.datamanager.models import SummaryDate - -client = TestClient(application) - - -def test_get_health() -> None: - response = client.get("/health") - assert response.status_code == status.HTTP_200_OK - - -class TestDataManagerModels(unittest.TestCase): - def test_summary_date_default(self) -> None: - summary_date = SummaryDate() - assert isinstance(summary_date.date, date) - - def test_summary_date_with_date(self) -> None: - test_date = date(2023, 1, 1) - summary_date = SummaryDate(date=test_date) - assert summary_date.date == test_date - - def test_summary_date_string_parsing(self) -> None: - summary_date = SummaryDate(date="2023-01-01") # type: ignore - assert summary_date.date == date(2023, 1, 1) - - -class TestMetricsEndpoint(unittest.TestCase): - @classmethod - def setUpClass(cls) -> None: - cls.test_app = FastAPI() - cls.test_app.get("/metrics")(get_metrics) - cls.test_client = TestClient(cls.test_app) - - def test_get_metrics_success(self) -> None: - mock_connection = MagicMock() - mock_connection.execute.return_value.fetchone.return_value = (1000,) - - mock_s3_client = MagicMock() - mock_s3_client.data_bucket_name = "test-bucket" - - self.test_app.state.connection = mock_connection - self.test_app.state.s3_client = mock_s3_client - - response = self.test_client.get("/metrics") - - assert response.status_code == status.HTTP_200_OK - response_data = response.json() - assert response_data["total_rows"] == 1000 # noqa: PLR2004 - - def test_get_metrics_database_error(self) -> None: - mock_connection = MagicMock() - mock_connection.execute.side_effect = IOException("Database error") - - mock_s3_client = MagicMock() - mock_s3_client.data_bucket_name = "test-bucket" - - self.test_app.state.connection = mock_connection - self.test_app.state.s3_client = mock_s3_client - - response = self.test_client.get("/metrics") - - mock_connection.execute.assert_called_once() - assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR - response_data = response.json() - assert "error" in response_data - assert response_data["error"] == "Failed to fetch metrics" - - -class TestEquityBarsEndpoints(unittest.TestCase): - def test_get_equity_bars_missing_parameters(self) -> None: - response = client.get("/equity-bars") - assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY - - def test_get_equity_bars_invalid_date_format(self) -> None: - response = client.get( - url="/equity-bars", - params={ - "start_date": "invalid-date", - "end_date": "2023-01-02", - }, - ) - assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY - - @patch("application.datamanager.src.datamanager.main.duckdb") - def test_get_equity_bars_database_error(self, mock_duckdb: MagicMock) -> None: - mock_connection = MagicMock() - mock_connection.execute.side_effect = IOException("Database error") - mock_duckdb.connect.return_value = mock_connection - - mock_s3_client = MagicMock() - mock_s3_client.data_bucket_name = "test-bucket" - - with patch.object(application, "state") as mock_app_state: - mock_app_state.connection = mock_connection - mock_app_state.s3_client = mock_s3_client - - response = client.get( - url="/equity-bars", - params={ - "start_date": "2023-01-01", - "end_date": "2023-01-02", - }, - ) - - assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR - - @patch("application.datamanager.src.datamanager.main.duckdb") - def test_get_equity_bars_no_data(self, mock_duckdb: MagicMock) -> None: - mock_connection = MagicMock() - mock_arrow_result = MagicMock() - mock_arrow_result.num_rows = 0 - mock_connection.execute.return_value.arrow.return_value = mock_arrow_result - mock_duckdb.connect.return_value = mock_connection - - mock_s3_client = MagicMock() - mock_s3_client.data_bucket_name = "test-bucket" - - with patch.object(application, "state") as mock_app_state: - mock_app_state.connection = mock_connection - mock_app_state.s3_client = mock_s3_client - - response = client.get( - url="/equity-bars", - params={ - "start_date": "2023-01-01", - "end_date": "2023-01-02", - }, - ) - - assert response.status_code == status.HTTP_404_NOT_FOUND - response_data = response.json() - assert "error" in response_data - - def test_delete_equity_bars_missing_body(self) -> None: - response = client.request("DELETE", "/equity-bars") - assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY - - def test_delete_equity_bars_invalid_date(self) -> None: - response = client.request( - method="DELETE", - url="/equity-bars", - json={ - "date": "invalid-date", - }, - ) - assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY - - @patch("application.datamanager.src.datamanager.main.S3Client") - def test_delete_equity_bars_success(self, mock_s3_client_class: MagicMock) -> None: - mock_s3_client = MagicMock() - mock_s3_client.list_objects.return_value = ["file1.parquet", "file2.parquet"] - mock_s3_client_class.return_value = mock_s3_client - - with patch.object(application, "state") as mock_app_state: - mock_app_state.s3_client = mock_s3_client - - response = client.request( - method="DELETE", - url="/equity-bars", - json={"date": "2023-01-01"}, - ) - - assert response.status_code == status.HTTP_204_NO_CONTENT - mock_s3_client.delete_objects.assert_called_once() - - @patch("application.datamanager.src.datamanager.main.S3Client") - def test_delete_equity_bars_not_found( - self, mock_s3_client_class: MagicMock - ) -> None: - mock_s3_client = MagicMock() - mock_s3_client.list_objects.return_value = [] - mock_s3_client_class.return_value = mock_s3_client - - with patch.object(application, "state") as mock_app_state: - mock_app_state.s3_client = mock_s3_client - - response = client.request( - method="DELETE", - url="/equity-bars", - json={"date": "2023-01-01"}, - ) - - assert response.status_code == status.HTTP_404_NOT_FOUND - response_data = response.json() - assert "error" in response_data - - -class TestFetchEquityBarsEndpoint(unittest.TestCase): - @patch("application.datamanager.src.datamanager.main.PolygonClient") - @patch("application.datamanager.src.datamanager.main.pl.DataFrame") - def test_fetch_equity_bars_success( - self, - mock_dataframe: MagicMock, - mock_polygon_client_class: MagicMock, - ) -> None: - mock_polygon_client = MagicMock() - mock_polygon_client.get_all_equity_bars.return_value = [{"test": "data"}] - mock_polygon_client_class.return_value = mock_polygon_client - - mock_df = MagicMock() - mock_df.__len__.return_value = 1 - mock_df.with_columns.return_value = mock_df - mock_dataframe.return_value = mock_df - - mock_s3_client = MagicMock() - mock_s3_client.daily_equity_bars_path = "s3://test-bucket/equity/bars/" - - with patch.object(application, "state") as mock_app_state: - mock_app_state.polygon_client = mock_polygon_client - mock_app_state.s3_client = mock_s3_client - - response = client.post("/equity-bars/fetch", json={"date": "2023-01-01"}) - - assert response.status_code == status.HTTP_200_OK - response_data = response.json() - assert "source" in response_data - assert "type" in response_data - assert response_data["type"] == "application.datamanager.equity.bars.created" - - def test_fetch_equity_bars_invalid_date(self) -> None: - response = client.post("/equity-bars/fetch", json={"date": "invalid-date"}) - assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY - - @patch("application.datamanager.src.datamanager.main.PolygonClient") - @patch("application.datamanager.src.datamanager.main.pl.DataFrame") - def test_fetch_equity_bars_write_error( - self, - mock_dataframe: MagicMock, - mock_polygon_client_class: MagicMock, - ) -> None: - mock_polygon_client = MagicMock() - mock_polygon_client.get_all_equity_bars.return_value = [{"test": "data"}] - mock_polygon_client_class.return_value = mock_polygon_client - - mock_df = MagicMock() - mock_df.__len__.return_value = 1 - mock_df.with_columns.return_value = mock_df - mock_df.write_parquet.side_effect = IOException("Write error") - mock_dataframe.return_value = mock_df - - mock_s3_client = MagicMock() - mock_s3_client.daily_equity_bars_path = "s3://test-bucket/equity/bars/" - - with patch.object(application, "state") as mock_app_state: - mock_app_state.polygon_client = mock_polygon_client - mock_app_state.s3_client = mock_s3_client - - response = client.post("/equity-bars/fetch", json={"date": "2023-01-01"}) - - assert response.status_code == status.HTTP_200_OK - response_data = response.json() - assert response_data["type"] == "application.datamanager.equity.bars.errored" - assert "error" in response_data["data"] - - -if __name__ == "__main__": - unittest.main() diff --git a/application/datamanager/tests/test_datamanager_models.py b/application/datamanager/tests/test_datamanager_models.py deleted file mode 100644 index 7ccbbf64e..000000000 --- a/application/datamanager/tests/test_datamanager_models.py +++ /dev/null @@ -1,131 +0,0 @@ -import unittest -from datetime import date - -import pytest -from pydantic import ValidationError - -from application.datamanager.src.datamanager.models import ( - BarsSummary, - DateRange, - SummaryDate, -) - - -class TestSummaryDate(unittest.TestCase): - def test_summary_date_initialization_default(self) -> None: - summary_date = SummaryDate() - assert isinstance(summary_date.date, date) - - def test_summary_date_initialization_with_date(self) -> None: - test_date = date(2023, 5, 15) - summary_date = SummaryDate(date=test_date) - assert summary_date.date == test_date - - def test_summary_date_string_parsing_iso_format(self) -> None: - summary_date = SummaryDate(date="2023-5-15") # type: ignore - assert summary_date.date == date(2023, 5, 15) - - def test_summary_date_string_parsing_slash_format(self) -> None: - summary_date = SummaryDate(date="2023/05/15") # type: ignore - assert summary_date.date == date(2023, 5, 15) - - def test_summary_date_invalid_format(self) -> None: - with pytest.raises(ValidationError, match="Invalid date format"): - SummaryDate(date="invalid-date") # type: ignore - - def test_summary_date_invalid_date_values(self) -> None: - with pytest.raises(ValidationError): - SummaryDate(date="2023-13-01") # type: ignore - - def test_summary_date_json_encoder(self) -> None: - test_date = date(2023, 5, 15) - summary_date = SummaryDate(date=test_date) - json_data = summary_date.model_dump(mode="json") - assert json_data["date"] == "2023/05/15" - - -class TestDateRange(unittest.TestCase): - def test_date_range_valid(self) -> None: - start_date = date(2023, 1, 1) - end_date = date(2023, 12, 31) - date_range = DateRange(start=start_date, end=end_date) - - assert date_range.start == start_date - assert date_range.end == end_date - - def test_date_range_same_dates(self) -> None: - same_date = date(2023, 5, 15) - with pytest.raises(ValidationError, match="End date must be after start date"): - DateRange(start=same_date, end=same_date) - - def test_date_range_end_before_start(self) -> None: - start_date = date(2023, 12, 31) - end_date = date(2023, 1, 1) - with pytest.raises(ValidationError, match="End date must be after start date"): - DateRange(start=start_date, end=end_date) - - def test_date_range_valid_one_day_apart(self) -> None: - start_date = date(2023, 5, 15) - end_date = date(2023, 5, 16) - date_range = DateRange(start=start_date, end=end_date) - - assert date_range.start == start_date - assert date_range.end == end_date - - -class TestBarsSummary(unittest.TestCase): - def test_bars_summary_initialization(self) -> None: - bars_summary = BarsSummary(date="2023-05-15", count=1500) - - assert bars_summary.date == "2023-05-15" - assert bars_summary.count == 1500 # noqa: PLR2004 - - def test_bars_summary_zero_count(self) -> None: - bars_summary = BarsSummary(date="2023-05-15", count=0) - - assert bars_summary.date == "2023-05-15" - assert bars_summary.count == 0 - - def test_bars_summary_negative_count(self) -> None: - bars_summary = BarsSummary(date="2023-05-15", count=-1) - - assert bars_summary.date == "2023-05-15" - assert bars_summary.count == -1 - - def test_bars_summary_json_serialization(self) -> None: - bars_summary = BarsSummary(date="2023-05-15", count=1500) - json_data = bars_summary.model_dump() - - assert json_data == {"date": "2023-05-15", "count": 1500} - - def test_bars_summary_from_dict(self) -> None: - data = {"date": "2023-05-15", "count": 1500} - bars_summary = BarsSummary.model_validate(data) - - assert bars_summary.date == "2023-05-15" - assert bars_summary.count == 1500 # noqa: PLR2004 - - -class TestModelIntegration(unittest.TestCase): - def test_summary_date_to_bars_summary(self) -> None: - summary_date = SummaryDate(date="2023-05-15") # type: ignore - bars_summary = BarsSummary( - date=summary_date.date.strftime("%Y-%m-%d"), count=100 - ) - - assert bars_summary.date == "2023-05-15" - assert bars_summary.count == 100 # noqa: PLR2004 - - def test_multiple_model_validation(self) -> None: - summary_date = SummaryDate(date="2023-05-15") # type: ignore - date_range = DateRange(start=date(2023, 1, 1), end=date(2023, 12, 31)) - bars_summary = BarsSummary(date="2023-05-15", count=1000) - - assert summary_date.date == date(2023, 5, 15) - assert date_range.start == date(2023, 1, 1) - assert date_range.end == date(2023, 12, 31) - assert bars_summary.count == 1000 # noqa: PLR2004 - - -if __name__ == "__main__": - unittest.main() diff --git a/application/positionmanager/Dockerfile b/application/positionmanager/Dockerfile deleted file mode 100644 index 7d780761d..000000000 --- a/application/positionmanager/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM python:3.12.10 - -COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv - -ENV PYTHONPATH=/app/src - -WORKDIR /app - -COPY pyproject.toml ./ - -RUN uv sync --no-dev - -COPY ./src ./src - -EXPOSE 8080 - -ENTRYPOINT ["uv", "run", "uvicorn", "positionmanager.main:application", "--host", "0.0.0.0", "--port", "8080", "--app-dir", "src"] diff --git a/application/positionmanager/pyproject.toml b/application/positionmanager/pyproject.toml deleted file mode 100644 index ffd0bd913..000000000 --- a/application/positionmanager/pyproject.toml +++ /dev/null @@ -1,26 +0,0 @@ -[project] -name = "positionmanager" -version = "0.1.0" -description = "Position management service" -requires-python = "==3.12.10" -dependencies = [ - "fastapi>=0.115.12", - "uvicorn>=0.34.2", - "alpaca-py>=0.15.0", - "pydantic>=2.8.2", - "requests>=2.31.0", - "polars>=1.29.0", - "pandas>=2.1.0", - "pyportfolioopt>=1.5.6", - "ecos>=2.0.14", - "prometheus-fastapi-instrumentator>=7.1.0", - "pyarrow>=20.0.0", - "cloudevents>=1.12.0", -] - -[tool.hatch.build.targets.wheel] -packages = ["positionmanager"] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" diff --git a/application/positionmanager/src/positionmanager/__init__.py b/application/positionmanager/src/positionmanager/__init__.py deleted file mode 100644 index 3596aa421..000000000 --- a/application/positionmanager/src/positionmanager/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# This file makes the directory a Python package diff --git a/application/positionmanager/src/positionmanager/clients.py b/application/positionmanager/src/positionmanager/clients.py deleted file mode 100644 index 3dd08199e..000000000 --- a/application/positionmanager/src/positionmanager/clients.py +++ /dev/null @@ -1,154 +0,0 @@ -from typing import TYPE_CHECKING, Any, cast - -import polars as pl -import pyarrow as pa -import requests -from alpaca.trading.client import TradingClient -from alpaca.trading.enums import OrderSide, TimeInForce -from alpaca.trading.requests import MarketOrderRequest - -from .models import DateRange, Money - -if TYPE_CHECKING: - from alpaca.trading.models import Position, TradeAccount - - -class AlpacaClient: - def __init__( - self, - *, - api_key: str | None = None, - api_secret: str | None = None, - paper: bool = True, - ) -> None: - if not api_key or not api_secret: - message = "Alpaca API key and secret are required" - raise ValueError(message) - - self.trading_client: TradingClient = TradingClient( - api_key, - api_secret, - paper=paper, - raw_data=False, - ) - - def get_cash_balance(self) -> Money: - account = self.trading_client.get_account() - cash_balance = getattr(account, "cash", None) - - if cash_balance is None: - message = "Cash balance is not available" - raise ValueError(message) - - return Money.from_float(float(cash_balance)) - - def place_notional_order( - self, - ticker: str, - notional_amount: Money, - ) -> dict[str, Any]: - market_order_request = MarketOrderRequest( - symbol=ticker, - notional=float(notional_amount), - side=OrderSide.BUY, - time_in_force=TimeInForce.DAY, - ) - - self.trading_client.submit_order(market_order_request) - - return { - "status": "success", - "message": f"Order placed [{ticker=}, {notional_amount}]", - } - - def clear_positions(self) -> dict[str, Any]: - self.trading_client.close_all_positions(cancel_orders=True) - - return { - "status": "success", - "message": "All positions have been closed", - } - - def get_account_information(self) -> dict[str, Any]: - account: TradeAccount = cast("TradeAccount", self.trading_client.get_account()) - return { - "portfolio_value": float(account.portfolio_value or 0), - "cash": float(account.cash or 0), - "buying_power": float(account.buying_power or 0), - "equity": float(account.equity or 0), - } - - def get_positions(self) -> list[dict[str, Any]]: - positions: list[Position] = cast( - "list[Position]", - self.trading_client.get_all_positions(), - ) - position_list = [] - - for position in positions: - position_data = { - "symbol": position.symbol, - "quantity": float(position.qty or 0), - "market_value": float(position.market_value or 0), - "cost_basis": float(position.cost_basis or 0), - "unrealized_profit_and_loss": float(position.unrealized_pl or 0), - "unrealized_profit_and_loss_percent": float( - position.unrealized_plpc or 0 - ), - "current_price": float(position.current_price or 0), - "side": position.side.value, - } - position_list.append(position_data) - - return position_list - - -class DataClient: - def __init__(self, datamanager_base_url: str | None) -> None: - self.datamanager_base_url = datamanager_base_url - - def get_data( - self, - date_range: DateRange, - ) -> pl.DataFrame: - if not self.datamanager_base_url: - message = "Data manager URL is not configured" - raise ValueError(message) - - endpoint = f"{self.datamanager_base_url}/equity-bars" - - params = { - "start_date": date_range.start.date().isoformat(), - "end_date": date_range.end.date().isoformat(), - } - - try: - response = requests.get(endpoint, params=params, timeout=30) - except requests.RequestException as err: - message = f"Data manager service call error: {err}" - raise RuntimeError(message) from err - - if response.status_code == requests.codes["no_content"]: - return pl.DataFrame() - if response.status_code != requests.codes["ok"]: - message = f"Data service error: {response.text}, status code: {response.status_code}" # noqa: E501 - raise requests.HTTPError( - message, - response=response, - ) - - buffer = pa.py_buffer(response.content) - reader = pa.ipc.RecordBatchStreamReader(buffer) - table = reader.read_all() - - data = pl.DataFrame(pl.from_arrow(table)) - - data = data.with_columns( - pl.col("datetime").cast(pl.Datetime).dt.date().alias("date") - ) - - return ( - data.sort("date") - .pivot(on="T", index="date", values="c") - .with_columns(pl.all().exclude("date").cast(pl.Float64)) - ) diff --git a/application/positionmanager/src/positionmanager/main.py b/application/positionmanager/src/positionmanager/main.py deleted file mode 100644 index e66351697..000000000 --- a/application/positionmanager/src/positionmanager/main.py +++ /dev/null @@ -1,279 +0,0 @@ -import json -import os -from datetime import datetime, timedelta -from zoneinfo import ZoneInfo - -import polars as pl -import requests -from alpaca.common.exceptions import APIError -from cloudevents.pydantic.v2 import CloudEvent -from fastapi import FastAPI, HTTPException, Response, status -from prometheus_client import Gauge -from prometheus_fastapi_instrumentator import Instrumentator -from pydantic import ValidationError - -from .clients import AlpacaClient, DataClient -from .models import DateRange, Money -from .portfolio import PortfolioOptimizer - -trading_days_per_year = 252 - - -application = FastAPI() -Instrumentator().instrument(application).expose(application) - -portfolio_value_gauge = Gauge( - "portfolio_total_value", - "Current total portfolio value from Alpaca", -) - -portfolio_cash_balance_gauge = Gauge( - "portfolio_cash_balance", - "Current cash balance in portfolio", -) - -portfolio_positions_count_gauge = Gauge( - "portfolio_positions_count", - "Number of current positions in portfolio", -) - -portfolio_position_value_gauge = Gauge( - "portfolio_position_value", - "Value of specific position", - ["symbol"], -) - -portfolio_position_profit_and_loss_gauge = Gauge( - "portfolio_position_profit_and_loss", - "Unrealized P&L for specific position", - ["symbol"], -) - - -@application.get("/health") -def get_health() -> Response: - return Response(status_code=status.HTTP_200_OK) - - -@application.get("/metrics") -def update_metrics() -> Response: - alpaca_client = AlpacaClient( - api_key=os.getenv("ALPACA_API_KEY", ""), - api_secret=os.getenv("ALPACA_API_SECRET", ""), - paper=os.getenv("ALPACA_PAPER", "true").lower() == "true", - ) - - try: - account_information = alpaca_client.get_account_information() - positions = alpaca_client.get_positions() - - portfolio_value_gauge.set(account_information["portfolio_value"]) - portfolio_cash_balance_gauge.set(account_information["cash"]) - portfolio_positions_count_gauge.set(len(positions)) - - position_metrics = [] - for position in positions: - symbol = position["symbol"] - portfolio_position_value_gauge.labels(symbol=symbol).set( - position["market_value"] - ) - portfolio_position_profit_and_loss_gauge.labels(symbol=symbol).set( - position["unrealized_profit_and_loss"] - ) - - position_metrics.append( - { - "symbol": symbol, - "market_value": position["market_value"], - "unrealized_profit_and_loss": position[ - "unrealized_profit_and_loss" - ], - "cost_basis": position["cost_basis"], - "current_price": position["current_price"], - } - ) - - return Response( - status_code=status.HTTP_200_OK, - content=json.dumps( - { - "portfolio_value": [account_information["portfolio_value"]], - "cash_balance": [account_information["cash"]], - "positions_count": [len(positions)], - "positions": position_metrics, - } - ), - media_type="application/json", - ) - - except (requests.RequestException, APIError, ValidationError) as e: - raise HTTPException( - status_code=500, - detail=f"Error updating metrics: {e!r}", - ) from e - - -@application.post("/positions/open") -def open_position(event: CloudEvent) -> CloudEvent: - alpaca_client = AlpacaClient( - api_key=os.getenv("ALPACA_API_KEY", ""), - api_secret=os.getenv("ALPACA_API_SECRET", ""), - paper=os.getenv("ALPACA_PAPER", "true").lower() == "true", - ) - - data_client = DataClient(datamanager_base_url=os.getenv("DATAMANAGER_BASE_URL", "")) - - portfolio_optimizer = PortfolioOptimizer( - minimum_portfolio_tickers=int(os.getenv("MINIMUM_PORTFOLIO_TICKERS", "5")), - maximum_portfolio_tickers=int(os.getenv("MAXIMUM_PORTFOLIO_TICKERS", "20")), - ) - - try: - cash_balance = alpaca_client.get_cash_balance() - - except (requests.RequestException, APIError, ValidationError) as e: - return create_cloud_event_error(f"Error opening position: {e!r}") - - eastern_timezone = ZoneInfo("America/New_York") - - date_range = DateRange( - start=datetime.now(tz=eastern_timezone) - timedelta(days=trading_days_per_year), - end=datetime.now(tz=eastern_timezone), - ) - - try: - historical_data = data_client.get_data(date_range=date_range) - - except (requests.RequestException, APIError, ValidationError) as e: - return create_cloud_event_error(f"Error fetching historical data: {e!r}") - - try: - event_data = event.data - if not isinstance(event_data, dict): - return create_cloud_event_error( - "Invalid event data format, expected a dictionary." - ) - - predictions: dict[str, dict[str, list[float]]] = event_data.get( - "predictions", {} - ) - - predictions_percentile_50 = { - key: value["percentile_50"] for key, value in predictions.items() - } - - optimized_portfolio = portfolio_optimizer.get_optimized_portfolio( - historical_data=historical_data, - portfolio_value=cash_balance, - predictions=predictions_percentile_50, - ) - - except (requests.RequestException, APIError, ValidationError) as e: - return create_cloud_event_error(f"Error optimizing portfolio: {e!r}") - - executed_trades = [] - for ticker, share_count in optimized_portfolio.items(): - if share_count <= 0: - continue - - latest_prices = historical_data.filter(pl.col(ticker).is_not_null()).select( - ticker, - ) - if latest_prices.is_empty(): - executed_trades.append( - { - "ticker": ticker, - "status": "error", - "error": "No recent price available", - }, - ) - continue - - latest_price = latest_prices.tail(1)[0, 0] - - notional_amount = Money.from_float( - latest_price * share_count * 0.95, - ) # 5% buffer - - try: - alpaca_client.place_notional_order(ticker, notional_amount) - - executed_trades.append( - { - "ticker": ticker, - "share_count": share_count, - "notional_amount": float(notional_amount), - "status": "success", - }, - ) - - except (requests.RequestException, APIError, ValidationError) as e: - executed_trades.append( - { - "ticker": ticker, - "share_count": share_count, - "notional_amount": float(notional_amount), - "status": "error", - "error": str(e), - }, - ) - - final_cash_balance = alpaca_client.get_cash_balance() - - return CloudEvent( - attributes={ - "source": "positionmanager", - "type": "application.positionmanager.positions.opened", - }, - data={ - "date": date_range.end.isoformat(), - "initial_cash_balance": float(cash_balance), - "final_cash_balance": float(final_cash_balance), - "optimized_portfolio": optimized_portfolio, - "executed_trades": executed_trades, - "time_period": date_range.to_payload(), - }, - ) - - -@application.post("/positions/close") -def close_positions() -> CloudEvent: - alpaca_client = AlpacaClient( - api_key=os.getenv("ALPACA_API_KEY", ""), - api_secret=os.getenv("ALPACA_API_SECRET", ""), - paper=os.getenv("ALPACA_PAPER", "true").lower() == "true", - ) - - try: - result = alpaca_client.clear_positions() - - except (requests.RequestException, APIError, ValidationError) as e: - return create_cloud_event_error(str(e)) - - cash_balance = alpaca_client.get_cash_balance() - - return CloudEvent( - attributes={ - "source": "positionmanager", - "type": "application.positionmanager.positions.closed", - }, - data={ - "date": datetime.now(tz=ZoneInfo("America/New_York")).isoformat(), - "status": result["status"], - "message": result["message"], - "cash_balance": float(cash_balance), - }, - ) - - -def create_cloud_event_error(error_message: str) -> CloudEvent: - return CloudEvent( - attributes={ - "source": "positionmanager", - "type": "application.positionmanager.positions.errored", - }, - data={ - "date": datetime.now(tz=ZoneInfo("America/New_York")).isoformat(), - "error": error_message, - }, - ) diff --git a/application/positionmanager/src/positionmanager/portfolio.py b/application/positionmanager/src/positionmanager/portfolio.py deleted file mode 100644 index 612171e0b..000000000 --- a/application/positionmanager/src/positionmanager/portfolio.py +++ /dev/null @@ -1,62 +0,0 @@ -import pandas as pd -import polars as pl -from pypfopt import EfficientFrontier, expected_returns, risk_models -from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices - -from .models import Money - - -class PortfolioOptimizer: - def __init__( - self, - minimum_portfolio_tickers: int = 5, - maximum_portfolio_tickers: int = 20, - ) -> None: - self.minimum_portfolio_tickers = minimum_portfolio_tickers - self.maximum_portfolio_tickers = maximum_portfolio_tickers - - def get_optimized_portfolio( - self, - historical_data: pl.DataFrame, - portfolio_value: Money, - predictions: dict[str, list[float]], - prediction_weight: float = 0.3, - ) -> dict[str, int]: - converted_data = historical_data.to_pandas() - - if "date" in converted_data.columns: - converted_data = converted_data.set_index("date") - - mu = expected_returns.mean_historical_return(converted_data, frequency=252) - - prediction_series = pd.Series(predictions).reindex(mu.index).dropna() - for ticker in prediction_series.index: - mu[ticker] = (1 - prediction_weight) * mu[ - ticker - ] + prediction_weight * prediction_series[ticker] - - covariance = risk_models.CovarianceShrinkage(converted_data).ledoit_wolf() - - long_only_weight_bounds = (0, 0.2) # 20% max weight per asset - efficient_frontier = EfficientFrontier( - mu, - covariance, - weight_bounds=long_only_weight_bounds, - ) - - efficient_frontier.max_sharpe(risk_free_rate=0.02) # 2% risk-free rate - weights = efficient_frontier.clean_weights() - - latest_prices = get_latest_prices(converted_data) - - discrete_allocation = DiscreteAllocation( - weights=weights, - latest_prices=latest_prices, - total_portfolio_value=int(float(portfolio_value)), - ) - - optimized_portfolio_ticker_share_counts, _ = ( - discrete_allocation.greedy_portfolio() - ) - - return optimized_portfolio_ticker_share_counts diff --git a/application/positionmanager/tests/test_positionmanager_main.py b/application/positionmanager/tests/test_positionmanager_main.py deleted file mode 100644 index 9359f2e61..000000000 --- a/application/positionmanager/tests/test_positionmanager_main.py +++ /dev/null @@ -1,150 +0,0 @@ -import unittest -from decimal import Decimal -from unittest.mock import MagicMock, patch - -from fastapi import HTTPException, status -from fastapi.testclient import TestClient - -from application.positionmanager.src.positionmanager.clients import AlpacaClient -from application.positionmanager.src.positionmanager.main import application -from application.positionmanager.src.positionmanager.models import Money - -client = TestClient(application) - - -def test_health_check() -> None: - response = client.get("/health") - assert response.status_code == status.HTTP_200_OK - - -class TestCreatePositionsEndpoint(unittest.TestCase): - @patch("application.positionmanager.src.positionmanager.main.AlpacaClient") - @patch("application.positionmanager.src.positionmanager.main.DataClient") - @patch("application.positionmanager.src.positionmanager.main.requests.get") - def test_open_position_success( - self, - mock_requests_get: MagicMock, - MockDataClient: MagicMock, # noqa: N803 - MockAlpacaClient: MagicMock, # noqa: N803 - ) -> None: - mock_alpaca_instance = MagicMock(spec=AlpacaClient) - mock_cash_balance = Money(amount=Decimal("100000.00")) - mock_alpaca_instance.get_cash_balance.return_value = mock_cash_balance - mock_alpaca_instance.place_notional_order.return_value = None - MockAlpacaClient.return_value = mock_alpaca_instance - - mock_data_client_instance = MagicMock() - mock_historical_data = MagicMock() - mock_data_client_instance.get_data.return_value = mock_historical_data - MockDataClient.return_value = mock_data_client_instance - - mock_response = MagicMock() - mock_response.content = b"mock_arrow_data" - mock_response.raise_for_status.return_value = None - mock_requests_get.return_value = mock_response - - with ( - patch( - "application.positionmanager.src.positionmanager.clients.pa.py_buffer" - ), - patch( - "application.positionmanager.src.positionmanager.clients.pa.ipc.RecordBatchStreamReader" - ), - patch( - "application.positionmanager.src.positionmanager.main.pl.DataFrame" - ) as mock_pl_dataframe, - patch( - "application.positionmanager.src.positionmanager.main.PortfolioOptimizer" - ) as MockPortfolioOptimizer, # noqa: N806 - ): - mock_df = MagicMock() - mock_df.unique.return_value.to_list.return_value = ["AAPL", "MSFT"] - mock_pl_dataframe.return_value = mock_df - - mock_optimizer_instance = MagicMock() - mock_optimizer_instance.get_optimized_portfolio.return_value = { - "AAPL": 50.0, - "MSFT": 30.0, - } - MockPortfolioOptimizer.return_value = mock_optimizer_instance - - cloud_event_data = { - "source": "test", - "type": "test.event", - "data": { - "predictions": { - "AAPL": {"percentile_50": [0.1, 0.2, 0.3]}, - "MSFT": {"percentile_50": [0.2, 0.3, 0.4]}, - } - }, - } - response = client.post("/positions/open", json=cloud_event_data) - - assert response.status_code == status.HTTP_200_OK - response_data = response.json() - assert "source" in response_data - assert "type" in response_data - - @patch("application.positionmanager.src.positionmanager.main.AlpacaClient") - def test_open_position_alpaca_error(self, MockAlpacaClient: MagicMock) -> None: # noqa: N803 - mock_alpaca_instance = MagicMock(spec=AlpacaClient) - mock_alpaca_instance.get_cash_balance.side_effect = HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="Error getting cash balance", - ) - MockAlpacaClient.return_value = mock_alpaca_instance - - cloud_event_data = { - "source": "test", - "type": "test.event", - "data": {"predictions": {"AAPL": {"percentile_50": [0.1, 0.2, 0.3]}}}, - } - response = client.post("/positions/open", json=cloud_event_data) - - assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR - assert "Error getting cash balance" in response.json()["detail"] - - MockAlpacaClient.assert_called_once() - mock_alpaca_instance.get_cash_balance.assert_called_once() - - @patch("application.positionmanager.src.positionmanager.main.AlpacaClient") - def test_close_positions_success(self, MockAlpacaClient: MagicMock) -> None: # noqa: N803 - mock_alpaca_instance = MagicMock(spec=AlpacaClient) - mock_alpaca_instance.clear_positions.return_value = { - "status": "success", - "message": "All positions have been closed", - } - mock_cash_balance = Money(amount=Decimal("100000.00")) - mock_alpaca_instance.get_cash_balance.return_value = mock_cash_balance - MockAlpacaClient.return_value = mock_alpaca_instance - - response = client.post("/positions/close") - - assert response.status_code == status.HTTP_200_OK - response_data = response.json() - assert "source" in response_data - assert "type" in response_data - - MockAlpacaClient.assert_called_once() - mock_alpaca_instance.clear_positions.assert_called_once() - mock_alpaca_instance.get_cash_balance.assert_called_once() - - @patch("application.positionmanager.src.positionmanager.main.AlpacaClient") - def test_close_positions_error( - self, - MockAlpacaClient: MagicMock, # noqa: N803 - ) -> None: - mock_alpaca_instance = MagicMock(spec=AlpacaClient) - mock_alpaca_instance.clear_positions.side_effect = HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="Error getting cash balance", - ) - MockAlpacaClient.return_value = mock_alpaca_instance - - response = client.post("/positions/close") - - assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR - assert "Error" in response.json()["detail"] - - MockAlpacaClient.assert_called_once() - mock_alpaca_instance.clear_positions.assert_called_once() diff --git a/application/predictionengine/Dockerfile b/application/predictionengine/Dockerfile deleted file mode 100644 index 0feabfc02..000000000 --- a/application/predictionengine/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM python:3.12.10 - -COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv - -ENV PYTHONPATH=/app/src - -WORKDIR /app - -COPY pyproject.toml ./ - -RUN uv sync --no-dev - -COPY ./src ./src - -COPY ./miniature_temporal_fusion_transformer.safetensor ./src/predictionengine/miniature_temporal_fusion_transformer.safetensor - -EXPOSE 8080 - -ENTRYPOINT ["uv", "run", "uvicorn", "predictionengine.main:application", "--host", "0.0.0.0", "--port", "8080", "--app-dir", "src"] diff --git a/application/predictionengine/compose.yaml b/application/predictionengine/compose.yaml deleted file mode 100644 index ab9695828..000000000 --- a/application/predictionengine/compose.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: Prediction engine integration tests - -services: - predictionengine: - build: - context: . - dockerfile: Dockerfile - ports: - - 8080:8080 - environment: - - DATAMANAGER_BASE_URL=${DATAMANAGER_BASE_URL} - - POSITIONMANAGER_BASE_URL=${POSITIONMANAGER_BASE_URL} - volumes: - - ./:/app/predictionengine - - ~/.config/gcloud/application_default_credentials.json:/root/.config/gcloud/application_default_credentials.json:ro - healthcheck: - test: ["CMD", "curl", "-f", "http://0.0.0.0:8080/health"] - interval: 10s - timeout: 5s - retries: 3 - start_period: 1s diff --git a/application/predictionengine/pyproject.toml b/application/predictionengine/pyproject.toml deleted file mode 100644 index aab789936..000000000 --- a/application/predictionengine/pyproject.toml +++ /dev/null @@ -1,24 +0,0 @@ -[project] -name = "predictionengine" -version = "0.1.0" -description = "Prediction engine service" -requires-python = "==3.12.10" -dependencies = [ - "fastapi>=0.115.12", - "uvicorn>=0.34.2", - "tinygrad>=0.10.3", - "polars>=1.29.0", - "requests>=2.31.0", - "prometheus-fastapi-instrumentator>=7.1.0", - "loguru>=0.7.3", - "numpy>=2.2.6", - "pyarrow>=20.0.0", - "cloudevents>=1.12.0", -] - -[tool.hatch.build.targets.wheel] -packages = ["predictionengine"] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" diff --git a/application/predictionengine/src/predictionengine/dataset.py b/application/predictionengine/src/predictionengine/dataset.py deleted file mode 100644 index 44c272c2b..000000000 --- a/application/predictionengine/src/predictionengine/dataset.py +++ /dev/null @@ -1,318 +0,0 @@ -from collections.abc import Generator -from typing import Any - -import polars as pl -from tinygrad.tensor import Tensor - - -class OrdinalEncoder: # implemented due to category-encoders package dependency issues - def __init__( - self, - columns: list[str] | None = None, - handle_unknown: str = "use_encoded_value", - handle_missing: str = "use_encoded_value", - ) -> None: - self.columns: list[str] = columns or [] - self.mapping_: dict[str, dict[str, int]] = {} - self.handle_unknown: str = handle_unknown - self.handle_missing: str = handle_missing - - def fit_transform(self, transformation_input: pl.DataFrame) -> pl.DataFrame: - result = transformation_input.clone() - - for column in self.columns: - if column not in transformation_input.columns: - continue - - unique_values = ( - transformation_input.select(column) - .drop_nulls() - .unique() - .to_series() - .to_list() - ) - - self.mapping_[column] = { - str(val): idx + 1 for idx, val in enumerate(unique_values) - } - - if self.handle_unknown == "use_encoded_value": - self.mapping_[column]["__unknown__"] = 0 - if self.handle_missing == "use_encoded_value": - self.mapping_[column]["__missing__"] = 0 - - result = result.with_columns( - pl.col(column) - .fill_null("__missing__") - .cast(pl.Utf8) - .map_elements( - lambda x, col=column: self.mapping_[col].get( - str(x), self.mapping_[col].get("__unknown__", 0) - ), - return_dtype=pl.Int32, - ) - .alias(column) - ) - - return result - - def transform(self, transformation_input: pl.DataFrame) -> pl.DataFrame: - result = transformation_input.clone() - - for column in self.columns: - if ( - column not in transformation_input.columns - or column not in self.mapping_ - ): - continue - - result = result.with_columns( - pl.col(column) - .fill_null("__missing__") - .cast(pl.Utf8) - .map_elements( - lambda x, col=column: self.mapping_[col].get( - str(x), self.mapping_[col].get("__unknown__", 0) - ), - return_dtype=pl.Int32, - ) - .alias(column) - ) - - return result - - def inverse_transform(self, transformation_input: pl.DataFrame) -> pl.DataFrame: - result = transformation_input.clone() - - for column in self.columns: - if ( - column not in transformation_input.columns - or column not in self.mapping_ - ): - continue - - reverse_mapping = {v: k for k, v in self.mapping_[column].items()} - - result = result.with_columns( - pl.col(column) - .cast(pl.Int32) - .map_elements( - lambda x, reverse_mapping=reverse_mapping: reverse_mapping.get( - int(x), "__unknown__" - ), - return_dtype=pl.Utf8, - ) - .alias(column) - ) - - return result - - -continuous_variable_columns = [ - "open_price", - "high_price", - "low_price", - "close_price", - "volume", - "volume_weighted_average_price", -] - - -class DataSet: - def __init__( - self, - batch_size: int, - sequence_length: int, - sample_count: int, - scalers: dict[str, dict[str, Tensor]] | None = None, - ) -> None: - self.batch_size: int = batch_size - self.sequence_length: int = sequence_length - self.sample_count: int = sample_count - self.scalers: dict[str, dict[str, Tensor]] = scalers or {} - self.preprocessors: dict[str, Any] = {} - - def __len__(self) -> int: - return (self.sample_count + self.batch_size - 1) // self.batch_size - - def _cast_columns(self, data: pl.DataFrame) -> pl.DataFrame: - return data.with_columns( - [ - pl.col("timestamp").str.strptime(pl.Datetime).cast(pl.Date), - pl.col("open_price").cast(pl.Float64), - pl.col("high_price").cast(pl.Float64), - pl.col("low_price").cast(pl.Float64), - pl.col("close_price").cast(pl.Float64), - pl.col("volume").cast(pl.Float64), - pl.col("volume_weighted_average_price").cast(pl.Float64), - pl.col("ticker").cast(pl.Utf8), - ] - ) - - def _generate_complete_time_series(self, data: pl.DataFrame) -> pl.DataFrame: - data = data.unique(subset=["ticker", "timestamp"]) - - tickers = data.select("ticker").unique() - minimum_timestamp = data.select(pl.col("timestamp").min())[0, 0] - maximum_timestamp = data.select(pl.col("timestamp").max())[0, 0] - - full_dates = pl.DataFrame( - { - "timestamp": pl.date_range( - start=minimum_timestamp, - end=maximum_timestamp, - interval="1d", - closed="both", - eager=True, - ) - } - ) - - full_tickers_and_dates = tickers.join(full_dates, how="cross") - - full_tickers_and_dates = full_tickers_and_dates.with_columns( - [ - pl.col("timestamp") - .rank(method="dense") - .cast(pl.Int32) - .alias("time_index") - - 1 - ] - ) - - data = full_tickers_and_dates.join(data, on=["ticker", "timestamp"], how="left") - data = data.sort(["ticker", "timestamp"]) - - return data.group_by("ticker").map_groups( - lambda df: df.sort("timestamp").with_columns( - [ - pl.col(col) - .interpolate() - .fill_null(strategy="forward") - .fill_null(strategy="backward") - for col in (continuous_variable_columns) - ] - ) - ) - - def _encode_tickers(self, data: pl.DataFrame) -> pl.DataFrame: - ticker_encoder = OrdinalEncoder( - columns=["ticker"], - handle_unknown="use_encoded_value", - handle_missing="use_encoded_value", - ) - self.preprocessors["ticker_encoder"] = ticker_encoder - - ticker_df = data.select("ticker") - encoded_data = ticker_encoder.fit_transform(ticker_df) - - return data.with_columns(encoded_data.select("ticker")) - - def _compute_scalers(self, data: pl.DataFrame) -> None: - if len(self.scalers) == 0: - self.scalers: dict[str, dict[str, Tensor]] = {} - for ticker_key, group in data.group_by("ticker"): - ticker = ticker_key[0] - means = group[continuous_variable_columns].mean() - standard_deviations = group[continuous_variable_columns].std() - - self.scalers[str(ticker)] = { - "means": Tensor(means.to_numpy()), - "standard_deviations": Tensor(standard_deviations.to_numpy()), - } - - def _scale_data(self, data: pl.DataFrame) -> Tensor: - groups: list[Tensor] = [] - for ticker_key, group in data.group_by("ticker"): - ticker = ticker_key[0] - means = self.scalers[str(ticker)]["means"] - standard_deviations = self.scalers[str(ticker)]["standard_deviations"] - - ticker_column = Tensor(group.select("ticker").to_numpy()) - group_data = Tensor(group.select(continuous_variable_columns).to_numpy()) - - scaled_group = (group_data.sub(means)).div(standard_deviations) - - combined_group = ticker_column.cat(scaled_group, dim=1) - groups.append(combined_group) - - if not groups: - message = "No data available after preprocessing" - raise ValueError(message) - - output_data = Tensor.empty(groups[0].shape) - return output_data.cat(*groups, dim=0) - - def load_data(self, data: pl.DataFrame) -> None: - data = self._cast_columns(data) - - self.preprocessors["indices"] = { - col: idx for idx, col in enumerate(data.columns) - } - - data = self._generate_complete_time_series(data) - data = self._encode_tickers(data) - self._compute_scalers(data) - self.data = self._scale_data(data) - - def get_preprocessors(self) -> dict[str, Any]: - if not self.preprocessors: - message = "Preprocessors have not been initialized." - raise ValueError(message) - - means_by_ticker = { - ticker: values["means"] for ticker, values in self.scalers.items() - } - standard_deviations_by_ticker = { - ticker: values["standard_deviations"] - for ticker, values in self.scalers.items() - } - - return { - "means_by_ticker": means_by_ticker, - "standard_deviations_by_ticker": standard_deviations_by_ticker, - "ticker_encoder": self.preprocessors["ticker_encoder"], - "indices": self.preprocessors["indices"], - } - - def batches(self) -> Generator[tuple[Tensor, Tensor, Tensor], None, None]: - close_price_idx = self.preprocessors["indices"]["close_price"] - - for i in range(0, self.sample_count, self.batch_size): - batch_data = self.data[i : i + self.batch_size + self.sequence_length] - - if batch_data.shape[0] < self.batch_size + self.sequence_length: - padding = Tensor.zeros( - ( - self.batch_size + self.sequence_length - batch_data.shape[0], - *batch_data.shape[1:], - ) - ) - - batch_data = batch_data.cat(padding, dim=0) - - tickers = batch_data[: self.batch_size, 0] - - batch_tensors = [ - batch_data[i : i + self.sequence_length, 1:] - for i in range(self.batch_size) - ] - - if not batch_tensors: - message = "Cannot stack empty batch tensors (batch_size must be ≥ 1)" - raise ValueError(message) - if len(batch_tensors) == 1: - historical_features = batch_tensors[0].unsqueeze(0) - else: - historical_features = Tensor.stack( - batch_tensors[0], - *batch_tensors[1:], - dim=0, - ) - - targets = batch_data[: self.batch_size, close_price_idx].reshape( - self.batch_size, - 1, - ) - - yield tickers, historical_features, targets diff --git a/application/predictionengine/src/predictionengine/gated_residual_network.py b/application/predictionengine/src/predictionengine/gated_residual_network.py deleted file mode 100644 index 617399692..000000000 --- a/application/predictionengine/src/predictionengine/gated_residual_network.py +++ /dev/null @@ -1,47 +0,0 @@ -from typing import cast - -from tinygrad.nn import LayerNorm, Linear -from tinygrad.tensor import Tensor - - -class GatedResidualNetwork: - def __init__( - self, - input_size: int, - hidden_size: int, - output_size: int | None = None, - ) -> None: - output_size = output_size if output_size is not None else input_size - - self.input_size = input_size - self.hidden_size = hidden_size - self.output_size = output_size - - self.dense_input = Linear(in_features=input_size, out_features=hidden_size) - self.dense_output = Linear(in_features=hidden_size, out_features=output_size) - self.gate = Linear(in_features=hidden_size, out_features=output_size) - self.layer_normalizer = LayerNorm(normalized_shape=output_size) - - self.residual_projection = None - if input_size != output_size: - self.residual_projection = Linear( - in_features=input_size, out_features=output_size - ) - - def forward( - self, - input_: Tensor, - ) -> Tensor: - hidden_state = self.dense_input(input_).relu() - - output_state = self.dense_output(hidden_state) - - gate_state = self.gate(hidden_state).sigmoid() - - if self.residual_projection is not None: - residual = self.residual_projection(input_) - else: - residual = input_ - - gated_output = cast("Tensor", gate_state * output_state + residual) - return self.layer_normalizer(gated_output) diff --git a/application/predictionengine/src/predictionengine/loss_function.py b/application/predictionengine/src/predictionengine/loss_function.py deleted file mode 100644 index fcbf49546..000000000 --- a/application/predictionengine/src/predictionengine/loss_function.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import cast - -from tinygrad.tensor import Tensor - -Quantiles = tuple[float, float, float] | tuple[float, float, float, float, float] - - -def quantile_loss( - y_pred: Tensor, y_true: Tensor, quantiles: Quantiles | None = None -) -> Tensor: - if quantiles is None: - quantiles = (0.25, 0.5, 0.75) - - if y_pred.shape != y_true.shape: - message = f"Shape mismatch: y_pred {y_pred.shape} vs y_true {y_true.shape}" - raise ValueError(message) - - if not all(0 <= q <= 1 for q in quantiles): - message = "All quantiles must be between 0 and 1" - raise ValueError(message) - - loss: Tensor = Tensor.zeros(1) - error = cast("Tensor", y_true - y_pred) - for quantile in quantiles: - quantile_error = cast("Tensor", quantile * error) - quantile_minus_one_error = cast("Tensor", (quantile - 1) * error) - loss += Tensor.maximum(quantile_error, quantile_minus_one_error).mean() - - return loss diff --git a/application/predictionengine/src/predictionengine/main.py b/application/predictionengine/src/predictionengine/main.py deleted file mode 100644 index 3a3d4eb48..000000000 --- a/application/predictionengine/src/predictionengine/main.py +++ /dev/null @@ -1,223 +0,0 @@ -import os -import traceback -from collections.abc import AsyncGenerator -from contextlib import asynccontextmanager -from datetime import date, datetime, timedelta -from pathlib import Path -from zoneinfo import ZoneInfo - -import polars as pl -import pyarrow as pa -import requests -from cloudevents.pydantic.v2 import CloudEvent -from fastapi import FastAPI, Request, Response, status -from loguru import logger -from prometheus_fastapi_instrumentator import Instrumentator - -from .dataset import DataSet -from .miniature_temporal_fusion_transformer import MiniatureTemporalFusionTransformer - -SEQUENCE_LENGTH = 30 - - -@asynccontextmanager -async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: - app.state.datamanager_base_url = os.getenv("DATAMANAGER_BASE_URL", "") - app.state.model = None - - yield - - if hasattr(app.state, "model"): - app.state.model = None - - -application = FastAPI(lifespan=lifespan) -Instrumentator().instrument(application).expose(application) - - -@application.get("/health") -def get_health() -> Response: - return Response(status_code=status.HTTP_200_OK) - - -def fetch_historical_data( - datamanager_url: str, - start_date: date, - end_date: date, -) -> pl.DataFrame: - url = f"{datamanager_url}/equity-bars" - parameters = { - "start_date": start_date.isoformat(), - "end_date": end_date.isoformat(), - } - - response = requests.get( - url=url, - params=parameters, - timeout=120, - ) - response.raise_for_status() - - buffer = pa.py_buffer(response.content) - reader = pa.ipc.RecordBatchStreamReader(buffer) - table = reader.read_all() - - return pl.DataFrame(pl.from_arrow(table)) - - -def load_or_initialize_model(data: pl.DataFrame) -> MiniatureTemporalFusionTransformer: - dataset = DataSet( - batch_size=32, - sequence_length=SEQUENCE_LENGTH, - sample_count=len(data), - ) - dataset.load_data(data) - preprocessors = dataset.get_preprocessors() - - model = MiniatureTemporalFusionTransformer( - input_size=6, - hidden_size=128, - output_size=3, - layer_count=2, - ticker_count=len(data["ticker"].unique()), - embedding_size=32, - attention_head_count=4, - means_by_ticker=preprocessors["means_by_ticker"], - standard_deviations_by_ticker=preprocessors["standard_deviations_by_ticker"], - ticker_encoder=preprocessors["ticker_encoder"], - dropout_rate=0.0, - ) - model_path = "miniature_temporal_fusion_transformer.safetensor" - if Path(model_path).exists(): - try: - model.load(model_path) - logger.info("Loaded existing model weights") - except Exception as e: # noqa: BLE001 - logger.warning(f"Failed to load model weights: {e}") - - return model - - -def get_predictions( - tickers: list[str], - data: pl.DataFrame, - model: MiniatureTemporalFusionTransformer, -) -> dict[str, dict[str, list[float]]]: - predictions: dict[str, dict[str, list[float]]] = {} - - valid_tickers = [] - for ticker in tickers: - ticker_data = data.filter(pl.col("ticker") == ticker) - if len(ticker_data) < SEQUENCE_LENGTH: - logger.warning(f"Insufficient data for ticker: {ticker}") - continue - valid_tickers.append(ticker) - - if not valid_tickers: - return predictions - - filtered_data = data.filter(pl.col("ticker").is_in(valid_tickers)) - dataset = DataSet( - batch_size=len(valid_tickers), - sequence_length=SEQUENCE_LENGTH, - sample_count=len(valid_tickers), - ) - dataset.load_data(filtered_data) - - try: - tickers_batch, features_batch, _ = next(iter(dataset.batches())) - except StopIteration: - logger.warning("No batches available for prediction") - return predictions - - percentile_25, percentile_50, percentile_75 = model.predict( - tickers_batch, - features_batch, - ) - - for i, ticker in enumerate(valid_tickers): - predictions[ticker] = { - "percentile_25": percentile_25[i].tolist(), - "percentile_50": percentile_50[i].tolist(), - "percentile_75": percentile_75[i].tolist(), - } - - return predictions - - -@application.post("/predictions/create") -def create_predictions(request: Request) -> CloudEvent: - try: - end_date = datetime.now(tz=ZoneInfo("America/New_York")).date() - start_date = end_date - timedelta(days=SEQUENCE_LENGTH) - - logger.info(f"Fetching data start and end dates: {start_date}, {end_date}") - data = fetch_historical_data( - request.app.state.datamanager_base_url, start_date, end_date - ) - - if data.is_empty(): - return CloudEvent( - attributes={ - "source": "predictionengine", - "type": "application.predictionengine.predictions.errored", - }, - data={ - "date": end_date.isoformat(), - "message": "No data available for prediction", - }, - ) - - if request.app.state.model is None: - logger.info("Initializing model") - request.app.state.model = load_or_initialize_model(data) - - model = request.app.state.model - - unique_tickers = data["ticker"].unique().to_list() - - predictions = get_predictions( - tickers=unique_tickers, - data=data, - model=model, - ) - - if not predictions: - return CloudEvent( - attributes={ - "source": "predictionengine", - "type": "application.predictionengine.predictions.errored", - }, - data={ - "date": end_date.isoformat(), - "message": "No predictions could be generated", - }, - ) - - return CloudEvent( - attributes={ - "source": "predictionengine", - "type": "application.predictionengine.predictions.created", - }, - data={ - "date": end_date.isoformat(), - "predictions": predictions, - }, - ) - - except Exception as e: # noqa: BLE001 - logger.error(f"Error creating predictions: {e}") - logger.error(traceback.format_exc()) - - return CloudEvent( - attributes={ - "source": "predictionengine", - "type": "application.predictionengine.predictions.errored", - }, - data={ - "date": datetime.now(tz=ZoneInfo("America/New_York")) - .date() - .isoformat(), - "error": str(e), - }, - ) diff --git a/application/predictionengine/src/predictionengine/miniature_temporal_fusion_transformer.py b/application/predictionengine/src/predictionengine/miniature_temporal_fusion_transformer.py deleted file mode 100644 index bbf9f8e8c..000000000 --- a/application/predictionengine/src/predictionengine/miniature_temporal_fusion_transformer.py +++ /dev/null @@ -1,195 +0,0 @@ -import numpy as np -import numpy.typing as npt -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 .dataset import DataSet, OrdinalEncoder -from .gated_residual_network import GatedResidualNetwork -from .long_short_term_memory import LongShortTermMemory -from .loss_function import quantile_loss -from .multi_head_self_attention import MultiHeadSelfAttention -from .post_processor import PostProcessor -from .ticker_embedding import TickerEmbedding - - -class MiniatureTemporalFusionTransformer: - def __init__( # noqa: PLR0913 - self, - input_size: int, - hidden_size: int, - output_size: int, - layer_count: int, - ticker_count: int, - embedding_size: int, - attention_head_count: int, - means_by_ticker: dict[str, Tensor], - standard_deviations_by_ticker: dict[str, Tensor], - ticker_encoder: OrdinalEncoder, - dropout_rate: float, # non-zero indicates training - ) -> None: - self.ticker_embedding: TickerEmbedding = TickerEmbedding( - ticker_count=ticker_count, - embedding_size=embedding_size, - ) - - self.lstm_encoder: LongShortTermMemory = LongShortTermMemory( - input_size=input_size + embedding_size, - hidden_size=hidden_size, - layer_count=layer_count, - dropout_rate=dropout_rate, - ) - - self.feature_processor: GatedResidualNetwork = GatedResidualNetwork( - input_size=hidden_size, - hidden_size=hidden_size, - output_size=hidden_size, - ) - - self.self_attention: MultiHeadSelfAttention = MultiHeadSelfAttention( - heads_count=attention_head_count, - embedding_size=hidden_size, - ) - - self.output_layer: GatedResidualNetwork = GatedResidualNetwork( - input_size=hidden_size, - hidden_size=hidden_size, - output_size=output_size, - ) - - self.post_processor: PostProcessor = PostProcessor( - means_by_ticker=means_by_ticker, - standard_deviations_by_ticker=standard_deviations_by_ticker, - ticker_encoder=ticker_encoder, - ) - - self.parameters = get_parameters(self) - - def get_parameters(self) -> list[Tensor]: - return self.parameters - - def forward( - self, - tickers: Tensor, - features: Tensor, - ) -> tuple[ - Tensor, - Tensor, - tuple[ - npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64] - ], - ]: - ticker_embeddings = self.ticker_embedding.forward( - tickers - ) # (batch_size, embedding_dim) - ticker_embeddings = ticker_embeddings.unsqueeze(1).expand( - -1, features.size(1), -1 - ) # (batch size, sequence length, embedding dimension) - lstm_input = Tensor.cat(features, ticker_embeddings, dim=-1) - - lstm_output, _ = self.lstm_encoder.forward(lstm_input) - - processed_features = self.feature_processor.forward(lstm_output) - - attention_output, attention_weights = self.self_attention.forward( - processed_features - ) - - output = self.output_layer.forward(attention_output) - - percentile_25, percentile_50, percentile_75 = ( - self.post_processor.post_process_predictions( - tickers.numpy(), - output.numpy(), - ) - ) - - return output, attention_weights, (percentile_25, percentile_50, percentile_75) - - def train( - self, - dataset: DataSet, - epoch_count: int, - learning_rate: float = 1e-3, - ) -> list[float]: - optimizer = Adam(params=self.parameters, lr=learning_rate) - - quantiles: tuple[float, float, float] = (0.25, 0.50, 0.75) - losses: list[float] = [] - - for _ in range(epoch_count): - epoch_loss: float = 0.0 - - for tickers, historical_features, targets in dataset.batches(): - predictions, _, _ = self.forward( - tickers, - historical_features, - ) - - loss: Tensor = quantile_loss(predictions, targets, quantiles) - - optimizer.zero_grad() - _ = loss.backward() - optimizer.step() - - epoch_loss += loss.numpy().item() - - avgerage_epoch_loss: float = epoch_loss / len(dataset) - losses.append(avgerage_epoch_loss) - - return losses - - def validate( - self, - dataset: DataSet, - ) -> float: - total_loss = 0.0 - batch_count = 0 - - for tickers, features, targets in dataset.batches(): - output, _, _ = self.forward(tickers, features) - loss = quantile_loss(output, targets) - total_loss += loss.item() - batch_count += 1 - - return total_loss / batch_count - - def save( - self, - path_and_file: str = "miniature_temporal_fusion_transformer.safetensor", - ) -> None: - states = get_state_dict(self) - safe_save(states, path_and_file) - - def load( - self, - path_and_file: str = "miniature_temporal_fusion_transformer.safetensor", - ) -> None: - states = safe_load(path_and_file) - _ = load_state_dict(self, states) - - def predict( - self, - tickers: Tensor, - input_: Tensor, - ) -> tuple[ - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ]: - predictions, _, _ = self.forward(tickers, input_) - - percentile_25, percentile_50, percentile_75 = ( - self.post_processor.post_process_predictions( - tickers.numpy(), - predictions.numpy(), - ) - ) - - return percentile_25, percentile_50, percentile_75 diff --git a/application/predictionengine/src/predictionengine/multi_head_self_attention.py b/application/predictionengine/src/predictionengine/multi_head_self_attention.py deleted file mode 100644 index 108363a04..000000000 --- a/application/predictionengine/src/predictionengine/multi_head_self_attention.py +++ /dev/null @@ -1,66 +0,0 @@ -from typing import cast - -from tinygrad.dtype import dtypes -from tinygrad.nn import Linear -from tinygrad.tensor import Tensor - - -class MultiHeadSelfAttention: - def __init__( - self, - heads_count: int, - embedding_size: int, - ) -> None: - if embedding_size % heads_count != 0: - message = "Embedding dimension must be divisible by heads count" - raise ValueError(message) - - self.heads_count: int = heads_count - self.embedding_size: int = embedding_size - self.heads_dimension: int = embedding_size // heads_count - - self.query_weight: Linear = Linear(self.embedding_size, self.embedding_size) - self.key_weight: Linear = Linear(self.embedding_size, self.embedding_size) - self.value_weight: Linear = Linear(self.embedding_size, self.embedding_size) - - self.fully_connected_out: Linear = Linear( - self.embedding_size, self.embedding_size - ) - - self.scale: Tensor = Tensor(self.heads_dimension**0.5, dtype=dtypes.float32) - - def forward( - self, - input_: Tensor, - ) -> tuple[Tensor, Tensor]: - batch_size, sequence_length, _ = input_.shape - - query_weights = self.query_weight(input_) - key_weights = self.key_weight(input_) - value_weights = self.value_weight(input_) - - query_weights = query_weights.view( - (batch_size, sequence_length, self.heads_count, self.heads_dimension), - ).transpose(1, 2) - key_weights = key_weights.view( - (batch_size, sequence_length, self.heads_count, self.heads_dimension), - ).transpose(1, 2) - value_weights = value_weights.view( - (batch_size, sequence_length, self.heads_count, self.heads_dimension), - ).transpose(1, 2) - - attention_scores = ( - query_weights.matmul(key_weights.transpose(-2, -1)) / self.scale - ) - - attention_weights: Tensor = cast("Tensor", attention_scores).softmax(axis=-1) - - 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) - - return output, attention_weights diff --git a/application/predictionengine/src/predictionengine/post_processor.py b/application/predictionengine/src/predictionengine/post_processor.py deleted file mode 100644 index ed9b1aece..000000000 --- a/application/predictionengine/src/predictionengine/post_processor.py +++ /dev/null @@ -1,63 +0,0 @@ -import numpy as np -import numpy.typing as npt -import polars as pl -from tinygrad.tensor import Tensor - -from .dataset import OrdinalEncoder - -TensorMapping = dict[str, Tensor] - - -class PostProcessor: - def __init__( - self, - means_by_ticker: TensorMapping, - standard_deviations_by_ticker: TensorMapping, - ticker_encoder: OrdinalEncoder, - ) -> None: - self.means_by_ticker: TensorMapping = means_by_ticker - self.standard_deviations_by_ticker: TensorMapping = ( - standard_deviations_by_ticker - ) - self.ticker_encoder: OrdinalEncoder = ticker_encoder - - def post_process_predictions( - self, - encoded_tickers: npt.NDArray[np.float64], - predictions: npt.NDArray[np.float64], - ) -> tuple[ - npt.NDArray[np.float64], - npt.NDArray[np.float64], - npt.NDArray[np.float64], - ]: - decoded_tickers = ( - self.ticker_encoder.inverse_transform( - transformation_input=pl.DataFrame( - { - "ticker": encoded_tickers, - } - ) - ) - .select("ticker") - .to_series() - .to_list() - ) - - rescaled_predictions = np.empty_like(predictions) - - for i, ticker in enumerate(decoded_tickers): - if ( - ticker not in self.means_by_ticker - or ticker not in self.standard_deviations_by_ticker - ): - message = f"Statistics not found for ticker: {ticker}" - raise ValueError(message) - - mean = self.means_by_ticker[ticker].numpy() - standard_deviation = self.standard_deviations_by_ticker[ticker].numpy() - rescaled_predictions[i, :] = predictions[i, :] * standard_deviation + mean - percentile_25 = np.percentile(rescaled_predictions, 25, axis=-1) - percentile_50 = np.percentile(rescaled_predictions, 50, axis=-1) - percentile_75 = np.percentile(rescaled_predictions, 75, axis=-1) - - return percentile_25, percentile_50, percentile_75 diff --git a/application/predictionengine/src/predictionengine/ticker_embedding.py b/application/predictionengine/src/predictionengine/ticker_embedding.py deleted file mode 100644 index ab57ed073..000000000 --- a/application/predictionengine/src/predictionengine/ticker_embedding.py +++ /dev/null @@ -1,10 +0,0 @@ -from tinygrad.nn import Embedding -from tinygrad.tensor import Tensor - - -class TickerEmbedding: - def __init__(self, ticker_count: int, embedding_size: int) -> None: - self.embedding = Embedding(ticker_count, embedding_size) - - def forward(self, tickers: Tensor) -> Tensor: - return self.embedding(tickers) diff --git a/application/predictionengine/tests/test_dataset.py b/application/predictionengine/tests/test_dataset.py deleted file mode 100644 index 64f8cf20a..000000000 --- a/application/predictionengine/tests/test_dataset.py +++ /dev/null @@ -1,140 +0,0 @@ -from typing import NamedTuple - -import polars as pl -import pytest - -from application.predictionengine.src.predictionengine.dataset import DataSet - - -def test_dataset_initialization() -> None: - dataset = DataSet( - batch_size=2, - sequence_length=3, - sample_count=3, - ) - - assert dataset.batch_size == 2 # noqa: PLR2004 - assert dataset.sequence_length == 3 # noqa: PLR2004 - assert dataset.sample_count == 3 # noqa: PLR2004 - assert len(dataset) == 2 # noqa: PLR2004 - - -def test_dataset_load_data() -> None: - data = pl.DataFrame( - { - "timestamp": [ - "2023-01-01", - "2023-01-02", - "2023-01-03", - "2023-01-01", - "2023-01-02", - "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.0, 1100.0, 1200.0, 500.0, 600.0, 700.0], - "volume_weighted_average_price": [105.0, 106.0, 107.0, 55.0, 56.0, 57.0], - "ticker": ["AAPL", "AAPL", "AAPL", "GOOGL", "GOOGL", "GOOGL"], - } - ) - - dataset = DataSet( - batch_size=1, - sequence_length=3, - sample_count=6, - ) - - dataset.load_data(data) - - assert hasattr(dataset, "data") - assert hasattr(dataset, "preprocessors") - assert "indices" in dataset.preprocessors - assert "ticker_encoder" in dataset.preprocessors - - -def test_dataset_get_preprocessors() -> None: - data = pl.DataFrame( - { - "timestamp": ["2023-01-01", "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.0, 1100.0], - "volume_weighted_average_price": [105.0, 106.0], - "ticker": ["AAPL", "AAPL"], - } - ) - - dataset = DataSet( - batch_size=1, - sequence_length=2, - sample_count=2, - ) - - dataset.load_data(data) - preprocessors = dataset.get_preprocessors() - - assert "means_by_ticker" in preprocessors - assert "standard_deviations_by_ticker" in preprocessors - assert "ticker_encoder" in preprocessors - assert "indices" in preprocessors - - -def test_dataset_batches() -> None: - data = pl.DataFrame( - { - "timestamp": ["2023-01-01", "2023-01-02", "2023-01-03"], - "open_price": [100.0, 101.0, 102.0], - "high_price": [110.0, 111.0, 112.0], - "low_price": [90.0, 91.0, 92.0], - "close_price": [105.0, 106.0, 107.0], - "volume": [1000.0, 1100.0, 1200.0], - "volume_weighted_average_price": [105.0, 106.0, 107.0], - "ticker": ["AAPL", "AAPL", "AAPL"], - } - ) - - dataset = DataSet( - batch_size=1, - sequence_length=2, - sample_count=3, - ) - - dataset.load_data(data) - - class Expected(NamedTuple): - batch_size: int = 1 - sequence_length: int = 2 - sample_count: int = 3 - observations: int = 2 - features: int = 6 - target: int = 1 - - expected = Expected() - - batch_count = 0 - for tickers, features, targets in dataset.batches(): - batch_count += 1 - assert tickers.shape[0] == expected.batch_size - assert features.shape == ( - expected.batch_size, - expected.sequence_length, - expected.features, - ) - assert targets.shape == (expected.batch_size, expected.target) - - assert batch_count > 0 - - -def test_dataset_preprocessors_validation() -> None: - dataset = DataSet( - batch_size=1, - sequence_length=2, - sample_count=2, - ) - - with pytest.raises(ValueError, match="Preprocessors have not been initialized"): - _ = dataset.get_preprocessors() diff --git a/application/predictionengine/tests/test_gated_residual_network.py b/application/predictionengine/tests/test_gated_residual_network.py deleted file mode 100644 index dd6a6d432..000000000 --- a/application/predictionengine/tests/test_gated_residual_network.py +++ /dev/null @@ -1,66 +0,0 @@ -import numpy as np -from numpy.random import PCG64, Generator -from tinygrad.tensor import Tensor - -from application.predictionengine.src.predictionengine.gated_residual_network import ( - GatedResidualNetwork, -) - -rng = Generator(PCG64()) - - -def test_gated_residual_network_initialization() -> None: - input_size = 64 - hidden_size = 128 - output_size = 32 - - grn = GatedResidualNetwork( - input_size=input_size, - hidden_size=hidden_size, - output_size=output_size, - ) - - assert grn.dense_input.weight.shape == (hidden_size, input_size) - - assert grn.dense_output.weight.shape == (output_size, hidden_size) - - assert grn.gate.weight.shape == (output_size, hidden_size) - - -def test_gated_residual_network_forward() -> None: - grn = GatedResidualNetwork(input_size=32, hidden_size=64, output_size=32) - - input_tensor = Tensor(rng.standard_normal((8, 32))) - output = grn.forward(input_tensor) - - assert output.shape == (8, 32) - - -def test_gated_residual_network_different_sizes() -> None: - grn = GatedResidualNetwork(input_size=16, hidden_size=32, output_size=8) - - input_tensor = Tensor(rng.standard_normal((4, 16))) - output = grn.forward(input_tensor) - - assert output.shape == (4, 8) - - -def test_gated_residual_network_single_sample() -> None: - grn = GatedResidualNetwork(input_size=10, hidden_size=20, output_size=10) - - input_tensor = Tensor(rng.standard_normal((1, 10))) - output = grn.forward(input_tensor) - - assert output.shape == (1, 10) - - -def test_gated_residual_network_consistency() -> None: - grn = GatedResidualNetwork(input_size=16, hidden_size=32, output_size=16) - - input_tensor = Tensor(rng.standard_normal((2, 16))) - - output1 = grn.forward(input_tensor) - output2 = grn.forward(input_tensor) - - assert output1.shape == output2.shape - assert np.allclose(output1.numpy(), output2.numpy()) diff --git a/application/predictionengine/tests/test_post_processor.py b/application/predictionengine/tests/test_post_processor.py deleted file mode 100644 index 380b85d74..000000000 --- a/application/predictionengine/tests/test_post_processor.py +++ /dev/null @@ -1,109 +0,0 @@ -import numpy as np -import polars as pl -from tinygrad.tensor import Tensor - -from application.predictionengine.src.predictionengine.dataset import OrdinalEncoder -from application.predictionengine.src.predictionengine.post_processor import ( - PostProcessor, -) - - -def test_post_processor_initialization() -> None: - ticker_encoder = OrdinalEncoder(columns=["ticker"]) - means_by_ticker = {"AAPL": Tensor([150.0])} - standard_deviations_by_ticker = {"AAPL": Tensor([5.0])} - - post_processor = PostProcessor( - means_by_ticker=means_by_ticker, - standard_deviations_by_ticker=standard_deviations_by_ticker, - ticker_encoder=ticker_encoder, - ) - - assert post_processor.means_by_ticker == means_by_ticker - assert post_processor.standard_deviations_by_ticker == standard_deviations_by_ticker - assert post_processor.ticker_encoder == ticker_encoder - - -def test_post_processor_predictions() -> None: - tickers = ["AAPL", "GOOGL"] - - ticker_encoder = OrdinalEncoder(columns=["ticker"]) - ticker_encoder.fit_transform(transformation_input=pl.DataFrame({"ticker": tickers})) - - means_by_ticker = { - "AAPL": Tensor([150.0]), - "GOOGL": Tensor([2800.0]), - } - - standard_deviations_by_ticker = { - "AAPL": Tensor([5.0]), - "GOOGL": Tensor([50.0]), - } - - encoded_tickers = ticker_encoder.transform( - transformation_input=pl.DataFrame({"ticker": tickers}) - )["ticker"].to_numpy() - - predictions = np.array( - [ - [0.0, 1.0, -1.0], # AAPL: mean, +1std, -1std - [0.0, 1.0, -1.0], # GOOGL: mean, +1std, -1std - ] - ) - - post_processor = PostProcessor( - means_by_ticker=means_by_ticker, - standard_deviations_by_ticker=standard_deviations_by_ticker, - ticker_encoder=ticker_encoder, - ) - - percentile_25, percentile_50, percentile_75 = ( - post_processor.post_process_predictions( - encoded_tickers=encoded_tickers, - predictions=predictions, - ) - ) - - assert isinstance(percentile_25, np.ndarray) - assert isinstance(percentile_50, np.ndarray) - assert isinstance(percentile_75, np.ndarray) - - percentile_size = 2 - assert len(percentile_25) == percentile_size - assert len(percentile_50) == percentile_size - assert len(percentile_75) == percentile_size - - assert np.all(percentile_25 <= percentile_50) - assert np.all(percentile_50 <= percentile_75) - - -def test_post_processor_single_ticker() -> None: - ticker_encoder = OrdinalEncoder(columns=["ticker"]) - ticker_encoder.fit_transform( - transformation_input=pl.DataFrame({"ticker": ["AAPL"]}) - ) - - means_by_ticker = {"AAPL": Tensor([100.0])} - standard_deviations_by_ticker = {"AAPL": Tensor([10.0])} - - encoded_tickers = ticker_encoder.transform( - transformation_input=pl.DataFrame({"ticker": ["AAPL"]}) - )["ticker"].to_numpy() - predictions = np.array([[0.5, 1.0, 1.5]]) # single prediction - - post_processor = PostProcessor( - means_by_ticker=means_by_ticker, - standard_deviations_by_ticker=standard_deviations_by_ticker, - ticker_encoder=ticker_encoder, - ) - - percentile_25, percentile_50, percentile_75 = ( - post_processor.post_process_predictions( - encoded_tickers=encoded_tickers, - predictions=predictions, - ) - ) - - assert len(percentile_25) == 1 - assert len(percentile_50) == 1 - assert len(percentile_75) == 1 diff --git a/application/predictionengine/tests/test_predictionengine_main.py b/application/predictionengine/tests/test_predictionengine_main.py deleted file mode 100644 index b579cf236..000000000 --- a/application/predictionengine/tests/test_predictionengine_main.py +++ /dev/null @@ -1,79 +0,0 @@ -import unittest -from unittest.mock import MagicMock, patch - -from fastapi import status -from fastapi.testclient import TestClient - -from application.predictionengine.src.predictionengine.main import application - -client = TestClient(application) - - -def test_health_check() -> None: - response = client.get("/health") - assert response.status_code == status.HTTP_200_OK - - -class TestCreatePredictionsEndpoint(unittest.TestCase): - @patch("application.predictionengine.src.predictionengine.main.requests.get") - def test_create_predictions_success( - self, - mock_requests_get: MagicMock, - ) -> None: - mock_response = MagicMock() - mock_response.content = b"mock_arrow_data" - mock_response.raise_for_status.return_value = None - mock_requests_get.return_value = mock_response - - with ( - patch( - "application.predictionengine.src.predictionengine.main.fetch_historical_data" - ) as mock_fetch_data, - patch( - "application.predictionengine.src.predictionengine.main.load_or_initialize_model" - ) as mock_load_model, - patch( - "application.predictionengine.src.predictionengine.main.get_predictions" - ) as mock_get_predictions, - patch.object(application, "state") as mock_app_state, - ): - mock_app_state.datamanager_base_url = "http://test-datamanager" - mock_app_state.model = None - - mock_df = MagicMock() - mock_df.is_empty.return_value = False - mock_df.unique.return_value.to_list.return_value = ["AAPL", "MSFT"] - mock_fetch_data.return_value = mock_df - - mock_model = MagicMock() - mock_load_model.return_value = mock_model - - mock_get_predictions.return_value = { - "AAPL": { - "percentile_25": 0.7, - "percentile_50": 0.8, - "percentile_75": 0.9, - }, - "MSFT": { - "percentile_25": 0.6, - "percentile_50": 0.75, - "percentile_75": 0.85, - }, - } - - response = client.post("/predictions/create") - - assert response.status_code == status.HTTP_200_OK - response_data = response.json() - assert "source" in response_data - assert "type" in response_data - assert ( - response_data["type"] == "application.predictionengine.predictions.created" - ) - assert "data" in response_data - assert "AAPL" in response_data["data"]["predictions"] - assert "MSFT" in response_data["data"]["predictions"] - - -if __name__ == "__main__": - unittest.main() diff --git a/application/predictionengine/tests/test_ticker_embedding.py b/application/predictionengine/tests/test_ticker_embedding.py deleted file mode 100644 index 5928832d6..000000000 --- a/application/predictionengine/tests/test_ticker_embedding.py +++ /dev/null @@ -1,56 +0,0 @@ -from tinygrad.tensor import Tensor - -from application.predictionengine.src.predictionengine.ticker_embedding import ( - TickerEmbedding, -) - - -def test_ticker_embedding_initialization() -> None: - embedding = TickerEmbedding(ticker_count=100, embedding_size=32) - - assert hasattr(embedding, "embedding") - - -def test_ticker_embedding_forward() -> None: - embedding = TickerEmbedding(ticker_count=10, embedding_size=16) - - ticker_ids: Tensor = Tensor([1]) - result: Tensor = embedding.forward(ticker_ids) - - assert result.shape == (1, 16) - - ticker_ids = Tensor([1, 2, 3]) - result = embedding.forward(ticker_ids) - - assert result.shape == (3, 16) - - -def test_ticker_embedding_different_sizes() -> None: - for embedding_size in [8, 16, 32, 64]: - embedding = TickerEmbedding(ticker_count=50, embedding_size=embedding_size) - ticker_ids = Tensor([0, 1, 2]) - result = embedding.forward(ticker_ids) - - assert result.shape == (3, embedding_size) - - -def test_ticker_embedding_range() -> None: - embedding = TickerEmbedding(ticker_count=5, embedding_size=8) - - for ticker_id in range(5): - ticker_ids = Tensor([ticker_id]) - result = embedding.forward(ticker_ids) - assert result.shape == (1, 8) - - -def test_ticker_embedding_consistency() -> None: - embedding = TickerEmbedding(ticker_count=10, embedding_size=3) - tickers = Tensor([1, 2, 3]) - - result = embedding.forward(tickers) - - assert result.shape == (3, 3) - - for _, ticker_id in enumerate([1, 2, 3]): - individual_result = embedding.forward(Tensor([ticker_id])) - assert individual_result.shape == (1, 3) diff --git a/applications/datamanager/pyproject.toml b/applications/datamanager/pyproject.toml new file mode 100644 index 000000000..cfa946393 --- /dev/null +++ b/applications/datamanager/pyproject.toml @@ -0,0 +1,9 @@ +[project] +name = "datamanager" +version = "0.1.0" +description = "Data collection and management service" +requires-python = "==3.12.10" +dependencies = ["internal"] + +[tool.uv.sources] +internal = { workspace = true } diff --git a/application/predictionengine/miniature_temporal_fusion_transformer.safetensor b/applications/datamanager/src/datamanager/main.py similarity index 100% rename from application/predictionengine/miniature_temporal_fusion_transformer.safetensor rename to applications/datamanager/src/datamanager/main.py diff --git a/applications/models/pyproject.toml b/applications/models/pyproject.toml new file mode 100644 index 000000000..c26828a8f --- /dev/null +++ b/applications/models/pyproject.toml @@ -0,0 +1,22 @@ +[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/get_alpaca_calendar.py b/applications/models/src/models/get_alpaca_calendar.py new file mode 100644 index 000000000..254a7aa80 --- /dev/null +++ b/applications/models/src/models/get_alpaca_calendar.py @@ -0,0 +1,58 @@ +import os +from datetime import datetime, timedelta +from typing import cast +from zoneinfo import ZoneInfo + +import polars as pl +from alpaca.trading import TradingClient +from alpaca.trading.models import Calendar +from alpaca.trading.requests import GetCalendarRequest +from loguru import logger + +if __name__ == "__main__": + 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_client = TradingClient( + api_key=api_key, + secret_key=secret_key, + paper=os.getenv("ALPACA_PAPER", "true").lower() == "true", + ) + + end = datetime.now(tz=ZoneInfo("America/New_York")) + start = end - timedelta(days=365 * 6) + + try: + calendars: list[Calendar] = cast( + "list[Calendar]", + alpaca_client.get_calendar( + GetCalendarRequest( + start=start.date(), + end=end.date(), + ) + ), + ) + + except Exception as e: + logger.error(f"Error fetching Alpaca calendar: {e}") + raise + + calendar_data: list[dict[str, str]] = [ + { + "date": str(calendar.date), + "open": str(calendar.open), + "close": str(calendar.close), + } + for calendar in calendars + ] + + calendar_content = pl.DataFrame(calendar_data) + + calendar_content.write_csv("calendar.csv") + + logger.info("Calendar data has been written to calendar.csv") diff --git a/applications/models/src/models/get_alpaca_equity_bars.py b/applications/models/src/models/get_alpaca_equity_bars.py new file mode 100644 index 000000000..b262b0f7d --- /dev/null +++ b/applications/models/src/models/get_alpaca_equity_bars.py @@ -0,0 +1,136 @@ +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 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_bars = pl.concat([pl.read_csv(fp) for fp in saved_files]) + all_bars.write_csv("equity_bars_combined.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 new file mode 100644 index 000000000..16152a8ff --- /dev/null +++ b/applications/models/src/models/train_tft_model.py @@ -0,0 +1,162 @@ +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.dataset import TemporalFusionTransformerDataset +from internal.tft_model import Parameters, TemporalFusionTransformer + +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) -> TemporalFusionTransformerDataset: + 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 TemporalFusionTransformerDataset(data=data) + + +@task +def train_model( + dataset: TemporalFusionTransformerDataset, + wandb_run: Run, + validation_split: float = 0.8, + epoch_count: int = 10, + learning_rate: float = 1e-3, +) -> TemporalFusionTransformer: + 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 = TemporalFusionTransformer(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: TemporalFusionTransformerDataset, + model: TemporalFusionTransformer, + 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: TemporalFusionTransformer) -> 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/pyproject.toml b/applications/portfoliomanager/pyproject.toml new file mode 100644 index 000000000..997cfba9c --- /dev/null +++ b/applications/portfoliomanager/pyproject.toml @@ -0,0 +1,9 @@ +[project] +name = "portfoliomanager" +version = "0.1.0" +description = "Portfolio prediction and construction service" +requires-python = "==3.12.10" +dependencies = ["internal"] + +[tool.uv.sources] +internal = { workspace = true } diff --git a/workflows/__init__.py b/applications/portfoliomanager/src/portfoliomanager/main.py similarity index 100% rename from workflows/__init__.py rename to applications/portfoliomanager/src/portfoliomanager/main.py diff --git a/cli/datamanager.py b/cli/datamanager.py deleted file mode 100644 index 9664e4ea3..000000000 --- a/cli/datamanager.py +++ /dev/null @@ -1,138 +0,0 @@ -import argparse -import json -from datetime import datetime, timedelta -from urllib.parse import urlparse -from zoneinfo import ZoneInfo - -import boto3 -import requests -from botocore.auth import SigV4Auth -from botocore.awsrequest import AWSRequest -from loguru import logger - - -def sign_request( - method: str, - url: str, - data: dict | None = None, - region: str = "us-east-1", -) -> dict: - session = boto3.Session() - credentials = session.get_credentials() - - request_payload = { - "method": method, - "url": url, - "headers": { - "Content-Type": "application/json", - "Host": urlparse(url).netloc, - }, - } - - if data: - request_payload["data"] = json.dumps(data) - request_payload["headers"]["Content-Type"] = "application/json" - - request = AWSRequest(**request_payload) - SigV4Auth(credentials, "execute-api", region).add_auth(request) - - return { - "method": method, - "url": url, - "headers": dict(request.headers), - "data": request.body, - } - - -def get_health(api_url: str, region: str) -> dict: - signed_request = sign_request(method="GET", url=f"{api_url}/health", region=region) - response = requests.request(**signed_request, timeout=10) - response.raise_for_status() - return response.json() - - -def get_equity_bars(api_url: str, start_date: str, end_date: str, region: str) -> dict: - url = f"{api_url}/equity-bars?start_date={start_date}&end_date={end_date}" - signed_request = sign_request(method="GET", url=url, region=region) - response = requests.request(**signed_request, timeout=30) - response.raise_for_status() - return response.json() - - -def get_metrics(api_url: str, region: str) -> dict: - signed_request = sign_request(method="GET", url=f"{api_url}/metrics", region=region) - response = requests.request(**signed_request, timeout=30) - response.raise_for_status() - return response.json() - - -def fetch_equity_bars(api_url: str, fetch_date: str, region: str) -> dict: - data = {"date": fetch_date} - signed_request = sign_request( - method="POST", - url=f"{api_url}/equity-bars/fetch", - data=data, - region=region, - ) - response = requests.request(**signed_request, timeout=60) - response.raise_for_status() - return response.json() - - -def main() -> None: - parser = argparse.ArgumentParser(description="PocketSizeFund CLI Example") - parser.add_argument("--api-url", required=True, help="API Gateway URL") - parser.add_argument("--region", default="us-east-1", help="AWS region") - parser.add_argument( - "--command", choices=["health", "bars", "metrics", "fetch"], default="health" - ) - parser.add_argument("--start-date", help="Start date for bars (YYYY-MM-DD)") - parser.add_argument("--end-date", help="End date for bars (YYYY-MM-DD)") - parser.add_argument("--fetch-date", help="Date to fetch bars for (YYYY-MM-DD)") - - args = parser.parse_args() - - eastern_timezone = ZoneInfo("America/New_York") - - today = datetime.now(tz=eastern_timezone).date() - try: - if args.command == "health": - result = get_health(args.api_url, args.region) - logger.info(json.dumps(result, indent=2)) - - elif args.command == "metrics": - result = get_metrics(args.api_url, args.region) - logger.info(json.dumps(result, indent=2)) - - elif args.command == "bars": - if not args.start_date or not args.end_date: - # Default to last 7 days - end_date = today - start_date = end_date - timedelta(days=7) - start_date_str = start_date.isoformat() - end_date_str = end_date.isoformat() - else: - start_date_str = args.start_date - end_date_str = args.end_date - - result = get_equity_bars( - args.api_url, start_date_str, end_date_str, args.region - ) - records = result.get("records", []) - logger.info(f"found {len(records)} records") - if records: - logger.info(json.dumps(records[0], indent=2)) - - elif args.command == "fetch": - fetch_date = args.fetch_date or today.isoformat() - result = fetch_equity_bars(args.api_url, fetch_date, args.region) - logger.info(json.dumps(result, indent=2)) - - except requests.exceptions.HTTPError as e: - logger.error(f"http error response: {e.response.text}") - except Exception as e: # noqa: BLE001 - logger.error(f"error: {e}") - - -if __name__ == "__main__": - main() diff --git a/cli/pyproject.toml b/cli/pyproject.toml deleted file mode 100644 index 3aac42fa3..000000000 --- a/cli/pyproject.toml +++ /dev/null @@ -1,10 +0,0 @@ -[project] -name = "cli" -version = "0.1.0" -requires-python = "==3.12.10" -dependencies = [ - "requests>=2.31.0", - "loguru>=0.7.3", - "boto3>=1.38.23", - "botocore>=1.38.23", -] diff --git a/infrastructure/environment_variables.py b/infrastructure/environment_variables.py new file mode 100644 index 000000000..aad13eac0 --- /dev/null +++ b/infrastructure/environment_variables.py @@ -0,0 +1,32 @@ +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 index 87d9a4bea..9bb5e6d2c 100644 --- a/infrastructure/images.py +++ b/infrastructure/images.py @@ -13,7 +13,7 @@ def build_image( dockerhub_username: pulumi.Output[str], dockerhub_password: pulumi.Output[str], ) -> docker_build.Image: - service_directory = Path("../application") / service_name + service_directory = Path("../applications") / service_name if not service_directory.exists(): message = f"Service directory not found: {service_directory}" raise FileNotFoundError(message) diff --git a/libraries/python/pyproject.toml b/libraries/python/pyproject.toml new file mode 100644 index 000000000..fda015fef --- /dev/null +++ b/libraries/python/pyproject.toml @@ -0,0 +1,16 @@ +[project] +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", +] + +[tool.uv] +package = true +src = ["src"] diff --git a/libraries/python/src/internal/__init__.py b/libraries/python/src/internal/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/python/src/internal/cloud_event.py b/libraries/python/src/internal/cloud_event.py new file mode 100644 index 000000000..669ebdeae --- /dev/null +++ b/libraries/python/src/internal/cloud_event.py @@ -0,0 +1,38 @@ +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/dataset.py b/libraries/python/src/internal/dataset.py new file mode 100644 index 000000000..1f9c834e2 --- /dev/null +++ b/libraries/python/src/internal/dataset.py @@ -0,0 +1,326 @@ +from typing import TYPE_CHECKING + +import polars as pl +from tinygrad.tensor import Tensor + +if TYPE_CHECKING: + from datetime import datetime + + +class Scaler: + def __init__(self) -> None: + pass + + def fit(self, data: pl.DataFrame) -> None: + self.means = data.mean() + self.standard_deviations = data.std() + self.standard_deviations = self.standard_deviations.select( + pl.all().replace(0, 1e-8) + ) # avoid division by zero + + def transform(self, data: pl.DataFrame) -> pl.DataFrame: + return (data - self.means) / self.standard_deviations + + def inverse_transform(self, data: pl.DataFrame) -> pl.DataFrame: + return data * self.standard_deviations + self.means + + +class TemporalFusionTransformerDataset: + def __init__(self, data: pl.DataFrame) -> None: + raw_columns = ( + "ticker", + "timestamp", + "open_price", + "high_price", + "low_price", + "close_price", + "volume", + "volume_weighted_average_price", + "sector", + "industry", + "is_holiday", + ) + + if set(data.columns) != set(raw_columns): + message = f"Expected columns {raw_columns} but got {data.columns}" + raise ValueError(message) + + self.continuous_columns = [ + "open_price", + "high_price", + "low_price", + "close_price", + "volume", + "volume_weighted_average_price", + ] + + self.categorical_columns = [ + "day_of_week", + "day_of_month", + "day_of_year", + "month", + "year", + "is_holiday", + ] + + self.static_categorical_columns = [ + "ticker", + "sector", + "industry", + ] + + data = data.with_columns( + pl.col("timestamp").cast(pl.Datetime(time_unit="ms")).alias("datetime") + ) + + minimum_datetime: datetime = data.select(data["datetime"].min()).item() + maximum_datetime: datetime = data.select(data["datetime"].max()).item() + + date_range = pl.DataFrame( + { + "datetime": pl.date_range( + minimum_datetime, + maximum_datetime, + "1d", + eager=True, + ) + } + ) + + expanded_data = date_range.join( + pl.DataFrame({"ticker": data["ticker"].unique()}), + how="cross", + ).with_columns( + pl.col("datetime") + .cast(pl.Datetime) + .cast(pl.Int64) + .floordiv(1000) # milliseconds + .alias("timestamp") + ) + + data = expanded_data.join(data, on=["ticker", "timestamp"], how="left") + data = data.fill_null(strategy="forward") + + friday_number = 4 + + # set is_holiday value for missing weekdays + data = ( + data.with_columns( + pl.col("datetime").dt.weekday().alias("temporary_weekday") + ) + .with_columns( + pl.when( + pl.col("is_holiday").is_null() + & (pl.col("temporary_weekday") <= friday_number) + ) + .then(True) # noqa: FBT003 + .when( + pl.col("is_holiday").is_null() + & (pl.col("temporary_weekday") > friday_number) + ) + .then(False) # noqa: FBT003 + .otherwise(pl.col("is_holiday")) # keep existing values + .alias("is_holiday") + ) + .drop("temporary_weekday") + ) + + data = data.unique(subset=["ticker", "timestamp"]) + + # ensure all rows have values instead of nulls + data = data.with_columns( + [ + pl.col("open_price").fill_null(0.0), + pl.col("high_price").fill_null(0.0), + pl.col("low_price").fill_null(0.0), + 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("ticker").fill_null("UNKNOWN"), + pl.col("is_holiday").fill_null(False), # noqa: FBT003 + ] + ) + + data = data.with_columns( # compute new columns + pl.col("datetime").dt.weekday().alias("day_of_week"), + pl.col("datetime").dt.day().alias("day_of_month"), + pl.col("datetime").dt.ordinal_day().alias("day_of_year"), + pl.col("datetime").dt.month().alias("month"), + pl.col("datetime").dt.year().alias("year"), + ) + + data = data.sort(["ticker", "timestamp"]).with_columns( # add time index column + pl.col("timestamp") + .rank("dense") + .over("ticker") + .cast(pl.Int32) + .alias("time_idx") + ) + + self.scaler = Scaler() + + self.scaler.fit(data[self.continuous_columns]) + + data = data.with_columns( # scale continuous columns + *[ + (pl.col(col) - self.scaler.means[col]) + / self.scaler.standard_deviations[col] + for col in self.continuous_columns + ] + ) + + mapping_columns = [ + "ticker", + "sector", + "industry", + "is_holiday", + ] + + mappings: dict[str, dict[str, int]] = {} + + for column in mapping_columns: + data, mapping = self._create_mapping_and_encoding(data, column) + mappings[column] = mapping + + self.mappings = mappings + + self.data = data + + def _create_mapping_and_encoding( + self, + data: pl.DataFrame, + column: str, + ) -> tuple[pl.DataFrame, dict]: + unique_values = data[column].unique().to_list() + + mapping = {val: idx for idx, val in enumerate(unique_values)} + + data = data.with_columns( + pl.col(column).replace(mapping).cast(pl.Int32).alias(column) + ) + + return data, mapping + + def _get_training_and_validation_data( + self, + validation_split: float = 0.8, + ) -> tuple[pl.DataFrame, pl.DataFrame]: + if validation_split in {0.0, 1.0}: + message = "Validation split must be between 0.0 and 1.0 (exclusive)." + raise ValueError(message) + + minimum_datetime: datetime = self.data.select( + self.data["datetime"].min() + ).item() + maximum_datetime: datetime = self.data.select( + self.data["datetime"].max() + ).item() + + time_difference = maximum_datetime - minimum_datetime + split_datetime = minimum_datetime + (time_difference * validation_split) + + training_data = self.data.filter(pl.col("datetime") <= split_datetime) + validation_data = self.data.filter(pl.col("datetime") > split_datetime) + + return training_data, validation_data + + def _get_prediction_data( + self, + maximum_encoder_length: int = 35, + ) -> pl.DataFrame: + return ( + self.data.sort("timestamp") + .group_by("ticker") + .agg(pl.col("*").tail(maximum_encoder_length)) + .explode([col for col in self.data.columns if col != "ticker"]) + ) + + def get_dimensions(self) -> dict[str, int]: + return { + "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 + "static_categorical_features": len(self.static_categorical_columns), + "static_continuous_features": 0, # not using static_continuous_features for now # noqa: E501 + } + + def get_batches( + self, + data_type: str = "train", # "train", "validate", or "predict" + validation_split: float = 0.8, + input_length: int = 35, + output_length: int = 7, + ) -> 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) + + if data_type == "train": + self.batch_data, _ = self._get_training_and_validation_data( + validation_split + ) + + elif data_type == "validate": + _, self.batch_data = self._get_training_and_validation_data( + validation_split + ) + + elif data_type == "predict": + self.batch_data = self._get_prediction_data(input_length + output_length) + + minimum_date: datetime = self.batch_data.select( + self.batch_data["datetime"].min() + ).item() + maximum_date: datetime = self.batch_data.select( + self.batch_data["datetime"].max() + ).item() + + total_days = (maximum_date - minimum_date).days + 1 + required_days = input_length + output_length + + if total_days < required_days: + message = ( + f"Total days available: {total_days}, required days: {required_days}." + ) + raise ValueError(message) + + for ticker in self.batch_data["ticker"].unique(): + ticker_data = self.batch_data.filter(pl.col("ticker") == ticker).sort( + "time_idx" + ) + + for i in range(len(ticker_data) - input_length - output_length + 1): + encoder_slice = ticker_data[i : i + input_length] + decoder_slice = ticker_data[ + 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 + } + + if data_type in {"train", "validate"}: + batch["targets"] = Tensor(decoder_slice[["close_price"]].to_numpy()) + + batches.append(batch) + + return batches diff --git a/application/datamanager/src/datamanager/models.py b/libraries/python/src/internal/dates.py similarity index 88% rename from application/datamanager/src/datamanager/models.py rename to libraries/python/src/internal/dates.py index f3533debf..de2e3903b 100644 --- a/application/datamanager/src/datamanager/models.py +++ b/libraries/python/src/internal/dates.py @@ -5,7 +5,7 @@ from pydantic_core import core_schema -class SummaryDate(BaseModel): +class Date(BaseModel): date: datetime.date = Field( default_factory=lambda: datetime.datetime.now( ZoneInfo("America/New_York") @@ -48,7 +48,8 @@ def check_end_after_start( raise ValueError(msg) return end_value - -class BarsSummary(BaseModel): - date: str - count: int + 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_bar.py new file mode 100644 index 000000000..2d75c8537 --- /dev/null +++ b/libraries/python/src/internal/equity_bar.py @@ -0,0 +1,49 @@ +from datetime import date + +from pydantic import BaseModel, Field, field_validator + + +class EquityBar(BaseModel): + ticker: str = Field(..., description="The stock symbol") + timestamp: date = Field(..., description="The date of the bar in YYYY-MM-DD format") + open_price: float = Field(..., description="The opening price") + high_price: float = Field(..., description="The highest price") + low_price: float = Field(..., description="The lowest price") + close_price: float = Field(..., description="The closing price") + volume: float = Field(..., description="The trading volume") + volume_weighted_average_price: float = Field( + ..., description="The volume-weighted average price" + ) + + @field_validator("ticker", mode="before") + @classmethod + def validate_ticker(cls, value: str) -> str: + if not value or not value.strip(): + message = "Ticker cannot be empty." + raise ValueError(message) + return value.strip().upper() + + @field_validator( + "open_price", + "high_price", + "low_price", + "close_price", + mode="before", + ) + @classmethod + def validate_prices(cls, value: float) -> float: + if value < 0: + message = "Price cannot be negative." + raise ValueError(message) + return value + + @field_validator("timestamp", mode="before") + @classmethod + def validate_timestamp(cls, value: date | str) -> date: + if isinstance(value, date): + return value + try: + return date.fromisoformat(value) + except ValueError as e: + message = "Invalid date format: expected YYYY-MM-DD" + raise ValueError(message) from e diff --git a/libraries/python/src/internal/loss_functions.py b/libraries/python/src/internal/loss_functions.py new file mode 100644 index 000000000..a11559e6d --- /dev/null +++ b/libraries/python/src/internal/loss_functions.py @@ -0,0 +1,28 @@ +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/application/predictionengine/src/predictionengine/long_short_term_memory.py b/libraries/python/src/internal/lstm_network.py similarity index 59% rename from application/predictionengine/src/predictionengine/long_short_term_memory.py rename to libraries/python/src/internal/lstm_network.py index c19e6e24f..c00119130 100644 --- a/application/predictionengine/src/predictionengine/long_short_term_memory.py +++ b/libraries/python/src/internal/lstm_network.py @@ -2,14 +2,19 @@ from tinygrad.tensor import Tensor -class LongShortTermMemory: +class LSTM: def __init__( self, input_size: int, hidden_size: int, - layer_count: int = 1, + 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 @@ -17,25 +22,36 @@ def __init__( 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, self.hidden_size)) + self.layers.append( + LSTMCell( + input_size=input_size, + hidden_size=self.hidden_size, + ) + ) def forward( self, - input_: Tensor, - ) -> tuple[Tensor, tuple[Tensor, Tensor]]: - batch_size, sequence_length, _ = input_.shape + inputs: Tensor, + state: tuple[list[Tensor], list[Tensor]] | None = None, + ) -> tuple[Tensor, tuple[list[Tensor], list[Tensor]]]: + batch_size, sequence_length, _ = inputs.shape - hidden_state = Tensor.zeros( - self.layer_count, batch_size, self.hidden_size - ).contiguous() - cell_state = Tensor.zeros( - self.layer_count, batch_size, self.hidden_size - ).contiguous() + 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 = input_[:, t] + layer_input = inputs[:, t] for index, layer in enumerate(self.layers): layer_hidden_state, layer_cell_state = layer( @@ -62,7 +78,7 @@ def forward( raise ValueError(message) if len(outputs) == 1: - output_tensor = outputs[0].unsqueeze(1) + output_tensor = outputs[0].unsqueeze(dim=1) else: output_tensor = Tensor.stack(outputs[0], *outputs[1:], dim=1) diff --git a/libraries/python/src/internal/mhsa_network.py b/libraries/python/src/internal/mhsa_network.py new file mode 100644 index 000000000..89e50b97b --- /dev/null +++ b/libraries/python/src/internal/mhsa_network.py @@ -0,0 +1,64 @@ +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/application/positionmanager/src/positionmanager/models.py b/libraries/python/src/internal/money.py similarity index 57% rename from application/positionmanager/src/positionmanager/models.py rename to libraries/python/src/internal/money.py index a5ddcb591..325d0c8f5 100644 --- a/application/positionmanager/src/positionmanager/models.py +++ b/libraries/python/src/internal/money.py @@ -1,8 +1,6 @@ -from datetime import datetime from decimal import ROUND_HALF_UP, Decimal from pydantic import BaseModel, Field, field_validator -from pydantic_core import core_schema class Money(BaseModel): @@ -33,28 +31,3 @@ def from_float(cls, value: float) -> "Money": def to_dict(self) -> dict[str, float]: return {"amount": float(self.amount)} - - -class DateRange(BaseModel): - start: datetime - end: datetime - - @field_validator("end") - @classmethod - def check_end_after_start( - cls, - end_value: datetime, - info: core_schema.ValidationInfo, - ) -> 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_payload(self) -> dict[str, str]: - return { - "start_date": self.start.isoformat(), - "end_date": self.end.isoformat(), - } diff --git a/libraries/python/src/internal/summaries.py b/libraries/python/src/internal/summaries.py new file mode 100644 index 000000000..fc6196467 --- /dev/null +++ b/libraries/python/src/internal/summaries.py @@ -0,0 +1,6 @@ +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 new file mode 100644 index 000000000..47ad83657 --- /dev/null +++ b/libraries/python/src/internal/tft_model.py @@ -0,0 +1,273 @@ +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 # closing price + 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 TemporalFusionTransformer: + 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"] + # TODO: static_continuous_features = Tensor.zeros(self.batch_size, 1, 0) # noqa: E501, FIX002 + + 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), + # sequence, # NOTE: unused (?) # noqa: ERA001 + # sequence, # NOTE: unused (?) # noqa: ERA001 + ) + + 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 new file mode 100644 index 000000000..13035c00f --- /dev/null +++ b/libraries/python/src/internal/variable_selection_network.py @@ -0,0 +1,21 @@ +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_dataset.py b/libraries/python/tests/test_dataset.py new file mode 100644 index 000000000..120034087 --- /dev/null +++ b/libraries/python/tests/test_dataset.py @@ -0,0 +1,134 @@ +import polars as pl +from internal.dataset import TemporalFusionTransformerDataset + + +def test_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.0, 1100.0, 1200.0, 500.0, 600.0, 700.0], + "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", + ], + "is_holiday": [True, False, False, True, False, False], + } + ) + + dataset = TemporalFusionTransformerDataset(data=data) + + assert hasattr(dataset, "data") + assert hasattr(dataset, "mappings") + + +def test_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.0, 1100.0], + "volume_weighted_average_price": [105.0, 106.0], + "ticker": ["AAPL", "AAPL"], + "sector": ["Technology", "Technology"], + "industry": ["Consumer Electronics", "Consumer Electronics"], + "is_holiday": [True, False], + } + ) + + dataset = TemporalFusionTransformerDataset(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_dataset_batches() -> None: + data = pl.DataFrame( + { + "timestamp": [ + 1672531200000, # 2023-01-01 + 1672617600000, # 2023-01-02 + 1672704000000, # 2023-01-03 + ], + "open_price": [100.0, 101.0, 102.0], + "high_price": [110.0, 111.0, 112.0], + "low_price": [90.0, 91.0, 92.0], + "close_price": [105.0, 106.0, 107.0], + "volume": [1000.0, 1100.0, 1200.0], + "volume_weighted_average_price": [105.0, 106.0, 107.0], + "ticker": ["AAPL", "AAPL", "AAPL"], + "sector": ["Technology", "Technology", "Technology"], + "industry": [ + "Consumer Electronics", + "Consumer Electronics", + "Consumer Electronics", + ], + "is_holiday": [True, False, False], + } + ) + + dataset = TemporalFusionTransformerDataset(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 diff --git a/libraries/python/tests/test_dates.py b/libraries/python/tests/test_dates.py new file mode 100644 index 000000000..b1a4bc21c --- /dev/null +++ b/libraries/python/tests/test_dates.py @@ -0,0 +1,109 @@ +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_bar.py new file mode 100644 index 000000000..2862ed0fd --- /dev/null +++ b/libraries/python/tests/test_equity_bar.py @@ -0,0 +1,202 @@ +from datetime import date + +import pytest +from internal.equity_bar import EquityBar +from pydantic import ValidationError + + +def test_equity_bar_valid_creation() -> None: + open_price = 150.0 + high_price = 155.0 + low_price = 149.0 + close_price = 153.0 + volume = 1000000 + volume_weighted_average_price = 152.5 + + equity_bar = EquityBar( + ticker="AAPL", + timestamp=date(2023, 1, 15), + open_price=open_price, + high_price=high_price, + low_price=low_price, + close_price=close_price, + volume=volume, + volume_weighted_average_price=volume_weighted_average_price, + ) + + assert equity_bar.ticker == "AAPL" + assert equity_bar.timestamp == date(2023, 1, 15) + assert equity_bar.open_price == open_price + assert equity_bar.high_price == high_price + assert equity_bar.low_price == low_price + assert equity_bar.close_price == close_price + assert equity_bar.volume == volume + assert equity_bar.volume_weighted_average_price == volume_weighted_average_price + + +def test_equity_bar_ticker_validation_uppercase() -> None: + equity_bar = EquityBar( + ticker="aapl", + timestamp=date(2023, 1, 15), + open_price=150.0, + high_price=155.0, + low_price=149.0, + close_price=153.0, + volume=1000000, + volume_weighted_average_price=152.5, + ) + + assert equity_bar.ticker == "AAPL" + + +def test_equity_bar_ticker_validation_strip_whitespace() -> None: + equity_bar = EquityBar( + ticker=" GOOGL ", + timestamp=date(2023, 1, 15), + open_price=100.0, + high_price=105.0, + low_price=99.0, + close_price=103.0, + volume=500000, + volume_weighted_average_price=102.0, + ) + + assert equity_bar.ticker == "GOOGL" + + +def test_equity_bar_ticker_validation_empty() -> None: + with pytest.raises(ValidationError) as exc_info: + EquityBar( + ticker="", + timestamp=date(2023, 1, 15), + open_price=150.0, + high_price=155.0, + low_price=149.0, + close_price=153.0, + volume=1000000, + volume_weighted_average_price=152.5, + ) + + assert "Ticker cannot be empty" in str(exc_info.value) + + +def test_equity_bar_ticker_validation_whitespace_only() -> None: + with pytest.raises(ValidationError) as exc_info: + EquityBar( + ticker=" ", + timestamp=date(2023, 1, 15), + open_price=150.0, + high_price=155.0, + low_price=149.0, + close_price=153.0, + volume=1000000, + volume_weighted_average_price=152.5, + ) + + assert "Ticker cannot be empty" in str(exc_info.value) + + +def test_equity_bar_negative_price_validation() -> None: + with pytest.raises(ValidationError) as exc_info: + EquityBar( + ticker="AAPL", + timestamp=date(2023, 1, 15), + open_price=-150.0, + high_price=155.0, + low_price=149.0, + close_price=153.0, + volume=1000000, + volume_weighted_average_price=152.5, + ) + + assert "Price cannot be negative" in str(exc_info.value) + + +def test_equity_bar_zero_price_allowed() -> None: + equity_bar = EquityBar( + ticker="AAPL", + timestamp=date(2023, 1, 15), + open_price=0.0, + high_price=0.0, + low_price=0.0, + close_price=0.0, + volume=1000000, + volume_weighted_average_price=0.0, + ) + + assert equity_bar.open_price == 0.0 + assert equity_bar.high_price == 0.0 + assert equity_bar.low_price == 0.0 + assert equity_bar.close_price == 0.0 + + +def test_equity_bar_timestamp_string_iso_format() -> None: + equity_bar = EquityBar( + ticker="AAPL", + timestamp=date.fromisoformat("2023-06-15"), + open_price=150.0, + high_price=155.0, + low_price=149.0, + close_price=153.0, + volume=1000000, + volume_weighted_average_price=152.5, + ) + + assert equity_bar.timestamp == date(2023, 6, 15) + + +def test_equity_bar_all_price_fields_negative() -> None: + price_fields = ["open_price", "high_price", "low_price", "close_price"] + + for field in price_fields: + kwargs = { + "ticker": "AAPL", + "timestamp": date(2023, 1, 15), + "open_price": 150.0, + "high_price": 155.0, + "low_price": 149.0, + "close_price": 153.0, + "volume": 1000000, + "volume_weighted_average_price": 152.5, + } + kwargs[field] = -1.0 + + with pytest.raises(ValidationError) as exc_info: + EquityBar(**kwargs) + + assert "Price cannot be negative" in str(exc_info.value) + + +def test_equity_bar_large_volume() -> None: + volume = 10**12 # Large volume for testing + + equity_bar = EquityBar( + ticker="NVDA", + timestamp=date(2023, 1, 15), + open_price=300.0, + high_price=305.0, + low_price=299.0, + close_price=303.0, + volume=volume, + volume_weighted_average_price=302.0, + ) + + assert equity_bar.volume == volume + + +def test_equity_bar_special_ticker_symbols() -> None: + special_tickers = ["brk.b", "BF-B", "META"] + + for ticker in special_tickers: + equity_bar = EquityBar( + ticker=ticker, + timestamp=date(2023, 1, 15), + open_price=100.0, + high_price=105.0, + low_price=99.0, + close_price=103.0, + volume=1000000, + volume_weighted_average_price=102.0, + ) + + assert equity_bar.ticker == ticker.upper() diff --git a/application/predictionengine/tests/test_loss_function.py b/libraries/python/tests/test_loss_functions.py similarity index 63% rename from application/predictionengine/tests/test_loss_function.py rename to libraries/python/tests/test_loss_functions.py index d9e5bd43f..f618fb9e9 100644 --- a/application/predictionengine/tests/test_loss_function.py +++ b/libraries/python/tests/test_loss_functions.py @@ -1,19 +1,16 @@ import numpy as np import pytest +from internal.loss_functions import quantile_loss from numpy.random import PCG64, Generator from tinygrad.tensor import Tensor -from application.predictionengine.src.predictionengine.loss_function import ( - quantile_loss, -) - rng = Generator(PCG64()) def test_quantile_loss_basic() -> None: - predictions = Tensor([[1.0], [2.0], [3.0]]) + 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) + quantiles = [0.25, 0.5, 0.75] loss = quantile_loss(predictions, targets, quantiles) @@ -22,9 +19,9 @@ def test_quantile_loss_basic() -> None: def test_quantile_loss_multiple_samples() -> None: - predictions = Tensor([[1.0], [2.0]]) + 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) + quantiles = [0.25, 0.5, 0.75] loss: Tensor = quantile_loss(predictions, targets, quantiles) @@ -33,9 +30,9 @@ def test_quantile_loss_multiple_samples() -> None: def test_quantile_loss_perfect_prediction() -> None: - predictions = Tensor([[2.0]]) + predictions = Tensor([[[2.0, 2.0, 2.0]]]) targets = Tensor([[2.0]]) - quantiles = (0.25, 0.5, 0.75) + quantiles = [0.25, 0.5, 0.75] loss = quantile_loss(predictions, targets, quantiles) @@ -43,9 +40,9 @@ def test_quantile_loss_perfect_prediction() -> None: def test_quantile_loss_different_quantiles() -> None: - predictions = Tensor([[3.0]]) + 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) + quantiles = [0.1, 0.25, 0.5, 0.75, 0.9] loss = quantile_loss(predictions, targets, quantiles) @@ -55,27 +52,18 @@ def test_quantile_loss_different_quantiles() -> None: def test_quantile_loss_shapes() -> None: for batch_size in [1, 2, 4, 8]: - predictions = Tensor(rng.standard_normal((batch_size, 1)).astype(np.float32)) + 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) + quantiles = [0.25, 0.5, 0.75] loss = quantile_loss(predictions, targets, quantiles) assert isinstance(loss, Tensor) -def test_quantile_loss_shape_mismatch() -> None: - predictions = Tensor([[1.0, 2.0, 3.0]]) - targets = Tensor([[2.0]]) - quantiles = (0.25, 0.5, 0.75) - - with pytest.raises(ValueError, match="Shape mismatch"): - quantile_loss(predictions, targets, quantiles) - - def test_quantile_loss_invalid_quantiles() -> None: - predictions = Tensor([[1.0]]) + predictions = Tensor([[[1.0, 1.2, 1.3]]]) targets = Tensor([[2.0]]) - quantiles = (0.25, 1.5, 0.75) # Invalid quantile > 1 + 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/application/predictionengine/tests/test_long_short_term_memory.py b/libraries/python/tests/test_lstm_network.py similarity index 69% rename from application/predictionengine/tests/test_long_short_term_memory.py rename to libraries/python/tests/test_lstm_network.py index bebabf759..3378b4e50 100644 --- a/application/predictionengine/tests/test_long_short_term_memory.py +++ b/libraries/python/tests/test_lstm_network.py @@ -1,27 +1,27 @@ 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 -from application.predictionengine.src.predictionengine.long_short_term_memory import ( - LongShortTermMemory, -) - rng = Generator(PCG64()) def test_lstm_initialization() -> None: - lstm = LongShortTermMemory( - input_size=32, hidden_size=64, layer_count=2, dropout_rate=0.1 + 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 = 2 + layer_count: int = 3 dropout_rate: float = 0.1 - expected = Expected(hidden_state=64, layer_count=2, dropout_rate=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 @@ -29,8 +29,11 @@ class Expected(NamedTuple): def test_lstm_forward() -> None: - lstm = LongShortTermMemory( - input_size=16, hidden_size=32, layer_count=1, dropout_rate=0.0 + lstm = LSTM( + input_size=16, + hidden_size=32, + layer_count=3, + dropout_rate=0.0, ) input_tensor = Tensor(rng.standard_normal((4, 10, 16))) @@ -44,8 +47,11 @@ def test_lstm_forward() -> None: def test_lstm_different_sequence_lengths() -> None: - lstm = LongShortTermMemory( - input_size=8, hidden_size=16, layer_count=1, dropout_rate=0.0 + lstm = LSTM( + input_size=8, + hidden_size=16, + layer_count=3, + dropout_rate=0.0, ) for sequence_length in [5, 10, 20]: @@ -56,8 +62,11 @@ def test_lstm_different_sequence_lengths() -> None: def test_lstm_multiple_layers() -> None: - lstm = LongShortTermMemory( - input_size=10, hidden_size=20, layer_count=3, dropout_rate=0.0 + lstm = LSTM( + input_size=10, + hidden_size=20, + layer_count=3, + dropout_rate=0.0, ) input_tensor = Tensor(rng.standard_normal((2, 5, 10))) @@ -68,8 +77,11 @@ def test_lstm_multiple_layers() -> None: def test_lstm_single_timestep() -> None: - lstm = LongShortTermMemory( - input_size=12, hidden_size=24, layer_count=1, dropout_rate=0.0 + lstm = LSTM( + input_size=12, + hidden_size=24, + layer_count=3, + dropout_rate=0.0, ) input_tensor = Tensor(rng.standard_normal((3, 1, 12))) @@ -79,8 +91,11 @@ def test_lstm_single_timestep() -> None: def test_lstm_consistency() -> None: - lstm = LongShortTermMemory( - input_size=6, hidden_size=12, layer_count=1, dropout_rate=0.0 + lstm = LSTM( + input_size=6, + hidden_size=12, + layer_count=3, + dropout_rate=0.0, ) input_tensor = Tensor(rng.standard_normal((1, 3, 6))) diff --git a/application/predictionengine/tests/test_multi_head_self_attention.py b/libraries/python/tests/test_mhsa_network.py similarity index 78% rename from application/predictionengine/tests/test_multi_head_self_attention.py rename to libraries/python/tests/test_mhsa_network.py index 11a257a22..05a03292d 100644 --- a/application/predictionengine/tests/test_multi_head_self_attention.py +++ b/libraries/python/tests/test_mhsa_network.py @@ -1,24 +1,21 @@ +from internal.mhsa_network import MultiHeadSelfAttentionNetwork from numpy.random import PCG64, Generator from tinygrad.tensor import Tensor -from application.predictionengine.src.predictionengine.multi_head_self_attention import ( # noqa: E501 - MultiHeadSelfAttention, -) - rng = Generator(PCG64()) def test_multi_head_attention_initialization() -> None: heads_count = 8 embedding_size = 64 - attention = MultiHeadSelfAttention(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 = MultiHeadSelfAttention(heads_count=4, embedding_size=32) + attention = MultiHeadSelfAttentionNetwork(heads_count=4, embedding_size=32) input_tensor = Tensor(rng.standard_normal((2, 10, 32))) output, attention_weights = attention.forward(input_tensor) @@ -34,7 +31,7 @@ def test_multi_head_attention_forward() -> None: def test_multi_head_attention_different_heads() -> None: for heads_count in [1, 2, 4, 8]: embedding_size = 32 - attention = MultiHeadSelfAttention( + attention = MultiHeadSelfAttentionNetwork( heads_count=heads_count, embedding_size=embedding_size ) @@ -46,7 +43,7 @@ def test_multi_head_attention_different_heads() -> None: def test_multi_head_attention_single_sequence() -> None: - attention = MultiHeadSelfAttention(heads_count=2, embedding_size=16) + attention = MultiHeadSelfAttentionNetwork(heads_count=2, embedding_size=16) input_tensor = Tensor(rng.standard_normal((1, 1, 16))) output, _ = attention.forward(input_tensor) @@ -55,7 +52,7 @@ def test_multi_head_attention_single_sequence() -> None: def test_multi_head_attention_longer_sequences() -> None: - attention = MultiHeadSelfAttention(heads_count=4, embedding_size=64) + 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))) @@ -65,7 +62,7 @@ def test_multi_head_attention_longer_sequences() -> None: def test_multi_head_attention_batch_processing() -> None: - attention = MultiHeadSelfAttention(heads_count=2, embedding_size=32) + 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))) diff --git a/libraries/python/tests/test_variable_selection_network.py b/libraries/python/tests/test_variable_selection_network.py new file mode 100644 index 000000000..262078b32 --- /dev/null +++ b/libraries/python/tests/test_variable_selection_network.py @@ -0,0 +1,193 @@ +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/pyproject.toml b/pyproject.toml index cb47eb985..5420341f9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,39 +3,19 @@ name = "pocketsizefund" version = "20250602.4" description = "Open source quantitative hedge fund 🍊" requires-python = "==3.12.10" - -[tool.uv.workspace] -members = [ - "infrastructure", - "application/datamanager", - "application/positionmanager", - "application/predictionengine", - "workflows", - "cli", -] +dependencies = ["internal"] [tool.uv.sources] -datamanager = { workspace = true } -positionmanager = { workspace = true } -predictionengine = { workspace = true } -workflows = { workspace = true } +internal = { workspace = true } -[tool.hatch.build.targets.wheel] -packages = ["pocketsizefund"] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" +[tool.uv.workspace] +members = ["applications/*", "libraries/python"] [dependency-groups] dev = ["coverage>=7.8.0", "pytest>=8.3.5", "behave>=1.2.6"] [tool.pytest.ini_options] -testpaths = [ - "application/datamanager/tests", - "application/positionmanager/tests", - "application/predictionengine/tests", -] +testpaths = ["applications/*/tests", "libraries/python/tests"] python_files = ["test_*.py"] python_classes = ["Test*"] python_functions = ["test_*"] diff --git a/uv.lock b/uv.lock index a2fce8198..e291f3446 100644 --- a/uv.lock +++ b/uv.lock @@ -1,16 +1,18 @@ version = 1 revision = 2 requires-python = "==3.12.10" +resolution-markers = [ + "sys_platform == 'linux'", + "sys_platform != 'linux'", +] [manifest] members = [ - "cli", "datamanager", - "infrastructure", + "internal", + "models", "pocketsizefund", - "positionmanager", - "predictionengine", - "workflows", + "portfoliomanager", ] [[package]] @@ -32,7 +34,7 @@ wheels = [ [[package]] name = "aiobotocore" -version = "2.23.0" +version = "2.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -43,18 +45,9 @@ dependencies = [ { name = "python-dateutil" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/25/4b06ea1214ddf020a28df27dc7136ac9dfaf87929d51e6f6044dd350ed67/aiobotocore-2.23.0.tar.gz", hash = "sha256:0333931365a6c7053aee292fe6ef50c74690c4ae06bb019afdf706cb6f2f5e32", size = 115825, upload-time = "2025-06-12T23:46:38.055Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/43/ccf9b29669cdb09fd4bfc0a8effeb2973b22a0f3c3be4142d0b485975d11/aiobotocore-2.23.0-py3-none-any.whl", hash = "sha256:8202cebbf147804a083a02bc282fbfda873bfdd0065fd34b64784acb7757b66e", size = 84161, upload-time = "2025-06-12T23:46:36.305Z" }, -] - -[[package]] -name = "aiofiles" -version = "24.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247, upload-time = "2024-06-24T11:02:03.584Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/ca/ac82c0c699815b6d5b4017f3d8fb2c2d49537f4937f4a0bdf58b4c75d321/aiobotocore-2.24.0.tar.gz", hash = "sha256:b32c0c45d38c22a18ce395a0b5448606c5260603296a152895b5bdb40ab3139d", size = 119597, upload-time = "2025-08-08T18:26:50.373Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896, upload-time = "2024-06-24T11:02:01.529Z" }, + { url = "https://files.pythonhosted.org/packages/e2/68/b29577197aa2e54b50d6f214524790cc1cb27d289585ad7c7bdfe5125285/aiobotocore-2.24.0-py3-none-any.whl", hash = "sha256:72bb1f8eb1b962779a95e1bcc9cf35bc33196ad763b622a40ae7fa9d2e95c87c", size = 84971, upload-time = "2025-08-08T18:26:48.777Z" }, ] [[package]] @@ -68,7 +61,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.12.1" +version = "3.12.15" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -79,25 +72,25 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d1/c8/f681bcfdbc8cc2d8d9310710020fa895be2862b5b291ff278dc1ef66e8dc/aiohttp-3.12.1.tar.gz", hash = "sha256:85b8256d911ae4462cdd39a2ad2fd95ec6d7cc97af8f159d29fa69ad0844f6bb", size = 7779561, upload-time = "2025-05-26T16:23:39.482Z" } +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/60/16/eee24f237c30281bf3720453d45be22c89bd9be75de6471789550403b156/aiohttp-3.12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8475e731b69063da96a92519bd78710c949c8ea26434507e957006e52c027d27", size = 692806, upload-time = "2025-05-26T16:21:49.429Z" }, - { url = "https://files.pythonhosted.org/packages/b2/00/aec552257a3c920fa3c8950e220f88d878b70d00d7306eb3b6589461100f/aiohttp-3.12.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:974d533968a574f6ce27b53b3662b4c1d895237fd151c2a1fff22b94214f0995", size = 467418, upload-time = "2025-05-26T16:21:51.103Z" }, - { url = "https://files.pythonhosted.org/packages/27/72/f5a31e4cff9f281e84b6683c6552669e6150c6d6fadac4c470b29f3cd86d/aiohttp-3.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6482fabe5947c109adb6646d1ebd1bbe79cf634d80c11b19b7a56b7d1d628487", size = 460257, upload-time = "2025-05-26T16:21:52.741Z" }, - { url = "https://files.pythonhosted.org/packages/71/95/2296b934f0ae0b1750310ee4f0189807f38fb26d6d2c98d5612936795e63/aiohttp-3.12.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b7f3ce2f86255b7245f6e2e15b1dc6f6473237bbdd5c0d2eee3c7ca66b556dc", size = 1707053, upload-time = "2025-05-26T16:21:54.453Z" }, - { url = "https://files.pythonhosted.org/packages/d0/c1/e3d1ed65479ae1c6cc5f244cb334da5a97345a3638905084e9b592ca3047/aiohttp-3.12.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:222fb161b3890b613184ef8d61c088d4ff3036c3687fcefb3ce54a1b2b41cf25", size = 1689700, upload-time = "2025-05-26T16:21:56.341Z" }, - { url = "https://files.pythonhosted.org/packages/92/49/1a9b4de1f39dcda4eb9427520e83bdc3fa112d38b45cecbb1feab7e6fef5/aiohttp-3.12.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03fcc6a08b322f69cd3c4e2f0358a5323ba075bff3af3f02640feaef1c9ca9c5", size = 1744799, upload-time = "2025-05-26T16:21:58.146Z" }, - { url = "https://files.pythonhosted.org/packages/ee/42/15a7621a305439bfe207af8729d8662584d1a97e7a09cd0b337ae953b389/aiohttp-3.12.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e583f988286f3d1b36b030c91008172561b88fa02c81bccda93442d6ff2f9c18", size = 1790952, upload-time = "2025-05-26T16:22:00.739Z" }, - { url = "https://files.pythonhosted.org/packages/e4/2c/8617ae6c8ac2761bda8e5492158061c3d4c28dc2dfc2a5dd4e5ae2b55f2d/aiohttp-3.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c18006fce18be8bc431f8178f24d3d8f0a1ea5c9b9d9cbdc9361158c81579da", size = 1710392, upload-time = "2025-05-26T16:22:03.564Z" }, - { url = "https://files.pythonhosted.org/packages/1c/0a/bc40f9f9c2d24662d9390c6fa7835782bdae990818436adc7d60e06649d1/aiohttp-3.12.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f988e07a4d3a5c0ee73ba2a7a2dea8de71ea0e6ebcf19d87d5daefc8ff63566", size = 1626192, upload-time = "2025-05-26T16:22:05.49Z" }, - { url = "https://files.pythonhosted.org/packages/53/dc/37fd5e64dd07b00bda99b14a27394f68e04703a0c8bdc5a1877c31ffad97/aiohttp-3.12.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:324bae9dcad6245f8aa2dbbea2daeae92cff757dab12ec438761462149cf74c0", size = 1687254, upload-time = "2025-05-26T16:22:07.304Z" }, - { url = "https://files.pythonhosted.org/packages/35/45/ddaa7c96aecdd5298e70e3eb38cd4cfdf215b338466085de7d28d88b5944/aiohttp-3.12.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:db35689970e62cc2e39f8e39fc45d6943ad623a14f601ba5f0bdfee87a8ba638", size = 1708707, upload-time = "2025-05-26T16:22:09.515Z" }, - { url = "https://files.pythonhosted.org/packages/a8/99/d1101a4fd0abe8b75c597164a5445cceb870ee6f13d50e680fa7ad257593/aiohttp-3.12.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5fa5e3029a251b88e69033fedeb3fb6df05817df60d2725fdf6b4665f9076efe", size = 1649360, upload-time = "2025-05-26T16:22:11.711Z" }, - { url = "https://files.pythonhosted.org/packages/1e/82/6b8ac40edc842a004fc17c013cf67a1d8a1f152dbeb8acd0fd12447d5017/aiohttp-3.12.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:284b3b9458b53c28a8ea273be8b63b320d9a7b55b3856c707421f05ea47f4930", size = 1728923, upload-time = "2025-05-26T16:22:13.536Z" }, - { url = "https://files.pythonhosted.org/packages/05/29/5999e3965569ead4332607d1cddc16c4932d53ce65fc6f1449814e5afa38/aiohttp-3.12.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:82552cf0d12e47e2976c59e1fba12a712f8ec321e759b9c48ce61a28b4449f26", size = 1756894, upload-time = "2025-05-26T16:22:15.341Z" }, - { url = "https://files.pythonhosted.org/packages/86/78/bc3df750b7e778940ef88c3e475ed5f91d8c124d343ee02e5db5a8c7c60c/aiohttp-3.12.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:00b17b19802e1900c6bd42c21f8c3a1668a069882ee182686b210f422f3d75b2", size = 1716505, upload-time = "2025-05-26T16:22:17.286Z" }, - { url = "https://files.pythonhosted.org/packages/cf/5b/d819bd9ea4ce0ad2f563d574f2911f35782738587a6b57274a63a2a0943b/aiohttp-3.12.1-cp312-cp312-win32.whl", hash = "sha256:c8acbe37e1e3393418c07b226e3c4e90e3e2d5204944c5b2011de0325c76b148", size = 413959, upload-time = "2025-05-26T16:22:19.143Z" }, - { url = "https://files.pythonhosted.org/packages/d5/d9/33b08e29692694b108d1105083d83d7079ba74d2f244ce2a2a341f67480a/aiohttp-3.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:21998081d931d5b0ef1288f01e8e204ca56f2cfb8055a69a01271ecb4a7b5258", size = 440065, upload-time = "2025-05-26T16:22:20.916Z" }, + { 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]] @@ -111,19 +104,20 @@ wheels = [ [[package]] name = "aiosignal" -version = "1.3.2" +version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" } +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/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" }, + { 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" }, ] [[package]] name = "alpaca-py" -version = "0.40.1" +version = "0.42.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "msgpack" }, @@ -133,9 +127,9 @@ dependencies = [ { name = "sseclient-py" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6f/6e/6d4e85d1d9f7bd1695587adfb87ef17ba1068972b235bae4bfb6eba6a22b/alpaca_py-0.40.1.tar.gz", hash = "sha256:188adcbb7c140d6f9eebe04011a0df68e1540374e2940098f032b8f21ff34bf3", size = 97233, upload-time = "2025-05-16T10:12:05.233Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/bf/3c2712ec8b9c4a36d5a7a2b58217512e4e26b3ffa02db554b33f9c9a5ba2/alpaca_py-0.42.0.tar.gz", hash = "sha256:3ac4fd3439b8701d678db38bbc797b12bc003190996b19b0aa5f0d22aea65be7", size = 97534, upload-time = "2025-07-04T15:31:54.727Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/a5/32534ea4071c8fa34d9f4b9434c5b96cf2c12347f4d52dd086a151ebb3d4/alpaca_py-0.40.1-py3-none-any.whl", hash = "sha256:4f9dff11b8b06b7ead0e98813136adc1b0259937299b8d0697059fa13e8015b1", size = 121709, upload-time = "2025-05-16T10:12:03.775Z" }, + { url = "https://files.pythonhosted.org/packages/e8/6f/669d3aba1d010be97169bfa25b55eba561545335ae97f9efce86954b20da/alpaca_py-0.42.0-py3-none-any.whl", hash = "sha256:e7e874fc9090c07a7b1698603e34f2e48be4f27beab47d7fc3d38d6f6855513a", size = 121974, upload-time = "2025-07-04T15:31:53.607Z" }, ] [[package]] @@ -147,29 +141,6 @@ 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 = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, -] - -[[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" @@ -181,16 +152,16 @@ wheels = [ [[package]] name = "azure-core" -version = "1.34.0" +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/c9/29/ff7a519a315e41c85bab92a7478c6acd1cf0b14353139a08caee4c691f77/azure_core-1.34.0.tar.gz", hash = "sha256:bdb544989f246a0ad1c85d72eeb45f2f835afdcbc5b45e43f0dbde7461c81ece", size = 297999, upload-time = "2025-05-01T23:17:27.59Z" } +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/84/9e/5c87b49f65bb16571599bc789857d0ded2f53014d3392bc88a5d1f3ad779/azure_core-1.34.0-py3-none-any.whl", hash = "sha256:0615d3b756beccdb6624d1c0ae97284f38b78fb59a2a9839bf927c66fbbdddd6", size = 207409, upload-time = "2025-05-01T23:17:29.818Z" }, + { 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]] @@ -209,7 +180,7 @@ wheels = [ [[package]] name = "azure-identity" -version = "1.23.0" +version = "1.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-core" }, @@ -218,14 +189,14 @@ dependencies = [ { name = "msal-extensions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/41/52/458c1be17a5d3796570ae2ed3c6b7b55b134b22d5ef8132b4f97046a9051/azure_identity-1.23.0.tar.gz", hash = "sha256:d9cdcad39adb49d4bb2953a217f62aec1f65bbb3c63c9076da2be2a47e53dde4", size = 265280, upload-time = "2025-05-14T00:18:30.408Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/16/a51d47780f41e4b87bb2d454df6aea90a44a346e918ac189d3700f3d728d/azure_identity-1.23.0-py3-none-any.whl", hash = "sha256:dbbeb64b8e5eaa81c44c565f264b519ff2de7ff0e02271c49f3cb492762a50b0", size = 186097, upload-time = "2025-05-14T00:18:32.734Z" }, + { 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" }, ] [[package]] name = "azure-storage-blob" -version = "12.25.1" +version = "12.26.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-core" }, @@ -233,51 +204,54 @@ dependencies = [ { name = "isodate" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8b/f3/f764536c25cc3829d36857167f03933ce9aee2262293179075439f3cd3ad/azure_storage_blob-12.25.1.tar.gz", hash = "sha256:4f294ddc9bc47909ac66b8934bd26b50d2000278b10ad82cc109764fdc6e0e3b", size = 570541, upload-time = "2025-03-27T17:13:05.424Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/57/33/085d9352d416e617993821b9d9488222fbb559bc15c3641d6cbd6d16d236/azure_storage_blob-12.25.1-py3-none-any.whl", hash = "sha256:1f337aab12e918ec3f1b638baada97550673911c4ceed892acc8e4e891b74167", size = 406990, upload-time = "2025-03-27T17:13:06.879Z" }, + { 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" }, ] [[package]] name = "behave" -version = "1.2.6" +version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "colorama" }, + { name = "cucumber-expressions" }, + { name = "cucumber-tag-expressions" }, { name = "parse" }, { name = "parse-type" }, { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c8/4b/d0a8c23b6c8985e5544ea96d27105a273ea22051317f850c2cdbf2029fe4/behave-1.2.6.tar.gz", hash = "sha256:b9662327aa53294c1351b0a9c369093ccec1d21026f050c3bd9b3e5cccf81a86", size = 701696, upload-time = "2018-02-25T20:06:38.851Z" } +sdist = { url = "https://files.pythonhosted.org/packages/74/6f/7d7c3bacf3d2e3209a5db760f3625cb943c5f044d1d21d8dd33e54e69cdc/behave-1.3.1.tar.gz", hash = "sha256:2a1f3a2490242132c4daf0732d9b65c99be6fef1f787f97fd028ea5a402025ff", size = 887256, upload-time = "2025-08-11T18:54:50.208Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/6c/ec9169548b6c4cb877aaa6773408ca08ae2a282805b958dbc163cb19822d/behave-1.2.6-py2.py3-none-any.whl", hash = "sha256:ebda1a6c9e5bfe95c5f9f0a2794e01c7098b3dde86c10a95d8621c5907ff6f1c", size = 136779, upload-time = "2018-02-25T20:06:34.436Z" }, + { url = "https://files.pythonhosted.org/packages/53/52/25901596ed8d22eb235a5634ca70280c6b66c4477daa8aef914deb582183/behave-1.3.1-py2.py3-none-any.whl", hash = "sha256:71b2dc00664de83c3aad61c91e5b3051b7b860aa2053e24db4742edecb800d21", size = 222099, upload-time = "2025-08-11T18:54:48.166Z" }, ] [[package]] name = "boto3" -version = "1.38.27" +version = "1.39.11" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e7/96/fc74d8521d2369dd8c412438401ff12e1350a1cd3eab5c758ed3dd5e5f82/boto3-1.38.27.tar.gz", hash = "sha256:94bd7fdd92d5701b362d4df100d21e28f8307a67ff56b6a8b0398119cf22f859", size = 111875, upload-time = "2025-05-30T19:32:41.352Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/8b/b2361188bd1e293eede1bc165e2461d390394f71ec0c8c21211c8dabf62c/boto3-1.38.27-py3-none-any.whl", hash = "sha256:95f5fe688795303a8a15e8b7e7f255cadab35eae459d00cc281a4fd77252ea80", size = 139938, upload-time = "2025-05-30T19:32:38.006Z" }, + { 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" }, ] [[package]] name = "botocore" -version = "1.38.27" +version = "1.39.11" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/36/5e/67899214ad57f7f26af5bd776ac5eb583dc4ecf5c1e52e2cbfdc200e487a/botocore-1.38.27.tar.gz", hash = "sha256:9788f7efe974328a38cbade64cc0b1e67d27944b899f88cb786ae362973133b6", size = 13919963, upload-time = "2025-05-30T19:32:29.657Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/83/a753562020b69fa90cebc39e8af2c753b24dcdc74bee8355ee3f6cefdf34/botocore-1.38.27-py3-none-any.whl", hash = "sha256:a785d5e9a5eda88ad6ab9ed8b87d1f2ac409d0226bba6ff801c55359e94d91a8", size = 13580545, upload-time = "2025-05-30T19:32:26.712Z" }, + { 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]] @@ -291,11 +265,11 @@ wheels = [ [[package]] name = "certifi" -version = "2025.4.26" +version = "2025.8.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, + { 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]] @@ -322,61 +296,22 @@ wheels = [ [[package]] name = "charset-normalizer" -version = "3.4.2" +version = "3.4.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, -] - -[[package]] -name = "clarabel" -version = "0.11.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi" }, - { name = "numpy" }, - { name = "scipy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/13/f4/77cd8679ab6787fb19f69f79a9a3b1676710a0903d2ca95bbdb7f40f10ef/clarabel-0.11.0.tar.gz", hash = "sha256:7a8ee6fe74eb7e7ba457b664e312e6953dec4bd1651d4725f5b5bcff5ef4dbc1", size = 253810, upload-time = "2025-05-23T17:59:30.434Z" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/e4/2e4d2db51fd106f54f0cd3e2d374732b63ca3c7c0c7c4587f56588237e18/clarabel-0.11.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e7cdc7ff5bebf04999fb990b740b7a9ec6e266382af406c8aa75aa3031ed219a", size = 1041064, upload-time = "2025-05-23T17:59:21.051Z" }, - { url = "https://files.pythonhosted.org/packages/35/17/3ac27e01ccf250c6f9df296f9787788db259b05bd715bc090b3e8661b2d2/clarabel-0.11.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:85bb474ba3c590fac47985d3dd19519ea247b77b62f1e1afb93c728799a594a2", size = 961333, upload-time = "2025-05-23T17:59:22.743Z" }, - { url = "https://files.pythonhosted.org/packages/e8/8d/1a933b8db929e2ce1f33bb9534c3fb0d1c83908d23d89d129a07a3f13536/clarabel-0.11.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:763cb448ba337e593bab1d442b671c854b85981ae551e6a64209fc864985098a", size = 1078244, upload-time = "2025-05-23T17:59:24.516Z" }, - { url = "https://files.pythonhosted.org/packages/9c/e8/361054c5d77185e780d126c4ef1520d7438863bb5b30c2f1fe6355b53a47/clarabel-0.11.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a08bb648b2cddce8ff80acb065da54aa80a76cf90ae1f2176f15a640f042cc2c", size = 1164905, upload-time = "2025-05-23T17:59:26.655Z" }, - { url = "https://files.pythonhosted.org/packages/19/89/d4caad4f3851e317e423359d31d9862b08321fd61db6281edb80455ca562/clarabel-0.11.0-cp39-abi3-win_amd64.whl", hash = "sha256:6b804f99741719531b7a8ce7e44c8162b4cac7782334ea48dad0c48d6904f7d7", size = 892575, upload-time = "2025-05-23T17:59:28.389Z" }, -] - -[[package]] -name = "cli" -version = "0.1.0" -source = { virtual = "cli" } -dependencies = [ - { name = "boto3" }, - { name = "botocore" }, - { name = "loguru" }, - { name = "requests" }, -] - -[package.metadata] -requires-dist = [ - { name = "boto3", specifier = ">=1.38.23" }, - { name = "botocore", specifier = ">=1.38.23" }, - { name = "loguru", specifier = ">=0.7.3" }, - { name = "requests", specifier = ">=2.31.0" }, + { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, + { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, + { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, + { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, + { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, ] [[package]] @@ -423,21 +358,22 @@ wheels = [ [[package]] name = "coverage" -version = "7.8.1" +version = "7.10.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/27/b4/a707d96c2c1ce9402ce1ce7124c53b9e4e1f3e617652a5ed2fbba4c9b4be/coverage-7.8.1.tar.gz", hash = "sha256:d41d4da5f2871b1782c6b74948d2d37aac3a5b39b43a6ba31d736b97a02ae1f1", size = 812193, upload-time = "2025-05-21T12:39:46.1Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/2c/253cc41cd0f40b84c1c34c5363e0407d73d4a1cae005fed6db3b823175bd/coverage-7.10.3.tar.gz", hash = "sha256:812ba9250532e4a823b070b0420a36499859542335af3dca8f47fc6aa1a05619", size = 822936, upload-time = "2025-08-10T21:27:39.968Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/78/781501aa4759026dcef8024b404cacc4094348e5e199ed660c31f4650a33/coverage-7.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d8f844e837374a9497e11722d9eb9dfeb33b1b5d31136786c39a4c1a3073c6d", size = 211875, upload-time = "2025-05-21T12:38:20.497Z" }, - { url = "https://files.pythonhosted.org/packages/e6/00/a8a4548c22b73f8fd4373714f5a4cce3584827e2603847a8d90fba129807/coverage-7.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9cd54a762667c32112df5d6f059c5d61fa532ee06460948cc5bcbf60c502f5c9", size = 212129, upload-time = "2025-05-21T12:38:22.085Z" }, - { url = "https://files.pythonhosted.org/packages/9e/41/5cdc34afdc53b7f200439eb915f50d6ba17e3b0b5cdb6bb04d0ed9662703/coverage-7.8.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:958b513e23286178b513a6b4d975fe9e7cddbcea6e5ebe8d836e4ef067577154", size = 246176, upload-time = "2025-05-21T12:38:23.802Z" }, - { url = "https://files.pythonhosted.org/packages/f0/1f/ca8e37fdd282dd6ebc4191a9fafcb46b6bf75e05a0fd796d6907399e44ea/coverage-7.8.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b31756ea647b6ef53190f6b708ad0c4c2ea879bc17799ba5b0699eee59ecf7b", size = 243068, upload-time = "2025-05-21T12:38:25.755Z" }, - { url = "https://files.pythonhosted.org/packages/cf/89/727503da5870fe1031ec443699beab44e02548d9873fe0a60adf6589fdd1/coverage-7.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccad4e29ac1b6f75bfeedb2cac4860fe5bd9e0a2f04c3e3218f661fa389ab101", size = 245329, upload-time = "2025-05-21T12:38:28.69Z" }, - { url = "https://files.pythonhosted.org/packages/25/1f/6935baf26071a66f390159ceb5c5bccfc898d00a90166b6ffc61b964856a/coverage-7.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:452f3831c64f5f50260e18a89e613594590d6ceac5206a9b7d76ba43586b01b3", size = 245100, upload-time = "2025-05-21T12:38:31.339Z" }, - { url = "https://files.pythonhosted.org/packages/3b/1f/0e5d68b12deb8a5c9648f61b515798e201f72fec17a0c7373a5f4903f8d8/coverage-7.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9296df6a33b8539cd753765eb5b47308602263a14b124a099cbcf5f770d7cf90", size = 243314, upload-time = "2025-05-21T12:38:34.974Z" }, - { url = "https://files.pythonhosted.org/packages/21/5d/375ba28a78e96a06ef0f1572b393e3fefd9d0deecf3ef9995eff1b1cea67/coverage-7.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d52d79dfd3b410b153b6d65b0e3afe834eca2b969377f55ad73c67156d35af0d", size = 244487, upload-time = "2025-05-21T12:38:37.84Z" }, - { url = "https://files.pythonhosted.org/packages/08/92/1b7fdf0924d8e6d7c2418d313c12d6e19c9a748448faedcc017082ec5b63/coverage-7.8.1-cp312-cp312-win32.whl", hash = "sha256:ebdf212e1ed85af63fa1a76d556c0a3c7b34348ffba6e145a64b15f003ad0a2b", size = 214367, upload-time = "2025-05-21T12:38:39.676Z" }, - { url = "https://files.pythonhosted.org/packages/07/b1/632f9e128ee9e149cfa80a3130362684244668b0dc6efedd6e466baaeb48/coverage-7.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:c04a7903644ccea8fa07c3e76db43ca31c8d453f93c5c94c0f9b82efca225543", size = 215169, upload-time = "2025-05-21T12:38:42.497Z" }, - { url = "https://files.pythonhosted.org/packages/1b/a1/4d968d4605f3a87a809f0c8f495eed81656c93cf6c00818334498ad6ad45/coverage-7.8.1-py3-none-any.whl", hash = "sha256:e54b80885b0e61d346accc5709daf8762471a452345521cc9281604a907162c2", size = 203623, upload-time = "2025-05-21T12:39:43.473Z" }, + { url = "https://files.pythonhosted.org/packages/b8/62/13c0b66e966c43d7aa64dadc8cd2afa1f5a2bf9bb863bdabc21fb94e8b63/coverage-7.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:449c1e2d3a84d18bd204258a897a87bc57380072eb2aded6a5b5226046207b42", size = 216262, upload-time = "2025-08-10T21:25:55.367Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f0/59fdf79be7ac2f0206fc739032f482cfd3f66b18f5248108ff192741beae/coverage-7.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d4f9ce50b9261ad196dc2b2e9f1fbbee21651b54c3097a25ad783679fd18294", size = 216496, upload-time = "2025-08-10T21:25:56.759Z" }, + { url = "https://files.pythonhosted.org/packages/34/b1/bc83788ba31bde6a0c02eb96bbc14b2d1eb083ee073beda18753fa2c4c66/coverage-7.10.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4dd4564207b160d0d45c36a10bc0a3d12563028e8b48cd6459ea322302a156d7", size = 247989, upload-time = "2025-08-10T21:25:58.067Z" }, + { url = "https://files.pythonhosted.org/packages/0c/29/f8bdf88357956c844bd872e87cb16748a37234f7f48c721dc7e981145eb7/coverage-7.10.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5ca3c9530ee072b7cb6a6ea7b640bcdff0ad3b334ae9687e521e59f79b1d0437", size = 250738, upload-time = "2025-08-10T21:25:59.406Z" }, + { url = "https://files.pythonhosted.org/packages/ae/df/6396301d332b71e42bbe624670af9376f63f73a455cc24723656afa95796/coverage-7.10.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6df359e59fa243c9925ae6507e27f29c46698359f45e568fd51b9315dbbe587", size = 251868, upload-time = "2025-08-10T21:26:00.65Z" }, + { url = "https://files.pythonhosted.org/packages/91/21/d760b2df6139b6ef62c9cc03afb9bcdf7d6e36ed4d078baacffa618b4c1c/coverage-7.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a181e4c2c896c2ff64c6312db3bda38e9ade2e1aa67f86a5628ae85873786cea", size = 249790, upload-time = "2025-08-10T21:26:02.009Z" }, + { url = "https://files.pythonhosted.org/packages/69/91/5dcaa134568202397fa4023d7066d4318dc852b53b428052cd914faa05e1/coverage-7.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a374d4e923814e8b72b205ef6b3d3a647bb50e66f3558582eda074c976923613", size = 247907, upload-time = "2025-08-10T21:26:03.757Z" }, + { url = "https://files.pythonhosted.org/packages/38/ed/70c0e871cdfef75f27faceada461206c1cc2510c151e1ef8d60a6fedda39/coverage-7.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:daeefff05993e5e8c6e7499a8508e7bd94502b6b9a9159c84fd1fe6bce3151cb", size = 249344, upload-time = "2025-08-10T21:26:05.11Z" }, + { url = "https://files.pythonhosted.org/packages/5f/55/c8a273ed503cedc07f8a00dcd843daf28e849f0972e4c6be4c027f418ad6/coverage-7.10.3-cp312-cp312-win32.whl", hash = "sha256:187ecdcac21f9636d570e419773df7bd2fda2e7fa040f812e7f95d0bddf5f79a", size = 218693, upload-time = "2025-08-10T21:26:06.534Z" }, + { url = "https://files.pythonhosted.org/packages/94/58/dd3cfb2473b85be0b6eb8c5b6d80b6fc3f8f23611e69ef745cef8cf8bad5/coverage-7.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:4a50ad2524ee7e4c2a95e60d2b0b83283bdfc745fe82359d567e4f15d3823eb5", size = 219501, upload-time = "2025-08-10T21:26:08.195Z" }, + { url = "https://files.pythonhosted.org/packages/56/af/7cbcbf23d46de6f24246e3f76b30df099d05636b30c53c158a196f7da3ad/coverage-7.10.3-cp312-cp312-win_arm64.whl", hash = "sha256:c112f04e075d3495fa3ed2200f71317da99608cbb2e9345bdb6de8819fc30571", size = 218135, upload-time = "2025-08-10T21:26:09.584Z" }, + { url = "https://files.pythonhosted.org/packages/84/19/e67f4ae24e232c7f713337f3f4f7c9c58afd0c02866fb07c7b9255a19ed7/coverage-7.10.3-py3-none-any.whl", hash = "sha256:416a8d74dc0adfd33944ba2f405897bab87b7e9e84a391e09d241956bd953ce1", size = 207921, upload-time = "2025-08-10T21:27:38.254Z" }, ] [[package]] @@ -455,57 +391,55 @@ wheels = [ [[package]] name = "cryptography" -version = "45.0.3" +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/13/1f/9fa001e74a1993a9cadd2333bb889e50c66327b8594ac538ab8a04f915b7/cryptography-45.0.3.tar.gz", hash = "sha256:ec21313dd335c51d7877baf2972569f40a4291b76a0ce51391523ae358d05899", size = 744738, upload-time = "2025-05-25T14:17:24.777Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/b2/2345dc595998caa6f68adf84e8f8b50d18e9fc4638d32b22ea8daedd4b7a/cryptography-45.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:7573d9eebaeceeb55285205dbbb8753ac1e962af3d9640791d12b36864065e71", size = 7056239, upload-time = "2025-05-25T14:16:12.22Z" }, - { url = "https://files.pythonhosted.org/packages/71/3d/ac361649a0bfffc105e2298b720d8b862330a767dab27c06adc2ddbef96a/cryptography-45.0.3-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d377dde61c5d67eb4311eace661c3efda46c62113ff56bf05e2d679e02aebb5b", size = 4205541, upload-time = "2025-05-25T14:16:14.333Z" }, - { url = "https://files.pythonhosted.org/packages/70/3e/c02a043750494d5c445f769e9c9f67e550d65060e0bfce52d91c1362693d/cryptography-45.0.3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fae1e637f527750811588e4582988932c222f8251f7b7ea93739acb624e1487f", size = 4433275, upload-time = "2025-05-25T14:16:16.421Z" }, - { url = "https://files.pythonhosted.org/packages/40/7a/9af0bfd48784e80eef3eb6fd6fde96fe706b4fc156751ce1b2b965dada70/cryptography-45.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ca932e11218bcc9ef812aa497cdf669484870ecbcf2d99b765d6c27a86000942", size = 4209173, upload-time = "2025-05-25T14:16:18.163Z" }, - { url = "https://files.pythonhosted.org/packages/31/5f/d6f8753c8708912df52e67969e80ef70b8e8897306cd9eb8b98201f8c184/cryptography-45.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af3f92b1dc25621f5fad065288a44ac790c5798e986a34d393ab27d2b27fcff9", size = 3898150, upload-time = "2025-05-25T14:16:20.34Z" }, - { url = "https://files.pythonhosted.org/packages/8b/50/f256ab79c671fb066e47336706dc398c3b1e125f952e07d54ce82cf4011a/cryptography-45.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f8f8f0b73b885ddd7f3d8c2b2234a7d3ba49002b0223f58cfde1bedd9563c56", size = 4466473, upload-time = "2025-05-25T14:16:22.605Z" }, - { url = "https://files.pythonhosted.org/packages/62/e7/312428336bb2df0848d0768ab5a062e11a32d18139447a76dfc19ada8eed/cryptography-45.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9cc80ce69032ffa528b5e16d217fa4d8d4bb7d6ba8659c1b4d74a1b0f4235fca", size = 4211890, upload-time = "2025-05-25T14:16:24.738Z" }, - { url = "https://files.pythonhosted.org/packages/e7/53/8a130e22c1e432b3c14896ec5eb7ac01fb53c6737e1d705df7e0efb647c6/cryptography-45.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c824c9281cb628015bfc3c59335163d4ca0540d49de4582d6c2637312907e4b1", size = 4466300, upload-time = "2025-05-25T14:16:26.768Z" }, - { url = "https://files.pythonhosted.org/packages/ba/75/6bb6579688ef805fd16a053005fce93944cdade465fc92ef32bbc5c40681/cryptography-45.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5833bb4355cb377ebd880457663a972cd044e7f49585aee39245c0d592904578", size = 4332483, upload-time = "2025-05-25T14:16:28.316Z" }, - { url = "https://files.pythonhosted.org/packages/2f/11/2538f4e1ce05c6c4f81f43c1ef2bd6de7ae5e24ee284460ff6c77e42ca77/cryptography-45.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bb5bf55dcb69f7067d80354d0a348368da907345a2c448b0babc4215ccd3497", size = 4573714, upload-time = "2025-05-25T14:16:30.474Z" }, - { url = "https://files.pythonhosted.org/packages/f5/bb/e86e9cf07f73a98d84a4084e8fd420b0e82330a901d9cac8149f994c3417/cryptography-45.0.3-cp311-abi3-win32.whl", hash = "sha256:3ad69eeb92a9de9421e1f6685e85a10fbcfb75c833b42cc9bc2ba9fb00da4710", size = 2934752, upload-time = "2025-05-25T14:16:32.204Z" }, - { url = "https://files.pythonhosted.org/packages/c7/75/063bc9ddc3d1c73e959054f1fc091b79572e716ef74d6caaa56e945b4af9/cryptography-45.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:97787952246a77d77934d41b62fb1b6f3581d83f71b44796a4158d93b8f5c490", size = 3412465, upload-time = "2025-05-25T14:16:33.888Z" }, - { url = "https://files.pythonhosted.org/packages/71/9b/04ead6015229a9396890d7654ee35ef630860fb42dc9ff9ec27f72157952/cryptography-45.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:c92519d242703b675ccefd0f0562eb45e74d438e001f8ab52d628e885751fb06", size = 7031892, upload-time = "2025-05-25T14:16:36.214Z" }, - { url = "https://files.pythonhosted.org/packages/46/c7/c7d05d0e133a09fc677b8a87953815c522697bdf025e5cac13ba419e7240/cryptography-45.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5edcb90da1843df85292ef3a313513766a78fbbb83f584a5a58fb001a5a9d57", size = 4196181, upload-time = "2025-05-25T14:16:37.934Z" }, - { url = "https://files.pythonhosted.org/packages/08/7a/6ad3aa796b18a683657cef930a986fac0045417e2dc428fd336cfc45ba52/cryptography-45.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38deed72285c7ed699864f964a3f4cf11ab3fb38e8d39cfcd96710cd2b5bb716", size = 4423370, upload-time = "2025-05-25T14:16:39.502Z" }, - { url = "https://files.pythonhosted.org/packages/4f/58/ec1461bfcb393525f597ac6a10a63938d18775b7803324072974b41a926b/cryptography-45.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5555365a50efe1f486eed6ac7062c33b97ccef409f5970a0b6f205a7cfab59c8", size = 4197839, upload-time = "2025-05-25T14:16:41.322Z" }, - { url = "https://files.pythonhosted.org/packages/d4/3d/5185b117c32ad4f40846f579369a80e710d6146c2baa8ce09d01612750db/cryptography-45.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e4253ed8f5948a3589b3caee7ad9a5bf218ffd16869c516535325fece163dcc", size = 3886324, upload-time = "2025-05-25T14:16:43.041Z" }, - { url = "https://files.pythonhosted.org/packages/67/85/caba91a57d291a2ad46e74016d1f83ac294f08128b26e2a81e9b4f2d2555/cryptography-45.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cfd84777b4b6684955ce86156cfb5e08d75e80dc2585e10d69e47f014f0a5342", size = 4450447, upload-time = "2025-05-25T14:16:44.759Z" }, - { url = "https://files.pythonhosted.org/packages/ae/d1/164e3c9d559133a38279215c712b8ba38e77735d3412f37711b9f8f6f7e0/cryptography-45.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:a2b56de3417fd5f48773ad8e91abaa700b678dc7fe1e0c757e1ae340779acf7b", size = 4200576, upload-time = "2025-05-25T14:16:46.438Z" }, - { url = "https://files.pythonhosted.org/packages/71/7a/e002d5ce624ed46dfc32abe1deff32190f3ac47ede911789ee936f5a4255/cryptography-45.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:57a6500d459e8035e813bd8b51b671977fb149a8c95ed814989da682314d0782", size = 4450308, upload-time = "2025-05-25T14:16:48.228Z" }, - { url = "https://files.pythonhosted.org/packages/87/ad/3fbff9c28cf09b0a71e98af57d74f3662dea4a174b12acc493de00ea3f28/cryptography-45.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f22af3c78abfbc7cbcdf2c55d23c3e022e1a462ee2481011d518c7fb9c9f3d65", size = 4325125, upload-time = "2025-05-25T14:16:49.844Z" }, - { url = "https://files.pythonhosted.org/packages/f5/b4/51417d0cc01802304c1984d76e9592f15e4801abd44ef7ba657060520bf0/cryptography-45.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:232954730c362638544758a8160c4ee1b832dc011d2c41a306ad8f7cccc5bb0b", size = 4560038, upload-time = "2025-05-25T14:16:51.398Z" }, - { url = "https://files.pythonhosted.org/packages/80/38/d572f6482d45789a7202fb87d052deb7a7b136bf17473ebff33536727a2c/cryptography-45.0.3-cp37-abi3-win32.whl", hash = "sha256:cb6ab89421bc90e0422aca911c69044c2912fc3debb19bb3c1bfe28ee3dff6ab", size = 2924070, upload-time = "2025-05-25T14:16:53.472Z" }, - { url = "https://files.pythonhosted.org/packages/91/5a/61f39c0ff4443651cc64e626fa97ad3099249152039952be8f344d6b0c86/cryptography-45.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:d54ae41e6bd70ea23707843021c778f151ca258081586f0cfa31d936ae43d1b2", size = 3395005, upload-time = "2025-05-25T14:16:55.134Z" }, -] - -[[package]] -name = "cvxpy" -version = "1.6.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "clarabel" }, - { name = "numpy" }, - { name = "osqp" }, - { name = "scipy" }, - { name = "scs" }, +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" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6c/9e/0aeb94d435f4aad947b45eb9354fba31b23066b5ed78c42bbf71a9e4105e/cvxpy-1.6.5.tar.gz", hash = "sha256:666081b9c1f6db8947bcfc3c6f250174f934fa1ba8e30b38e3d32eba779ff785", size = 1610956, upload-time = "2025-04-13T02:53:40.27Z" } + +[[package]] +name = "cucumber-expressions" +version = "18.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/7d/f4e231167b23b3d7348aa1c90117ce8854fae186d6984ad66d705df24061/cucumber_expressions-18.0.1.tar.gz", hash = "sha256:86ce41bf28ee520408416f38022e5a083d815edf04a0bd1dae46d474ca597c60", size = 22232, upload-time = "2024-10-28T11:38:48.672Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/30/ae/4acbab3ab701ec0873d54c2d704472cbbbe58d29090f28685ad1df4028ae/cvxpy-1.6.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4c3365de01866f3f3a14f2c754d52f1aa361184c4f5f004b7257622b2c177237", size = 1490248, upload-time = "2025-04-13T02:58:36.616Z" }, - { url = "https://files.pythonhosted.org/packages/40/a5/39ae4adec78e063e5a5a3f751701ff5d72d5b1548712771ec337b35883d5/cvxpy-1.6.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9f70e39a41e1691783a4e55a73440f9e68b852fe0e0498c4d0c5a1505f3a2640", size = 1154518, upload-time = "2025-04-13T02:58:38.005Z" }, - { url = "https://files.pythonhosted.org/packages/c2/ba/ab502c2cc25e4b6eeaf7833b6bef5f1a5aa14c394a9bf9822bdcd7efcf9d/cvxpy-1.6.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:579b0039fa097e2e20272028bd2d4b592de7c67e60fd8eb6991629b5d53204a2", size = 1205970, upload-time = "2025-04-13T02:53:36.889Z" }, - { url = "https://files.pythonhosted.org/packages/27/e7/56c6fea9afc1ff1a8abcd60a40a21370bea37b620902237045b5083b9044/cvxpy-1.6.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a82c6de45a39065dd8c5ff5b30bee21b09ca85eac6b6dcbd3f5ed1b19986bec1", size = 1231908, upload-time = "2025-04-13T02:53:39.057Z" }, - { url = "https://files.pythonhosted.org/packages/de/0c/d0dd074b17076665e5a28145944c88eac07e8ecf05d8ece9a06dbd495b8b/cvxpy-1.6.5-cp312-cp312-win_amd64.whl", hash = "sha256:436aed23d0ca84df81944018d971cf8bda8f19bfa2362ae3c540313d5183eca6", size = 1098416, upload-time = "2025-04-13T02:43:04.189Z" }, + { url = "https://files.pythonhosted.org/packages/80/e0/31ce90dad5234c3d52432bfce7562aa11cda4848aea90936a4be6c67d7ab/cucumber_expressions-18.0.1-py3-none-any.whl", hash = "sha256:86230d503cdda7ef35a1f2072a882d7d57c740aa4c163c82b07f039b6bc60c42", size = 20211, upload-time = "2024-10-28T11:38:47.101Z" }, +] + +[[package]] +name = "cucumber-tag-expressions" +version = "6.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/81/32a2dc51c0720b34f642a6e79da6d89525c1eafd8902798026c233201f6f/cucumber_tag_expressions-6.2.0.tar.gz", hash = "sha256:b60aa2cdbf9ac43e28d9b0e4fd49edf9f09d5d941257d2912f5228f9d166c023", size = 41459, upload-time = "2025-05-25T12:30:43.25Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/99/0e9ac5b8429f39a05de5cd4731eac57738ce030dcd852aefe36a7102a4ce/cucumber_tag_expressions-6.2.0-py2.py3-none-any.whl", hash = "sha256:f94404b656831c56a3815da5305ac097003884d2ae64fa51f5f4fad82d97e583", size = 9333, upload-time = "2025-05-25T12:30:41.408Z" }, ] [[package]] @@ -525,56 +459,13 @@ wheels = [ [[package]] name = "datamanager" version = "0.1.0" -source = { editable = "application/datamanager" } +source = { virtual = "applications/datamanager" } dependencies = [ - { name = "boto3" }, - { name = "cloudevents" }, - { name = "duckdb" }, - { name = "fastapi" }, - { name = "loguru" }, - { name = "polars" }, - { name = "polygon-api-client" }, - { name = "prometheus-fastapi-instrumentator" }, - { name = "pyarrow" }, - { name = "requests" }, - { name = "uvicorn" }, -] - -[package.dev-dependencies] -dev = [ - { name = "behave" }, + { name = "internal" }, ] [package.metadata] -requires-dist = [ - { name = "boto3", specifier = ">=1.38.23" }, - { name = "cloudevents", specifier = ">=1.12.0" }, - { name = "duckdb", specifier = ">=1.2.2" }, - { name = "fastapi", specifier = ">=0.115.12" }, - { name = "loguru", specifier = ">=0.7.3" }, - { name = "polars", specifier = ">=1.29.0" }, - { name = "polygon-api-client", specifier = ">=1.14.6" }, - { name = "prometheus-fastapi-instrumentator", specifier = ">=7.1.0" }, - { name = "pyarrow", specifier = ">=20.0.0" }, - { name = "requests", specifier = ">=2.31.0" }, - { name = "uvicorn", specifier = ">=0.34.2" }, -] - -[package.metadata.requires-dev] -dev = [{ name = "behave", specifier = ">=1.2.6" }] - -[[package]] -name = "debugpy" -version = "1.8.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/3a9a28ddb750a76eaec445c7f4d3147ea2c579a97dbd9e25d39001b92b21/debugpy-1.8.15.tar.gz", hash = "sha256:58d7a20b7773ab5ee6bdfb2e6cf622fdf1e40c9d5aef2857d85391526719ac00", size = 1643279, upload-time = "2025-07-15T16:43:29.135Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/4a/4508d256e52897f5cdfee6a6d7580974811e911c6d01321df3264508a5ac/debugpy-1.8.15-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:3dcc7225cb317469721ab5136cda9ff9c8b6e6fb43e87c9e15d5b108b99d01ba", size = 2511197, upload-time = "2025-07-15T16:43:42.343Z" }, - { url = "https://files.pythonhosted.org/packages/99/8d/7f6ef1097e7fecf26b4ef72338d08e41644a41b7ee958a19f494ffcffc29/debugpy-1.8.15-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:047a493ca93c85ccede1dbbaf4e66816794bdc214213dde41a9a61e42d27f8fc", size = 4229517, upload-time = "2025-07-15T16:43:44.14Z" }, - { url = "https://files.pythonhosted.org/packages/3f/e8/e8c6a9aa33a9c9c6dacbf31747384f6ed2adde4de2e9693c766bdf323aa3/debugpy-1.8.15-cp312-cp312-win32.whl", hash = "sha256:b08e9b0bc260cf324c890626961dad4ffd973f7568fbf57feb3c3a65ab6b6327", size = 5276132, upload-time = "2025-07-15T16:43:45.529Z" }, - { url = "https://files.pythonhosted.org/packages/e9/ad/231050c6177b3476b85fcea01e565dac83607b5233d003ff067e2ee44d8f/debugpy-1.8.15-cp312-cp312-win_amd64.whl", hash = "sha256:e2a4fe357c92334272eb2845fcfcdbec3ef9f22c16cf613c388ac0887aed15fa", size = 5317645, upload-time = "2025-07-15T16:43:46.968Z" }, - { url = "https://files.pythonhosted.org/packages/07/d5/98748d9860e767a1248b5e31ffa7ce8cb7006e97bf8abbf3d891d0a8ba4e/debugpy-1.8.15-py2.py3-none-any.whl", hash = "sha256:bce2e6c5ff4f2e00b98d45e7e01a49c7b489ff6df5f12d881c67d2f1ac635f3d", size = 5282697, upload-time = "2025-07-15T16:44:07.996Z" }, -] +requires-dist = [{ name = "internal", editable = "libraries/python" }] [[package]] name = "decorator" @@ -597,15 +488,6 @@ 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" }, ] -[[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 = "diskcache" version = "5.6.3" @@ -631,74 +513,30 @@ wheels = [ [[package]] name = "docstring-parser" -version = "0.16" +version = "0.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/08/12/9c22a58c0b1e29271051222d8906257616da84135af9ed167c9e28f85cb3/docstring_parser-0.16.tar.gz", hash = "sha256:538beabd0af1e2db0146b6bd3caa526c35a34d61af9fd2887f3a8a27a739aa6e", size = 26565, upload-time = "2024-03-15T10:39:44.419Z" } +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/d5/7c/e9fcff7623954d86bdc17782036cbf715ecab1bec4847c008557affe1ca8/docstring_parser-0.16-py3-none-any.whl", hash = "sha256:bf0a1387354d3691d102edef7ec124f219ef639982d096e26e3b60aeffa90637", size = 36533, upload-time = "2024-03-15T10:39:41.527Z" }, -] - -[[package]] -name = "duckdb" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3e/82/680b108da1870e48d98464ddcf03820f983421b5bbd8dd8beff98d583db7/duckdb-1.3.0.tar.gz", hash = "sha256:09aaa4b1dca24f4d1f231e7ae66b6413e317b7e04e2753541d42df6c8113fac7", size = 11617648, upload-time = "2025-05-21T16:06:49.93Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/b8/0931871f55a10aacd1af024c8d1e5de68337032379438aba05e26e9a1132/duckdb-1.3.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:f24038fe9b83dcbaeafb1ed76ec3b3f38943c1c8d27ab464ad384db8a6658b61", size = 15516284, upload-time = "2025-05-21T16:05:51.596Z" }, - { url = "https://files.pythonhosted.org/packages/af/d5/a08f76900391ff248b18fc1d5742db4b7bcf910c4be00314ce7b3069223f/duckdb-1.3.0-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:956c85842841bef68f4a5388c6b225b933151a7c06d568390fc895fc44607913", size = 32490915, upload-time = "2025-05-21T16:05:54.731Z" }, - { url = "https://files.pythonhosted.org/packages/05/f1/9dfa45484422bd6c598e76fb2d005de48373aea66b037471b4568c1e938a/duckdb-1.3.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:efe883d822ed56fcfbb6a7b397c13f6a0d2eaeb3bc4ef4510f84fadb3dfe416d", size = 17086690, upload-time = "2025-05-21T16:05:57.51Z" }, - { url = "https://files.pythonhosted.org/packages/8e/4e/093944cbca2e4b3fe5da99c46df9f4ae293c6768f15f14a959aaa2064a50/duckdb-1.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3872a3a1b80ffba5264ea236a3754d0c41d3c7b01bdf8cdcb1c180fc1b8dc8e2", size = 19140518, upload-time = "2025-05-21T16:06:00.521Z" }, - { url = "https://files.pythonhosted.org/packages/b0/9e/b1a7c086db03f3cc85c513e70034bd515e68e25013875e5f0b40c4bf5d0a/duckdb-1.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:30bf45ad78a5a997f378863e036e917b481d18d685e5c977cd0a3faf2e31fbaf", size = 21103893, upload-time = "2025-05-21T16:06:03.643Z" }, - { url = "https://files.pythonhosted.org/packages/5e/b4/5baef852efec9480dcfb44bed5adc56f6fcee09919037cf54fbbe87ac427/duckdb-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:85cbd8e1d65df8a0780023baf5045d3033fabd154799bc9ea6d9ab5728f41eb3", size = 22753505, upload-time = "2025-05-21T16:06:06.773Z" }, - { url = "https://files.pythonhosted.org/packages/36/4f/f7ab120ecd827fdff59f14e1de9771335aa7656a29c3259fa7949de1f276/duckdb-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:8754c40dac0f26d9fb0363bbb5df02f7a61ce6a6728d5efc02c3bc925d7c89c3", size = 11424449, upload-time = "2025-05-21T16:06:09.43Z" }, -] - -[[package]] -name = "ecos" -version = "2.0.14" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "scipy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2e/5f/17716c533da95ed110815b159efa22b1064c8c41fd5c862f21aff7a7fec0/ecos-2.0.14.tar.gz", hash = "sha256:64b3201c0e0a7f0129050557c4ac50b00031e80a10534506dba1200c8dc1efe4", size = 142430, upload-time = "2024-06-18T03:48:34.809Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/c3/84e392f2410f51fa557198937cc52a2e80f887c517ef4e3fb6d46e3bb008/ecos-2.0.14-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4a7e2704a3ef9acfb8146d594deff9942d3a0f0d0399de8fe2e0bd95e8b0855c", size = 92545, upload-time = "2024-06-18T03:47:50.589Z" }, - { url = "https://files.pythonhosted.org/packages/82/12/42f4d953f9284571726b085f99e13bfa84522bf63bf2e7a81460013b09e6/ecos-2.0.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3cbb1a66ecf10955a1a4bcd6b99db55148000cb79fd176bfac26d98b21a4814", size = 222132, upload-time = "2024-06-18T03:47:47.498Z" }, - { url = "https://files.pythonhosted.org/packages/56/9a/ca30572f3e3ff3cef6a0ea8aa6cdc12c36f9fefe559f65c7d6265713196a/ecos-2.0.14-cp312-cp312-win_amd64.whl", hash = "sha256:718eb62afb8e45426bcc365ebaf3ca9f610afcbb754de6073ef5f104da8fca1f", size = 72248, upload-time = "2024-06-18T03:48:51.504Z" }, -] - -[[package]] -name = "fastapi" -version = "0.115.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236, upload-time = "2025-03-23T22:55:43.822Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164, upload-time = "2025-03-23T22:55:42.101Z" }, + { 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" }, ] [[package]] name = "flyteidl" -version = "1.15.3" +version = "1.16.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, { name = "protobuf" }, { name = "protoc-gen-openapiv2" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/6d/252aaa552a21e42a15e642abd2828ccda936eacffcfc2ec7dfad11292d01/flyteidl-1.15.3.tar.gz", hash = "sha256:4c24aebd6b001efd4f65ee64b849ca0b22be7ab4ccd0e92bc247acb41fcc20cf", size = 129334, upload-time = "2025-04-22T02:05:09.741Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/2d/4cbc3e7f8616234ca5fc3f8d3e28deecd4ad9f0ce75593a797abefc1adae/flyteidl-1.15.3-py3-none-any.whl", hash = "sha256:7dca58e85afec5594e029cd4dfd046c9f156d95537051b744ccdc9f18a236467", size = 220503, upload-time = "2025-04-22T02:05:07.885Z" }, + { 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" }, ] [[package]] name = "flytekit" -version = "1.16.1" +version = "1.16.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "adlfs" }, @@ -738,49 +576,49 @@ dependencies = [ { name = "typing-extensions" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/44/6109f1bdacaf56a6b8389f8377ab065c75af64686d054d7dcb568ee79256/flytekit-1.16.1.tar.gz", hash = "sha256:1e3f3e621bfaeb2c5d144ebf0301254eb6f9a646a797f2924e127747d22cb16e", size = 564262, upload-time = "2025-06-10T16:13:25.968Z" } +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/ea/df/055427d5793bb5055b4fc5fb8e13b27c6c652b4bf8660f82b67789f4fbe0/flytekit-1.16.1-py3-none-any.whl", hash = "sha256:c54a8477fc95312f14aebd3e735d5f46e42fcc18963a7d508e095a6de0b819c2", size = 665827, upload-time = "2025-06-10T16:13:23.571Z" }, + { 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.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/f4/d744cba2da59b5c1d88823cf9e8a6c74e4659e2b27604ed973be2a0bf5ab/frozenlist-1.6.0.tar.gz", hash = "sha256:b99655c32c1c8e06d111e7f41c06c29a5318cb1835df23a45518e02a47c63b68", size = 42831, upload-time = "2025-04-17T22:38:53.099Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/8a/289b7d0de2fbac832ea80944d809759976f661557a38bb8e77db5d9f79b7/frozenlist-1.6.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c5b9e42ace7d95bf41e19b87cec8f262c41d3510d8ad7514ab3862ea2197bfb1", size = 160193, upload-time = "2025-04-17T22:36:47.382Z" }, - { url = "https://files.pythonhosted.org/packages/19/80/2fd17d322aec7f430549f0669f599997174f93ee17929ea5b92781ec902c/frozenlist-1.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ca9973735ce9f770d24d5484dcb42f68f135351c2fc81a7a9369e48cf2998a29", size = 123831, upload-time = "2025-04-17T22:36:49.401Z" }, - { url = "https://files.pythonhosted.org/packages/99/06/f5812da431273f78c6543e0b2f7de67dfd65eb0a433978b2c9c63d2205e4/frozenlist-1.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6ac40ec76041c67b928ca8aaffba15c2b2ee3f5ae8d0cb0617b5e63ec119ca25", size = 121862, upload-time = "2025-04-17T22:36:51.899Z" }, - { url = "https://files.pythonhosted.org/packages/d0/31/9e61c6b5fc493cf24d54881731204d27105234d09878be1a5983182cc4a5/frozenlist-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b7a8a3180dfb280eb044fdec562f9b461614c0ef21669aea6f1d3dac6ee576", size = 316361, upload-time = "2025-04-17T22:36:53.402Z" }, - { url = "https://files.pythonhosted.org/packages/9d/55/22ca9362d4f0222324981470fd50192be200154d51509ee6eb9baa148e96/frozenlist-1.6.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c444d824e22da6c9291886d80c7d00c444981a72686e2b59d38b285617cb52c8", size = 307115, upload-time = "2025-04-17T22:36:55.016Z" }, - { url = "https://files.pythonhosted.org/packages/ae/39/4fff42920a57794881e7bb3898dc7f5f539261711ea411b43bba3cde8b79/frozenlist-1.6.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb52c8166499a8150bfd38478248572c924c003cbb45fe3bcd348e5ac7c000f9", size = 322505, upload-time = "2025-04-17T22:36:57.12Z" }, - { url = "https://files.pythonhosted.org/packages/55/f2/88c41f374c1e4cf0092a5459e5f3d6a1e17ed274c98087a76487783df90c/frozenlist-1.6.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b35298b2db9c2468106278537ee529719228950a5fdda686582f68f247d1dc6e", size = 322666, upload-time = "2025-04-17T22:36:58.735Z" }, - { url = "https://files.pythonhosted.org/packages/75/51/034eeb75afdf3fd03997856195b500722c0b1a50716664cde64e28299c4b/frozenlist-1.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d108e2d070034f9d57210f22fefd22ea0d04609fc97c5f7f5a686b3471028590", size = 302119, upload-time = "2025-04-17T22:37:00.512Z" }, - { url = "https://files.pythonhosted.org/packages/2b/a6/564ecde55ee633270a793999ef4fd1d2c2b32b5a7eec903b1012cb7c5143/frozenlist-1.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e1be9111cb6756868ac242b3c2bd1f09d9aea09846e4f5c23715e7afb647103", size = 316226, upload-time = "2025-04-17T22:37:02.102Z" }, - { url = "https://files.pythonhosted.org/packages/f1/c8/6c0682c32377f402b8a6174fb16378b683cf6379ab4d2827c580892ab3c7/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:94bb451c664415f02f07eef4ece976a2c65dcbab9c2f1705b7031a3a75349d8c", size = 312788, upload-time = "2025-04-17T22:37:03.578Z" }, - { url = "https://files.pythonhosted.org/packages/b6/b8/10fbec38f82c5d163ca1750bfff4ede69713badf236a016781cf1f10a0f0/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d1a686d0b0949182b8faddea596f3fc11f44768d1f74d4cad70213b2e139d821", size = 325914, upload-time = "2025-04-17T22:37:05.213Z" }, - { url = "https://files.pythonhosted.org/packages/62/ca/2bf4f3a1bd40cdedd301e6ecfdbb291080d5afc5f9ce350c0739f773d6b9/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ea8e59105d802c5a38bdbe7362822c522230b3faba2aa35c0fa1765239b7dd70", size = 305283, upload-time = "2025-04-17T22:37:06.985Z" }, - { url = "https://files.pythonhosted.org/packages/09/64/20cc13ccf94abc2a1f482f74ad210703dc78a590d0b805af1c9aa67f76f9/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:abc4e880a9b920bc5020bf6a431a6bb40589d9bca3975c980495f63632e8382f", size = 319264, upload-time = "2025-04-17T22:37:08.618Z" }, - { url = "https://files.pythonhosted.org/packages/20/ff/86c6a2bbe98cfc231519f5e6d712a0898488ceac804a917ce014f32e68f6/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9a79713adfe28830f27a3c62f6b5406c37376c892b05ae070906f07ae4487046", size = 326482, upload-time = "2025-04-17T22:37:10.196Z" }, - { url = "https://files.pythonhosted.org/packages/2f/da/8e381f66367d79adca245d1d71527aac774e30e291d41ef161ce2d80c38e/frozenlist-1.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a0318c2068e217a8f5e3b85e35899f5a19e97141a45bb925bb357cfe1daf770", size = 318248, upload-time = "2025-04-17T22:37:12.284Z" }, - { url = "https://files.pythonhosted.org/packages/39/24/1a1976563fb476ab6f0fa9fefaac7616a4361dbe0461324f9fd7bf425dbe/frozenlist-1.6.0-cp312-cp312-win32.whl", hash = "sha256:853ac025092a24bb3bf09ae87f9127de9fe6e0c345614ac92536577cf956dfcc", size = 115161, upload-time = "2025-04-17T22:37:13.902Z" }, - { url = "https://files.pythonhosted.org/packages/80/2e/fb4ed62a65f8cd66044706b1013f0010930d8cbb0729a2219561ea075434/frozenlist-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:2bdfe2d7e6c9281c6e55523acd6c2bf77963cb422fdc7d142fb0cb6621b66878", size = 120548, upload-time = "2025-04-17T22:37:15.326Z" }, - { url = "https://files.pythonhosted.org/packages/71/3e/b04a0adda73bd52b390d730071c0d577073d3d26740ee1bad25c3ad0f37b/frozenlist-1.6.0-py3-none-any.whl", hash = "sha256:535eec9987adb04701266b92745d6cdcef2e77669299359c3009c3404dd5d191", size = 12404, upload-time = "2025-04-17T22:38:51.668Z" }, +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.5.1" +version = "2025.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/f7/27f15d41f0ed38e8fcc488584b57e902b331da7f7c6dcda53721b15838fc/fsspec-2025.5.1.tar.gz", hash = "sha256:2e55e47a540b91843b755e83ded97c6e897fa0942b11490113f09e9c443c2475", size = 303033, upload-time = "2025-05-24T12:03:23.792Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/61/78c7b3851add1481b048b5fdc29067397a1784e2910592bc81bb3f608635/fsspec-2025.5.1-py3-none-any.whl", hash = "sha256:24d3a2e663d5fc735ab256263c4075f374a174c3410c0b25e5bd1970bceaa462", size = 199052, upload-time = "2025-05-24T12:03:21.66Z" }, + { 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" }, ] [[package]] name = "gcsfs" -version = "2025.5.1" +version = "2025.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -791,14 +629,38 @@ dependencies = [ { name = "google-cloud-storage" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d8/4a/47ad326cc74ccfd97e125c0087a36d516ed74c61f53e458067737378d0f2/gcsfs-2025.5.1.tar.gz", hash = "sha256:ba945530cf4857cd9d599ccb3ae729c65c39088880b11c4df1fecac30df5f3e3", size = 82173, upload-time = "2025-05-24T12:12:58.519Z" } +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/ff/eb/9182e875592c48d282c5eab602000f0618817b9011b2b2925165e4b4b7f3/gcsfs-2025.5.1-py2.py3-none-any.whl", hash = "sha256:48712471ff71ac83d3e2152ba4dc232874698466e344d5e700feba06b0a0de7b", size = 36581, upload-time = "2025-05-24T12:12:57.011Z" }, + { 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.24.2" +version = "2.25.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-auth" }, @@ -807,29 +669,23 @@ dependencies = [ { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/5c/085bcb872556934bb119e5e09de54daa07873f6866b8f0303c49e72287f7/google_api_core-2.24.2.tar.gz", hash = "sha256:81718493daf06d96d6bc76a91c23874dbf2fac0adbbf542831b805ee6e974696", size = 163516, upload-time = "2025-03-10T15:55:26.201Z" } +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/46/95/f472d85adab6e538da2025dfca9e976a0d125cc0af2301f190e77b76e51c/google_api_core-2.24.2-py3-none-any.whl", hash = "sha256:810a63ac95f3c441b7c0e43d344e372887f62ce9071ba972eacf32672e072de9", size = 160061, upload-time = "2025-03-10T15:55:24.386Z" }, -] - -[package.optional-dependencies] -grpc = [ - { name = "grpcio" }, - { name = "grpcio-status" }, + { 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.2" +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/66/84/f67f53c505a6b2c5da05c988e2a5483f5ba9eee4b1841d2e3ff22f547cd5/google_auth-2.40.2.tar.gz", hash = "sha256:a33cde547a2134273226fa4b853883559947ebe9207521f7afc707efbf690f58", size = 280990, upload-time = "2025-05-21T18:04:59.816Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/c7/e2d82e6702e2a9e2311c138f8e1100f21d08aed0231290872b229ae57a86/google_auth-2.40.2-py2.py3-none-any.whl", hash = "sha256:f7e568d42eedfded58734f6a60c58321896a621f7c116c411550a4b4a13da90b", size = 216102, upload-time = "2025-05-21T18:04:57.547Z" }, + { 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" }, ] [[package]] @@ -858,25 +714,9 @@ 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-run" -version = "0.10.18" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core", extra = ["grpc"] }, - { name = "google-auth" }, - { name = "grpc-google-iam-v1" }, - { name = "proto-plus" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7e/43/fc4df525681150790edfd6159ea7ca87849fdcaf3c440bd46390df1e63ac/google_cloud_run-0.10.18.tar.gz", hash = "sha256:53e61a0b313ce266c16e57165a9cb29bb801799beb944fd87c206cfca72c76cc", size = 358083, upload-time = "2025-05-15T16:41:03.195Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/93/6c/706c30daaf51b364c54cf9d549eed6c59982c45450a1ae6364d705e0ba91/google_cloud_run-0.10.18-py3-none-any.whl", hash = "sha256:754974343bde47f0ccbe30b0bfebd0632369126898ee6a305783ab7a6afcea3c", size = 333783, upload-time = "2025-05-15T16:41:01.719Z" }, -] - [[package]] name = "google-cloud-storage" -version = "3.1.0" +version = "3.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core" }, @@ -886,9 +726,9 @@ dependencies = [ { name = "google-resumable-media" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f3/08/52143124415a889bbab60a8ecede1e31ea0e8d992ca078317886f26dc3be/google_cloud_storage-3.1.0.tar.gz", hash = "sha256:944273179897c7c8a07ee15f2e6466a02da0c7c4b9ecceac2a26017cb2972049", size = 7666527, upload-time = "2025-02-28T00:20:02.383Z" } +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/13/b8/c99c965659f45efa73080477c49ffddf7b9aecb00806be8422560bb5b824/google_cloud_storage-3.1.0-py2.py3-none-any.whl", hash = "sha256:eaf36966b68660a9633f03b067e4a10ce09f1377cae3ff9f2c699f69a81c66c6", size = 174861, upload-time = "2025-02-28T00:19:59.459Z" }, + { 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]] @@ -928,91 +768,36 @@ 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" }, ] -[package.optional-dependencies] -grpc = [ - { name = "grpcio" }, -] - -[[package]] -name = "grpc-google-iam-v1" -version = "0.14.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "googleapis-common-protos", extra = ["grpc"] }, - { name = "grpcio" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/4e/8d0ca3b035e41fe0b3f31ebbb638356af720335e5a11154c330169b40777/grpc_google_iam_v1-0.14.2.tar.gz", hash = "sha256:b3e1fc387a1a329e41672197d0ace9de22c78dd7d215048c4c78712073f7bd20", size = 16259, upload-time = "2025-03-17T11:40:23.586Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/66/6f/dd9b178aee7835b96c2e63715aba6516a9d50f6bebbd1cc1d32c82a2a6c3/grpc_google_iam_v1-0.14.2-py3-none-any.whl", hash = "sha256:a3171468459770907926d56a440b2bb643eec1d7ba215f48f3ecece42b4d8351", size = 19242, upload-time = "2025-03-17T11:40:22.648Z" }, -] - [[package]] name = "grpcio" -version = "1.66.2" +version = "1.74.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/71/d1/49a96df4eb1d805cf546247df40636515416d2d5c66665e5129c8b4162a8/grpcio-1.66.2.tar.gz", hash = "sha256:563588c587b75c34b928bc428548e5b00ea38c46972181a4d8b75ba7e3f24231", size = 12489713, upload-time = "2024-09-28T12:44:01.429Z" } +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/6b/5c/c4da36b7a77dbb15c4bc72228dff7161874752b2c6bddf7bb046d9da1b90/grpcio-1.66.2-cp312-cp312-linux_armv7l.whl", hash = "sha256:802d84fd3d50614170649853d121baaaa305de7b65b3e01759247e768d691ddf", size = 5002933, upload-time = "2024-09-28T12:38:24.109Z" }, - { url = "https://files.pythonhosted.org/packages/a0/d5/b631445dff250a5301f51ff56c5fc917c7f955cd02fa55379f158a89abeb/grpcio-1.66.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:80fd702ba7e432994df208f27514280b4b5c6843e12a48759c9255679ad38db8", size = 10793953, upload-time = "2024-09-28T12:38:27.02Z" }, - { url = "https://files.pythonhosted.org/packages/c8/1c/2179ac112152e92c02990f98183edf645df14aa3c38b39f1a3a60358b6c6/grpcio-1.66.2-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:12fda97ffae55e6526825daf25ad0fa37483685952b5d0f910d6405c87e3adb6", size = 5499791, upload-time = "2024-09-28T12:38:30.065Z" }, - { url = "https://files.pythonhosted.org/packages/0b/53/8d7ab865fbd983309c8242930f00b28a01047f70c2b2e4c79a5c92a46a08/grpcio-1.66.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:950da58d7d80abd0ea68757769c9db0a95b31163e53e5bb60438d263f4bed7b7", size = 6109606, upload-time = "2024-09-28T12:38:33.566Z" }, - { url = "https://files.pythonhosted.org/packages/86/e9/3dfb5a3ff540636d46b8b723345e923e8c553d9b3f6a8d1b09b0d915eb46/grpcio-1.66.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e636ce23273683b00410f1971d209bf3689238cf5538d960adc3cdfe80dd0dbd", size = 5762866, upload-time = "2024-09-28T12:38:36.023Z" }, - { url = "https://files.pythonhosted.org/packages/f1/cb/c07493ad5dd73d51e4e15b0d483ff212dfec136ee1e4f3b49d115bdc7a13/grpcio-1.66.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a917d26e0fe980b0ac7bfcc1a3c4ad6a9a4612c911d33efb55ed7833c749b0ee", size = 6446819, upload-time = "2024-09-28T12:38:38.69Z" }, - { url = "https://files.pythonhosted.org/packages/ff/5f/142e19db367a34ea0ee8a8451e43215d0a1a5dbffcfdcae8801f22903301/grpcio-1.66.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49f0ca7ae850f59f828a723a9064cadbed90f1ece179d375966546499b8a2c9c", size = 6040273, upload-time = "2024-09-28T12:38:41.348Z" }, - { url = "https://files.pythonhosted.org/packages/5c/3b/12fcd752c55002e4b0e0a7bd5faec101bc0a4e3890be3f95a43353142481/grpcio-1.66.2-cp312-cp312-win32.whl", hash = "sha256:31fd163105464797a72d901a06472860845ac157389e10f12631025b3e4d0453", size = 3537988, upload-time = "2024-09-28T12:38:44.544Z" }, - { url = "https://files.pythonhosted.org/packages/f1/70/76bfea3faa862bfceccba255792e780691ff25b8227180759c9d38769379/grpcio-1.66.2-cp312-cp312-win_amd64.whl", hash = "sha256:ff1f7882e56c40b0d33c4922c15dfa30612f05fb785074a012f7cda74d1c3679", size = 4275553, upload-time = "2024-09-28T12:38:47.734Z" }, + { 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.62.3" +version = "1.74.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, { name = "grpcio" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/d7/013ef01c5a1c2fd0932c27c904934162f69f41ca0f28396d3ffe4d386123/grpcio-status-1.62.3.tar.gz", hash = "sha256:289bdd7b2459794a12cf95dc0cb727bd4a1742c37bd823f760236c937e53a485", size = 13063, upload-time = "2024-08-06T00:37:08.003Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/40/972271de05f9315c0d69f9f7ebbcadd83bc85322f538637d11bb8c67803d/grpcio_status-1.62.3-py3-none-any.whl", hash = "sha256:f9049b762ba8de6b1086789d8315846e094edac2c50beaf462338b301a8fd4b8", size = 14448, upload-time = "2024-08-06T00:30:15.702Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, + { 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" }, ] [[package]] @@ -1036,29 +821,6 @@ 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" }, ] -[[package]] -name = "infrastructure" -version = "20250716.1" -source = { virtual = "infrastructure" } -dependencies = [ - { name = "pulumi" }, - { name = "pulumi-aws" }, - { name = "pulumi-docker" }, - { name = "pulumi-docker-build" }, - { name = "pulumi-eks" }, - { name = "pulumi-kubernetes" }, -] - -[package.metadata] -requires-dist = [ - { name = "pulumi", specifier = ">=3.169.0" }, - { name = "pulumi-aws", specifier = ">=6.0.0" }, - { name = "pulumi-docker", specifier = ">=3.0.0" }, - { name = "pulumi-docker-build", specifier = ">=0.0.12" }, - { name = "pulumi-eks", specifier = ">=3.9.1" }, - { name = "pulumi-kubernetes", specifier = ">=4.23.0" }, -] - [[package]] name = "iniconfig" version = "2.1.0" @@ -1068,6 +830,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, ] +[[package]] +name = "internal" +version = "0.1.0" +source = { editable = "libraries/python" } +dependencies = [ + { name = "cloudevents" }, + { name = "numpy" }, + { name = "polars" }, + { name = "pydantic" }, + { name = "tinygrad" }, +] + +[package.metadata] +requires-dist = [ + { name = "cloudevents", specifier = ">=1.12.0" }, + { name = "numpy", specifier = ">=2.2.6" }, + { 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" @@ -1100,14 +883,14 @@ wheels = [ [[package]] name = "jaraco-functools" -version = "4.1.0" +version = "4.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "more-itertools" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/23/9894b3df5d0a6eb44611c36aec777823fc2e07740dabbd0b810e19594013/jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", size = 19159, upload-time = "2024-09-27T19:47:09.122Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/1c/831faaaa0f090b711c355c6d8b2abf277c72133aab472b6932b03322294c/jaraco_functools-4.2.1.tar.gz", hash = "sha256:be634abfccabce56fa3053f8c7ebe37b682683a4ee7793670ced17bab0087353", size = 19661, upload-time = "2025-06-21T19:22:03.201Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/4f/24b319316142c44283d7540e76c7b5a6dbd5db623abd86bb7b3491c21018/jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649", size = 10187, upload-time = "2024-09-27T19:47:07.14Z" }, + { url = "https://files.pythonhosted.org/packages/f3/fd/179a20f832824514df39a90bb0e5372b314fea99f217f5ab942b10a8a4e8/jaraco_functools-4.2.1-py3-none-any.whl", hash = "sha256:590486285803805f4b1f99c60ca9e94ed348d4added84b74c7a12885561e524e", size = 10349, upload-time = "2025-06-21T19:22:02.039Z" }, ] [[package]] @@ -1119,18 +902,6 @@ 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 = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - [[package]] name = "jmespath" version = "1.0.1" @@ -1163,11 +934,11 @@ wheels = [ [[package]] name = "jsonpickle" -version = "4.1.0" +version = "4.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/4f/1dde1e344dc41c40bc3f0eb721d7ddc5fed827bf518ba410c369f6bbaa07/jsonpickle-4.1.0.tar.gz", hash = "sha256:d417d6d693a63fb137e53334164aba618d18aca05a4fd025ff01c2ec134ae4c8", size = 318466, upload-time = "2025-05-21T19:40:19.02Z" } +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/0e/b5/8d90bb4951a1e821d0b4e559edb3c70918b8954b566c7eb9211846a48c47/jsonpickle-4.1.0-py3-none-any.whl", hash = "sha256:763f837a0b2586b45424d9a07108a798d9feac52f3a152606336f7f9e1a22ffa", size = 46615, upload-time = "2025-05-21T19:40:13.344Z" }, + { 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]] @@ -1202,32 +973,14 @@ wheels = [ [[package]] name = "markdown-it-py" -version = "3.0.0" +version = "4.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +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/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { 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]] @@ -1287,6 +1040,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] +[[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" @@ -1298,16 +1086,16 @@ wheels = [ [[package]] name = "msal" -version = "1.32.3" +version = "1.33.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, { name = "pyjwt", extra = ["crypto"] }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3f/90/81dcc50f0be11a8c4dcbae1a9f761a26e5f905231330a7cacc9f04ec4c61/msal-1.32.3.tar.gz", hash = "sha256:5eea038689c78a5a70ca8ecbe1245458b55a857bd096efb6989c69ba15985d35", size = 151449, upload-time = "2025-04-25T13:12:34.204Z" } +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/04/bf/81516b9aac7fd867709984d08eb4db1d2e3fe1df795c8e442cde9b568962/msal-1.32.3-py3-none-any.whl", hash = "sha256:b2798db57760b1961b142f027ffb7c8169536bf77316e99a0df5c4aaebb11569", size = 115358, upload-time = "2025-04-25T13:12:33.034Z" }, + { 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]] @@ -1324,47 +1112,47 @@ wheels = [ [[package]] name = "msgpack" -version = "1.1.0" +version = "1.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cb/d0/7555686ae7ff5731205df1012ede15dd9d927f6227ea151e901c7406af4f/msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e", size = 167260, upload-time = "2024-09-10T04:25:52.197Z" } +sdist = { url = "https://files.pythonhosted.org/packages/45/b1/ea4f68038a18c77c9467400d166d74c4ffa536f34761f7983a104357e614/msgpack-1.1.1.tar.gz", hash = "sha256:77b79ce34a2bdab2594f490c8e80dd62a02d650b91a75159a63ec413b8d104cd", size = 173555, upload-time = "2025-06-13T06:52:51.324Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/d6/716b7ca1dbde63290d2973d22bbef1b5032ca634c3ff4384a958ec3f093a/msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d", size = 152421, upload-time = "2024-09-10T04:25:49.63Z" }, - { url = "https://files.pythonhosted.org/packages/70/da/5312b067f6773429cec2f8f08b021c06af416bba340c912c2ec778539ed6/msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2", size = 85277, upload-time = "2024-09-10T04:24:48.562Z" }, - { url = "https://files.pythonhosted.org/packages/28/51/da7f3ae4462e8bb98af0d5bdf2707f1b8c65a0d4f496e46b6afb06cbc286/msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420", size = 82222, upload-time = "2024-09-10T04:25:36.49Z" }, - { url = "https://files.pythonhosted.org/packages/33/af/dc95c4b2a49cff17ce47611ca9ba218198806cad7796c0b01d1e332c86bb/msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2", size = 392971, upload-time = "2024-09-10T04:24:58.129Z" }, - { url = "https://files.pythonhosted.org/packages/f1/54/65af8de681fa8255402c80eda2a501ba467921d5a7a028c9c22a2c2eedb5/msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39", size = 401403, upload-time = "2024-09-10T04:25:40.428Z" }, - { url = "https://files.pythonhosted.org/packages/97/8c/e333690777bd33919ab7024269dc3c41c76ef5137b211d776fbb404bfead/msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f", size = 385356, upload-time = "2024-09-10T04:25:31.406Z" }, - { url = "https://files.pythonhosted.org/packages/57/52/406795ba478dc1c890559dd4e89280fa86506608a28ccf3a72fbf45df9f5/msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247", size = 383028, upload-time = "2024-09-10T04:25:17.08Z" }, - { url = "https://files.pythonhosted.org/packages/e7/69/053b6549bf90a3acadcd8232eae03e2fefc87f066a5b9fbb37e2e608859f/msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c", size = 391100, upload-time = "2024-09-10T04:25:08.993Z" }, - { url = "https://files.pythonhosted.org/packages/23/f0/d4101d4da054f04274995ddc4086c2715d9b93111eb9ed49686c0f7ccc8a/msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b", size = 394254, upload-time = "2024-09-10T04:25:06.048Z" }, - { url = "https://files.pythonhosted.org/packages/1c/12/cf07458f35d0d775ff3a2dc5559fa2e1fcd06c46f1ef510e594ebefdca01/msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b", size = 69085, upload-time = "2024-09-10T04:25:01.494Z" }, - { url = "https://files.pythonhosted.org/packages/73/80/2708a4641f7d553a63bc934a3eb7214806b5b39d200133ca7f7afb0a53e8/msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f", size = 75347, upload-time = "2024-09-10T04:25:33.106Z" }, + { url = "https://files.pythonhosted.org/packages/e3/26/389b9c593eda2b8551b2e7126ad3a06af6f9b44274eb3a4f054d48ff7e47/msgpack-1.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ae497b11f4c21558d95de9f64fff7053544f4d1a17731c866143ed6bb4591238", size = 82359, upload-time = "2025-06-13T06:52:03.909Z" }, + { url = "https://files.pythonhosted.org/packages/ab/65/7d1de38c8a22cf8b1551469159d4b6cf49be2126adc2482de50976084d78/msgpack-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:33be9ab121df9b6b461ff91baac6f2731f83d9b27ed948c5b9d1978ae28bf157", size = 79172, upload-time = "2025-06-13T06:52:05.246Z" }, + { url = "https://files.pythonhosted.org/packages/0f/bd/cacf208b64d9577a62c74b677e1ada005caa9b69a05a599889d6fc2ab20a/msgpack-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f64ae8fe7ffba251fecb8408540c34ee9df1c26674c50c4544d72dbf792e5ce", size = 425013, upload-time = "2025-06-13T06:52:06.341Z" }, + { url = "https://files.pythonhosted.org/packages/4d/ec/fd869e2567cc9c01278a736cfd1697941ba0d4b81a43e0aa2e8d71dab208/msgpack-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a494554874691720ba5891c9b0b39474ba43ffb1aaf32a5dac874effb1619e1a", size = 426905, upload-time = "2025-06-13T06:52:07.501Z" }, + { url = "https://files.pythonhosted.org/packages/55/2a/35860f33229075bce803a5593d046d8b489d7ba2fc85701e714fc1aaf898/msgpack-1.1.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb643284ab0ed26f6957d969fe0dd8bb17beb567beb8998140b5e38a90974f6c", size = 407336, upload-time = "2025-06-13T06:52:09.047Z" }, + { url = "https://files.pythonhosted.org/packages/8c/16/69ed8f3ada150bf92745fb4921bd621fd2cdf5a42e25eb50bcc57a5328f0/msgpack-1.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d275a9e3c81b1093c060c3837e580c37f47c51eca031f7b5fb76f7b8470f5f9b", size = 409485, upload-time = "2025-06-13T06:52:10.382Z" }, + { url = "https://files.pythonhosted.org/packages/c6/b6/0c398039e4c6d0b2e37c61d7e0e9d13439f91f780686deb8ee64ecf1ae71/msgpack-1.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fd6b577e4541676e0cc9ddc1709d25014d3ad9a66caa19962c4f5de30fc09ef", size = 412182, upload-time = "2025-06-13T06:52:11.644Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d0/0cf4a6ecb9bc960d624c93effaeaae75cbf00b3bc4a54f35c8507273cda1/msgpack-1.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb29aaa613c0a1c40d1af111abf025f1732cab333f96f285d6a93b934738a68a", size = 419883, upload-time = "2025-06-13T06:52:12.806Z" }, + { url = "https://files.pythonhosted.org/packages/62/83/9697c211720fa71a2dfb632cad6196a8af3abea56eece220fde4674dc44b/msgpack-1.1.1-cp312-cp312-win32.whl", hash = "sha256:870b9a626280c86cff9c576ec0d9cbcc54a1e5ebda9cd26dab12baf41fee218c", size = 65406, upload-time = "2025-06-13T06:52:14.271Z" }, + { url = "https://files.pythonhosted.org/packages/c0/23/0abb886e80eab08f5e8c485d6f13924028602829f63b8f5fa25a06636628/msgpack-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:5692095123007180dca3e788bb4c399cc26626da51629a31d40207cb262e67f4", size = 72558, upload-time = "2025-06-13T06:52:15.252Z" }, ] [[package]] name = "multidict" -version = "6.4.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/2f/a3470242707058fe856fe59241eee5635d79087100b7042a867368863a27/multidict-6.4.4.tar.gz", hash = "sha256:69ee9e6ba214b5245031b76233dd95408a0fd57fdb019ddcc1ead4790932a8e8", size = 90183, upload-time = "2025-05-19T14:16:37.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/b5/5675377da23d60875fe7dae6be841787755878e315e2f517235f22f59e18/multidict-6.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc388f75a1c00000824bf28b7633e40854f4127ede80512b44c3cfeeea1839a2", size = 64293, upload-time = "2025-05-19T14:14:44.724Z" }, - { url = "https://files.pythonhosted.org/packages/34/a7/be384a482754bb8c95d2bbe91717bf7ccce6dc38c18569997a11f95aa554/multidict-6.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:98af87593a666f739d9dba5d0ae86e01b0e1a9cfcd2e30d2d361fbbbd1a9162d", size = 38096, upload-time = "2025-05-19T14:14:45.95Z" }, - { url = "https://files.pythonhosted.org/packages/66/6d/d59854bb4352306145bdfd1704d210731c1bb2c890bfee31fb7bbc1c4c7f/multidict-6.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aff4cafea2d120327d55eadd6b7f1136a8e5a0ecf6fb3b6863e8aca32cd8e50a", size = 37214, upload-time = "2025-05-19T14:14:47.158Z" }, - { url = "https://files.pythonhosted.org/packages/99/e0/c29d9d462d7cfc5fc8f9bf24f9c6843b40e953c0b55e04eba2ad2cf54fba/multidict-6.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:169c4ba7858176b797fe551d6e99040c531c775d2d57b31bcf4de6d7a669847f", size = 224686, upload-time = "2025-05-19T14:14:48.366Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4a/da99398d7fd8210d9de068f9a1b5f96dfaf67d51e3f2521f17cba4ee1012/multidict-6.4.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9eb4c59c54421a32b3273d4239865cb14ead53a606db066d7130ac80cc8ec93", size = 231061, upload-time = "2025-05-19T14:14:49.952Z" }, - { url = "https://files.pythonhosted.org/packages/21/f5/ac11add39a0f447ac89353e6ca46666847051103649831c08a2800a14455/multidict-6.4.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cf3bd54c56aa16fdb40028d545eaa8d051402b61533c21e84046e05513d5780", size = 232412, upload-time = "2025-05-19T14:14:51.812Z" }, - { url = "https://files.pythonhosted.org/packages/d9/11/4b551e2110cded705a3c13a1d4b6a11f73891eb5a1c449f1b2b6259e58a6/multidict-6.4.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f682c42003c7264134bfe886376299db4cc0c6cd06a3295b41b347044bcb5482", size = 231563, upload-time = "2025-05-19T14:14:53.262Z" }, - { url = "https://files.pythonhosted.org/packages/4c/02/751530c19e78fe73b24c3da66618eda0aa0d7f6e7aa512e46483de6be210/multidict-6.4.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920f9cf2abdf6e493c519492d892c362007f113c94da4c239ae88429835bad1", size = 223811, upload-time = "2025-05-19T14:14:55.232Z" }, - { url = "https://files.pythonhosted.org/packages/c7/cb/2be8a214643056289e51ca356026c7b2ce7225373e7a1f8c8715efee8988/multidict-6.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:530d86827a2df6504526106b4c104ba19044594f8722d3e87714e847c74a0275", size = 216524, upload-time = "2025-05-19T14:14:57.226Z" }, - { url = "https://files.pythonhosted.org/packages/19/f3/6d5011ec375c09081f5250af58de85f172bfcaafebff286d8089243c4bd4/multidict-6.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ecde56ea2439b96ed8a8d826b50c57364612ddac0438c39e473fafad7ae1c23b", size = 229012, upload-time = "2025-05-19T14:14:58.597Z" }, - { url = "https://files.pythonhosted.org/packages/67/9c/ca510785df5cf0eaf5b2a8132d7d04c1ce058dcf2c16233e596ce37a7f8e/multidict-6.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:dc8c9736d8574b560634775ac0def6bdc1661fc63fa27ffdfc7264c565bcb4f2", size = 226765, upload-time = "2025-05-19T14:15:00.048Z" }, - { url = "https://files.pythonhosted.org/packages/36/c8/ca86019994e92a0f11e642bda31265854e6ea7b235642f0477e8c2e25c1f/multidict-6.4.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7f3d3b3c34867579ea47cbd6c1f2ce23fbfd20a273b6f9e3177e256584f1eacc", size = 222888, upload-time = "2025-05-19T14:15:01.568Z" }, - { url = "https://files.pythonhosted.org/packages/c6/67/bc25a8e8bd522935379066950ec4e2277f9b236162a73548a2576d4b9587/multidict-6.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:87a728af265e08f96b6318ebe3c0f68b9335131f461efab2fc64cc84a44aa6ed", size = 234041, upload-time = "2025-05-19T14:15:03.759Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a0/70c4c2d12857fccbe607b334b7ee28b6b5326c322ca8f73ee54e70d76484/multidict-6.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9f193eeda1857f8e8d3079a4abd258f42ef4a4bc87388452ed1e1c4d2b0c8740", size = 231046, upload-time = "2025-05-19T14:15:05.698Z" }, - { url = "https://files.pythonhosted.org/packages/c1/0f/52954601d02d39742aab01d6b92f53c1dd38b2392248154c50797b4df7f1/multidict-6.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be06e73c06415199200e9a2324a11252a3d62030319919cde5e6950ffeccf72e", size = 227106, upload-time = "2025-05-19T14:15:07.124Z" }, - { url = "https://files.pythonhosted.org/packages/af/24/679d83ec4379402d28721790dce818e5d6b9f94ce1323a556fb17fa9996c/multidict-6.4.4-cp312-cp312-win32.whl", hash = "sha256:622f26ea6a7e19b7c48dd9228071f571b2fbbd57a8cd71c061e848f281550e6b", size = 35351, upload-time = "2025-05-19T14:15:08.556Z" }, - { url = "https://files.pythonhosted.org/packages/52/ef/40d98bc5f986f61565f9b345f102409534e29da86a6454eb6b7c00225a13/multidict-6.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:5e2bcda30d5009996ff439e02a9f2b5c3d64a20151d34898c000a6281faa3781", size = 38791, upload-time = "2025-05-19T14:15:09.825Z" }, - { url = "https://files.pythonhosted.org/packages/84/5d/e17845bb0fa76334477d5de38654d27946d5b5d3695443987a094a71b440/multidict-6.4.4-py3-none-any.whl", hash = "sha256:bd4557071b561a8b3b6075c3ce93cf9bfb6182cb241805c3d66ced3b75eff4ac", size = 10481, upload-time = "2025-05-19T14:16:36.024Z" }, +version = "6.6.4" +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" } +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" }, ] [[package]] @@ -1378,48 +1166,30 @@ wheels = [ [[package]] name = "numpy" -version = "2.2.6" +version = "2.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, - { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, - { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, - { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, - { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, - { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, - { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, - { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, - { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, - { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, + { 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" }, ] [[package]] name = "oauthlib" -version = "3.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6d/fa/fbf4001037904031639e6bfbfc02badfc7e12f137a8afa254df6c4c8a670/oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918", size = 177352, upload-time = "2022-10-17T20:04:27.471Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/80/cab10959dc1faead58dc8384a781dfbf93cb4d33d50988f7a69f1b7c9bbe/oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", size = 151688, upload-time = "2022-10-17T20:04:24.037Z" }, -] - -[[package]] -name = "osqp" -version = "1.0.4" +version = "3.3.1" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "joblib" }, - { name = "numpy" }, - { name = "scipy" }, - { name = "setuptools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/30/13/c74c50bab7477029daf9fc99455cc9c8b25e50843e44cf096b237d3ac6b2/osqp-1.0.4.tar.gz", hash = "sha256:0877552e325ff4cc1c676796ba482904eb4b66e750eff5b91df3273201f5ed00", size = 56640, upload-time = "2025-05-08T15:16:26.376Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/0f/e5896586d495c82a37f68e4ba26c10c7969858f6991584f4ddb477e83be4/osqp-1.0.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6432c8ea5db1b334eb20abce2c0eca081edc070ea86ec634bb62e8ca1a014e21", size = 313468, upload-time = "2025-05-08T15:16:07.015Z" }, - { url = "https://files.pythonhosted.org/packages/4b/79/a1e26d05e2026489c0ea76503d8ae614af0cc436d4c9cdedae0f17da6fc3/osqp-1.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8510861708fe664a0942bccfea4b3ea566b12927e54b415f539c24b8cad095c0", size = 291828, upload-time = "2025-05-08T15:16:08.133Z" }, - { url = "https://files.pythonhosted.org/packages/17/f3/428837a4fee6080bda8017367fc1bef1f61a80144576978cb404be5b6f97/osqp-1.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a3e3321b11426fa7a33b84f87f8d8608fdcd56c3992739012370f4d475b6a8f", size = 345079, upload-time = "2025-05-08T15:16:09.317Z" }, - { url = "https://files.pythonhosted.org/packages/3c/17/46343994f07d0b629a661274b40632499e4920ee355b67717458d3d2b47e/osqp-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:73357ceb0cee581a8a18f32a50dda8954c80374bc94e77c06d8ececb402e2a22", size = 303076, upload-time = "2025-05-08T15:16:11.035Z" }, + { 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" }, ] [[package]] @@ -1433,7 +1203,7 @@ wheels = [ [[package]] name = "pandas" -version = "2.2.3" +version = "2.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, @@ -1441,15 +1211,15 @@ dependencies = [ { name = "pytz" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", size = 4399213, upload-time = "2024-09-20T13:10:04.827Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/6f/75aa71f8a14267117adeeed5d21b204770189c0a0025acbdc03c337b28fc/pandas-2.3.1.tar.gz", hash = "sha256:0a95b9ac964fe83ce317827f80304d37388ea77616b1425f0ae41c9d2d0d7bb2", size = 4487493, upload-time = "2025-07-07T19:20:04.079Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", size = 12529893, upload-time = "2024-09-20T13:09:09.655Z" }, - { url = "https://files.pythonhosted.org/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", size = 11363475, upload-time = "2024-09-20T13:09:14.718Z" }, - { url = "https://files.pythonhosted.org/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", size = 15188645, upload-time = "2024-09-20T19:02:03.88Z" }, - { url = "https://files.pythonhosted.org/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319", size = 12739445, upload-time = "2024-09-20T13:09:17.621Z" }, - { url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", size = 16359235, upload-time = "2024-09-20T19:02:07.094Z" }, - { url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", size = 14056756, upload-time = "2024-09-20T13:09:20.474Z" }, - { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248, upload-time = "2024-09-20T13:09:23.137Z" }, + { url = "https://files.pythonhosted.org/packages/46/de/b8445e0f5d217a99fe0eeb2f4988070908979bec3587c0633e5428ab596c/pandas-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:689968e841136f9e542020698ee1c4fbe9caa2ed2213ae2388dc7b81721510d3", size = 11588172, upload-time = "2025-07-07T19:18:52.054Z" }, + { url = "https://files.pythonhosted.org/packages/1e/e0/801cdb3564e65a5ac041ab99ea6f1d802a6c325bb6e58c79c06a3f1cd010/pandas-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:025e92411c16cbe5bb2a4abc99732a6b132f439b8aab23a59fa593eb00704232", size = 10717365, upload-time = "2025-07-07T19:18:54.785Z" }, + { url = "https://files.pythonhosted.org/packages/51/a5/c76a8311833c24ae61a376dbf360eb1b1c9247a5d9c1e8b356563b31b80c/pandas-2.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b7ff55f31c4fcb3e316e8f7fa194566b286d6ac430afec0d461163312c5841e", size = 11280411, upload-time = "2025-07-07T19:18:57.045Z" }, + { url = "https://files.pythonhosted.org/packages/da/01/e383018feba0a1ead6cf5fe8728e5d767fee02f06a3d800e82c489e5daaf/pandas-2.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dcb79bf373a47d2a40cf7232928eb7540155abbc460925c2c96d2d30b006eb4", size = 11988013, upload-time = "2025-07-07T19:18:59.771Z" }, + { url = "https://files.pythonhosted.org/packages/5b/14/cec7760d7c9507f11c97d64f29022e12a6cc4fc03ac694535e89f88ad2ec/pandas-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:56a342b231e8862c96bdb6ab97170e203ce511f4d0429589c8ede1ee8ece48b8", size = 12767210, upload-time = "2025-07-07T19:19:02.944Z" }, + { url = "https://files.pythonhosted.org/packages/50/b9/6e2d2c6728ed29fb3d4d4d302504fb66f1a543e37eb2e43f352a86365cdf/pandas-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ca7ed14832bce68baef331f4d7f294411bed8efd032f8109d690df45e00c4679", size = 13440571, upload-time = "2025-07-07T19:19:06.82Z" }, + { url = "https://files.pythonhosted.org/packages/80/a5/3a92893e7399a691bad7664d977cb5e7c81cf666c81f89ea76ba2bff483d/pandas-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ac942bfd0aca577bef61f2bc8da8147c4ef6879965ef883d8e8d5d2dc3e744b8", size = 10987601, upload-time = "2025-07-07T19:19:09.589Z" }, ] [[package]] @@ -1463,50 +1233,24 @@ wheels = [ [[package]] name = "parse-type" -version = "0.6.4" +version = "0.6.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "parse" }, { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/e9/a3b2ae5f8a852542788ac1f1865dcea0c549cc40af243f42cabfa0acf24d/parse_type-0.6.4.tar.gz", hash = "sha256:5e1ec10440b000c3f818006033372939e693a9ec0176f446d9303e4db88489a6", size = 96480, upload-time = "2024-10-03T11:51:00.353Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/ea/42ba6ce0abba04ab6e0b997dcb9b528a4661b62af1fe1b0d498120d5ea78/parse_type-0.6.6.tar.gz", hash = "sha256:513a3784104839770d690e04339a8b4d33439fcd5dd99f2e4580f9fc1097bfb2", size = 98012, upload-time = "2025-08-11T22:53:48.066Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/b3/f6cc950042bfdbe98672e7c834d930f85920fb7d3359f59096e8d2799617/parse_type-0.6.4-py2.py3-none-any.whl", hash = "sha256:83d41144a82d6b8541127bf212dd76c7f01baff680b498ce8a4d052a7a5bce4c", size = 27442, upload-time = "2024-10-03T11:50:58.519Z" }, + { 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" +name = "platformdirs" +version = "4.3.8" 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.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/59/de/241caa0ca606f2ec5fe0c1f4261b0465df78d786a38da693864a116c37f4/pip-25.1.1.tar.gz", hash = "sha256:3de45d411d308d5054c2168185d8da7f9a2cd753dbac8acbfa88a8909ecd9077", size = 1940155, upload-time = "2025-05-02T15:14:02.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/a2/d40fb2460e883eca5199c62cfc2463fd261f760556ae6290f88488c362c0/pip-25.1.1-py3-none-any.whl", hash = "sha256:2913a38a2abf4ea6b64ab507bd9e967f3b53dc1ede74b01b0931e1ce548751af", size = 1825227, upload-time = "2025-05-02T15:13:59.102Z" }, -] - -[[package]] -name = "plotly" -version = "5.24.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "tenacity" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/79/4f/428f6d959818d7425a94c190a6b26fbc58035cbef40bf249be0b62a9aedd/plotly-5.24.1.tar.gz", hash = "sha256:dbc8ac8339d248a4bcc36e08a5659bacfe1b079390b8953533f4eb22169b4bae", size = 9479398, upload-time = "2024-09-12T15:36:31.068Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/ae/580600f441f6fc05218bd6c9d5794f4aef072a7d9093b291f1c50a9db8bc/plotly-5.24.1-py3-none-any.whl", hash = "sha256:f67073a1e637eb0dc3e46324d9d51e2fe76e9727c892dde64ddf1e1b51f29089", size = 19054220, upload-time = "2024-09-12T15:36:24.08Z" }, + { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, ] [[package]] @@ -1521,7 +1265,10 @@ wheels = [ [[package]] name = "pocketsizefund" version = "20250602.4" -source = { editable = "." } +source = { virtual = "." } +dependencies = [ + { name = "internal" }, +] [package.dev-dependencies] dev = [ @@ -1531,6 +1278,7 @@ dev = [ ] [package.metadata] +requires-dist = [{ name = "internal", editable = "libraries/python" }] [package.metadata.requires-dev] dev = [ @@ -1541,143 +1289,66 @@ dev = [ [[package]] name = "polars" -version = "1.30.0" +version = "1.32.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/b6/8dbdf626c0705a57f052708c9fc0860ffc2aa97955930d5faaf6a66fcfd3/polars-1.30.0.tar.gz", hash = "sha256:dfe94ae84a5efd9ba74e616e3e125b24ca155494a931890a8f17480737c4db45", size = 4668318, upload-time = "2025-05-21T13:33:24.175Z" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/f2/1a76a8bd902bc4942e435a480f362c8687bba60d438ff3283191e38568fa/polars-1.32.3.tar.gz", hash = "sha256:57c500dc1b5cba49b0589034478db031815f3d57a20cb830b05ecee1a9ba56b1", size = 4838448, upload-time = "2025-08-14T17:28:10.702Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/48/e9b2cb379abcc9f7aff2e701098fcdb9fe6d85dc4ad4cec7b35d39c70951/polars-1.30.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:4c33bc97c29b7112f0e689a2f8a33143973a3ff466c70b25c7fd1880225de6dd", size = 35704342, upload-time = "2025-05-21T13:32:22.996Z" }, - { url = "https://files.pythonhosted.org/packages/36/ca/f545f61282f75eea4dfde4db2944963dcd59abd50c20e33a1c894da44dad/polars-1.30.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:e3d05914c364b8e39a5b10dcf97e84d76e516b3b1693880bf189a93aab3ca00d", size = 32459857, upload-time = "2025-05-21T13:32:27.728Z" }, - { url = "https://files.pythonhosted.org/packages/76/20/e018cd87d7cb6f8684355f31f4e193222455a6e8f7b942f4a2934f5969c7/polars-1.30.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a52af3862082b868c1febeae650af8ae8a2105d2cb28f0449179a7b44f54ccf", size = 36267243, upload-time = "2025-05-21T13:32:31.796Z" }, - { url = "https://files.pythonhosted.org/packages/cb/e7/b88b973021be07b13d91b9301cc14392c994225ef5107a32a8ffd3fd6424/polars-1.30.0-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:ffb3ef133454275d4254442257c5f71dd6e393ce365c97997dadeb6fa9d6d4b5", size = 33416871, upload-time = "2025-05-21T13:32:35.077Z" }, - { url = "https://files.pythonhosted.org/packages/dd/7c/d46d4381adeac537b8520b653dc30cb8b7edbf59883d71fbb989e9005de1/polars-1.30.0-cp39-abi3-win_amd64.whl", hash = "sha256:c26b633a9bd530c5fc09d317fca3bb3e16c772bd7df7549a9d8ec1934773cc5d", size = 36363630, upload-time = "2025-05-21T13:32:38.286Z" }, - { url = "https://files.pythonhosted.org/packages/fb/b5/5056d0c12aadb57390d0627492bef8b1abf3549474abb9ae0fd4e2bfa885/polars-1.30.0-cp39-abi3-win_arm64.whl", hash = "sha256:476f1bde65bc7b4d9f80af370645c2981b5798d67c151055e58534e89e96f2a8", size = 32643590, upload-time = "2025-05-21T13:32:42.107Z" }, + { url = "https://files.pythonhosted.org/packages/4c/9b/5937ab9f8fa49c8e00617aeb817a5ffa5740434d5bb8a90f2afa657875aa/polars-1.32.3-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c7c472ea1d50a5104079cb64e34f78f85774bcc69b875ba8daf21233f4c70d42", size = 37935794, upload-time = "2025-08-14T17:26:55.565Z" }, + { url = "https://files.pythonhosted.org/packages/6e/e9/88f5332001b9dd5c8e0a4fab51015f740e01715a081c41bc0f7ad2bf76a5/polars-1.32.3-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:fd87275f0cc795e72a2030b58293198cfa748d4b009cf52218e27db5397ed07f", size = 34621102, upload-time = "2025-08-14T17:27:00.521Z" }, + { url = "https://files.pythonhosted.org/packages/ab/8a/6f56af7e535c34c95decc8654786bfce4632ba32817dc2f8bad18571ef9a/polars-1.32.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9a9b9668ef310e5a77a7e7daa9c753874779c8da52e93f654bfd7953eb4b60b", size = 38443071, upload-time = "2025-08-14T17:27:08.382Z" }, + { url = "https://files.pythonhosted.org/packages/46/aa/63536ea5780edc0ef6850679dc81d519f3966c7bb11a5cf10ccecb541095/polars-1.32.3-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:c8f5d2f43b80b68e39bfaa2948ce632563633466576f12e74e8560d6481f5851", size = 35639598, upload-time = "2025-08-14T17:27:12.261Z" }, + { url = "https://files.pythonhosted.org/packages/d7/c8/226953cda6cf9ae63aa9714d396a9138029e31db3c504c15d6711b618f8f/polars-1.32.3-cp39-abi3-win_amd64.whl", hash = "sha256:db56a7cb4898e173d62634e182f74bdff744c62be5470e0fe20df8d10f659af7", size = 38038192, upload-time = "2025-08-14T17:27:15.993Z" }, + { 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.14.6" +version = "1.15.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/ba/9a20534f09c029127b2fe8dafc25e2765a605bba22b20b471b0e5ae569e4/polygon_api_client-1.14.6.tar.gz", hash = "sha256:6ed518a43db05de544b5a86b8d1aed8ab390df0c59b8e49f656b6a638ce3c1ce", size = 30957, upload-time = "2025-06-03T18:37:24.506Z" } +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/6b/42/afb74666ee99195a7a0a18cd51dcc834f35078b857133b1e2155431ad305/polygon_api_client-1.14.6-py3-none-any.whl", hash = "sha256:7f29d028f712da3a31ca1283a47e4ccd6f145bd355f35f33f638d8675f9d22a9", size = 44201, upload-time = "2025-06-03T18:37:23.182Z" }, -] - -[[package]] -name = "positionmanager" -version = "0.1.0" -source = { editable = "application/positionmanager" } -dependencies = [ - { name = "alpaca-py" }, - { name = "cloudevents" }, - { name = "ecos" }, - { name = "fastapi" }, - { name = "pandas" }, - { name = "polars" }, - { name = "prometheus-fastapi-instrumentator" }, - { name = "pyarrow" }, - { name = "pydantic" }, - { name = "pyportfolioopt" }, - { name = "requests" }, - { name = "uvicorn" }, -] - -[package.metadata] -requires-dist = [ - { name = "alpaca-py", specifier = ">=0.15.0" }, - { name = "cloudevents", specifier = ">=1.12.0" }, - { name = "ecos", specifier = ">=2.0.14" }, - { name = "fastapi", specifier = ">=0.115.12" }, - { name = "pandas", specifier = ">=2.1.0" }, - { name = "polars", specifier = ">=1.29.0" }, - { name = "prometheus-fastapi-instrumentator", specifier = ">=7.1.0" }, - { name = "pyarrow", specifier = ">=20.0.0" }, - { name = "pydantic", specifier = ">=2.8.2" }, - { name = "pyportfolioopt", specifier = ">=1.5.6" }, - { name = "requests", specifier = ">=2.31.0" }, - { name = "uvicorn", specifier = ">=0.34.2" }, + { 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 = "predictionengine" +name = "portfoliomanager" version = "0.1.0" -source = { editable = "application/predictionengine" } +source = { virtual = "applications/portfoliomanager" } dependencies = [ - { name = "cloudevents" }, - { name = "fastapi" }, - { name = "loguru" }, - { name = "numpy" }, - { name = "polars" }, - { name = "prometheus-fastapi-instrumentator" }, - { name = "pyarrow" }, - { name = "requests" }, - { name = "tinygrad" }, - { name = "uvicorn" }, + { name = "internal" }, ] [package.metadata] -requires-dist = [ - { name = "cloudevents", specifier = ">=1.12.0" }, - { name = "fastapi", specifier = ">=0.115.12" }, - { name = "loguru", specifier = ">=0.7.3" }, - { name = "numpy", specifier = ">=2.2.6" }, - { name = "polars", specifier = ">=1.29.0" }, - { name = "prometheus-fastapi-instrumentator", specifier = ">=7.1.0" }, - { name = "pyarrow", specifier = ">=20.0.0" }, - { name = "requests", specifier = ">=2.31.0" }, - { name = "tinygrad", specifier = ">=0.10.3" }, - { name = "uvicorn", specifier = ">=0.34.2" }, -] - -[[package]] -name = "prometheus-client" -version = "0.22.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5b/5a/3fa1fa7e91a203759aaf316be394f70f2ef598d589b9785a8611b6094c00/prometheus_client-0.22.0.tar.gz", hash = "sha256:18da1d2241ac2d10c8d2110f13eedcd5c7c0c8af18c926e8731f04fc10cd575c", size = 74443, upload-time = "2025-05-16T20:50:18.333Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/c7/cee159ba3d7192e84a4c166ec1752f44a5fa859ac0eeda2d73a1da65ab47/prometheus_client-0.22.0-py3-none-any.whl", hash = "sha256:c8951bbe64e62b96cd8e8f5d917279d1b9b91ab766793f33d4dce6c228558713", size = 62658, upload-time = "2025-05-16T20:50:16.978Z" }, -] - -[[package]] -name = "prometheus-fastapi-instrumentator" -version = "7.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "prometheus-client" }, - { name = "starlette" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/69/6d/24d53033cf93826aa7857699a4450c1c67e5b9c710e925b1ed2b320c04df/prometheus_fastapi_instrumentator-7.1.0.tar.gz", hash = "sha256:be7cd61eeea4e5912aeccb4261c6631b3f227d8924542d79eaf5af3f439cbe5e", size = 20220, upload-time = "2025-03-19T19:35:05.351Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/72/0824c18f3bc75810f55dacc2dd933f6ec829771180245ae3cc976195dec0/prometheus_fastapi_instrumentator-7.1.0-py3-none-any.whl", hash = "sha256:978130f3c0bb7b8ebcc90d35516a6fe13e02d2eb358c8f83887cdef7020c31e9", size = 19296, upload-time = "2025-03-19T19:35:04.323Z" }, -] +requires-dist = [{ name = "internal", editable = "libraries/python" }] [[package]] name = "propcache" -version = "0.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/07/c8/fdc6686a986feae3541ea23dcaa661bd93972d3940460646c6bb96e21c40/propcache-0.3.1.tar.gz", hash = "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf", size = 43651, upload-time = "2025-03-26T03:06:12.05Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/41/aa/ca78d9be314d1e15ff517b992bebbed3bdfef5b8919e85bf4940e57b6137/propcache-0.3.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723", size = 80430, upload-time = "2025-03-26T03:04:26.436Z" }, - { url = "https://files.pythonhosted.org/packages/1a/d8/f0c17c44d1cda0ad1979af2e593ea290defdde9eaeb89b08abbe02a5e8e1/propcache-0.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976", size = 46637, upload-time = "2025-03-26T03:04:27.932Z" }, - { url = "https://files.pythonhosted.org/packages/ae/bd/c1e37265910752e6e5e8a4c1605d0129e5b7933c3dc3cf1b9b48ed83b364/propcache-0.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b", size = 46123, upload-time = "2025-03-26T03:04:30.659Z" }, - { url = "https://files.pythonhosted.org/packages/d4/b0/911eda0865f90c0c7e9f0415d40a5bf681204da5fd7ca089361a64c16b28/propcache-0.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f", size = 243031, upload-time = "2025-03-26T03:04:31.977Z" }, - { url = "https://files.pythonhosted.org/packages/0a/06/0da53397c76a74271621807265b6eb61fb011451b1ddebf43213df763669/propcache-0.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70", size = 249100, upload-time = "2025-03-26T03:04:33.45Z" }, - { url = "https://files.pythonhosted.org/packages/f1/eb/13090e05bf6b963fc1653cdc922133ced467cb4b8dab53158db5a37aa21e/propcache-0.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7", size = 250170, upload-time = "2025-03-26T03:04:35.542Z" }, - { url = "https://files.pythonhosted.org/packages/3b/4c/f72c9e1022b3b043ec7dc475a0f405d4c3e10b9b1d378a7330fecf0652da/propcache-0.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25", size = 245000, upload-time = "2025-03-26T03:04:37.501Z" }, - { url = "https://files.pythonhosted.org/packages/e8/fd/970ca0e22acc829f1adf5de3724085e778c1ad8a75bec010049502cb3a86/propcache-0.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277", size = 230262, upload-time = "2025-03-26T03:04:39.532Z" }, - { url = "https://files.pythonhosted.org/packages/c4/42/817289120c6b9194a44f6c3e6b2c3277c5b70bbad39e7df648f177cc3634/propcache-0.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8", size = 236772, upload-time = "2025-03-26T03:04:41.109Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9c/3b3942b302badd589ad6b672da3ca7b660a6c2f505cafd058133ddc73918/propcache-0.3.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e", size = 231133, upload-time = "2025-03-26T03:04:42.544Z" }, - { url = "https://files.pythonhosted.org/packages/98/a1/75f6355f9ad039108ff000dfc2e19962c8dea0430da9a1428e7975cf24b2/propcache-0.3.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee", size = 230741, upload-time = "2025-03-26T03:04:44.06Z" }, - { url = "https://files.pythonhosted.org/packages/67/0c/3e82563af77d1f8731132166da69fdfd95e71210e31f18edce08a1eb11ea/propcache-0.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815", size = 244047, upload-time = "2025-03-26T03:04:45.983Z" }, - { url = "https://files.pythonhosted.org/packages/f7/50/9fb7cca01532a08c4d5186d7bb2da6c4c587825c0ae134b89b47c7d62628/propcache-0.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5", size = 246467, upload-time = "2025-03-26T03:04:47.699Z" }, - { url = "https://files.pythonhosted.org/packages/a9/02/ccbcf3e1c604c16cc525309161d57412c23cf2351523aedbb280eb7c9094/propcache-0.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7", size = 241022, upload-time = "2025-03-26T03:04:49.195Z" }, - { url = "https://files.pythonhosted.org/packages/db/19/e777227545e09ca1e77a6e21274ae9ec45de0f589f0ce3eca2a41f366220/propcache-0.3.1-cp312-cp312-win32.whl", hash = "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b", size = 40647, upload-time = "2025-03-26T03:04:50.595Z" }, - { url = "https://files.pythonhosted.org/packages/24/bb/3b1b01da5dd04c77a204c84e538ff11f624e31431cfde7201d9110b092b1/propcache-0.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3", size = 44784, upload-time = "2025-03-26T03:04:51.791Z" }, - { url = "https://files.pythonhosted.org/packages/b8/d3/c3cb8f1d6ae3b37f83e1de806713a9b3642c5895f0215a62e1a4bd6e5e34/propcache-0.3.1-py3-none-any.whl", hash = "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40", size = 12376, upload-time = "2025-03-26T03:06:10.5Z" }, +version = "0.3.2" +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" } +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" }, ] [[package]] @@ -1694,16 +1365,16 @@ wheels = [ [[package]] name = "protobuf" -version = "4.25.7" +version = "6.32.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/74/63/84fdeac1f03864c2b8b9f0b7fe711c4af5f95759ee281d2026530086b2f5/protobuf-4.25.7.tar.gz", hash = "sha256:28f65ae8c14523cc2c76c1e91680958700d3eac69f45c96512c12c63d9a38807", size = 380612, upload-time = "2025-04-24T02:56:58.685Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/ed/9a58076cfb8edc237c92617f1d3744660e9b4457d54f3c2fdf1a4bbae5c7/protobuf-4.25.7-cp310-abi3-win32.whl", hash = "sha256:dc582cf1a73a6b40aa8e7704389b8d8352da616bc8ed5c6cc614bdd0b5ce3f7a", size = 392457, upload-time = "2025-04-24T02:56:40.798Z" }, - { url = "https://files.pythonhosted.org/packages/28/b3/e00870528029fe252cf3bd6fa535821c276db3753b44a4691aee0d52ff9e/protobuf-4.25.7-cp310-abi3-win_amd64.whl", hash = "sha256:cd873dbddb28460d1706ff4da2e7fac175f62f2a0bebc7b33141f7523c5a2399", size = 413446, upload-time = "2025-04-24T02:56:44.199Z" }, - { url = "https://files.pythonhosted.org/packages/60/1d/f450a193f875a20099d4492d2c1cb23091d65d512956fb1e167ee61b4bf0/protobuf-4.25.7-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:4c899f09b0502eb39174c717ccf005b844ea93e31137c167ddcacf3e09e49610", size = 394248, upload-time = "2025-04-24T02:56:45.75Z" }, - { url = "https://files.pythonhosted.org/packages/c8/b8/ea88e9857484a0618c74121618b9e620fc50042de43cdabbebe1b93a83e0/protobuf-4.25.7-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:6d2f5dede3d112e573f0e5f9778c0c19d9f9e209727abecae1d39db789f522c6", size = 293717, upload-time = "2025-04-24T02:56:47.427Z" }, - { url = "https://files.pythonhosted.org/packages/a7/81/d0b68e9a9a76804113b6dedc6fffed868b97048bbe6f1bedc675bdb8523c/protobuf-4.25.7-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:d41fb7ae72a25fcb79b2d71e4247f0547a02e8185ed51587c22827a87e5736ed", size = 294636, upload-time = "2025-04-24T02:56:48.976Z" }, - { url = "https://files.pythonhosted.org/packages/17/d7/1e7c80cb2ea2880cfe38580dcfbb22b78b746640c9c13fc3337a6967dc4c/protobuf-4.25.7-py3-none-any.whl", hash = "sha256:e9d969f5154eaeab41404def5dcf04e62162178f4b9de98b2d3c1c70f5f84810", size = 156468, upload-time = "2025-04-24T02:56:56.957Z" }, + { 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" }, ] [[package]] @@ -1719,111 +1390,19 @@ 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" }, ] -[[package]] -name = "pulumi" -version = "3.184.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/d1/2a/45bfef6b6dbbceba00a37d3a5928fc0dee61b7ece0383d3f5244c9d26ae2/pulumi-3.184.0-py3-none-any.whl", hash = "sha256:2f4345763d6e171bfb1d900611ab15583bb7aacb97e332a0c8e04dc7e7299ff1", size = 364173, upload-time = "2025-07-18T12:24:47.195Z" }, -] - -[[package]] -name = "pulumi-aws" -version = "6.83.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parver" }, - { name = "pulumi" }, - { name = "semver" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ef/c8/d16a58afdab5c4dafb8043a4370c0673c48ae314aea5ac7d1ce4eee2af76/pulumi_aws-6.83.0.tar.gz", hash = "sha256:24ce88ad5bb81eb937935d9e40466e164addef86140a32cac22ed17176812cb7", size = 7839650, upload-time = "2025-06-16T21:58:19.009Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/0b/3ed17e6fc68d9c0b572c4b259c5e291a8267011c640a9a9bb5a26b596763/pulumi_aws-6.83.0-py3-none-any.whl", hash = "sha256:e61144b9680ae1ebd98daa7bfffce1f646796a9640f9b73119b91e72c26e3bbc", size = 10608060, upload-time = "2025-06-16T21:58:14.969Z" }, -] - -[[package]] -name = "pulumi-docker" -version = "4.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parver" }, - { name = "pulumi" }, - { name = "semver" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/88/47/4ef6f5c2f2a53b6883c152d945bab0ee5e66ed3d295eca8b1e16aa462ca1/pulumi_docker-4.8.0.tar.gz", hash = "sha256:c2460c1d3f011a3602f46d8ef0a4fabd7cc08556a84e7c43ee31acb09d064ad7", size = 106590, upload-time = "2025-06-18T21:39:52.577Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/a7/c345d79c6f5592b41b76e31e27d08ff43fce4ba92a1040fe885065e1f4cb/pulumi_docker-4.8.0-py3-none-any.whl", hash = "sha256:75f2be3d9a646292b6d1985edcc03239cc0ab077e96a188e8423b737cf6c958f", size = 128007, upload-time = "2025-06-18T21:39:50.8Z" }, -] - -[[package]] -name = "pulumi-docker-build" -version = "0.0.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parver" }, - { name = "pulumi" }, - { name = "semver" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2f/d4/4f645603ce8197d2b84b11418d6c8f67a4d40e0d3e5cfdb32f5c79bb8342/pulumi_docker_build-0.0.12.tar.gz", hash = "sha256:e42119d5453df68de30eb554e0d3e6ab317e2fd25bd201296b07611b0e81e45b", size = 39357, upload-time = "2025-05-16T19:30:57.54Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/6f/8b4d6410f8a0ce968374a499555197b08b16dbb2e7d2752e46836fb7f6cd/pulumi_docker_build-0.0.12-py3-none-any.whl", hash = "sha256:fc9b2720650411bccd3de2c2e8dc1b26be1f3b1d4fcbde343343f6829a365e2b", size = 44056, upload-time = "2025-05-16T19:30:55.832Z" }, -] - -[[package]] -name = "pulumi-eks" -version = "3.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parver" }, - { name = "pulumi" }, - { name = "pulumi-aws" }, - { name = "pulumi-kubernetes" }, - { name = "semver" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2b/e3/bbee66003056654b3151092a2f753dea7992cae3710531dda07305c48e0a/pulumi_eks-3.9.1.tar.gz", hash = "sha256:c2a05e63a80080a0241e507c72fece638547e09cdd25507eff5267820bd083f0", size = 89467, upload-time = "2025-05-06T00:09:25.917Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/34/cd37b876ba706593bab423cf4f9b235d3db411328d98f807a0b8fc631349/pulumi_eks-3.9.1-py3-none-any.whl", hash = "sha256:6a7e91bc1468444dd0ae3a0c8985673e740f46f338a24c39373f85f160b561c9", size = 98637, upload-time = "2025-05-06T00:09:24.456Z" }, -] - -[[package]] -name = "pulumi-kubernetes" -version = "4.23.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "parver" }, - { name = "pulumi" }, - { name = "requests" }, - { name = "semver" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7b/9f/23dc36a2982faf8bc66e48e55f5cb44a6580a3e81e1849e0732462982531/pulumi_kubernetes-4.23.0.tar.gz", hash = "sha256:6b697146039d7367f397db77dc1d2b23d918202f4276071bfa105652bb5e5fd4", size = 1775394, upload-time = "2025-05-02T17:34:12.813Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/00/983975f1bcf02601f12b4afb60a4dfdf9f81ab11cbf2493aa349781684ae/pulumi_kubernetes-4.23.0-py3-none-any.whl", hash = "sha256:4866c00259170e5e1604c0a3335063036e80c29000bf9b88a380cd600fe44c4e", size = 2794243, upload-time = "2025-05-02T17:34:10.082Z" }, -] - [[package]] name = "pyarrow" -version = "20.0.0" +version = "21.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/ee/a7810cb9f3d6e9238e61d312076a9859bf3668fd21c69744de9532383912/pyarrow-20.0.0.tar.gz", hash = "sha256:febc4a913592573c8d5805091a6c2b5064c8bd6e002131f01061797d91c783c1", size = 1125187, upload-time = "2025-04-27T12:34:23.264Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/d6/0c10e0d54f6c13eb464ee9b67a68b8c71bcf2f67760ef5b6fbcddd2ab05f/pyarrow-20.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:75a51a5b0eef32727a247707d4755322cb970be7e935172b6a3a9f9ae98404ba", size = 30815067, upload-time = "2025-04-27T12:29:44.384Z" }, - { url = "https://files.pythonhosted.org/packages/7e/e2/04e9874abe4094a06fd8b0cbb0f1312d8dd7d707f144c2ec1e5e8f452ffa/pyarrow-20.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:211d5e84cecc640c7a3ab900f930aaff5cd2702177e0d562d426fb7c4f737781", size = 32297128, upload-time = "2025-04-27T12:29:52.038Z" }, - { url = "https://files.pythonhosted.org/packages/31/fd/c565e5dcc906a3b471a83273039cb75cb79aad4a2d4a12f76cc5ae90a4b8/pyarrow-20.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ba3cf4182828be7a896cbd232aa8dd6a31bd1f9e32776cc3796c012855e1199", size = 41334890, upload-time = "2025-04-27T12:29:59.452Z" }, - { url = "https://files.pythonhosted.org/packages/af/a9/3bdd799e2c9b20c1ea6dc6fa8e83f29480a97711cf806e823f808c2316ac/pyarrow-20.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c3a01f313ffe27ac4126f4c2e5ea0f36a5fc6ab51f8726cf41fee4b256680bd", size = 42421775, upload-time = "2025-04-27T12:30:06.875Z" }, - { url = "https://files.pythonhosted.org/packages/10/f7/da98ccd86354c332f593218101ae56568d5dcedb460e342000bd89c49cc1/pyarrow-20.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:a2791f69ad72addd33510fec7bb14ee06c2a448e06b649e264c094c5b5f7ce28", size = 40687231, upload-time = "2025-04-27T12:30:13.954Z" }, - { url = "https://files.pythonhosted.org/packages/bb/1b/2168d6050e52ff1e6cefc61d600723870bf569cbf41d13db939c8cf97a16/pyarrow-20.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4250e28a22302ce8692d3a0e8ec9d9dde54ec00d237cff4dfa9c1fbf79e472a8", size = 42295639, upload-time = "2025-04-27T12:30:21.949Z" }, - { url = "https://files.pythonhosted.org/packages/b2/66/2d976c0c7158fd25591c8ca55aee026e6d5745a021915a1835578707feb3/pyarrow-20.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:89e030dc58fc760e4010148e6ff164d2f44441490280ef1e97a542375e41058e", size = 42908549, upload-time = "2025-04-27T12:30:29.551Z" }, - { url = "https://files.pythonhosted.org/packages/31/a9/dfb999c2fc6911201dcbf348247f9cc382a8990f9ab45c12eabfd7243a38/pyarrow-20.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6102b4864d77102dbbb72965618e204e550135a940c2534711d5ffa787df2a5a", size = 44557216, upload-time = "2025-04-27T12:30:36.977Z" }, - { url = "https://files.pythonhosted.org/packages/a0/8e/9adee63dfa3911be2382fb4d92e4b2e7d82610f9d9f668493bebaa2af50f/pyarrow-20.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:96d6a0a37d9c98be08f5ed6a10831d88d52cac7b13f5287f1e0f625a0de8062b", size = 25660496, upload-time = "2025-04-27T12:30:42.809Z" }, + { 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" }, ] [[package]] @@ -1858,7 +1437,7 @@ wheels = [ [[package]] name = "pydantic" -version = "2.11.5" +version = "2.11.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, @@ -1866,9 +1445,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f0/86/8ce9040065e8f924d642c58e4a344e33163a07f6b57f836d0d734e0ad3fb/pydantic-2.11.5.tar.gz", hash = "sha256:7f853db3d0ce78ce8bbb148c401c2cdd6431b3473c0cdff2755c7690952a7b7a", size = 787102, upload-time = "2025-05-22T21:18:08.761Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/69/831ed22b38ff9b4b64b66569f0e5b7b97cf3638346eb95a2147fdb49ad5f/pydantic-2.11.5-py3-none-any.whl", hash = "sha256:f9c26ba06f9747749ca1e5c94d6a85cb84254577553c8785576fd38fa64dc0f7", size = 444229, upload-time = "2025-05-22T21:18:06.329Z" }, + { 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" }, ] [[package]] @@ -1898,11 +1477,11 @@ wheels = [ [[package]] name = "pygments" -version = "2.19.1" +version = "2.19.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, + { 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]] @@ -1919,36 +1498,20 @@ crypto = [ { name = "cryptography" }, ] -[[package]] -name = "pyportfolioopt" -version = "1.5.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cvxpy" }, - { name = "ecos" }, - { name = "numpy" }, - { name = "pandas" }, - { name = "plotly" }, - { name = "scipy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b3/54/902758bac4322d0eae8199aa5bf2d9c41316ddad82d82d5960ca27174ceb/pyportfolioopt-1.5.6.tar.gz", hash = "sha256:7e94f41c84fb5865c7a64de995a3ba580188f3ba494f6dfbc02721b5de323f6e", size = 56782, upload-time = "2024-12-01T19:42:09.509Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/9e/c8ffe7e9ba4ff0317fccd2e1dc466c47e64acea1b5e6b2f167d7d3097c93/pyportfolioopt-1.5.6-py3-none-any.whl", hash = "sha256:22cfa4978dac893fa78cbd91b0793c4d8fa024a577118d47769f19f069e09d8c", size = 62703, upload-time = "2024-12-01T19:42:07.784Z" }, -] - [[package]] name = "pytest" -version = "8.3.5" +version = "8.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, + { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } +sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, + { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" }, ] [[package]] @@ -1992,12 +1555,12 @@ wheels = [ [[package]] name = "pywin32" -version = "310" +version = "311" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, + { 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]] @@ -2028,7 +1591,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.3" +version = "2.32.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -2036,9 +1599,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, ] [[package]] @@ -2056,15 +1619,15 @@ wheels = [ [[package]] name = "rich" -version = "14.0.0" +version = "14.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, + { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" }, ] [[package]] @@ -2095,66 +1658,28 @@ wheels = [ [[package]] name = "s3fs" -version = "2025.5.1" +version = "2025.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiobotocore" }, { name = "aiohttp" }, { name = "fsspec" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7f/6f/d0ee452580d7d0643a1a776b95dfef2144023f3fc077038e07d651995d34/s3fs-2025.5.1.tar.gz", hash = "sha256:84beffa231b8ed94f8d667e93387b38351e1c4447aedea5c2c19dd88b7fcb658", size = 77276, upload-time = "2025-05-24T12:14:11.442Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/c0/f5cc95ec88694429fcb841a37456be0a27463bc39d43edbd36e3164120ed/s3fs-2025.5.1-py3-none-any.whl", hash = "sha256:7475e7c40a3a112f17144907ffae50782ab6c03487fe0b45a9c3942bb7a5c606", size = 30476, upload-time = "2025-05-24T12:14:10.056Z" }, + { 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" }, ] [[package]] name = "s3transfer" -version = "0.13.0" +version = "0.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ed/5d/9dcc100abc6711e8247af5aa561fc07c4a046f72f659c3adea9a449e191a/s3transfer-0.13.0.tar.gz", hash = "sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177", size = 150232, upload-time = "2025-05-22T19:24:50.245Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/17/22bf8155aa0ea2305eefa3a6402e040df7ebe512d1310165eda1e233c3f8/s3transfer-0.13.0-py3-none-any.whl", hash = "sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be", size = 85152, upload-time = "2025-05-22T19:24:48.703Z" }, -] - -[[package]] -name = "scipy" -version = "1.15.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/37/4b/683aa044c4162e10ed7a7ea30527f2cbd92e6999c10a8ed8edb253836e9c/scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019", size = 38766735, upload-time = "2025-05-08T16:06:06.471Z" }, - { url = "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6", size = 30173284, upload-time = "2025-05-08T16:06:11.686Z" }, - { url = "https://files.pythonhosted.org/packages/07/9c/0ddb0d0abdabe0d181c1793db51f02cd59e4901da6f9f7848e1f96759f0d/scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477", size = 22446958, upload-time = "2025-05-08T16:06:15.97Z" }, - { url = "https://files.pythonhosted.org/packages/af/43/0bce905a965f36c58ff80d8bea33f1f9351b05fad4beaad4eae34699b7a1/scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c", size = 25242454, upload-time = "2025-05-08T16:06:20.394Z" }, - { url = "https://files.pythonhosted.org/packages/56/30/a6f08f84ee5b7b28b4c597aca4cbe545535c39fe911845a96414700b64ba/scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45", size = 35210199, upload-time = "2025-05-08T16:06:26.159Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1f/03f52c282437a168ee2c7c14a1a0d0781a9a4a8962d84ac05c06b4c5b555/scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49", size = 37309455, upload-time = "2025-05-08T16:06:32.778Z" }, - { url = "https://files.pythonhosted.org/packages/89/b1/fbb53137f42c4bf630b1ffdfc2151a62d1d1b903b249f030d2b1c0280af8/scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e", size = 36885140, upload-time = "2025-05-08T16:06:39.249Z" }, - { url = "https://files.pythonhosted.org/packages/2e/2e/025e39e339f5090df1ff266d021892694dbb7e63568edcfe43f892fa381d/scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539", size = 39710549, upload-time = "2025-05-08T16:06:45.729Z" }, - { url = "https://files.pythonhosted.org/packages/e6/eb/3bf6ea8ab7f1503dca3a10df2e4b9c3f6b3316df07f6c0ded94b281c7101/scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed", size = 40966184, upload-time = "2025-05-08T16:06:52.623Z" }, -] - -[[package]] -name = "scs" -version = "3.2.7.post2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "scipy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/2f/3f15676b0f4cc73879400d94f2c5c64130cad0bbca266aff1365dc643e79/scs-3.2.7.post2.tar.gz", hash = "sha256:4245a4f76328cc73911f20e1414df68d41ead4bcc4a187503a9cd639b644014b", size = 1600725, upload-time = "2025-01-04T17:02:03.387Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/ef/982d35cadee11137a27c80404155265bb2c4e5899551436ef5e6cc28a0bc/scs-3.2.7.post2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:99e4af2968b046ee55fa0dc89dcd3bfba771f1027d9224cb6efa10008d8bfee1", size = 107289, upload-time = "2025-01-04T17:00:52.385Z" }, - { url = "https://files.pythonhosted.org/packages/33/2a/f807b0f9dd108c9c75c4d12692803d687be7bd32c91dbfd7213837b3b6ed/scs-3.2.7.post2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc46fef9743d4629337382f034fda92dfce338659e8377afae674517b7d8345f", size = 93544, upload-time = "2025-01-04T17:00:53.574Z" }, - { url = "https://files.pythonhosted.org/packages/82/0e/f56426e3b3d9ac12dac252c1c4a0e65a530d460b9448e3fc2e20ac8e6bed/scs-3.2.7.post2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f92e925d89004276a449850926a45536f75c03cab701b5e758b1a7efa119ba08", size = 10443128, upload-time = "2025-01-04T17:00:55.188Z" }, - { url = "https://files.pythonhosted.org/packages/e4/f3/343803e20415bf604e4b237fdce4203f51c35e89707d18eafa7e3fe172d7/scs-3.2.7.post2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:640faf61f85b933fdfc3d33d7ce4f0049b082b245e82d2d6a8c2c54aa0b7f540", size = 5066484, upload-time = "2025-01-04T17:00:58.509Z" }, - { url = "https://files.pythonhosted.org/packages/33/9a/5b06bc2ba789aa2ce5ba57be503f2563bbc772c0e7b4249e646e44fdcd2b/scs-3.2.7.post2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a520c9bef84eee734df0da3e5e06aa9192d3be34cd5e6d4221cc01f4d09b20c0", size = 11612180, upload-time = "2025-01-04T17:01:00.789Z" }, - { url = "https://files.pythonhosted.org/packages/30/49/1645fa1219493ac94475ab8f48a2520d2fc27f486327f2b0f167440a8188/scs-3.2.7.post2-cp312-cp312-win_amd64.whl", hash = "sha256:2995d4099943c3fd754b3e39fe178a9c03dcb9c7d84b40f64ac5eb26d8d6085a", size = 7432205, upload-time = "2025-01-04T17:01:03.536Z" }, + { 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" }, ] [[package]] @@ -2162,43 +1687,25 @@ name = "secretstorage" version = "3.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cryptography" }, - { name = "jeepney" }, + { 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" } 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" }, ] -[[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" }, -] - [[package]] name = "sentry-sdk" -version = "2.29.1" +version = "2.35.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/67/d552a5f8e5a6a56b2feea6529e2d8ccd54349084c84176d5a1f7295044bc/sentry_sdk-2.29.1.tar.gz", hash = "sha256:8d4a0206b95fa5fe85e5e7517ed662e3888374bdc342c00e435e10e6d831aa6d", size = 325518, upload-time = "2025-05-19T14:27:38.512Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/e5/da07b0bd832cefd52d16f2b9bbbe31624d57552602c06631686b93ccb1bd/sentry_sdk-2.29.1-py2.py3-none-any.whl", hash = "sha256:90862fe0616ded4572da6c9dadb363121a1ae49a49e21c418f0634e9d10b4c19", size = 341553, upload-time = "2025-05-19T14:27:36.882Z" }, -] - -[[package]] -name = "setuptools" -version = "80.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8d/d2/ec1acaaff45caed5c2dedb33b67055ba9d4e96b091094df90762e60135fe/setuptools-80.8.0.tar.gz", hash = "sha256:49f7af965996f26d43c8ae34539c8d99c5042fbff34302ea151eaa9c207cd257", size = 1319720, upload-time = "2025-05-20T14:02:53.503Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/29/93c53c098d301132196c3238c312825324740851d77a8500a2462c0fd888/setuptools-80.8.0-py3-none-any.whl", hash = "sha256:95a60484590d24103af13b686121328cc2736bee85de8936383111e421b9edc0", size = 1201470, upload-time = "2025-05-20T14:02:51.348Z" }, + { 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" }, ] [[package]] @@ -2211,12 +1718,12 @@ wheels = [ ] [[package]] -name = "sniffio" -version = "1.3.1" +name = "smmap" +version = "5.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, + { 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" }, ] [[package]] @@ -2228,18 +1735,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/49/58/97655efdfeb5b4eeab85b1fc5d3fa1023661246c2ab2a26ea8e47402d4f2/sseclient_py-1.8.0-py2.py3-none-any.whl", hash = "sha256:4ecca6dc0b9f963f8384e9d7fd529bf93dd7d708144c4fb5da0e0a1a926fee83", size = 8828, upload-time = "2023-09-01T19:39:17.627Z" }, ] -[[package]] -name = "starlette" -version = "0.46.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, -] - [[package]] name = "statsd" version = "4.0.1" @@ -2249,15 +1744,6 @@ 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" }, ] -[[package]] -name = "tenacity" -version = "9.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, -] - [[package]] name = "tinygrad" version = "0.10.3" @@ -2269,11 +1755,11 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.13.2" +version = "4.14.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967, upload-time = "2025-04-10T14:19:05.416Z" } +sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806, upload-time = "2025-04-10T14:19:03.967Z" }, + { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, ] [[package]] @@ -2310,75 +1796,42 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, ] -[[package]] -name = "union" -version = "0.1.183" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiofiles" }, - { name = "click" }, - { name = "flyteidl" }, - { name = "flytekit" }, - { name = "fsspec" }, - { name = "googleapis-common-protos" }, - { name = "grpcio" }, - { name = "grpcio-status" }, - { name = "importlib-metadata" }, - { name = "keyring" }, - { name = "mashumaro" }, - { name = "protobuf", marker = "sys_platform == 'win32'" }, - { name = "pyyaml" }, - { name = "rich" }, - { name = "rich-click" }, - { name = "sentry-sdk" }, - { name = "typing-extensions" }, - { name = "unionai-actor", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/da/1b/9041b3f14509b57c0bc6f16dd22d863199805d3e4039dc0ea19abb58c112/union-0.1.183.tar.gz", hash = "sha256:d5d5753d8300b789878b2e8a19d378373bde48955facd7adb0037f5a60f881de", size = 190763, upload-time = "2025-06-04T21:01:27.98Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/93/f098aad93d3f02efbd8d98b3ef1cd884071b70a47fc1b05567215386580e/union-0.1.183-py3-none-any.whl", hash = "sha256:b451ee4d3daea1fcc4e1cab9151e0f7c9946ad9b4df1854e6b58144aa980fd8a", size = 280422, upload-time = "2025-06-04T21:01:26.509Z" }, -] - -[[package]] -name = "unionai" -version = "0.1.183" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "union" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/85/8c/d322746f9e03eb7bd688816b9c6f589f0466ca507eb81c7d98c74af31215/unionai-0.1.183.tar.gz", hash = "sha256:3112866b91878c7f2689e532d3e04af9942c2911b076334f9adb2500c30f1138", size = 8589, upload-time = "2025-06-04T21:02:20.111Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/43/d1835087eebf4432631b7b3e72de5e16186e429c43823f97177c40281ddf/unionai-0.1.183-py3-none-any.whl", hash = "sha256:9d53582c1a43b216deb594b78cb533bbe73d4519d2e28e2264bab4bf1e03d3e9", size = 10136, upload-time = "2025-06-04T21:02:18.797Z" }, -] - -[[package]] -name = "unionai-actor" -version = "0.1.9" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/3e/cdff9276036d89ff45f039b53806ae1f3fa997f47e3194154d307e95caa0/unionai_actor-0.1.9-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbd09062569dd30c7566392a5c90493924a0418af88c481a56196b94cd43b80b", size = 1875176, upload-time = "2025-04-22T19:25:36.617Z" }, -] - [[package]] name = "urllib3" -version = "2.4.0" +version = "2.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, ] [[package]] -name = "uvicorn" -version = "0.34.2" +name = "wandb" +version = "0.21.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, - { name = "h11" }, + { 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/a6/ae/9bbb19b9e1c450cf9ecaef06463e40234d98d95bf572fab11b4f19ae5ded/uvicorn-0.34.2.tar.gz", hash = "sha256:0e929828f6186353a80b58ea719861d2629d766293b6d19baf086ba31d4f3328", size = 76815, upload-time = "2025-04-19T06:02:50.101Z" } +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/b1/4b/4cef6ce21a2aaca9d852a6e84ef4f135d99fcd74fa75105e2fc0c8308acd/uvicorn-0.34.2-py3-none-any.whl", hash = "sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403", size = 62483, upload-time = "2025-04-19T06:02:48.42Z" }, + { 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]] @@ -2410,89 +1863,61 @@ 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 = "workflows" -version = "0.1.0" -source = { virtual = "workflows" } -dependencies = [ - { name = "flytekit" }, - { name = "google-auth" }, - { name = "google-cloud-run" }, - { name = "httpx" }, - { name = "loguru" }, - { name = "polars" }, - { name = "pyarrow" }, - { name = "unionai" }, -] - -[package.metadata] -requires-dist = [ - { name = "flytekit", specifier = ">=1.16.1" }, - { name = "google-auth", specifier = ">=2.40.2" }, - { name = "google-cloud-run", specifier = ">=0.10.18" }, - { name = "httpx", specifier = ">=0.28.1" }, - { name = "loguru", specifier = ">=0.7.3" }, - { name = "polars", specifier = ">=1.30.0" }, - { name = "pyarrow", specifier = ">=20.0.0" }, - { name = "unionai", specifier = ">=0.1.183" }, -] - [[package]] name = "wrapt" -version = "1.17.2" +version = "1.17.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/fc/e91cc220803d7bc4db93fb02facd8461c37364151b8494762cc88b0fbcef/wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", size = 55531, upload-time = "2025-01-14T10:35:45.465Z" } +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/a1/bd/ab55f849fd1f9a58ed7ea47f5559ff09741b25f00c191231f9f059c83949/wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925", size = 53799, upload-time = "2025-01-14T10:33:57.4Z" }, - { url = "https://files.pythonhosted.org/packages/53/18/75ddc64c3f63988f5a1d7e10fb204ffe5762bc663f8023f18ecaf31a332e/wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392", size = 38821, upload-time = "2025-01-14T10:33:59.334Z" }, - { url = "https://files.pythonhosted.org/packages/48/2a/97928387d6ed1c1ebbfd4efc4133a0633546bec8481a2dd5ec961313a1c7/wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40", size = 38919, upload-time = "2025-01-14T10:34:04.093Z" }, - { url = "https://files.pythonhosted.org/packages/73/54/3bfe5a1febbbccb7a2f77de47b989c0b85ed3a6a41614b104204a788c20e/wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d", size = 88721, upload-time = "2025-01-14T10:34:07.163Z" }, - { url = "https://files.pythonhosted.org/packages/25/cb/7262bc1b0300b4b64af50c2720ef958c2c1917525238d661c3e9a2b71b7b/wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b", size = 80899, upload-time = "2025-01-14T10:34:09.82Z" }, - { url = "https://files.pythonhosted.org/packages/2a/5a/04cde32b07a7431d4ed0553a76fdb7a61270e78c5fd5a603e190ac389f14/wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98", size = 89222, upload-time = "2025-01-14T10:34:11.258Z" }, - { url = "https://files.pythonhosted.org/packages/09/28/2e45a4f4771fcfb109e244d5dbe54259e970362a311b67a965555ba65026/wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82", size = 86707, upload-time = "2025-01-14T10:34:12.49Z" }, - { url = "https://files.pythonhosted.org/packages/c6/d2/dcb56bf5f32fcd4bd9aacc77b50a539abdd5b6536872413fd3f428b21bed/wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae", size = 79685, upload-time = "2025-01-14T10:34:15.043Z" }, - { url = "https://files.pythonhosted.org/packages/80/4e/eb8b353e36711347893f502ce91c770b0b0929f8f0bed2670a6856e667a9/wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9", size = 87567, upload-time = "2025-01-14T10:34:16.563Z" }, - { url = "https://files.pythonhosted.org/packages/17/27/4fe749a54e7fae6e7146f1c7d914d28ef599dacd4416566c055564080fe2/wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9", size = 36672, upload-time = "2025-01-14T10:34:17.727Z" }, - { url = "https://files.pythonhosted.org/packages/15/06/1dbf478ea45c03e78a6a8c4be4fdc3c3bddea5c8de8a93bc971415e47f0f/wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991", size = 38865, upload-time = "2025-01-14T10:34:19.577Z" }, - { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594, upload-time = "2025-01-14T10:35:44.018Z" }, + { 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.0" +version = "1.20.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/62/51/c0edba5219027f6eab262e139f73e2417b0f4efffa23bf562f6e18f76ca5/yarl-1.20.0.tar.gz", hash = "sha256:686d51e51ee5dfe62dec86e4866ee0e9ed66df700d55c828a615640adc885307", size = 185258, upload-time = "2025-04-17T00:45:14.661Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/e8/3efdcb83073df978bb5b1a9cc0360ce596680e6c3fac01f2a994ccbb8939/yarl-1.20.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e06b9f6cdd772f9b665e5ba8161968e11e403774114420737f7884b5bd7bdf6f", size = 147089, upload-time = "2025-04-17T00:42:39.602Z" }, - { url = "https://files.pythonhosted.org/packages/60/c3/9e776e98ea350f76f94dd80b408eaa54e5092643dbf65fd9babcffb60509/yarl-1.20.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b9ae2fbe54d859b3ade40290f60fe40e7f969d83d482e84d2c31b9bff03e359e", size = 97706, upload-time = "2025-04-17T00:42:41.469Z" }, - { url = "https://files.pythonhosted.org/packages/0c/5b/45cdfb64a3b855ce074ae607b9fc40bc82e7613b94e7612b030255c93a09/yarl-1.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d12b8945250d80c67688602c891237994d203d42427cb14e36d1a732eda480e", size = 95719, upload-time = "2025-04-17T00:42:43.666Z" }, - { url = "https://files.pythonhosted.org/packages/2d/4e/929633b249611eeed04e2f861a14ed001acca3ef9ec2a984a757b1515889/yarl-1.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:087e9731884621b162a3e06dc0d2d626e1542a617f65ba7cc7aeab279d55ad33", size = 343972, upload-time = "2025-04-17T00:42:45.391Z" }, - { url = "https://files.pythonhosted.org/packages/49/fd/047535d326c913f1a90407a3baf7ff535b10098611eaef2c527e32e81ca1/yarl-1.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69df35468b66c1a6e6556248e6443ef0ec5f11a7a4428cf1f6281f1879220f58", size = 339639, upload-time = "2025-04-17T00:42:47.552Z" }, - { url = "https://files.pythonhosted.org/packages/48/2f/11566f1176a78f4bafb0937c0072410b1b0d3640b297944a6a7a556e1d0b/yarl-1.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b2992fe29002fd0d4cbaea9428b09af9b8686a9024c840b8a2b8f4ea4abc16f", size = 353745, upload-time = "2025-04-17T00:42:49.406Z" }, - { url = "https://files.pythonhosted.org/packages/26/17/07dfcf034d6ae8837b33988be66045dd52f878dfb1c4e8f80a7343f677be/yarl-1.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c903e0b42aab48abfbac668b5a9d7b6938e721a6341751331bcd7553de2dcae", size = 354178, upload-time = "2025-04-17T00:42:51.588Z" }, - { url = "https://files.pythonhosted.org/packages/15/45/212604d3142d84b4065d5f8cab6582ed3d78e4cc250568ef2a36fe1cf0a5/yarl-1.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf099e2432131093cc611623e0b0bcc399b8cddd9a91eded8bfb50402ec35018", size = 349219, upload-time = "2025-04-17T00:42:53.674Z" }, - { url = "https://files.pythonhosted.org/packages/e6/e0/a10b30f294111c5f1c682461e9459935c17d467a760c21e1f7db400ff499/yarl-1.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7f62f5dc70a6c763bec9ebf922be52aa22863d9496a9a30124d65b489ea672", size = 337266, upload-time = "2025-04-17T00:42:55.49Z" }, - { url = "https://files.pythonhosted.org/packages/33/a6/6efa1d85a675d25a46a167f9f3e80104cde317dfdf7f53f112ae6b16a60a/yarl-1.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:54ac15a8b60382b2bcefd9a289ee26dc0920cf59b05368c9b2b72450751c6eb8", size = 360873, upload-time = "2025-04-17T00:42:57.895Z" }, - { url = "https://files.pythonhosted.org/packages/77/67/c8ab718cb98dfa2ae9ba0f97bf3cbb7d45d37f13fe1fbad25ac92940954e/yarl-1.20.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:25b3bc0763a7aca16a0f1b5e8ef0f23829df11fb539a1b70476dcab28bd83da7", size = 360524, upload-time = "2025-04-17T00:43:00.094Z" }, - { url = "https://files.pythonhosted.org/packages/bd/e8/c3f18660cea1bc73d9f8a2b3ef423def8dadbbae6c4afabdb920b73e0ead/yarl-1.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2586e36dc070fc8fad6270f93242124df68b379c3a251af534030a4a33ef594", size = 365370, upload-time = "2025-04-17T00:43:02.242Z" }, - { url = "https://files.pythonhosted.org/packages/c9/99/33f3b97b065e62ff2d52817155a89cfa030a1a9b43fee7843ef560ad9603/yarl-1.20.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:866349da9d8c5290cfefb7fcc47721e94de3f315433613e01b435473be63daa6", size = 373297, upload-time = "2025-04-17T00:43:04.189Z" }, - { url = "https://files.pythonhosted.org/packages/3d/89/7519e79e264a5f08653d2446b26d4724b01198a93a74d2e259291d538ab1/yarl-1.20.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:33bb660b390a0554d41f8ebec5cd4475502d84104b27e9b42f5321c5192bfcd1", size = 378771, upload-time = "2025-04-17T00:43:06.609Z" }, - { url = "https://files.pythonhosted.org/packages/3a/58/6c460bbb884abd2917c3eef6f663a4a873f8dc6f498561fc0ad92231c113/yarl-1.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737e9f171e5a07031cbee5e9180f6ce21a6c599b9d4b2c24d35df20a52fabf4b", size = 375000, upload-time = "2025-04-17T00:43:09.01Z" }, - { url = "https://files.pythonhosted.org/packages/3b/2a/dd7ed1aa23fea996834278d7ff178f215b24324ee527df53d45e34d21d28/yarl-1.20.0-cp312-cp312-win32.whl", hash = "sha256:839de4c574169b6598d47ad61534e6981979ca2c820ccb77bf70f4311dd2cc64", size = 86355, upload-time = "2025-04-17T00:43:11.311Z" }, - { url = "https://files.pythonhosted.org/packages/ca/c6/333fe0338305c0ac1c16d5aa7cc4841208d3252bbe62172e0051006b5445/yarl-1.20.0-cp312-cp312-win_amd64.whl", hash = "sha256:3d7dbbe44b443b0c4aa0971cb07dcb2c2060e4a9bf8d1301140a33a93c98e18c", size = 92904, upload-time = "2025-04-17T00:43:13.087Z" }, - { url = "https://files.pythonhosted.org/packages/ea/1f/70c57b3d7278e94ed22d85e09685d3f0a38ebdd8c5c73b65ba4c0d0fe002/yarl-1.20.0-py3-none-any.whl", hash = "sha256:5d0fe6af927a47a230f31e6004621fd0959eaa915fc62acfafa67ff7229a3124", size = 46124, upload-time = "2025-04-17T00:45:12.199Z" }, +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.22.0" +version = "3.23.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/b6/7b3d16792fdf94f146bed92be90b4eb4563569eca91513c8609aebf0c167/zipp-3.22.0.tar.gz", hash = "sha256:dd2f28c3ce4bc67507bfd3781d21b7bb2be31103b51a4553ad7d90b84e57ace5", size = 25257, upload-time = "2025-05-26T14:46:32.217Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/da/f64669af4cae46f17b90798a827519ce3737d31dbafad65d391e49643dc4/zipp-3.22.0-py3-none-any.whl", hash = "sha256:fe208f65f2aca48b81f9e6fd8cf7b8b32c26375266b009b413d45306b6148343", size = 9796, upload-time = "2025-05-26T14:46:30.775Z" }, + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, ] diff --git a/workflows/fetch_data.py b/workflows/fetch_data.py deleted file mode 100644 index 9b8829a5d..000000000 --- a/workflows/fetch_data.py +++ /dev/null @@ -1,54 +0,0 @@ -import os -import subprocess -from io import BytesIO - -import httpx -import polars as pl -from google.cloud import run_v2 -from pyarrow import ipc -from union import task - - -@task -def get_identity_token() -> str: - result = subprocess.run( # noqa: S603 - ["gcloud", "auth", "print-identity-token"], # noqa: S607 - capture_output=True, - check=True, - text=True, - ) - return result.stdout.strip() - - -@task -def fetch_dates(start_date: str, end_date: str, token: str) -> pl.DataFrame | pl.Series: - client = run_v2.ServicesClient() - project = os.getenv("GCP_PROJECT", "pocketsizefund") - region = os.getenv("GCP_REGION", "us-east1") - parent: str = f"projects/{project}/locations/{region}" - - datamanager_url: str | None = next( - ( - service.uri - for service in client.list_services(parent=parent) - if "datamanager" in service.name - ), - None, - ) - - if datamanager_url is None: - message = "Datamanager service not found in the specified project and region" - raise ValueError(message) - - response: httpx.Response = httpx.get( - f"{datamanager_url}/equity-bars", - headers={"Authorization": f"Bearer {token}"}, - params={"start_date": start_date, "end_date": end_date}, - timeout=60, - ) - response.raise_for_status() - - with BytesIO(response.content) as buf: - reader = ipc.open_stream(buf) - arrow_table = reader.read_all() - return pl.from_arrow(arrow_table) diff --git a/workflows/pyproject.toml b/workflows/pyproject.toml deleted file mode 100644 index b5011658e..000000000 --- a/workflows/pyproject.toml +++ /dev/null @@ -1,18 +0,0 @@ -[project] -name = "workflows" -description = "Data and model workflows" -version = "0.1.0" -requires-python = "==3.12.10" -dependencies = [ - "google-auth>=2.40.2", - "google-cloud-run>=0.10.18", - "httpx>=0.28.1", - "loguru>=0.7.3", - "polars>=1.30.0", - "pyarrow>=20.0.0", - "unionai>=0.1.183", - "flytekit>=1.16.1", -] - -[tool.hatch.build.targets.wheel] -packages = ["workflows"] diff --git a/workflows/train_predictionengine.py b/workflows/train_predictionengine.py deleted file mode 100644 index ec6e62856..000000000 --- a/workflows/train_predictionengine.py +++ /dev/null @@ -1,138 +0,0 @@ -import os -import tempfile -import uuid -from datetime import datetime -from pathlib import Path -from typing import Any, cast - -import polars as pl -import pyarrow as pa -import requests -from flytekit import task, workflow -from loguru import logger -from tinygrad.nn.state import get_state_dict, safe_save - -from application.predictionengine.src.predictionengine.dataset import DataSet -from application.predictionengine.src.predictionengine.miniature_temporal_fusion_transformer import ( # noqa: E501 - MiniatureTemporalFusionTransformer, -) - - -@task -def fetch_data( - start_date: datetime, - end_date: datetime, -) -> list[dict[str, Any]]: - base_url = os.getenv("DATAMANAGER_BASE_URL", "http://localhost:8080") - response = requests.get( - f"{base_url}/equity-bars", - params={ - "start_date": start_date.date().isoformat(), - "end_date": end_date.date().isoformat(), - }, - timeout=30, - ) - response.raise_for_status() - - buffer = pa.py_buffer(response.content) - reader = pa.ipc.RecordBatchStreamReader(buffer) - table = reader.read_all() - - data = pl.DataFrame(pl.from_arrow(table)) - - data = data.with_columns( - [ - pl.col("t").cast(pl.Datetime).alias("timestamp"), - pl.col("o").alias("open_price"), - pl.col("h").alias("high_price"), - pl.col("l").alias("low_price"), - pl.col("c").alias("close_price"), - pl.col("v").alias("volume"), - pl.col("vw").alias("volume_weighted_average_price"), - pl.col("T").alias("ticker"), - ] - ).select( - [ - "timestamp", - "open_price", - "high_price", - "low_price", - "close_price", - "volume", - "volume_weighted_average_price", - "ticker", - ] - ) - - return data.to_dicts() - - -@task -def train_model( - data: list[dict[str, Any]], - epochs: int = 100, -) -> bytes: - if not data: - msg = "No data provided for training" - raise ValueError(msg) - - training_data = pl.DataFrame(data) - - dataset = DataSet( - batch_size=32, - sequence_length=30, - sample_count=len(training_data), - ) - dataset.load_data(training_data) - preprocessors = dataset.get_preprocessors() - - model = MiniatureTemporalFusionTransformer( - input_size=6, - hidden_size=128, - output_size=3, - layer_count=2, - ticker_count=len(training_data["ticker"].unique()), - embedding_size=32, - attention_head_count=4, - means_by_ticker=preprocessors["means_by_ticker"], - standard_deviations_by_ticker=preprocessors["standard_deviations_by_ticker"], - ticker_encoder=preprocessors["ticker_encoder"], - dropout_rate=0.1, - ) - - losses = model.train(dataset, epochs, learning_rate=0.001) - - for epoch, loss in enumerate(losses): - if epoch % 10 == 0: - logger.info(f"Epoch {epoch}, Loss: {loss}") - - with tempfile.NamedTemporaryFile( - suffix=".safetensor", - delete=False, - ) as temporary_file: - safe_save(get_state_dict(model), temporary_file.name) - temporary_file.seek(0) - model_bytes = temporary_file.read() - - return model_bytes # noqa: RET504 - - -@task -def store_model(model_bytes: bytes) -> str: - bucket_path = os.getenv("MODEL_BUCKET", "/tmp") # noqa: S108 - filename = f"miniature_temporal_fusion_transformer-{uuid.uuid4().hex}.safetensor" - path = Path(bucket_path) / filename - path.write_bytes(model_bytes) - return str(path) - - -@workflow -def training_workflow( - start_date: datetime, - end_date: datetime, - epochs: int = 100, -) -> str: - data = fetch_data(start_date=start_date, end_date=end_date) - model_bytes = train_model(data=cast("list[dict[str, Any]]", data), epochs=epochs) - artifact_path = store_model(model_bytes=cast("bytes", model_bytes)) - return cast("str", artifact_path)