diff --git a/.fern/metadata.json b/.fern/metadata.json index 5593c22..aeb65b7 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -1,7 +1,7 @@ { - "cliVersion": "5.89.4", + "cliVersion": "5.143.0", "generatorName": "fernapi/fern-python-sdk", - "generatorVersion": "5.26.0", + "generatorVersion": "5.34.1", "generatorConfig": { "package_name": "newscatcher_catchall", "client": { @@ -9,10 +9,10 @@ "filename": "client.py" } }, - "originGitCommit": "3f4bdad0a71333b0f9fb6f42d44d174f2e40167b", + "originGitCommit": "6ef7448ab601e5b372caec45717b0390a4150d2c", "originGitCommitIsDirty": true, "invokedBy": "ci", "requestedVersion": "AUTO", "ciProvider": "unknown", - "sdkVersion": "0.0.0.dev0" + "sdkVersion": "4.0.0" } \ No newline at end of file diff --git a/.fern/replay.lock b/.fern/replay.lock index 89ba635..0b3d77e 100644 --- a/.fern/replay.lock +++ b/.fern/replay.lock @@ -24,5 +24,11 @@ generations: cli_version: unknown generator_versions: fernapi/fern-python-sdk: 5.26.0 -current_generation: b704df16629ce3bc11edbb454d74da293c9d838d + - commit_sha: f8e992adaca05714361e6b5b4f245d944311c13c + tree_hash: 667ddf5495de66ce1174e40af482005e0fa9dbe2 + timestamp: 2026-09-30T10:09:07.724Z + cli_version: unknown + generator_versions: + fernapi/fern-python-sdk: 5.34.1 +current_generation: f8e992adaca05714361e6b5b4f245d944311c13c patches: [] diff --git a/README.md b/README.md index 9476dd9..4a8c102 100644 --- a/README.md +++ b/README.md @@ -221,3 +221,4 @@ On the other hand, contributions to the README are always very welcome! + diff --git a/changelog.md b/changelog.md index 1273fa0..0462d8a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,23 @@ +## [4.0.0] - 2026-09-30 +### Breaking Changes +- **`MonitorsClient` / `AsyncMonitorsClient`** — renamed to `EventMonitorsClient` / `AsyncEventMonitorsClient`; update all imports and type annotations accordingly. +- **`RawMonitorsClient` / `AsyncRawMonitorsClient`** — renamed to `RawEventMonitorsClient` / `AsyncRawEventMonitorsClient`; update any direct references to these raw client classes. +- **`client.monitors`** — accessor renamed to `client.event_monitors`; replace all `client.monitors.*` call sites with `client.event_monitors.*`. +- **`newscatcher_catchall.monitors` module** — renamed to `newscatcher_catchall.event_monitors`; update all imports from `from newscatcher_catchall.monitors import …` to `from newscatcher_catchall.event_monitors import …`. + +### Added +- **`EventMonitorsClient.update_monitor()` `schedule` and `timezone` parameters** — new optional parameters (sync and async) allow replacing an event monitor's schedule and IANA timezone in a single call; omit to leave the current schedule unchanged. +- **`JobsClient.list_source_groups()` / `AsyncJobsClient.list_source_groups()`** — new paginated method returning all `ListSourceGroupsResponseDto` source groups visible to your organization. +- **`JobsClient.submit()` `source_groups` parameter** — new optional `list[str]` parameter (sync and async) that scopes article fetching to up to 20 curated domain allowlists by slug. +- **`EventTags`, `ListSourceGroupsResponseDto`, `SourceGroupRef`** — three new types added to the top-level `newscatcher_catchall` namespace. +- **`project_id` filter parameter** — new optional `project_id: str` added to `EntitiesClient.list_entities()` and `WebhooksClient.list_webhooks()` (sync and async) to scope results to a specific project. + +### Changed +- **`UnauthorizedError` (HTTP 401) handling** — all event-monitor, job, entity, project, webhook, dataset, and meta endpoints now raise `UnauthorizedError` on 401 instead of falling through to a generic `ApiError`. +- **`HttpClient` request body handling** — requests with no body fields supplied now omit the body and strip the `Content-Type` header entirely instead of sending an empty JSON object. +- **`pydantic_utilities` alias coercion** — field-alias rewriting is now cached per model class via a `WeakKeyDictionary`, reducing introspection overhead on hot deserialization paths. +- **`BaseHttpResponse.response` property** — exposes the underlying `httpx.Response` object directly from any `HttpResponse` or `AsyncHttpResponse` instance. + ## 3.0.0 - 2026-05-27 ### Breaking Changes * **`MonitorsClient.create_monitor()` and `MonitorsClient.update_monitor()`** — the `webhook` parameter (type `WebhookDto`) has been replaced by `webhook_ids` (type `list[str]`); rename the argument and pass a list of webhook ID strings instead of a `WebhookDto` object. diff --git a/poetry.lock b/poetry.lock index 8c2d598..f74750b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -188,20 +188,20 @@ files = [ [[package]] name = "anyio" -version = "4.14.2" +version = "4.15.1" description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494"}, - {file = "anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f"}, + {file = "anyio-4.15.1-py3-none-any.whl", hash = "sha256:6152fdbbf9a77fdec97731721bebf7c4c44f7c29b424b0065826173efc7ed101"}, + {file = "anyio-4.15.1.tar.gz", hash = "sha256:9f28306018cbd6d329e64a36d58256edff76dd996fe423bc957326e578b82a94"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" -typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} +typing_extensions = {version = ">=4.16.0", markers = "python_version < \"3.15\""} [package.extras] trio = ["trio (>=0.32.0)"] @@ -523,18 +523,18 @@ httpx = ">=0.27.0" [[package]] name = "idna" -version = "3.18" +version = "3.20" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2"}, - {file = "idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848"}, + {file = "idna-3.20-py3-none-any.whl", hash = "sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c"}, + {file = "idna-3.20.tar.gz", hash = "sha256:a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44"}, ] [package.extras] -all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +all = ["coverage (>=7.10.0)", "hypothesis (>=6.141.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.16.0)", "ty (>=0.0.37)"] [[package]] name = "iniconfig" @@ -550,159 +550,184 @@ files = [ [[package]] name = "multidict" -version = "6.7.1" +version = "6.9.1" description = "multidict implementation" optional = true -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] markers = "extra == \"aiohttp\"" files = [ - {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5"}, - {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8"}, - {file = "multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872"}, - {file = "multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991"}, - {file = "multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03"}, - {file = "multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981"}, - {file = "multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6"}, - {file = "multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190"}, - {file = "multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92"}, - {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee"}, - {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2"}, - {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568"}, - {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40"}, - {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962"}, - {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505"}, - {file = "multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122"}, - {file = "multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df"}, - {file = "multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db"}, - {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d"}, - {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e"}, - {file = "multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855"}, - {file = "multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3"}, - {file = "multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e"}, - {file = "multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a"}, - {file = "multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8"}, - {file = "multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0"}, - {file = "multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144"}, - {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49"}, - {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71"}, - {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3"}, - {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c"}, - {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0"}, - {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa"}, - {file = "multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a"}, - {file = "multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b"}, - {file = "multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6"}, - {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172"}, - {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd"}, - {file = "multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7"}, - {file = "multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53"}, - {file = "multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75"}, - {file = "multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b"}, - {file = "multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733"}, - {file = "multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a"}, - {file = "multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961"}, - {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582"}, - {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e"}, - {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3"}, - {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6"}, - {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a"}, - {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba"}, - {file = "multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511"}, - {file = "multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19"}, - {file = "multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf"}, - {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23"}, - {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2"}, - {file = "multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445"}, - {file = "multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177"}, - {file = "multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23"}, - {file = "multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060"}, - {file = "multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d"}, - {file = "multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed"}, - {file = "multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429"}, - {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6"}, - {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9"}, - {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c"}, - {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84"}, - {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d"}, - {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33"}, - {file = "multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3"}, - {file = "multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5"}, - {file = "multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df"}, - {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1"}, - {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963"}, - {file = "multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34"}, - {file = "multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65"}, - {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292"}, - {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43"}, - {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca"}, - {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd"}, - {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7"}, - {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3"}, - {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4"}, - {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8"}, - {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c"}, - {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52"}, - {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108"}, - {file = "multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32"}, - {file = "multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8"}, - {file = "multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118"}, - {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee"}, - {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2"}, - {file = "multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1"}, - {file = "multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d"}, - {file = "multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31"}, - {file = "multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048"}, - {file = "multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362"}, - {file = "multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37"}, - {file = "multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709"}, - {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0"}, - {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb"}, - {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd"}, - {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601"}, - {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1"}, - {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b"}, - {file = "multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d"}, - {file = "multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f"}, - {file = "multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5"}, - {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581"}, - {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a"}, - {file = "multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c"}, - {file = "multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262"}, - {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59"}, - {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889"}, - {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4"}, - {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d"}, - {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609"}, - {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489"}, - {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c"}, - {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e"}, - {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c"}, - {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9"}, - {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2"}, - {file = "multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7"}, - {file = "multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5"}, - {file = "multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2"}, - {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f"}, - {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358"}, - {file = "multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5"}, - {file = "multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0"}, - {file = "multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8"}, - {file = "multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0"}, - {file = "multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f"}, - {file = "multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f"}, - {file = "multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e"}, - {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2"}, - {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8"}, - {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941"}, - {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a"}, - {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de"}, - {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5"}, - {file = "multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0"}, - {file = "multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4"}, - {file = "multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9"}, - {file = "multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56"}, - {file = "multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d"}, + {file = "multidict-6.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aef74e9beabbd6c4aafc091dabff86d046ccf013ce1e4396c0fbb01b4cad9de8"}, + {file = "multidict-6.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1ca5ebe6d454f1e5496cf052386a559f1080bf2de75bf327ebca0a6003b79f19"}, + {file = "multidict-6.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f6d0c4b70f783305e73f9944d8efe6be1022550f0974ba0ae9d8893c0350fa"}, + {file = "multidict-6.9.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8050e75af7e4c6e2d5260b84eeedb618f3e452e66473432e085b5d1b81429299"}, + {file = "multidict-6.9.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4736d350371337825cac1793c9f7c40701c32a03912548c2a7608e51679cbb96"}, + {file = "multidict-6.9.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:02fe09dc197b8ae7e355371e51e5dce2f39060cd5a8badf94904527e23a3f188"}, + {file = "multidict-6.9.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ad4528cdce058b684f75fad1faf4a6a6c992fe2f08376370ca66e4ce5916a84a"}, + {file = "multidict-6.9.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8885e3808aedbd6725b921fb67dacaae0678933561ddd47c2b01315198c70e2e"}, + {file = "multidict-6.9.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3b6e6840421c83ccb60398e333b44f910b0907bb409597685ab2eedd1e22eab"}, + {file = "multidict-6.9.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c9648ed33dc8179e4ec04bbc73bd7f0038e1e81217a69467f61f02a78bf07e88"}, + {file = "multidict-6.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d9d6544790ba50438a9c1a903c3c4afb1ec8a7832db5518549275b40ef0dd4b1"}, + {file = "multidict-6.9.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1c9f3c25df6c9d3bbae4f6fd3f514b1c5c740a2110f56ccf36069c85417e289c"}, + {file = "multidict-6.9.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cf22b43f35b7dbb9f71e8ee2041b5c00029cdfc28ede3a2f31cf8906f9a6c126"}, + {file = "multidict-6.9.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8ed78ccad4c7b421804f5d524b7740946a7ef75d89dc0dac52e9d7c24c472410"}, + {file = "multidict-6.9.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:e3b1aa25f01238886a6baed9e13b9a9240ed344346c79ae280ae65e8603b21d5"}, + {file = "multidict-6.9.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bc94a68ea5e18f8e85dc6b522bcb53093f692c8eb62b4837ac047da73956cbe4"}, + {file = "multidict-6.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:73533644e1f69ea1164d56cc6505f564c6c44072b646b66d67df2d31fed0348c"}, + {file = "multidict-6.9.1-cp310-cp310-win32.whl", hash = "sha256:66987aa68b0f7c2a1cc5f388ca962b8ed92b10f79de38d6d0d8c716154f519d9"}, + {file = "multidict-6.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:a32b78c1e52ebd8e247bb68300b90b233300d8816faa008ed0713bc539fb6af0"}, + {file = "multidict-6.9.1-cp310-cp310-win_arm64.whl", hash = "sha256:ab64ace1a68682d191d9bedd9d4c939406ad86b1d9f628180410644249ad46c2"}, + {file = "multidict-6.9.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:910d4260512660484c0dc1588a316fbb35a40c081c36fc51d1225351af17cfe4"}, + {file = "multidict-6.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:33fa55b990f81c2927e01399ace0d18926c69d69baa8cdaa819424132fb97987"}, + {file = "multidict-6.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:369b5aa01b241cd3fea6890bdbb11a1425d87bf1515831500d518f4223e9d72c"}, + {file = "multidict-6.9.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:803f8b575a71b1b299d677c28db0653459c79b5308874efec813f17b7457c7f1"}, + {file = "multidict-6.9.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8a65621b98984a62e59403009591b8a5a7736273aefe1cab64cfb85b365cc07"}, + {file = "multidict-6.9.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:13849a1d4f54c3809ae721e9e83ab28f5ea602f33660cb84eb6ef261eac706c1"}, + {file = "multidict-6.9.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dd9a137a4a9becda3094f3831cd026380f75f6855e051eefe4c73ade524f1cc3"}, + {file = "multidict-6.9.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9ae9614c317c50836689ce2dfde07c05fe0b16378562e2221746c3913ede3c80"}, + {file = "multidict-6.9.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8f1e362c9352b50ed120f001046fdbb80810c9d56580f4c3fc13bbe30823387"}, + {file = "multidict-6.9.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0dd655518f136febd96c05131a76a863e32fc2a1d7acd4e3c959e3ceb77d8345"}, + {file = "multidict-6.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2c5d675da8f1cb5650271c8ad5e95c0a3e5a183c105e72d953b12877b1c8d0fd"}, + {file = "multidict-6.9.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:658f90f49cf5af2441cad0a2b801c3ef520471989a1ec55bcb25b255b2ca8d2f"}, + {file = "multidict-6.9.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:43124fe172ada86d03ac3c8dc8179091341f6724d5e5d5b160e1587e4cd3761b"}, + {file = "multidict-6.9.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f0adc22a4eb31e545221d93fc73a0f6a8cc2379d0f4309f71d1d17ba938b82"}, + {file = "multidict-6.9.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7fc59e9ba821b220944ccfe0f89c9dc4745f6d097569992356eb03869f21e953"}, + {file = "multidict-6.9.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:87cc632c88ee5dc80e12681047839304d98ee5c9a708d686505767001c9b8b9a"}, + {file = "multidict-6.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b828cf64d62dc09ac183f03c1aeedd164ade96a2ce4934109452edf29de1dd13"}, + {file = "multidict-6.9.1-cp311-cp311-win32.whl", hash = "sha256:2c1aeb92eea59d824f004341b26d5e4b47a8a441cf9726769b9a90abf9d0e08f"}, + {file = "multidict-6.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:5f89dad732280e7a10b74d40b91364f88e13c3f2c08c2ef83a8cd42f7a61af2e"}, + {file = "multidict-6.9.1-cp311-cp311-win_arm64.whl", hash = "sha256:5800368526647146978389dfaa46da3356291e9f0fff9a4ef12e8c2bef964a0d"}, + {file = "multidict-6.9.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:29138fef49828542e859828107e42e50d0e587c513b7eb4b2d92bade2b0860fe"}, + {file = "multidict-6.9.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:19e31815d41cefc365489e591d105d2baceb2f65aa75d29471fbdbda8651e006"}, + {file = "multidict-6.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6ed30be8918e18c8bed0a2e8b70639ecf02feb61ed00ca2e41cfcb2a50fa3f42"}, + {file = "multidict-6.9.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:637f4ae36264bd7b8d9a60193acddc1d735ad52e8ed53a19931ea6d921fea8e5"}, + {file = "multidict-6.9.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:35fc236507fb1b3138f0af5ecd5f94ed752d4d6d826248eae425f86204013eea"}, + {file = "multidict-6.9.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e58952f04772f59f11c6e007471449809a30165188669bca8fdb19dde40a8f24"}, + {file = "multidict-6.9.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d35a4f1c63f07fbb8c8f9946dea98b21eddf6c57421585f71d91864be3ba2a24"}, + {file = "multidict-6.9.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b5f8771aaaed7f80e84a4e471d2f29ab6721e4595075e54d03ae1ed951b2000a"}, + {file = "multidict-6.9.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:976fd7689d69ec78d67d31d38d396d8adb562f7e8368279f76aed4aa451fa06d"}, + {file = "multidict-6.9.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:95052e8777a86bae87c0bd0b5ab22d809e3d1d02bf69e3e66ddda5ba75a05805"}, + {file = "multidict-6.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1a8adfcaf96f587ab138476eaddef95f29b8a2a8a9afbfea8d2fd62180995d02"}, + {file = "multidict-6.9.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1a53de2772cfb74559df2eb4456ec4eeb908435ec55a84b69370d9d745d62aa8"}, + {file = "multidict-6.9.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f2ce963299d42fa3f22a90adc0fdf174792ffef5ff4c7ffb68260548fb05580"}, + {file = "multidict-6.9.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5b30ddf7234e611ca877575b62840e6af5977f92f1f9d532eedbb05a44ff8004"}, + {file = "multidict-6.9.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:63ada7ee2e9345695f9e9bc4c65d72222253f07b1ac94fd0e37555cc6f3c7f60"}, + {file = "multidict-6.9.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3c95601ed98fad3f6e2f8fe809c3b526b0fab31ef525e00a155e227f3d17f58a"}, + {file = "multidict-6.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c148e8b596000dd3e4bfe206e70f3e666be18d72032e0012555f2373c52e35d6"}, + {file = "multidict-6.9.1-cp312-cp312-win32.whl", hash = "sha256:f9dad513626a33670f17cddc6078e30e311f444c957e8dbfc5b2b4603c8b4edb"}, + {file = "multidict-6.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:a16a1dc8529f9e734a41c3b856f3eae7ebacdc061dde3f8a844e0c7889c97203"}, + {file = "multidict-6.9.1-cp312-cp312-win_arm64.whl", hash = "sha256:361f7206cf341ba94fb015688f5c8b480f8e63bd58a4c14a48aeca7851a241cc"}, + {file = "multidict-6.9.1-cp313-cp313-android_24_x86_64.whl", hash = "sha256:d7bf9e43282d69561618e8a0ea33368d532ebef42f15c096f427090521dd74f3"}, + {file = "multidict-6.9.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:03d47df72f084f757c1cb771188d5f4e3a805e4abc4d67e32509272343ae9382"}, + {file = "multidict-6.9.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6bc94fe17c3c56e5418f79515b786b101845f70609b0d19d0c1ba13448e5633a"}, + {file = "multidict-6.9.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8f2973bbd2bebd9d2e0cd6394c1292a1a19ccd56bdcbe1e174059f1a39be5b40"}, + {file = "multidict-6.9.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de7738b8c0bb74c4cc16bbd7fb49fc2bcf6430dba11b3432cd52768ae40933e8"}, + {file = "multidict-6.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e5ccad4b7bac125722f48d6f862bed3b514d8526deea06316bb72f152cd30a7c"}, + {file = "multidict-6.9.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a49ff5cdb33654cb7d6a3c377aa2a83ddefaa1db31eb10bcf3c180aa84f9af8a"}, + {file = "multidict-6.9.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b22ff30006a2f28f8bff878fb93413cbe3a4d1fd517c28081d848c90e9cfd2c8"}, + {file = "multidict-6.9.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3adf06c66041aa21eeb8a71e82379b74773298c8e6d3d839b151aae441a99b94"}, + {file = "multidict-6.9.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:963a8d8f97057082679523d0fd4c53a38f86bc58cabe4556faef682ae53fa2fa"}, + {file = "multidict-6.9.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b66ccc5c2cdd26e74fa5d4c29ffae424cc6148bf93ce574821783fb3b6d452c5"}, + {file = "multidict-6.9.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7fd79c521f6290c69125fa2b85fa65d9e657e6a8ffaf722dc881b926bef4aa5c"}, + {file = "multidict-6.9.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d804e4caf5d5da37d6dac1325da5629ebef1e27a294c2b568b295814aa36c7b"}, + {file = "multidict-6.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bb0d664505f4b112f384cffeee82e91e3f6448d8e574989479db4439b68cba05"}, + {file = "multidict-6.9.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9e14d17773b1b3c758ff153659a1824608a0cb562c45f484b5ed8a433428444a"}, + {file = "multidict-6.9.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:083735b7f395894e43adb278d5dae901448883a835ff8f1977e285fefdb10418"}, + {file = "multidict-6.9.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b65121091567847a8cb520d364ab22ba90e00d3cc55fa9eb34bb439f0684bcd1"}, + {file = "multidict-6.9.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ea999ae6e80e66ad5eea287860951b033d0104ca34d6d87c7b5125ebe0e12721"}, + {file = "multidict-6.9.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:095d900c242e00fbe5f321ee072e7278b4153e78c5ce9c1efde167d62c1e4771"}, + {file = "multidict-6.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6441cc837aea58be7d9baef1b2383eb8311ab9303f500f99ac90b584cd78bb14"}, + {file = "multidict-6.9.1-cp313-cp313-win32.whl", hash = "sha256:9c4880d017555d70dea367dd49271830842d48e3891c2da97da7ce8c4abcee40"}, + {file = "multidict-6.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:ac51cd64bae51c462ea58ad2492c9b8209667a4ef60c45c4a304518b67598d5d"}, + {file = "multidict-6.9.1-cp313-cp313-win_arm64.whl", hash = "sha256:37a9ebe00c698279213d56e6c64e1962ab1e092918270649b397cac3dc196ca4"}, + {file = "multidict-6.9.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:fc0dcb22fa9aeabfe3fa4e0430099acff985ec5d77a851382f76cc6146e780e5"}, + {file = "multidict-6.9.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:024123f0ab402ab33828e24eb80fa8f25167d0d3783ba5f287e39ed741e6abf9"}, + {file = "multidict-6.9.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:af1b5a92315048c3e36bbebfa7d4760a9c3e910bc4166f11b20d77d20d6bcfca"}, + {file = "multidict-6.9.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:b2483da477932ad1983d1d33c18bc3771c6fb00cfbaaed70a875fd547ef8e840"}, + {file = "multidict-6.9.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:db4d697b18b6ef5528b1f36bfa25072cd2a421869f5963bc0e92c8a34b9e2800"}, + {file = "multidict-6.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:854fd2f1bc6e8a56b89910b5cd7261a8b40f13ebb31572da985ce59c7da0886d"}, + {file = "multidict-6.9.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:03731f6fc036180700c9dc2308205a48e5ca6f3ff03087739ab746f294022201"}, + {file = "multidict-6.9.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:989261c5f1735a165f2e4e87cf6d5f17ab734fa18f9ad0383d5adfcdaefce701"}, + {file = "multidict-6.9.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b4c9e5d05b126b267ac048a89a0e2d9b48b1b648add62d4872906304a8590610"}, + {file = "multidict-6.9.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9d0a21cf76153de8f2d96a877991d6bc59b9ab5180b949e50db73cc193b4a694"}, + {file = "multidict-6.9.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e7386aa18d98d6b8af44b92173654ec469237fda35f8e8523e43b581a86f476a"}, + {file = "multidict-6.9.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b69651732c64afb691e50cdc3387cae305e0eeff8804fe3e3ce203876494932a"}, + {file = "multidict-6.9.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1fee9a16d88a1c4865610de31ef5c666671020d7a81d1f510eaf3c97d00ebeba"}, + {file = "multidict-6.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7814bbee202acd3bd240204c17d8b87a4c48c81064fd8674dbe527d94d5a4290"}, + {file = "multidict-6.9.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:95f273bea318a194f656527ee2ed19494327bc500b8e87d9358e3222579aa28d"}, + {file = "multidict-6.9.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:73bcafa21a78d0776b3ee7cd2a63c66f968eb7db8e8d594e32d7329950f6e828"}, + {file = "multidict-6.9.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:1a938761c77e0e6edb0c93d02f4e988d44a69e5195e5a3b893e5553311347132"}, + {file = "multidict-6.9.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:37245ca4105386194dd1d292a6f2aae09bfe1bd7ac6f9ec25093e3cf8e9b143b"}, + {file = "multidict-6.9.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f0700527dd5bfa8b7204b08330542f4f388899d3c14d885d8a368992e0eb562d"}, + {file = "multidict-6.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6b7e54fd883671d1a8810704851c044b7173287c552b9f5c3d9e0eb9f00ae194"}, + {file = "multidict-6.9.1-cp314-cp314-win32.whl", hash = "sha256:e81ae656b9935ac4528a71f96bb7a14d949778ed1897c573d3e7ebb9187f8841"}, + {file = "multidict-6.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:acddcac38adc8342ba48aba98896faa7928854bebb62542362138655b5367ee3"}, + {file = "multidict-6.9.1-cp314-cp314-win_arm64.whl", hash = "sha256:32217133dddc58c927805cf6c0731d8144584176b768042ee886d51e71860bc9"}, + {file = "multidict-6.9.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0b2fb8c349d1103863750b5d8cb5ace766917f4b35f3d883c8f778853eaa9f76"}, + {file = "multidict-6.9.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:56d834b74c993a7d7cb2b8ab33a0d55c3e0d4a3d2f2da2808a4ad3d79189711b"}, + {file = "multidict-6.9.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:783ba7d845d79ce976afd9c1e91a4e5714671defa198ee789e8b23316083a485"}, + {file = "multidict-6.9.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4d718fa1b5f0d0dd75e86fbbc5b0c93ea3a5d65216c85c61cd5d7cdddfe08455"}, + {file = "multidict-6.9.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a313bad717dde740959d50850c315b75fd4eb0c5e6b4dc8535db0f1c369be125"}, + {file = "multidict-6.9.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ef01d29fca550ab871fd99154f82c6472aacf8e7def272dfb07b460123850390"}, + {file = "multidict-6.9.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f3bd290711c6e9486173a6ee7cd4e7f00c3971c7908c1ec1b6e5437c5e4c6f9"}, + {file = "multidict-6.9.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:81cdc537e0a42e3c0170752fcadbe450246d5c3b4b7231d6eb9672456605ac94"}, + {file = "multidict-6.9.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8b193bf7a443c97d81c47052f60c486071a4bdef4a573fa2514f920089414d45"}, + {file = "multidict-6.9.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7a0c98f6a636adf0d7edd60c61589eaf52d149239af754d0bfeb0effedba53a8"}, + {file = "multidict-6.9.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6e6b7e3a1520c39a2772f414cd9ddf5995f77e4e823dfa1522af383addd465a3"}, + {file = "multidict-6.9.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:ca65cced0d67a9039e93bcd98a369920e499bf98296844ff56ead01c9085321f"}, + {file = "multidict-6.9.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:372c063f37480f62c1ae32dc3a1a0a5942b180c883f99789075a8a8ec3c4e709"}, + {file = "multidict-6.9.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:827c92145b3b976b39430129c89d213b250dacbe5fce678e9a03940e6e848983"}, + {file = "multidict-6.9.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:9b0124b9c17e9890f0819b2e7a5f65ec9a2f5aabd6c8e7ad090c1675cf70dee6"}, + {file = "multidict-6.9.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:23136f5a564654eb61061ec6d5620a4c1ea32c8f552b65e9982a12b72bff601b"}, + {file = "multidict-6.9.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f2524ec55b3e65cbe235a8b3c36e2af3b635be02ed05e20c94e70c5c943c009e"}, + {file = "multidict-6.9.1-cp314-cp314t-win32.whl", hash = "sha256:35ba0263bae5dd3ad5aad767cc9afc01a8598c7dae30f1b3b2de98b1b32c28bd"}, + {file = "multidict-6.9.1-cp314-cp314t-win_amd64.whl", hash = "sha256:7c8d5882ba25ac0282258be435d8a05aa0cbcacfce15799154a338f847f159b9"}, + {file = "multidict-6.9.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ac348379cf4de5538a0a213be1532d289aa801ec5d267c5909446b9ea2f8e2c3"}, + {file = "multidict-6.9.1-cp315-cp315-android_24_x86_64.whl", hash = "sha256:f04551dce5a7db8c9659f2e4245494c182d0663b83661803e08d46bfcae5eda1"}, + {file = "multidict-6.9.1-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:c0c88085affd35c33e124e36930c5ad96aff9294ce195eaa0fd9cec962b64a82"}, + {file = "multidict-6.9.1-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a8b75dd3d3638d9a19f23e84af4ffab3b8940422c0df2da2a77005ef5aa3d7ea"}, + {file = "multidict-6.9.1-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:006c4478de0a1876f4834e14255776286f09b9846b505fe63f67f9d173a9487c"}, + {file = "multidict-6.9.1-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:2784090c30a586d5b45197bd9c32f87fb927216cde302f6cfd76d76577e90f08"}, + {file = "multidict-6.9.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:7c708566da8014b120a64b1eb6d200c6c0c8cb36296383723cdb6fc82038270b"}, + {file = "multidict-6.9.1-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:042fb0196047e786936a730bd302de83143950da45f2c16078da8f35e1cf7919"}, + {file = "multidict-6.9.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2212a0c842c723d919ea4a22a9296cb6b244b386e4e6ea92adfc7fbf3095519"}, + {file = "multidict-6.9.1-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fd882aa29bf402b62bf1fd7c19fd5df4b6528cf468a908864b39368572b662a9"}, + {file = "multidict-6.9.1-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c57541034d12b215ab0a2bfa371d1a8a198da18176d0426c27105b9161a6862d"}, + {file = "multidict-6.9.1-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d73fed4e37158ff00cd271871170b79e40138db51e625fd352fa17c6acb34f67"}, + {file = "multidict-6.9.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:79da2491348b30810728050b4a8ec0416f85884125c2fd44655b3d01150d9c3e"}, + {file = "multidict-6.9.1-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b4da208a63434d21a3df64d29758e650fc4aa8cb05848554b76949c296539cca"}, + {file = "multidict-6.9.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:877ca17fdcfdf5c397493a71e5ff97a87bb181417fe717fdadc77c08c09301ac"}, + {file = "multidict-6.9.1-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:40aec5299e1ed71fbb988389059da381c3c1a60e0c649acceb2a35d9b128848e"}, + {file = "multidict-6.9.1-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:4a409ccc42aefec904038695d5d7fd6d8f3af2721b7b6401d55135ec7d6d298e"}, + {file = "multidict-6.9.1-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:0a5769559e3312dd96731fbe15b4abb6033368ac1cad5a98dadd21946a4c7d6c"}, + {file = "multidict-6.9.1-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:03fac50ddfd8302175b77863a015eccfae76767cda5506eef86df559ba861e1f"}, + {file = "multidict-6.9.1-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:5ecace251ccfa705bf3d7d35c5032cf750f5c629809740405697bce5c118c4a4"}, + {file = "multidict-6.9.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:ecc89dbd4155b2f8a47f4bbd89242a35ed15e8e0ec581cab5ac65fa38407329d"}, + {file = "multidict-6.9.1-cp315-cp315-win32.whl", hash = "sha256:a3ffe881246d28a862f1985824f484cb7361f44d6b99c4c620436ef56462f38d"}, + {file = "multidict-6.9.1-cp315-cp315-win_amd64.whl", hash = "sha256:59c123d0e948d760a5f930f316cfefa07e8d632ab84327c0693ee6a88171154f"}, + {file = "multidict-6.9.1-cp315-cp315-win_arm64.whl", hash = "sha256:31199204b3ced121ff5407a2c342326a5d27e3870abbf94bd80dbd2451b7bc8f"}, + {file = "multidict-6.9.1-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:8879510a76940670517ea1cb589978da44b86e286ec3e50d664ef330817afce7"}, + {file = "multidict-6.9.1-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:aec65b53a07f580606593f877eefbb29a45939bfc0d3fe6e6d9f42b41b749f68"}, + {file = "multidict-6.9.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:14c56f73e78faa1f68bbb826197cd5871994e70e841b8590829c35912ece5c64"}, + {file = "multidict-6.9.1-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:38c9986f9ce50c459b10de216a05f4bd7ed5ac63887d56e500a52bb464b861ce"}, + {file = "multidict-6.9.1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:15db6a102cbaf1949cf028ecf080aac76d20bcd29ad4e092574db6c6b7af78a5"}, + {file = "multidict-6.9.1-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd82c4977196681a499bb6ca9e462afbc5c91c1c15b6a991dfbd72733fea4dd2"}, + {file = "multidict-6.9.1-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bb58ba73a3f96f9a3e46b1fab69929d7edbbddb3133ee74b5c3c54074a53c4f1"}, + {file = "multidict-6.9.1-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7c6eecfab7ce4cd9487ff8ba936fe38cdfd68c04faf3d5c710363c6a8e695659"}, + {file = "multidict-6.9.1-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c62e71e6289d78c0108d8aeb495f8bd3cad4bc1632fedddc9297ddf287ecc20"}, + {file = "multidict-6.9.1-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:539c2cd5fed0947c135cd7eabaaac55f48300dfa1de0f3ca4edb5efa6606f471"}, + {file = "multidict-6.9.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:3100d169ceb7bc8f05f89a6db11d1b21f119975fc26f29dc45a472e3569f0879"}, + {file = "multidict-6.9.1-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:696477ad71385c4795e3b8e4cf10b0d2c28c2a1ca6a955e031cb1e62993e9ee3"}, + {file = "multidict-6.9.1-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:f5844e7befc707367807586f550fa97e23dcfef0728f02b98c7bc498a961a5df"}, + {file = "multidict-6.9.1-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:abc7c2e4b47bfe6a9aea434d3fdebb9597ee636e914e92ba352f2068b9142f4c"}, + {file = "multidict-6.9.1-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:7ab379f95caee071a37cbd8be86d4c65accc651d391f9f97748fef006f38769c"}, + {file = "multidict-6.9.1-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:557a4e1708df428ebe6c3081c83a273d275dad2446ce0d81fc648ac71afdb18d"}, + {file = "multidict-6.9.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:475d04d5192eba487a3e2f935976340baa24529046e9c1c9c7a3b7bf80445ae1"}, + {file = "multidict-6.9.1-cp315-cp315t-win32.whl", hash = "sha256:10083a8a0f4e1b26b599889e90b9802504ce5d3f7722f925bbb7ca47dd22a7c1"}, + {file = "multidict-6.9.1-cp315-cp315t-win_amd64.whl", hash = "sha256:e96ca64383efa107262ee3949f047af5ee4f1845ba09463466c04d35a83bd3ec"}, + {file = "multidict-6.9.1-cp315-cp315t-win_arm64.whl", hash = "sha256:501ed8b02a5990c67a91c732843609d43a6be1f7576fcdfc867331239f37fbd3"}, + {file = "multidict-6.9.1-py3-none-any.whl", hash = "sha256:7bf6478188f4e47bf5686e8a33da4ae28bf43b1b2528d9ee144d28492bfac60b"}, + {file = "multidict-6.9.1.tar.gz", hash = "sha256:0f06e60fa190aa7abd0914c2a766736fdc8e9f34878c4346338534b73d1b20e2"}, ] [package.dependencies] @@ -776,14 +801,14 @@ files = [ [[package]] name = "packaging" -version = "26.2" +version = "26.3" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"}, - {file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"}, + {file = "packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c"}, + {file = "packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79"}, ] [[package]] @@ -804,151 +829,168 @@ testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "propcache" -version = "0.5.2" +version = "0.5.4" description = "Accelerated property cache" optional = true python-versions = ">=3.10" groups = ["main"] markers = "extra == \"aiohttp\"" files = [ - {file = "propcache-0.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a81be28596d6559f6131ef33e10200de6e17643b3c74ce03f9eb103be6ae8b"}, - {file = "propcache-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29cbaac5ea0212663e6845e04b5e188d5a6ae6dd919810ac835bf1d3b42c3f4c"}, - {file = "propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6bf3be92233808fcd338eba0fb4d0b59ec5772af4f4ecfcec450d1bfc0f8b5eb"}, - {file = "propcache-0.5.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2f8ea531c794b9d6274acd4e8d2c2ebcac590a4361d27482edd3010b79f1325e"}, - {file = "propcache-0.5.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:decfca4c79dd53ebab484b00cc4b6717d8c369f86e74aa4ca395a64ac651495e"}, - {file = "propcache-0.5.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4621064bbf28fa77ff64dd5d94367c04684c67d3a5bf1dff25f0cd0d98a38f3b"}, - {file = "propcache-0.5.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b96db7141a592cbc968daf1feea83a118e6ab378af4abbc72b248c895414c22d"}, - {file = "propcache-0.5.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1ca071adabaab6e9219924bbe00af821f1ee7de113a9eca1cdc292de3d120f4d"}, - {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e4294d04a94dcab1b3bccd8b66d962dcad411a1d19414b2a41d1445f1de32ad0"}, - {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a0e399a2eccb91ed18721f86aa85757727400b6865c89e88934781deb9c8498b"}, - {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:823581fd5cb08b12a48bfa11fe962a7916766b6170c17b028fbdf762b85eb9bf"}, - {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:949c91d1a990cf3b2e8188dfcfb25005e0b834a06c63fa4ef9f360878ce21ecf"}, - {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:cc1177027eda740fdb152706bd215a3f124e3eea15afc39f2cb9fe351b50619e"}, - {file = "propcache-0.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b05d643f944a8c3c4bd86d65ffd87bf3264b617f87791940302bc474d2ff5274"}, - {file = "propcache-0.5.2-cp310-cp310-win32.whl", hash = "sha256:8114f28879e0904748e831c3a7774261bd9e75f49be089f389a76f959dcd13fe"}, - {file = "propcache-0.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:5fcb98e7598b1ee0addab320d90f65b530297a867dbfe9de52ea838077e16e3d"}, - {file = "propcache-0.5.2-cp310-cp310-win_arm64.whl", hash = "sha256:04dc2390d9edbbaef7461f33322555976ffddf0b650a038649d026358714e6c5"}, - {file = "propcache-0.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74b70780220e2dd89175ca24b81b68b67c83db499ae611e7f2313cb329801c78"}, - {file = "propcache-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4840ab0ae0216d952f4b53dc6d0b992bfc2bedbfe360bdd9b548bc184c08959"}, - {file = "propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6844ba6364fb12f403928a82cfd295ab103a2b315c77c747b2dbe4a41894ea7"}, - {file = "propcache-0.5.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2293949b855ce597f2826452d17c2d545fb5622379c4ea6fdf525e9b8e8a2511"}, - {file = "propcache-0.5.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0fd59b5af35f74da48d905dcbad55449ba13be91823cb05a9bd590bbf5b61660"}, - {file = "propcache-0.5.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29f9309a2e42b0d273be006fdb4be2d6c39a47f6f57d8fb1cf9f81481df81b66"}, - {file = "propcache-0.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5aaa2b923c1944ac8febd6609cb373540a5563e7cbcb0fd770f75dace2eb817b"}, - {file = "propcache-0.5.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66ea454f095ddf5b6b14f56c064c0941c4788be11e18d2464cf643bf7203ff67"}, - {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:95f1e3f4760d404b13c9976c0229b2b49a3c8e2c62a9ce92efdd2b11ada75e3f"}, - {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:85341b12b9d55bad0bded24cac341bb34289469e03a11f3f583ea1cc1db0326c"}, - {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:26a4dca084132874e639895c3135dfad5eb20bae209f62d1aeb31b03e601c3c0"}, - {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3b199b9b2b3d6a7edf3183ba8a9a137a22b97f7df525feb5ae1eccf026d2a9c6"}, - {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e59bc9e66329185b93dab73f210f1a37f81cb40f321501db8017c9aea15dba27"}, - {file = "propcache-0.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:552ffadf6ad409844bc5919c42a0a83d88314cedddaea0e41e80a8b8fffe881f"}, - {file = "propcache-0.5.2-cp311-cp311-win32.whl", hash = "sha256:cd416c1de191973c52ff1a12a57446bfc7642797b282d7caf2162d7d1b8aa9a0"}, - {file = "propcache-0.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:44e488ef40dbb452700b2b1f8188934121f6648f52c295055662d2191959ff82"}, - {file = "propcache-0.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:54adaa85a22078d1e306304a40984dc5be99d599bf3dc0a24dc98f7daeab89ab"}, - {file = "propcache-0.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:806719138ecd720339a12410fb9614ac9b2b2d3a5fdf8235d56981c36f4039ba"}, - {file = "propcache-0.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2b80ea58eab4f86b2beec3cc8b39e8ff9276ac20e96b7cce43c8ae84cd6b5a"}, - {file = "propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5cbfac9f61484f7e9f3597775500cd3ebe8274e9b050c38f9525c77c97520bf"}, - {file = "propcache-0.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbc581d2814337da56222fab8dc5f161cd798a434e49bac27930aaef798e144"}, - {file = "propcache-0.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:857187f381f88c8e2fa2fe56ab94879d011b883d5a2ee5a1b60a8cd2a06846d9"}, - {file = "propcache-0.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:178b4a2cdaac1818e2bf1c5a99b94383fa73ea5382e032a48dec07dc5668dc42"}, - {file = "propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f328175a2cde1f0ff2c4ed8ce968b9dcfb55f3a7153f39e2957ed994da13476"}, - {file = "propcache-0.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5671d09a36b06d0fd4a3da0fccbcae360e9b1570924171a15e9e0997f0249fba"}, - {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80168e2ebe4d3ec6599d10ad8f520304ae1cad9b6c5a95372aef1b66b7bfb53a"}, - {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:45f11346f884bc47444f6e6647131055844134c3175b629f84952e2b5cd62b64"}, - {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e778ebd44ef4f66ed60a0416b06b489687db264a9c0b3620362f26489492913"}, - {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c0cb9ed24c8964e172768d455a38254c2dd8a552905729ce006cad3d3dda59b1"}, - {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1d1ad32d9d4355e2be65574fd0bfd3677e7066b009cd5b9b2dee8aa6a6393b33"}, - {file = "propcache-0.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c80f4ba3e8f00189165999a742ee526ebeccedf6c3f7beb0c7df821e9772435a"}, - {file = "propcache-0.5.2-cp312-cp312-win32.whl", hash = "sha256:8c7972d8f193740d9175f0998ab38717e6cd322d5935c5b0fef8c0d323fd9031"}, - {file = "propcache-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:d9ee8826a7d47863a08ac44e1a5f611a462eefc3a194b492da242128bec75b42"}, - {file = "propcache-0.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:2800a4a8ead6b28cccd1ec54b59346f0def7922ee1c7598e8499c733cfbb7c84"}, - {file = "propcache-0.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:099aaf4b4d1a02265b92a977edf00b5c4f63b3b17ac6de39b0d637c9cac0188a"}, - {file = "propcache-0.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68ce1c44c7a813a7f71ea04315a8c7b330b63db99d059a797a4651bb6f69f117"}, - {file = "propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fc299c129490f55f254cd90be0deca4764e36e9a7c08b4aa588479a3bbed3098"}, - {file = "propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6ae2198be502c10f09b2516e7b5d019816924bc3183a43ce792a7bd6625e6f4"}, - {file = "propcache-0.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6041d31504dc1779d700e1edcfb08eea334b357620b06681a4eabb57a74e574e"}, - {file = "propcache-0.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7eabc04151c78a9f4d5bbb5f1faf571e4defeb4b585e0fe95b60ff2dbe4d3d7"}, - {file = "propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4db0ba63d693afd40d249bd93f842b5f144f8fcbb83de05660373bcf30517b1d"}, - {file = "propcache-0.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dbcf7675229b35d31abb6547d8ebc8c27a830ac3f9a794edff6254873ec7c0a"}, - {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d310c013aad2c72f1c3f2f8dd3279d460a858c551f97aeb8c63e4693cca7b4d2"}, - {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06187263ddad280d05b4d8a8b3bb7d164cbebd469236544a42e6d9b28ac6a4fa"}, - {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3115559b8effafd63b142ea5ed53d63a16ea6469cbc63dce4ee194b42db5d853"}, - {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c60462af8e6dc30c35407c7237ea908d777b22862bbee27bc4699c0d8bcdc45a"}, - {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40314bca9ac559716fe374094fc81c11dcc34b64fd6c585360f5775690505704"}, - {file = "propcache-0.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cfa21e036ce1e1db2be04ba3b85d2df1bb1702fa01932d984c5464c665228ff4"}, - {file = "propcache-0.5.2-cp313-cp313-win32.whl", hash = "sha256:f156a3529f38063b6dbaf356e15602a7f95f8055b1295a438433a6386f10463d"}, - {file = "propcache-0.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:dfed59d0a5aeb01e242e66ff0300bc4a265a7c05f612d30016f0b60b1017d757"}, - {file = "propcache-0.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:ba338430e87ceb9c8f0cf754de38a9860560261e56c00376debd628698a7364f"}, - {file = "propcache-0.5.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a592f5f3da71c8691c788c13cb6734b6d17663d2e1cb8caddf0673d01ef8847d"}, - {file = "propcache-0.5.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6a997d0489e9668a384fcfd5061b857aa5361de73191cac204d04b889cfbbafa"}, - {file = "propcache-0.5.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:10734b5484ea113152ee25a91dccedf81631791805d2c9ccb054958e51842c94"}, - {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cafca7e56c12bb02ae16d283742bef25a61122e9dab2b5b3f2ccbe589ce32164"}, - {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f064f8d2b59177878b7615df1735cd8fe3462ed6be8c7b217d17a276489c2b7f"}, - {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f78abfa8dfc32376fd1aacf597b2f2fbbe0ea751419aee718af5d4f82537ef8c"}, - {file = "propcache-0.5.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7467da8a9822bf1a55336f877340c5bcbd3c482afc43a99771169f74a26dedc"}, - {file = "propcache-0.5.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a6ddc6ac9e25de626c1f129c1b467d7ecd33ce2237d3fd0c4e429feef0a7ee1f"}, - {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f22cbbac9e26a8e864c0985ff1268d5d939d53d9d9411a9824279097e03a2cb"}, - {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:fc76378c62a0f04d0cd82fbb1a2cd2d7e28fcb40d5873f28a6c44e388aaa2751"}, - {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:acd2c8edba48e31e58a363b8cf4e5c7db3b04b3f9e371f601df30d9b0d244836"}, - {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:452b5065457eb9991ec5eb38ff41d6cd4c991c9ac7c531c4d5849ae473a9a13f"}, - {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3430bb2bfe1331885c427745a751e774ee679fd4344f80b97bf879815fe8fa55"}, - {file = "propcache-0.5.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cef6cea3922890dd6c9654971001fa797b526c16ab5e1e46c05fd6f877be7568"}, - {file = "propcache-0.5.2-cp313-cp313t-win32.whl", hash = "sha256:72d61e16dd78228b58c5d47be830ff3da7e5f139abdf0aef9d86cde1c5cf2191"}, - {file = "propcache-0.5.2-cp313-cp313t-win_amd64.whl", hash = "sha256:0958834041a0166d343b8d2cedcd8bcbaeb4fdbe0cf08320c5379f143c3be6e7"}, - {file = "propcache-0.5.2-cp313-cp313t-win_arm64.whl", hash = "sha256:6de8bd93ddde9b992cf2b2e0d796d501a19026b5b9fd87356d7d0779531a8d96"}, - {file = "propcache-0.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:46088abff4cba581dea21ae0467a480526cb25aa5f3c269e909f800328bc3999"}, - {file = "propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fc88b26f08d634f7bc819a7852e5214f5802641ab8d9fd5326892292eee1993e"}, - {file = "propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97797ebb098e670a2f92dd66f32897e30d7615b14e7f59711de23e30a9072539"}, - {file = "propcache-0.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba57fffe4ac99c5d30076161b5866336d97600769bad35cc68f7774b15298a4e"}, - {file = "propcache-0.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:583c19759d9eec1e5b69e2fbef36a7d9c326041be9746cb822d335c8cedc2979"}, - {file = "propcache-0.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d0326e2e5e1f3163fa306c834e48e8d490e5fae607a097a40c0648109b47ba80"}, - {file = "propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e00820e192c8dbebcafb383ebbf99030895f09905e7a0eb2e0340a0bcc2bc825"}, - {file = "propcache-0.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c66afea89b1e43725731d2004732a046fe6fe955d51f952c3e95a7314a284a39"}, - {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc37dec6c6cdad0b57881a5658fd14fbf53e333b1a86cf86559f190e1d9ec4"}, - {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5570dbcc97571c15f68068e529c92715a12f8d54030e272d264b377e22bd17a5"}, - {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f814362777a9f841adddb200ecdf8f5cb1e5a3c4b7a86378edbd6ccb26edd702"}, - {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:196913dea116aeb5a2ba95af4ddcb7ea85559ae07d8eee8751688310d09168c3"}, - {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6e7b8719005dd1175be4ab1cd25e9b98659a5e0347331506ec6760d2773a7fb5"}, - {file = "propcache-0.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:51f96d685ab16e88cab128cd37a52c5da540809c8b879fa047731bfcb4ad35a4"}, - {file = "propcache-0.5.2-cp314-cp314-win32.whl", hash = "sha256:cc6fc3cc62e8501d3ed62894425040d2728ecddb1ed072737a5c70bd537aa9f0"}, - {file = "propcache-0.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:81e3a30b0bb60caa22033dd0f8a3618d1d67356212514f62c57db75cb0ef410c"}, - {file = "propcache-0.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:0d2c9bf8528f135dbb805ce027567e09164f7efa51a2be07458a2c0420f292d0"}, - {file = "propcache-0.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:4bc8ff1feffc6a61c7002ffe84634c41b822e104990ae009f44a0834430070bb"}, - {file = "propcache-0.5.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:79aa3ff0a9b566633b642fa9caf7e21ed1c13d6feca718187873f199e1514078"}, - {file = "propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1b31822f4474c4036bae62de9402710051d431a606d6a0f907fec79935a071aa"}, - {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13fef48778b5a2a756523fdb781326b028ca75e32858b04f2cdd19f394564917"}, - {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b73ab70f1a3351fbc71f663b3e645af6dd0329100c353081cf69c37433fc6fe"}, - {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5538d2c13d93e4698af7e092b57bc7298fd35d1d58e656ae18f23ee0d0378e03"}, - {file = "propcache-0.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd645f03898405cabe694fb8bc35241e3a9c332ec85627584fe3de201452b335"}, - {file = "propcache-0.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a473b3440261e0c60706e732b2ed2f517857344fc21bf48fdfe211e2d98eb285"}, - {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7afa37062e6650640e932e4cc9297d81f9f42d9944029cc386b8247dea4da837"}, - {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8a90efd5777e996e42d568db9ac740b944d691e565cbfd31b2f7832f9184b2b8"}, - {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f19bb891234d72535764d703bfed1153cc34f4214d5bd7150aee1eec9e8f4366"}, - {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:32775082acd2d807ee3db715c7770d38767b817870acfa08c29e057f3c4d5b56"}, - {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9282fb1a3bccd038da9f768b927b24a0c753e466c086b7c4f3c6982851eefb2d"}, - {file = "propcache-0.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc49723e2f60d6b32a0f0b08a3fd6d13203c07f1cd9566cfce0f12a917c967a2"}, - {file = "propcache-0.5.2-cp314-cp314t-win32.whl", hash = "sha256:2d7aa89ebca5acc98cba9d1472d976e394782f587bad6661003602a619fd1821"}, - {file = "propcache-0.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d447bb0b3054be5818458fbb171208b1d9ff11eba14e18ca18b90cbb45767370"}, - {file = "propcache-0.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:fe67a3d11cd9b4efabfa45c3d00ffba2b26811442a73a581a94b67c2b5faccf6"}, - {file = "propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe"}, - {file = "propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427"}, + {file = "propcache-0.5.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b77c313314524ca9c38fbd70f73515d04597ac58c40c939bc0e71eeb4abff680"}, + {file = "propcache-0.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8f911c395cef73c510bac566da9507bb6a43e7763d0c79138dc60ee53f11207e"}, + {file = "propcache-0.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d83b12902eb8bce151259c86c03ba746600b2d994543de46e370cecf96c452f2"}, + {file = "propcache-0.5.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9281e922c072158c91974d4589f1dbe0fee6d467f284c28e463f9f5a4d933f4"}, + {file = "propcache-0.5.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9f3551b8a35c1df3e7ea4d2d86edee15f0dde1bddd434a71744048683544d0ef"}, + {file = "propcache-0.5.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ec6a85f424afa8d23e0d9a094e5dbb6eda01da91c92b9183cd433768247ffc97"}, + {file = "propcache-0.5.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f574e460d1c8a08384a016fdb09ccf3543433263ed6b2f97104f979e64ea57c2"}, + {file = "propcache-0.5.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d8e017eeb7482bed34cdb0d61cf2bcfc88d104bbab296a17cd16a6af8aabc70e"}, + {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f273dcf7149a50527c4fd1f55cfe9eac0f60753f5af544b4c9352578e20c0874"}, + {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:fc2461ecc45f17893f8207e73b46ea8ba93e33630e51cf4af3fbc21d47462b1a"}, + {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:279655a16973f1ee2bd2fe79973137681642fd9ae0d89215bba263726eb0dc3a"}, + {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:e9f165403b81fea7e89c932d89046a1e3d9a3a60e8d7ef2f249dccdcb0982bf5"}, + {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1783582065a1f07f9d9ee1e992e13f15d7dc8fb1eb3a7476d43eb3f2e69d26bb"}, + {file = "propcache-0.5.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d605bb239b796e82a81c6709548b2bd460ab73b4590cb0c83de8a2dd9694d0f"}, + {file = "propcache-0.5.4-cp310-cp310-win32.whl", hash = "sha256:141fdbd73748db0cf7636035030aaac383d2efde8f34e7bc24594cc776d225b8"}, + {file = "propcache-0.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:146f48a9e4812611a7581003b1a39de56c34967046310c4171a68ef908c9a745"}, + {file = "propcache-0.5.4-cp310-cp310-win_arm64.whl", hash = "sha256:6c7599df2b57ebeea8de011b5f2f7b85de95e76037d43d34b95e328430275487"}, + {file = "propcache-0.5.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:897d1ddf6716e8f47200f7aad9a0efa6cc7586df66c6defa572f9eab379c078e"}, + {file = "propcache-0.5.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9cbfff4423eef4cc6cafc021469641a2b835f610b2647a6c5281903e21b8670d"}, + {file = "propcache-0.5.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3fc24f209c1b7f7f688b66b98293954f5504279760999b58920ee12dd8471c1d"}, + {file = "propcache-0.5.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:62530ca89187827e4a4fe733f971abe81a7542eeea48ff61995f19b64d7199c8"}, + {file = "propcache-0.5.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fc3f7599528db40b1efa0889a620116e2704144495273d66066e8164e45838"}, + {file = "propcache-0.5.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4f2d880ff60f45898f4acfa152aac8d04e3ee627d90ff4003491bf92239d5757"}, + {file = "propcache-0.5.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e9368e87a3efc285e559131092c5db643eb8e56de4ee42064d5baec22ef2bb5"}, + {file = "propcache-0.5.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:004e685b315646c410771836e72a44f143bbe624f29653a42687815069a303d5"}, + {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:594eb4c6ec35e7179b058481f4e9f02521b56de16fa577c4b85c76fb1bf8a9f8"}, + {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2dba2f02d2d5c09ef8a0e6c1a42aeaa451f4be9898cb00b04fe98717da2eb23b"}, + {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c3ef2818d63bc86071e9d2989ae75a1bc32b8f7059cfd9f5abbbee70c32e2ed6"}, + {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:dd2ac8f5b643454c2cc6b6118b13da16e88f4a6434fc3ba61aca384029f04f36"}, + {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4054acf80d40456a0537f2913b349718649d8d6458a14ab7f48d0ce28c30869d"}, + {file = "propcache-0.5.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40e94adb1e7d39ff28a8bd8d8b8fbd1df6b9f40976dbe379134f1ce058e532dd"}, + {file = "propcache-0.5.4-cp311-cp311-win32.whl", hash = "sha256:9f86f7259efe2c951f43e57d471c9b41daa5bfc7db9f67189059cf1ae6d77fd9"}, + {file = "propcache-0.5.4-cp311-cp311-win_amd64.whl", hash = "sha256:e904d4d01f36bd6e197590be1533c44e06058771e0746dd073a8ebb3ef880858"}, + {file = "propcache-0.5.4-cp311-cp311-win_arm64.whl", hash = "sha256:d42a9a856a4a6e2f6c10f1318c07e7daa498d6593abe745c71dae4521a26ca39"}, + {file = "propcache-0.5.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b28f41fa3b8c6900457f858ec5b03998f3a6d535fbc1bb2edec5961ea05ec429"}, + {file = "propcache-0.5.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:dcbf346a318a5e30063f547630b02bb787ce2f45b6368d5da143660b6a3835d8"}, + {file = "propcache-0.5.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:87a3caecf8095e48dc72f84bfa42e23a848cf410cc9cc13031fba4869b706a21"}, + {file = "propcache-0.5.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60a64cbccaa11b7760ce705a14ada17ba459e7ca9f23ba587eb013821032d7ef"}, + {file = "propcache-0.5.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a74bfa37147cc08fb29df10bd9c16f40fa7f860cd3a6d2fff853323a94f6e17f"}, + {file = "propcache-0.5.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a4d7a54719b67338a305dca2ce6aafe366817df94ddfd4b5514374356f5ca546"}, + {file = "propcache-0.5.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2814ecd8e818f487bee4b0f921bc4d1c176cc5fc71ac0f072d0fa67eda4ac14b"}, + {file = "propcache-0.5.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6af4693716bfb03f1752ef1b30faa593db2c01d5272e9b8564a1549452a979ab"}, + {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4fbc1a15dc8cd1689508758d626b372b1f09d28d9577667feaf9e6bfcd8efcbc"}, + {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:cdee8205a44d0be91bbac4c41b95d86641b72dfc7aef1279400e4fda3f26a937"}, + {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9a2a8a50a93dee0268a860a07fa3b4bd968f8ce4dbd794957da772f395368526"}, + {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7ffafcbfc7b549ab940047e505c831eabac5e67de53e1bc174adbc5285c55944"}, + {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d1f5a500bfcbb2c0ab85e98a0dcd70f5899d34efe365a0187700369a79603031"}, + {file = "propcache-0.5.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a235f73d6e020855dc29dff012d920c02ee0feab8d73a24185a7569f4be1161"}, + {file = "propcache-0.5.4-cp312-cp312-win32.whl", hash = "sha256:b3083bfe87f95c756e610bd8025f26cbd1cd4aaa03a422f2d65efb7a97cd53d8"}, + {file = "propcache-0.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:98914de2c4d7f0f9f4a8c6ea4bf05841f4175796941e3ef7d47eb718f22311fb"}, + {file = "propcache-0.5.4-cp312-cp312-win_arm64.whl", hash = "sha256:8876b39961e33d912afe3c1bee18ee564fdad0206f873cc15d522756b7f50737"}, + {file = "propcache-0.5.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:36c0d9db44b523ef93d03341b1c42d69ff01d673c053d1b1c6c3a363bcaa39ba"}, + {file = "propcache-0.5.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1d52a05dc417279f7e5c7618c5dfbbc29923aaf9bc0a5c1802ddcebf54c61a0"}, + {file = "propcache-0.5.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:44149f46500a0a41b95b4d99c2e586a77319539730607b9892974a092788b111"}, + {file = "propcache-0.5.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbab5f5ff6897c81f355d079010cdae85b02e5a0b518b5251523b8ad8ae9ac3c"}, + {file = "propcache-0.5.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c3e98c55bde2bcf7db3c70d1aed7ae9aa8aebbf19a250c66645cde44cdb8b867"}, + {file = "propcache-0.5.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db3ae52ccc150dbc84704e9d642743897f3e1c54742ff34cacb661e52e3818a9"}, + {file = "propcache-0.5.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f85915e00dcb1cd9f2f890ead064ed40a27df06f0db65be427b29482ae357572"}, + {file = "propcache-0.5.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c2ba30a89035b57b73e00475de948521602f543d79ce01db10b04b36c4c76fc8"}, + {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ae58f361bd5dae942717c65d3413b478c70aea9c462599e7b9adad3731db3894"}, + {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:96f7c5c15656040ddcbc51e56dc59b58aa25999d743c126abd425b9766ab43e9"}, + {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7cc528e760a8af06f2b13e9b9f362cd90c7c718ea61228a96dbd31ba16ed7f47"}, + {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:425f8cc86ab5018b4b8d4a23bc8e74d964bd3d757c3702e301aa79be76c53f6c"}, + {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:a5793c7698a53f56f4a1889a4737c7eeb1b7ad0842fa6b1abca22913ff79c8c1"}, + {file = "propcache-0.5.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c02c0e570c5c7e077b0181a9f3cdb7d4c3617d1cda6b5c95bd5d34022923d82c"}, + {file = "propcache-0.5.4-cp313-cp313-win32.whl", hash = "sha256:3e413d7a4a9b4866b7a761d6060d434b64d23cd35122eda3b026a0bbe8196b25"}, + {file = "propcache-0.5.4-cp313-cp313-win_amd64.whl", hash = "sha256:0c889f6fa84957bc7e8b4eab71fd16a0455068d5045e3aa40c733071d2b2fd77"}, + {file = "propcache-0.5.4-cp313-cp313-win_arm64.whl", hash = "sha256:69fc35c0779522da366c563e5faf203ffc1f8ff0021d5b1337fa4efa5be73177"}, + {file = "propcache-0.5.4-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:e6720ba44ad7e72174314d0e1fb0172494cff5c73a3a8a2159c3d2402ff15565"}, + {file = "propcache-0.5.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4cfe0a92ae30151869e67a4b5f5e105e4e03ad30b3f38e5211b5bf77d0881993"}, + {file = "propcache-0.5.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d759d05634f1b038fb625a66662a8c85e5a8fec912da381b5149ddac107482b"}, + {file = "propcache-0.5.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:251c63dd46a0659bb875cb254dc4c1e79ee91a847c737cd62373295afc2235dc"}, + {file = "propcache-0.5.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7a8d5ff04eb1f85698a78d20c62a14676e7b960dcafde09a388d60ad377d355d"}, + {file = "propcache-0.5.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b9100a93b372418d8688f3f2a3e5b45c64d70ca4d6176e121aca1e3bfc1e32f"}, + {file = "propcache-0.5.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cc07876cfb079b6f6f36d21ce75784ad6c2c6b563eeac0ed26c2fa2669b85df9"}, + {file = "propcache-0.5.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0951315a6b3142ee2167404d707743f0157c110091342b1aa0accac5cf0e4acf"}, + {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bee7d3aed13d56f54e681df38c3a23031bc9e3863f687d9d598825c9146acd7d"}, + {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4e985382be6d15da8d0c2710a6fa7b9070fc9ecdeefb7f580e88373984ec8be3"}, + {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e9ab13760aa8b6d0881ae7cb04fd891d8d490cd2554ea8e79bb278399169bcc"}, + {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:1b2f3bec4261a94019575481c726c29850f72e27907773c75b1de421e20e9f9d"}, + {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:720cf832eb2d0b0dfee129cb3335a26f6ce3cc45ee1187e8f0731758caa16792"}, + {file = "propcache-0.5.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9fb0a5be8d9aa213150e8d8148a42aca4984b285bcad1e69587dc4298edd929b"}, + {file = "propcache-0.5.4-cp314-cp314-win32.whl", hash = "sha256:30cc1cebaf9aef49db06357a50398323ae04d70460c0491837d026ab7d6452ea"}, + {file = "propcache-0.5.4-cp314-cp314-win_amd64.whl", hash = "sha256:0a095db8e15a6020db149ecbed6461939fe74f6acaa3ae8b702a1fe8c38cd983"}, + {file = "propcache-0.5.4-cp314-cp314-win_arm64.whl", hash = "sha256:45488d1a5f9ab5bd90aaa1ca20f50fe1922b8ffad71a2009d2adf41355897aac"}, + {file = "propcache-0.5.4-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:53eaa697c4d0422ff4cb714d00231b43352064d97b944033b30c1d57cc506ec0"}, + {file = "propcache-0.5.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:886b59c4d28ca97dd23b025fdfc50a0356be934efbbbca89ad26230067f86fe5"}, + {file = "propcache-0.5.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fa15757fea1dfcd5b7745cad9f4638929605531bd4018ab2adff7955f1a403d"}, + {file = "propcache-0.5.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f0093ac3e9daada202c2082439d414a625c57184727a46e112a3fb2a81cb788"}, + {file = "propcache-0.5.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3cd3a7edb6b95b9b33998135ebfa18d709da82290fb8f27c858970b5a12c8b56"}, + {file = "propcache-0.5.4-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c174bfd1c48a1b51a3078e95586dde718374bac79719ab3541ec9e74aec40574"}, + {file = "propcache-0.5.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a219f0ac59817a9114dd2aa57c13180f993e819ba658c7ddab4b66ed1ee0d370"}, + {file = "propcache-0.5.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:17a7400cec0256f0a71ae71f9da398f9894c956ff6668a1c9d317b3367316320"}, + {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:978f28401afbc76cdc3df9e1717b4229a06b626a1dcc75db4e1f2beb3884c3e9"}, + {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4a1f4f5ffa55dce6307631f3cb2948e117e665966ea512e0d502b16c24f567e7"}, + {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:213bb68d9ced5cf2bf717b1071bf2b09b4b04c426256f9fe6d054c60318424c4"}, + {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:286867fb156488c251a3721766e380ac4495e4fd6b51aaa1403d89ce7f4359d9"}, + {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:445ee3bfb46e85838387fb3c536a73cc0b994dc192b004e40e170adc54aa2a7e"}, + {file = "propcache-0.5.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:48cb48c5346a97de792254af77715aa2529c2a1ebc5f586aa0aae44a02f1fe57"}, + {file = "propcache-0.5.4-cp314-cp314t-win32.whl", hash = "sha256:03b229037d25b801e7af53fd52b9fc49d9439b036fca1e087e02780631adfa97"}, + {file = "propcache-0.5.4-cp314-cp314t-win_amd64.whl", hash = "sha256:8a1fc236528c457cd739c88abe823da851b7ab645d72792f88658114cc340c12"}, + {file = "propcache-0.5.4-cp314-cp314t-win_arm64.whl", hash = "sha256:135036c5cfc93864affb0f9af9a27e5d7a71cb7bd745e7b6dbfc2d56cc30e827"}, + {file = "propcache-0.5.4-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:45bf2e730ab8905d0527fe05a86500f406e64305c34cc81ebe64b4617cab9760"}, + {file = "propcache-0.5.4-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:31eb43ba2edc704ab2ec27815315dd8a19def0fb16215be4cfe8d32fe78ffd51"}, + {file = "propcache-0.5.4-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:174507f82d3594622acb1dd2dafecf2d899d6d506335494e7107767bf05f3aae"}, + {file = "propcache-0.5.4-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50e337653721d20ead710da33bf44487fbe8a0db8782714b60306481e9f95b51"}, + {file = "propcache-0.5.4-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0d21d0d2c82bbfeb1677a9711f38df968f9837576102bb4add1bd449d28d88f1"}, + {file = "propcache-0.5.4-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ccf4f7a79e26bb7efb06ecd50c177833b71df05cbc748701372325e6bcc17f6f"}, + {file = "propcache-0.5.4-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23278f808cd81d5ada7184a76606b925fb3389c60e1077b2cd7da7b1fcf0553c"}, + {file = "propcache-0.5.4-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e738ab81179510ce79b2eac9a6ecf47feffd9e76d1c72e403005dddb6e36c06c"}, + {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:a419ee85e654927baabda3929c03c0cc1112bf472ff0dfd6142f4e3a81ca4162"}, + {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:b61805357d966680acf68b3b6d49772631ed9df44ebece10ff1460e117a7da8a"}, + {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:58134228927cee6c047d626c08e60a81be604a20578a12ce752cc5c9a84d4826"}, + {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:350b272b2279f4135a64fc0c304a5d08e28a137c9573442c606152446638a831"}, + {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:45bebbe252550fec975ba3b62bc6f931643cfd3b5464ef47619cf3fef154e01c"}, + {file = "propcache-0.5.4-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:ada748108a43d29b7c328ba7db3755327cd94f028bcc1a7ee3f0addcfacd9c38"}, + {file = "propcache-0.5.4-cp315-cp315-win32.whl", hash = "sha256:ee19113bce2f3acd46432050688b70f61acd6857d75abb9ec96341b7e9ced123"}, + {file = "propcache-0.5.4-cp315-cp315-win_amd64.whl", hash = "sha256:ceb3e879afac028f93d272c957814695dc5569e4904262dbee92f6c41bd5e4a3"}, + {file = "propcache-0.5.4-cp315-cp315-win_arm64.whl", hash = "sha256:c83acbce9f2b5e3f5f5eda9e53d2001fed22fcdfef81274a9e02d8fd53b70a30"}, + {file = "propcache-0.5.4-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:a5e8ef588c109725dc713ba69aadcac00a1ef90c2ce9c0a8c7075128f569f47f"}, + {file = "propcache-0.5.4-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:4d86476a935c88963d9b8e1a9a0d38188790e9622169bfbafa173046846709d3"}, + {file = "propcache-0.5.4-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:f5470694918830da62fac9e69133b53d23b736d7070e587b27a4a2be37e08e68"}, + {file = "propcache-0.5.4-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10ef33a68a61ce317e095fd2e202a592ea92392b90944a78c993f0d9a73ab06c"}, + {file = "propcache-0.5.4-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5cacf3c9efd09df409dc33654dd077e1c245ba8fb747b0f0236ef41b7c49b589"}, + {file = "propcache-0.5.4-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:770e8209d018175fc0063936fa9583b6d27e88c5ad31543f3383d66080efdd62"}, + {file = "propcache-0.5.4-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03969626faf0783a592dfa17e28eac06018bd0b44dafae6943d53b92421a7f72"}, + {file = "propcache-0.5.4-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ef3b928d9c984322b5c44e6964d8dbc653da87d2d8ee1647fa6da43072e650a9"}, + {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:7177c43eddf10a0893c4fec52ebb408fdcd7f7d63962caace9180d8f81b14ece"}, + {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:420162a77f94eb1cf5ef7893f500016dabd548e73de956785a1dd899cc73006a"}, + {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:3eb2e820e8e2101407da93f17c57cbb7d225461955fc60105daaba14cd421ee2"}, + {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:13e52b6e0bde97dee98ab66552dbff2931649c96f1ac432eac299fe689ec373b"}, + {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:12682126712ddc19b70ff819debbd279e58adf1f0c8f8f8138c18ade2044b284"}, + {file = "propcache-0.5.4-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:3af0c8642b2da4815d86e631232ac8286e17644fad907c19508aa8e7cb4ba8ad"}, + {file = "propcache-0.5.4-cp315-cp315t-win32.whl", hash = "sha256:1df8d8561b21465c5dd56110a01caf897e026d065b4b84e98a488209094272ec"}, + {file = "propcache-0.5.4-cp315-cp315t-win_amd64.whl", hash = "sha256:02c0a34f16889cf800f10f0247a564d8ce6eeab6ffcd7c87198f769067eb8432"}, + {file = "propcache-0.5.4-cp315-cp315t-win_arm64.whl", hash = "sha256:dc4242ca653c9b30ab51c5f8193323e7bc0928f897ee9103201e59a43abcb72e"}, + {file = "propcache-0.5.4-py3-none-any.whl", hash = "sha256:62c60aec739ed00124573cce1178138fd690c7676352d67a37328c1cf51d7468"}, + {file = "propcache-0.5.4.tar.gz", hash = "sha256:ff6b113f50bc066a698db5d944d2c6dc7507168dd3341e255a8892fd0715a558"}, ] [[package]] name = "pydantic" -version = "2.13.4" +version = "2.13.5" description = "Data validation using Python type hints" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba"}, - {file = "pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6"}, + {file = "pydantic-2.13.5-py3-none-any.whl", hash = "sha256:346a034f080da3755d8e9cb5e00e8b07de1d39e4f6e2c87d8ab7cafa0b269a73"}, + {file = "pydantic-2.13.5.tar.gz", hash = "sha256:51a9c5f7b2f8e636f04c6cada605d9b6a3bf1348fdf945a3d8869b19bba0ee08"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.46.4" +pydantic-core = "2.46.5" typing-extensions = ">=4.14.1" typing-inspection = ">=0.4.2" @@ -958,132 +1000,132 @@ timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows [[package]] name = "pydantic-core" -version = "2.46.4" +version = "2.46.5" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pydantic_core-2.46.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a396dcc17e5a0b164dbe026896245a4fa9ff402edca1dff0be3d53a517f74de4"}, - {file = "pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da4b951fe36dc7c3a1ccb4e3cd1747c3542b8c9ceede8fc86cae054e764485f5"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb63e0198ca18aad131c089b9204c23079c3afa95487e561f4c522d519e55aba"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f47286a97f0bc9b8859519809077b91b2cefe4ae47fcbf5e466a009c1c5d742b"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:905a0ed8ea6f2d61c1738835f99b699348d7857379083e5fc497fa0c967a407c"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea793e075b70290d89d8142074262885d3f7da19634845135751bd6344f73b50"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395aebd9183f9d112f569aeb5b2214d1a10a33bec8456447f7fbdfa51d38d4cd"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b078afbc25f3a1436c7a1d2cd3e322497ee99615ba97c563566fdf46aff1ee01"}, - {file = "pydantic_core-2.46.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f747929cf940cddb5b3668a390056ddd5ba2e5010615ea2dcf4f9c4f3ab8791d"}, - {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:daa27d92c36f24388fe3ad306b174781c747627f134452e4f128ea00ce1fe8c4"}, - {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:19e51f073cd3df251856a8a4189fbdf1de4012c3ebacfb1884f94f1eb406079f"}, - {file = "pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1747f85cee84c26985853c6f3d9bd3e75da5212912443fa111c113b9c246f39"}, - {file = "pydantic_core-2.46.4-cp310-cp310-win32.whl", hash = "sha256:2f84c03c8607173d16b5a854ec68a2f9079ae03237a54fb506d13af47e1d018d"}, - {file = "pydantic_core-2.46.4-cp310-cp310-win_amd64.whl", hash = "sha256:8358a950c8909158e3df31538a7e4edc2d7265a7c54b47f0864d9e5bae9dcebf"}, - {file = "pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594"}, - {file = "pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398"}, - {file = "pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3"}, - {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848"}, - {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3"}, - {file = "pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109"}, - {file = "pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda"}, - {file = "pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33"}, - {file = "pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d"}, - {file = "pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2"}, - {file = "pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987"}, - {file = "pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b"}, - {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458"}, - {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b"}, - {file = "pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c"}, - {file = "pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894"}, - {file = "pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89"}, - {file = "pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a"}, - {file = "pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008"}, - {file = "pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262"}, - {file = "pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e"}, - {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd"}, - {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be"}, - {file = "pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d"}, - {file = "pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb"}, - {file = "pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292"}, - {file = "pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d"}, - {file = "pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb"}, - {file = "pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c"}, - {file = "pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb"}, - {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898"}, - {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e"}, - {file = "pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519"}, - {file = "pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4"}, - {file = "pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac"}, - {file = "pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5"}, - {file = "pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596"}, - {file = "pydantic_core-2.46.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:fd8b3d9fd264be37976686c7f65cd52a83f5e84f4bfd2adf9c1d469676bbb6ae"}, - {file = "pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9f444c499b3eefd3a92e348059471ea0c3a6e303d9c1cec09fa748fd9f895201"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3447661d99f75a3683a4cf5c87da72f2161964611864dbbeac7fbb118bb4bfc0"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b9bab013d1c7a79d3501ff86d0bc9c31bf587db4551677b96bec07df78c6b15"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d995260fdf4e1db774581b4900e0f832abe3c7c84996726bbc161b19c8f29e76"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f13a646d65d09fbf1bc6b3a9635d30095c8e7e5cc419ff35ecc563c5fd04cd49"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432c179df7874eeb73307aad2df0755e1ae0efa61ff0ea89b93e194411ae3928"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:e68b7a074f65a2fd746c52a7ce6142ab7006074ac269ace0c25cd8ba171f8066"}, - {file = "pydantic_core-2.46.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4a05d69cba51d852c5c3e92758653245a50c0b646ced0cf05bd793ed592839d6"}, - {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:228ee9bae8bef5b1e97ec58302f80357c37199e0d0a99174e138d28e6957b9d9"}, - {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:10e17cbb10a330363733efc4d7c4d0dd827ac0909b8f6a6542298fed1ea62f29"}, - {file = "pydantic_core-2.46.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:91a06d2e259ecfbd8c901d70c3c507900458498142b3026a296b7de4d1322cc9"}, - {file = "pydantic_core-2.46.4-cp39-cp39-win32.whl", hash = "sha256:d80ee3d731373b24cebbc10d689ca4ee1875caf0d5703a245db18efd4dd37fc1"}, - {file = "pydantic_core-2.46.4-cp39-cp39-win_amd64.whl", hash = "sha256:3be77f45df024d789a672ae34f8b06fb346c4f9f46ea714956660ea4862e89ac"}, - {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c"}, - {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b"}, - {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b"}, - {file = "pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea"}, - {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7"}, - {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df"}, - {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526"}, - {file = "pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc"}, - {file = "pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983"}, - {file = "pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1"}, + {file = "pydantic_core-2.46.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:657b40d6240c0a7b6a64b30f22d1e3aa631c7e846c621b0c0f6d1d75e2e15ea6"}, + {file = "pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ecb42011e12ee19cafbc312887cbf3546959fe02fbad44f272d4be5baa997615"}, + {file = "pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dedce55295becb61921e386b99d4f2706045306e7fa52249a33004c837379fb"}, + {file = "pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f47b8a949e60f027f0aa0a6f6c7b7e9c55cbf4380d10b344e282fa4e7ab1e1b"}, + {file = "pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:200aa3dc9f8d54f0754f43247c0bad0999fdcfbfd2488384dd44f37279271fe6"}, + {file = "pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d30e1a4f138b8951063e9a394752a9179b51da288ffa507b1e659222f4c1793"}, + {file = "pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:850a08d167dde16db8702c274f320c7be9d7da6f6dff2b58b18f9e815bd94f5b"}, + {file = "pydantic_core-2.46.5-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:c3471e5c4a949c26ec00a77f01df59096aa9495877de76fd60a980f8ee6be461"}, + {file = "pydantic_core-2.46.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3a3e26b6a8274211bddee2d0e4d0d42778f17a34510f49d2ec44b58abfc41736"}, + {file = "pydantic_core-2.46.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fc5d783bd4a2387e97b8a2d5ec781cfb92b3d893bf82370548e99db5915935d3"}, + {file = "pydantic_core-2.46.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:356c8368cbc321050b169595683a2e1d63413b1e0e2868b330af9fc14c616d3f"}, + {file = "pydantic_core-2.46.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eb7d8d0e5886a89a55d2eef490e272fa965a9d57c6b29a5b5088a7997ec2cad1"}, + {file = "pydantic_core-2.46.5-cp310-cp310-win32.whl", hash = "sha256:4d44cf99ddebf875f9b68cc267aa684c99b7b44fe63ee1cac4ec163807290069"}, + {file = "pydantic_core-2.46.5-cp310-cp310-win_amd64.whl", hash = "sha256:1e5aad1220a1192c42341c8fd4a8686657e73ab2a920c970bdc4de334fe3193d"}, + {file = "pydantic_core-2.46.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a1dee1b804ff4d11c663636cf15d2ea47e9f79cd56c033fb1cbf08924842a48f"}, + {file = "pydantic_core-2.46.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d625a186a65201c23a9e3b8ed9c47e90a026e03256608cc91851c6709096844f"}, + {file = "pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f8507560a9284e1370bb048ed4282012fbef4e8d109875b95e884d228552061"}, + {file = "pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f93c5fe914d75fbec9a49209b00da5f08e9e467d69da2b1510c81940cfd10be"}, + {file = "pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aca6c767f552b21b10f774aeac128e828eafb796adfa1b666a18bf6321453c3a"}, + {file = "pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:701b2e04b560eeb4bddf7a25ab8ca476176e34fdbd9a0e18196f0d12d4685f0b"}, + {file = "pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49776eab08766a08dfff7012f8b422dcd7e25e43b316eedf0477c24fcfa84b7c"}, + {file = "pydantic_core-2.46.5-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:a2468d93d181667a7abd66e1b64bb9f76f361b0fef8faddf687456453576f5ee"}, + {file = "pydantic_core-2.46.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:53feb344243bb9510a9dec7bf3cf1b64d88a98af5dc7872a5160465f8b198c8e"}, + {file = "pydantic_core-2.46.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cd5214352ae68f3b5e9af7768bdc5253695ee069675db3480518420b3be881f2"}, + {file = "pydantic_core-2.46.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:9432f3598db432cb51c5b37fdbf29a60fcccc79e30d37a05022776a6bc4ab689"}, + {file = "pydantic_core-2.46.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8feeac04b5794e513e710af2f9c87d49f31a6dc47967bb264a1fed61a8989bec"}, + {file = "pydantic_core-2.46.5-cp311-cp311-win32.whl", hash = "sha256:892a881d5f68c2b9ea304b7a6c2c60d9343df578a311b0f86b94bc8f1ffe8129"}, + {file = "pydantic_core-2.46.5-cp311-cp311-win_amd64.whl", hash = "sha256:40375c2d05acec10323e45dfe2077ac44bc74659008614af5069034e2cfc781c"}, + {file = "pydantic_core-2.46.5-cp311-cp311-win_arm64.whl", hash = "sha256:28a6a556cd3b6066bea827857f9d9cce027c96f776e512f544a581f9e42161f8"}, + {file = "pydantic_core-2.46.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b9fe6fb92520e3fd61f2e49000b6911b188824f089b75973ea06d6267f0b476d"}, + {file = "pydantic_core-2.46.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a39ac25a9a2fa4072efdb429833c4a4c8009a51ff9eea3eeae131713cd27991e"}, + {file = "pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fdc8b93a41521988916eeaa271173fcca7fa0803d62f87675aac8dcec1c8e29"}, + {file = "pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b98134087d9de723658d17a42c7d0da8d6e2ef08015dee7dc93889047315f5e4"}, + {file = "pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e652ab17569c94bff5475520f907b7148b8c24036a8ebbe5cf7cf7493d28579a"}, + {file = "pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d925f3d9afd05a8c0fb3a1031463a8d59ebe5e2afad297e29c78be19e13b4e62"}, + {file = "pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fc5be0abd4a407e200d844b404e33639a554e7bd0d448e7b9ae181be4789ac2"}, + {file = "pydantic_core-2.46.5-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:816ff0a6550ffc06c098ccd2e0698600f9aa7da192a79eaa6f9af504a35db869"}, + {file = "pydantic_core-2.46.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c7ea57fc63aa7da93a1bd2d644e6577befae10c52c4e36377635eea1056a74f5"}, + {file = "pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:efd62a42486f1bda5d24cb4f63d15a3c7768375fe83d36f9417b4ad7a2fb20b3"}, + {file = "pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:2bc9419666990c06d7397831f2126a1ecc3594aaa3ff7de5bf2d066802f4e07b"}, + {file = "pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:18a09e1e1011b462f2e32774f25859ef1223d5c2b0546a633cf56654710721e0"}, + {file = "pydantic_core-2.46.5-cp312-cp312-win32.whl", hash = "sha256:5cb482e9e84c851f4e623fe4acc1ced89168cf1fe18f7089db4548c8f5bbb65b"}, + {file = "pydantic_core-2.46.5-cp312-cp312-win_amd64.whl", hash = "sha256:5e81740c09e310f5aa5cbd3e434a01c154d4bef93241c7877b39f211d2b78ba8"}, + {file = "pydantic_core-2.46.5-cp312-cp312-win_arm64.whl", hash = "sha256:f7b0ec93a2893de856652154d73b7ba622f26fa97726487dcac373de5f4c6084"}, + {file = "pydantic_core-2.46.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:b7ca9034437b6022f941f4857459562ee00a560b97e7cce8a0ec5a74fc6766e0"}, + {file = "pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f332f0e72a5a0400141f830744e141bf9f97917878dbe968669e8a7fefea78ff"}, + {file = "pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:193375f3548919d3f0b60936ca113ada3e38f264f91b9b8e0508efaad57be931"}, + {file = "pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:79bdfa52f843137045b2d081cc05c120ba6665d29b7559c2c47690906f39279f"}, + {file = "pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:24922243639cbdac66c75fcb6fd6495a9cb52b213d62f9a0d16f0310b1ff8038"}, + {file = "pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c76fe65e607be28c7fd4d56fc3c42b1583aa058ce3408b7ad0fd540171d31f9f"}, + {file = "pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f7b393a8b3da82f5c1fc0751e6d01ac6c55b93c18226a60bdfba4a724efafd1"}, + {file = "pydantic_core-2.46.5-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:7ac031912d54f3d83ef3b3eb98dfabc1608802e2202263d25957eeed40b94761"}, + {file = "pydantic_core-2.46.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:837b396ca3d7b74091ca623f6cbd8351bd42d670a79c2683e79fb089f06a2de5"}, + {file = "pydantic_core-2.46.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:5ee239d575f80b08eca11f6e20f90c4c695de7825c67eefe6091fbf20dda648e"}, + {file = "pydantic_core-2.46.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:e80675d75ae2cd14372cb65cad5400d9347a3d3f6c13000183f22dfd027283ed"}, + {file = "pydantic_core-2.46.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:9c4b71f10dd532fb7a5cbc8f58707779e64f03a258c2bf8bfbaecfcd9970b519"}, + {file = "pydantic_core-2.46.5-cp313-cp313-win32.whl", hash = "sha256:97bf8de4d541598c94a59344eeb988a94c08ff76b5723c41f6567ec18c7892ea"}, + {file = "pydantic_core-2.46.5-cp313-cp313-win_amd64.whl", hash = "sha256:15f4a94963c95accac15b7b657bb177d3ad82bb90b0d0526d9a9b85079925db5"}, + {file = "pydantic_core-2.46.5-cp313-cp313-win_arm64.whl", hash = "sha256:d22a945598fb91236b4dd793a6e42e4f3dd7740bb5aace5ebd7d4c08d13bb575"}, + {file = "pydantic_core-2.46.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c1c43ad4339643d70ebb8124e1305a7dab423001eff58bb41a0f731adbc98355"}, + {file = "pydantic_core-2.46.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1a353f84de772f423b5ffb11d7ae352fbbef0f446f3c0b0af0f8236d7233606e"}, + {file = "pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5086029a57366b8cf81b130a43908738095c270c21a8d7f0e8bdfdb89718e2f3"}, + {file = "pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46c25dda9d092a06c08db76ffe0a197107904d0dfac653f7d5306bbcd6d6119c"}, + {file = "pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:37ea7b83c935e5b0d68c9449b82651accf78a10828b2c02b2f2d9e9496446c21"}, + {file = "pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e64e88d5585bea9ce95861079de72006c7fa6d3df4e3a3b65ba31eb979c15c9f"}, + {file = "pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54d510bac3ee52247af28ed4bb18a1e799f040ac60fd2bf5ccd4c92f1fbe786f"}, + {file = "pydantic_core-2.46.5-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:a2a5e1d0ff29adddc9f6d6821a66302e4493f8ca898b715b6b1182c2c201ea0a"}, + {file = "pydantic_core-2.46.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:03b9666e41e35d8909852ba191a0607520f81b74eaf12ccf8737005dbb313821"}, + {file = "pydantic_core-2.46.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:a91c17edf6eea2402cb5457b4c89e99bc5ed1004aa34c4adf1d4258c1a5c22c2"}, + {file = "pydantic_core-2.46.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b49924c73a235e969511bf2aabdff3beebf9820931f646c80274d5d780010c47"}, + {file = "pydantic_core-2.46.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:2cbd9a5eff05e51c447c34dfa4632145b26b09120cf04bd0c871e44c1a5e1c9a"}, + {file = "pydantic_core-2.46.5-cp314-cp314-win32.whl", hash = "sha256:2d5d76654becf5efd62c9e51c3756c67b49498b0c9a40884934c40807adbd074"}, + {file = "pydantic_core-2.46.5-cp314-cp314-win_amd64.whl", hash = "sha256:fa10ef4112775900e7a0661068635eb67b2ab824fbde764de6e0e21982a93db0"}, + {file = "pydantic_core-2.46.5-cp314-cp314-win_arm64.whl", hash = "sha256:045ab3b6d308439e32b81cc173bba5b9018bc6ed896afd0c65b3b009b1699af5"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8816f3d218beb4b787de5c9759c259b8fa61f9dec42dc7811f320a33771778b7"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:bce57638e08ac148e5778cce7feb968307a727d66f8e2274a543d0cf0c9ad6a3"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:976e1128455aa595ea04c79ccfedff1aaeab96ee013fcc916bed120c4f0ad94f"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b891faeedeafba41b2983e5001a81b6a915b69544c7e7570d1989ce1c36ac7"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f194189415698233dd1114a093a9b56e61e2c57e11b469be3b0506f46f0771c"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82a36973cf8a2ef5406f4fe2edbf8ed0c99629535d959e0b100c76a32535a111"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdbb78909f52b981d3b2d56b97328d71eb0b974c36bd77c920123a7ebb192829"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:52e24eacdb536cade636aa90fb851835222becff8484b7001fdc78cb0290f2aa"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:37ae34309d7bd8c0d61ab839668058f2a7962ea1fc51d105d2db228fe0618034"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:0cdbada856a1c69a7624a64d3d9aefe79300bd6ef827b43a4f265010b9b55184"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:545f26c504b27c3758439a5e6d9349931f0a04f855668d5fe323c89e82300a38"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:ff218293c9c806138dca139765e3b067621be52bcd93cdc14c7711be7ddc90a9"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-win32.whl", hash = "sha256:97cf3eb53a8cccacf9d46686a0926186c9bfb5574f2ed66d3639d5fe117cd3a9"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-win_amd64.whl", hash = "sha256:d2f9fc07a8042a8f95925b35c4f04f469707c981fc33245b6ca187cf5d2dd290"}, + {file = "pydantic_core-2.46.5-cp314-cp314t-win_arm64.whl", hash = "sha256:acf8a67ba51f4ca9ddbd0e6b3000a65ac51ab734661778b3e7ba64d99a710f2f"}, + {file = "pydantic_core-2.46.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c583b927a8838dab890706a6fa7573fbb8b70e24000ef9f7238e2d6f6435a5ed"}, + {file = "pydantic_core-2.46.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cdc8b74ecc48c0cb1e9607a05ec4e9e88db60a19ffcc9a1d5f9088ede40c8dc0"}, + {file = "pydantic_core-2.46.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b10e3e8fd7ddc2bd915848a2768e44c15b22936f1cc54c462ad1164deb02655"}, + {file = "pydantic_core-2.46.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f077d0b97ab11fa7dcc633fca53515f290bca8a8a633e966d5b6d1879d9ed01a"}, + {file = "pydantic_core-2.46.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b0fc826b16c55e561e5d2a0c5c77b051ba1d92808118c4e4b5390f5e0cf191d"}, + {file = "pydantic_core-2.46.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef3fbbf161dc9351a2fe0422e51b129f9e97e42385bd0320b309c15f7d287dd8"}, + {file = "pydantic_core-2.46.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:978e7b97d4824b5be09c69fb70507cbde3b0323fc147332ca40a94d9a6a0ebbf"}, + {file = "pydantic_core-2.46.5-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:9b68938dd5b0c783d88ff8e2dcc69451b5eb936fe212d516b21b9d5567f6d464"}, + {file = "pydantic_core-2.46.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:771cf63ae0b1b50dd22e5f3e3549fab5f3f4ff1635d352a9e1a97fe01c7b2e64"}, + {file = "pydantic_core-2.46.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7c6be839a5a8312626b32029a415644a0846b420bc8b52b95b28cd92da162168"}, + {file = "pydantic_core-2.46.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:895395f8918627b04efb1ad2a4cf605387143300ba03304cd1dfa6d03f5e095e"}, + {file = "pydantic_core-2.46.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fc8515076c11f3cfdf4fb142dcca0fe384b1230a3b5415458ac84f3e0903ec13"}, + {file = "pydantic_core-2.46.5-cp39-cp39-win32.whl", hash = "sha256:3d2652072b2d774947ba5cf78a9e59644ac62ee572daf6dd2e1dfe905e15b2b7"}, + {file = "pydantic_core-2.46.5-cp39-cp39-win_amd64.whl", hash = "sha256:3aa166e99c4f2985407fb8714aebede877ecb5455cf321b606adca926d30d5a0"}, + {file = "pydantic_core-2.46.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:c14ad3bdc85ee7f318742c457ca3968a92126d144b15721c759033bfb06296c2"}, + {file = "pydantic_core-2.46.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0bddb4020d8f04175865ccd17eff3040874fc11fb593f424edb452653b4b947c"}, + {file = "pydantic_core-2.46.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2471fd51c61c610e1dcf7de44d7299283661654d11264ab4802b303368d69c47"}, + {file = "pydantic_core-2.46.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b10ec717381bdbfafef34607824db4c91de69ff085e4fca3b2af91b4fa17e68a"}, + {file = "pydantic_core-2.46.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:013d6f3483d81e02e7c328831808f336c8596ee33b4bd4026b9ffb1e960b8942"}, + {file = "pydantic_core-2.46.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:e9c134bb666dd54b778b9fc0d2b50cbb7f979b9e3716f26a88c9ab3b6fc1dd0f"}, + {file = "pydantic_core-2.46.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:347ec774390c87326a2e4929d58d3f7e8763a104d5d35f4cd595a4c952366433"}, + {file = "pydantic_core-2.46.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e24d8f05fa2d28513d94e877e9c75ad66175376209b3977f916e240e623193c"}, + {file = "pydantic_core-2.46.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ab4b66edffb32d9e951efb3814bd104b8367a7501b81b955cacb5726d897389f"}, + {file = "pydantic_core-2.46.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:337639ba62a11acde6ef3aeb08c8ea755f8ef1fe5e513356c0f36a2b0d7568b0"}, + {file = "pydantic_core-2.46.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:413a717a410d0c817ef5b786a059415550b3794e1d0c2abffd9efb93a3d9f7b4"}, + {file = "pydantic_core-2.46.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e449def1945a462c464331254e5a44fca7c3b4f9aedf59ec2f50f8066dd8e25"}, + {file = "pydantic_core-2.46.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a445486499897b88a7d6c310c88ed64dd37b1b59bfd7ae9107490bbb362f47d6"}, + {file = "pydantic_core-2.46.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:2d330aaba8621b1edcec8ae2c4050f63b84ccf6d98723a8f212e9684713abf0e"}, + {file = "pydantic_core-2.46.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b6acfb46a814762367fb7ba0828b0a17d441b92ce249a0e007474c9072662dda"}, + {file = "pydantic_core-2.46.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d0a24b40877af2de4950252be9d21eaf7fb07660f3c2cae1f56c6b599ada5266"}, + {file = "pydantic_core-2.46.5.tar.gz", hash = "sha256:10416c15b8839ecc4ef4d0885da76da6fd0f67333a0eb8aff6d93c4b8f2910fc"}, ] [package.dependencies] @@ -1091,14 +1133,14 @@ typing-extensions = ">=4.14.1" [[package]] name = "pygments" -version = "2.20.0" +version = "2.21.0" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, - {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, + {file = "pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9"}, + {file = "pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c"}, ] [package.extras] @@ -1285,14 +1327,14 @@ files = [ [[package]] name = "types-python-dateutil" -version = "2.9.0.20260716" +version = "2.9.0.20260807" description = "Typing stubs for python-dateutil" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "types_python_dateutil-2.9.0.20260716-py3-none-any.whl", hash = "sha256:1ae41d51a5c5f6bbeeb7f1f34df7086d55ff1605cf88d2ed71a7a276e1a7794e"}, - {file = "types_python_dateutil-2.9.0.20260716.tar.gz", hash = "sha256:1d55d1c3024bdb4861bb6a6622c9ec800c433d87bdc5b16fb84cdd0eed4ef2cb"}, + {file = "types_python_dateutil-2.9.0.20260807-py3-none-any.whl", hash = "sha256:54aa3707350ed7a9cc0776fd2f6739679d6967d11b40150985e81edcb86df4db"}, + {file = "types_python_dateutil-2.9.0.20260807.tar.gz", hash = "sha256:e0b8a90d464c8684c66b7b8e4556d9074afdddcc56ca45323f0987134f9e7034"}, ] [[package]] @@ -1309,29 +1351,29 @@ files = [ [[package]] name = "typing-inspection" -version = "0.4.2" +version = "0.4.4" description = "Runtime typing introspection tools" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, - {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, + {file = "typing_inspection-0.4.4-py3-none-any.whl", hash = "sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147"}, + {file = "typing_inspection-0.4.4.tar.gz", hash = "sha256:547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47"}, ] [package.dependencies] -typing-extensions = ">=4.12.0" +typing-extensions = ">=4.15.0" [[package]] name = "urllib3" -version = "2.7.0" +version = "2.8.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897"}, - {file = "urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c"}, + {file = "urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3"}, + {file = "urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63"}, ] [package.extras] @@ -1342,117 +1384,151 @@ zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] [[package]] name = "yarl" -version = "1.24.5" +version = "1.25.1" description = "Yet another URL library" optional = true python-versions = ">=3.10" groups = ["main"] markers = "extra == \"aiohttp\"" files = [ - {file = "yarl-1.24.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88f50c94e21a0a7f14042c015b0eba1881af78562e7bf007e0033e624da59750"}, - {file = "yarl-1.24.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6efbccc3d7f75d5b03105172a8dc86d82ba4da86817952529dd93185f4a88be2"}, - {file = "yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0ebfaffe1a16cb72141c8e09f18cc76856dbe58639f393a4f2b26e474b96b871"}, - {file = "yarl-1.24.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8ac73abdc7ab75610f95a8fd994c6457e87752b02a63987e188f937a1fc180f0"}, - {file = "yarl-1.24.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4d97a951a81039050e45f04e96689b58b8243fa5e62aa14fe67cb6075300885e"}, - {file = "yarl-1.24.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fe7b7bb170daccbba19ad33012d2b15f1e7942296fd4d45fc1b79013da8cc0f2"}, - {file = "yarl-1.24.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:89a1bbb58e0e3f7a283653d854b1e95d65e5cfd4af224dac5f02629ec1a3e621"}, - {file = "yarl-1.24.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7fa5e51397466ea7e98de493fa2ff1b8193cfef8a7b0f9b4842f92d342df0dba"}, - {file = "yarl-1.24.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4103b77b8a8225e413107d2349b65eb3c1c52627b5cc5c3c4c1c6a798b218950"}, - {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f9f3e9c8a9ecffa57bef8fb4fa19e5fa4d2d8307cf6bac5b1fca5e5860f4ba00"}, - {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0ebc836c47a6477e182169c6a476fc691d12b518894bf7dd2572f0d59f1c7ed"}, - {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:96d30286dd02679e32a39aa8f0b7498fc847fcda46cfc09df5513e82ce252440"}, - {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:fd8c81f346b58f45818d09ea11db69a8d5fd34a224b79871f6d44f12cd7977b1"}, - {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5c55256dee8f4b27bfbf636c8363383c7c8db7890c7cba5217d7bd5f5f21dab6"}, - {file = "yarl-1.24.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9f4d8cf085a4c6a40fb97ea0f46938a8df43c85d31f9d45e2a8867ea9293790d"}, - {file = "yarl-1.24.5-cp310-cp310-win_amd64.whl", hash = "sha256:240cbec09667c1fed4c6cd0060b9ec57332427d7441289a2ed8875dc9fb2b224"}, - {file = "yarl-1.24.5-cp310-cp310-win_arm64.whl", hash = "sha256:8a6987eaad834cb32dd57d9d582225f0054a5d1af706ccfbbdba735af4927e13"}, - {file = "yarl-1.24.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2c1fe720934a16ea8e7146175cba2126f87f54912c8c5435e7f7c7a51ef808d3"}, - {file = "yarl-1.24.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c687ed078e145f5fd53a14854beff320e1d2ab76df03e2009c98f39a0f68f39a"}, - {file = "yarl-1.24.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:709f1efed56c4a145793c046cd4939f9959bcd818979a787b77d8e09c57a0840"}, - {file = "yarl-1.24.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:874019bd513008b009f58657134e5d0c5e030b3559bd0553976837adf52fe966"}, - {file = "yarl-1.24.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a4582acf7ef76482f6f511ebaf1946dae7f2e85ec4728b81a678c01df63bd723"}, - {file = "yarl-1.24.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2cabe6546e41dabe439999a23fcb5246e0c3b595b4315b96ef755252be90caeb"}, - {file = "yarl-1.24.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:17f57620f5475b3c69109376cc87e42a7af5db13c9398e4292772a706ff10780"}, - {file = "yarl-1.24.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:570fec8fbd22b032733625f03f10b7ff023bc399213db15e72a7acaef28c2f4e"}, - {file = "yarl-1.24.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5fede79c6f73ff2c3ef822864cb1ada23196e62756df53bc6231d351a49516a2"}, - {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ccf9aca873b767977c73df497a85dbedee4ee086ae9ae49dc461333b9b79f58"}, - {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ad5d8201d310b031e6cd839d9bac2d4e5a01533ce5d3d5b50b7de1ef3af1de61"}, - {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:841f0852f48fefea3b12c9dfec00704dfa3aef5215d0e3ce564bb3d7cd8d57c6"}, - {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:9baafc71b04f8f4bb0703b21d6fc9f0c30b346c636a532ff16ec8491a5ea4b1f"}, - {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d897129df1a22b12aeed2c2c98df0785a2e8e6e0bde87b389491d0025c187077"}, - {file = "yarl-1.24.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dd625535328fd9882374356269227670189adfcc6a2d90284f323c05862eecbd"}, - {file = "yarl-1.24.5-cp311-cp311-win_amd64.whl", hash = "sha256:f4239bbec5a3577ddb49e4b50aeb32d8e5792098262ae2f63723f916a29b1a25"}, - {file = "yarl-1.24.5-cp311-cp311-win_arm64.whl", hash = "sha256:3ac6aff147deb9c09461b2d4bbdf6256831198f5d8a23f5d37138213090b6d8a"}, - {file = "yarl-1.24.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d693396e5aea78db03decd60aec9ece16c9b40ba00a587f089615ff4e718a81d"}, - {file = "yarl-1.24.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3363fcc96e665878946ad7a106b9a13eac0541766a690ef287c0232ac768b6ec"}, - {file = "yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9d399bdcfb4a0f659b9b3788bbc89babe63d9a6a65aacdf4d4e7065ff2e6316c"}, - {file = "yarl-1.24.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90333fd89b43c0d08ac85f3f1447593fc2c66de18c3d6378d7125ea118dc7a54"}, - {file = "yarl-1.24.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:665b0a2c463cc9423dd647e0bfd9f4ccc9b50f768c55304d5e9f80b177c1de12"}, - {file = "yarl-1.24.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e006d3a974c4ee19512e5f058abedb6eef36a5e553c14812bdeba1758d812e6d"}, - {file = "yarl-1.24.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e7d42c531243450ef0d4d9c172e7ed6ef052640f195629065041b5add4e058d1"}, - {file = "yarl-1.24.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f08c7513ecef5aad65687bfdf6bc601ae9fccd04a42904501f8f7141abad9eb9"}, - {file = "yarl-1.24.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c95b17fe34ed802f17e205112e6e10db92275c34fee290aa9bdc55a9c724027"}, - {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:56b149b22de33b23b0c6077ab9518c6dcb538ad462e1830e68d06591ccf6e38b"}, - {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a8fe66b8f300da93798025a785a5b90b42f3810dc2b72283ff84a41aaaebc293"}, - {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:377fe3732edbaf78ee74efdf2c9f49f6e99f20e7f9d2649fda3eb4badd77d76e"}, - {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e8ffa78582120024f476a611d7befc123cee59e47e8309d470cf667d806e613b"}, - {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:daba5e594f06114e37db186efd2dd916609071e59daca901a0a2e71f02b142ce"}, - {file = "yarl-1.24.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:65be18ec59496c13908f02a2472751d9ef840b4f3fb5726f129306bf6a2a7bba"}, - {file = "yarl-1.24.5-cp312-cp312-win_amd64.whl", hash = "sha256:a929d878fec099030c292803b31e5d5540a7b6a31e6a3cc76cb4685fc2a2f51b"}, - {file = "yarl-1.24.5-cp312-cp312-win_arm64.whl", hash = "sha256:7ce27823052e2013b597e0c738b13e7e36b8ccb9400df8959417b052ab0fd92c"}, - {file = "yarl-1.24.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:79af890482fc94648e8cde4c68620378f7fef60932710fa17a66abc039244da2"}, - {file = "yarl-1.24.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46c2f213e23a04b93a392942d782eb9e413e6ef6bf7c8c53884e599a5c174dcb"}, - {file = "yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92ab3e11448f2ff7bf53c5a26eff0edc086898ec8b21fb154b85839ce1d88075"}, - {file = "yarl-1.24.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ebb0ec7f17803063d5aeb982f3b1bd2b2f4e4fae6751226cbd6ba1fcfe9e63ff"}, - {file = "yarl-1.24.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:82632daed195dcc8ea664e8556dc9bdbd671960fb3776bd92806ce05792c2448"}, - {file = "yarl-1.24.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:53e549287ef628fecba270045c9701b0c564563a9b0577d24a4ec75b8ab8040f"}, - {file = "yarl-1.24.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fcd3b77e2f17bbe4ca56ec7bcb07992647d19d0b9c05d84886dcd6f9eb810afd"}, - {file = "yarl-1.24.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d46b86567dd4e248c6c159fcbcdcce01e0a5c8a7cd2334a0fff759d0fa075b16"}, - {file = "yarl-1.24.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7f72c74aa99359e27a2ee8d6613fefa28b5f76a983c083074dfc2aaa4ab46213"}, - {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3f45789ce415a7ec0820dc4f82925f9b5f7732070be1dec1f5f23ec381435a24"}, - {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6e73e7fe93f17a7b191f52ec9da9dd8c06a8fe735a1ecbd13b97d1c723bff385"}, - {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4a36f9becdd4c5c52a20c3e9484128b070b1dcfc8944c006f3a528295a359a9c"}, - {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:7bcbe0fcf850eae67b6b01749815a4f7161c560a844c769ad7b48fcd99f791c4"}, - {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:24e861e9630e0daddcb9191fb187f60f034e17a4426f8101279f0c475cd74144"}, - {file = "yarl-1.24.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9335a099ad87287c37fe5d1a982ff392fa5efe5d14b40a730b1ec1d6a41382b4"}, - {file = "yarl-1.24.5-cp313-cp313-win_amd64.whl", hash = "sha256:2dbe06fc16bc91502bca713704022182e5729861ae00277c3a23354b40929740"}, - {file = "yarl-1.24.5-cp313-cp313-win_arm64.whl", hash = "sha256:6b8536851f9f65e7f00c7a1d49ba7f2be0ffe2c11555367fc9f50d9f842410a1"}, - {file = "yarl-1.24.5-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:2729fcfc4f6a596fb0c50f32090400aa9367774ac296a00387e65098c0befa76"}, - {file = "yarl-1.24.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ff330d3c30db4eb6b01d79e29d2d0b407a7ecad39cfd9ec993ece57396a2ec0d"}, - {file = "yarl-1.24.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e42d75862735da90e7fc5a7b23db0c976f737113a54b3c9777a9b665e9cbff75"}, - {file = "yarl-1.24.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3732e66413163e72508da9eff9ce9d2846fde51fae45d3605393d3e6cd303e9"}, - {file = "yarl-1.24.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5b8ee53be440a0cffc991a27be3057e0530122548dbe7c0892df08822fce5ede"}, - {file = "yarl-1.24.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:af3aefa655adb5869491fa907e652290386800ae99cc50095cba71e2c6aefdca"}, - {file = "yarl-1.24.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2120b96872df4a117cde97d270bac96aea7cc52205d305cf4611df694a487027"}, - {file = "yarl-1.24.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:66410eb6345d467151934b49bfa70fb32f5b35a6140baa40ad97d6436abea2e9"}, - {file = "yarl-1.24.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4af7b7e1be0a69bee8210735fe6dcfc38879adfac6d62e789d53ba432d1ffa41"}, - {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa139875ff98ab97da323cfadfaff08900d1ad42f1b5087b0b812a55c5a06373"}, - {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:0055afc45e864b92729ac7600e2d102c17bef060647e74bca75fa84d66b9ff36"}, - {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f0e466ed7511fe9d459a819edbc6c2585c0b6eabde9fa8a8947552468a7a6ef0"}, - {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f141474e85b7e54998ec5180530a7cda99ab29e282fa50e0756d89981a9b43c5"}, - {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:e2935f8c39e3b03e83519292d78f075189978f3f4adc15a78144c7c8e2a1cba5"}, - {file = "yarl-1.24.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9d1216a7f6f77836617dba35687c5b78a4170afc3c3f18fc788f785ba26565c4"}, - {file = "yarl-1.24.5-cp314-cp314-win_amd64.whl", hash = "sha256:5ba4f78df2bcc19f764a4b26a8a4f5049c110090ad5825993aacb052bf8003ad"}, - {file = "yarl-1.24.5-cp314-cp314-win_arm64.whl", hash = "sha256:9e4e16c73d717c5cf27626c524d0a2e261ad20e46932b2670f64ad5dde23e26f"}, - {file = "yarl-1.24.5-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:e1ae548a9d901adca07899a4147a7c826bbcc06239d3ce9a59f57886a28a4c88"}, - {file = "yarl-1.24.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:ff405d91509d88e8d44129cd87b18d70acd1f0c1aeabd7bc3c46792b1fe2acba"}, - {file = "yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:47e98aab9d8d82ff682e7b0b5dded33bf138a32b817fcf7fa3b27b2d7c412928"}, - {file = "yarl-1.24.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f0a658a6d3fafee5c6f63c58f3e785c8c43c93fbc02bf9f2b6663f8185e0971f"}, - {file = "yarl-1.24.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4377407001ca3c057773f44d8ddd6358fa5f691407c1ba92210bd3cf8d9e4c95"}, - {file = "yarl-1.24.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7c0494a31a1ac5461a226e7947a9c9b78c44e1dc7185164fa7e9651557a5d9bc"}, - {file = "yarl-1.24.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a7cff474ab7cd149765bb784cf6d78b32e18e20473fb7bda860bce98ab58e9da"}, - {file = "yarl-1.24.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cbb833ccacdb5519eff9b8b71ee618cc2801c878e77e288775d77c3a2ced858a"}, - {file = "yarl-1.24.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:82f75e05912e84b7a0fe57075d9c59de3cb352b928330f2eb69b2e1f54c3e1f0"}, - {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:16a2f5010280020e90f5330257e6944bc33e73593b136cc5a241e6c1dc292498"}, - {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:ffcd54362564dc1a30fb74d8b8a6e5a6b11ebd5e27266adc3b7427a21a6c9104"}, - {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0465ec8cedc2349b97a6b595ace64084a50c6e839eca40aa0626f38b8350e331"}, - {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4db9aecb141cb7a5447171b57aa1ed3a8fee06af40b992ffc31206c0b0121550"}, - {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:f540c013589084679a6c7fac07096b10159737918174f5dfc5e11bf5bca4dfe6"}, - {file = "yarl-1.24.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a61834fb15d81322d872eaafd333838ae7c9cea84067f232656f75965933d047"}, - {file = "yarl-1.24.5-cp314-cp314t-win_amd64.whl", hash = "sha256:5c88e5815a49d289e599f3513aa7fde0bc2092ff188f99c940f007f90f53d104"}, - {file = "yarl-1.24.5-cp314-cp314t-win_arm64.whl", hash = "sha256:cf139c02f5f23ef6532040a30ff662c00a318c952334f211046b8e60b7f17688"}, - {file = "yarl-1.24.5-py3-none-any.whl", hash = "sha256:a33700d13d9b7d84fd10947b09ff69fb9a792e519c8cb9764a3ca70baa6c23a7"}, - {file = "yarl-1.24.5.tar.gz", hash = "sha256:e81b83143bee16329c23db3c1b2d82b29892fcbcb849186d2f6e98a5abe9a57f"}, + {file = "yarl-1.25.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:142c06c4d6a35ee3ec5da08499805e879cb3ca7c1fbfbecb0140fe72403818d6"}, + {file = "yarl-1.25.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:24ce942011a61953e7d313438038f4d32ff21387b775f58a957f7a07dd55ef95"}, + {file = "yarl-1.25.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e23c82b63cd7652fc24d33ed6cc17099d607aa3b4fc4ddc75e95062f3d82df4"}, + {file = "yarl-1.25.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8ee202350cf57abf0e9502a41601841019c25d3db7ff52d980aaf31446254059"}, + {file = "yarl-1.25.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5df89f769cc8ff94c3d7e7603386fba309d25ce5240132d26c15baa8d0e96c4c"}, + {file = "yarl-1.25.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:83e9f4a25085bd4b7214701a0794ff1f50fc633ffb8bdfebf07abdd81c2db126"}, + {file = "yarl-1.25.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e636b64d24fd9c38053c5e389a1174c66361fa49dcfd220f4dd35b4abde7cb89"}, + {file = "yarl-1.25.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e5637ca8d0bd7fb72648a6c7934af4baaccb697657f7438c9d264fc2abb8b0b1"}, + {file = "yarl-1.25.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:683e362b8ba453080f7489c66f4ea794e751c35b72e7eab3575ef784c2fbc7fb"}, + {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:df23df54b5114a17c2d0ef192433e2e5a9f0c5178c32375e90b7cfc965f349d0"}, + {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f53dcd26694f148f738edc052b5a69234833e739f10f4c3287bdfd8ec0f7b326"}, + {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:b8075fe90bc08e40b8b8a1874fab42ee4c7b56af05c5886e9cc841397f916908"}, + {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:a8c2b841478068440d8b733005d13a5ef535b9928cbc05f17182d410f32ba449"}, + {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ca32926d7d77bcc8838425c4c95e040a3ace1cb7dfdae599013458dcda2607ca"}, + {file = "yarl-1.25.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:192a866877a49993949ef1975864ad8728bea28ee810f6abe1a0729c2b500426"}, + {file = "yarl-1.25.1-cp310-cp310-win_amd64.whl", hash = "sha256:3f4d48a6112712973e676bd792121fee470e432d749177162d9949d5c9460a1b"}, + {file = "yarl-1.25.1-cp310-cp310-win_arm64.whl", hash = "sha256:48796ea00a303961507dc6c8437c4b325a6fc3f95f7c36c71b91ea9a8150963c"}, + {file = "yarl-1.25.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9d693bf4bf534e9ba3ae2780cfd577f5135629f7b5ac653490859d0b77864865"}, + {file = "yarl-1.25.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ab2054c5531af2a9ba7b69b8ec91e4f884420e83a8c5e579b013084cb57e5e5d"}, + {file = "yarl-1.25.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:564fdc7085d2245ab84f88882fdb1d6ac0723124bff6ded35bfb1c00f812630d"}, + {file = "yarl-1.25.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:acae6b45d1ace09b6ba3876da43b88366ef368f73b988c7f57e14231753d4420"}, + {file = "yarl-1.25.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1fb2a01ba8cd9c5d2c5dc1ec35e0fc951d04b4f037541d4ac090c993ce58b3d7"}, + {file = "yarl-1.25.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e92b6bcc741b86d67606c40d3cb9c7cc8e6c737f81e31f4a94efc204456c92e3"}, + {file = "yarl-1.25.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:72c34ac7ad4314c19362d5ce27626dcc8429bd30bbf8c179f4234078851f9492"}, + {file = "yarl-1.25.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5add7b4ca7afeea91d52e4d4e4db3b1fe9885b71f07054560d8c4296b7441a2"}, + {file = "yarl-1.25.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:def538065f9e4d4cf1ae164bd59aba00dfa84f03923e0de4c3788f252d6bcd17"}, + {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a191bfdb30a79b98e5d175d75285f9fcb78bf0e46ba5efda042e1c72071a0de"}, + {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:71f42c5b9a948c113bbdebfa544598321431d064ff959d32e99b1feb61d68345"}, + {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:72849d892954be4d09e569b8b831ac39ce58417fedc767d4308a0fe542018a40"}, + {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:efb01a106f971cb3752856bca2318bbdf7f01bd8823779c461586cbe5ffd5258"}, + {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a1daf47cd95a7c3a63456336bc5aaa8c86dd3a47d07ed3d0e76132ae4666a5a1"}, + {file = "yarl-1.25.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9489e6abf47ba37f332075a91444c7cfedb03e6ce99fbb2f116bfe1ce810da3b"}, + {file = "yarl-1.25.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7306dee25b8a0e737363f347362b875094b4dc4e367311470656ae420fdbf8e"}, + {file = "yarl-1.25.1-cp311-cp311-win_arm64.whl", hash = "sha256:abb1384477f5901d436b5d2e5465954de46ea6098f59163d243660b5c4461d35"}, + {file = "yarl-1.25.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:94d7aa6debf92a1dd14cb5280b083a764169a13cfb23a452111160274ed989f4"}, + {file = "yarl-1.25.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:83d4a37e4b95da4d8bda930d6d35b75b4cdadbacbb4980cae290ea3100b5d51d"}, + {file = "yarl-1.25.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e029648f9c951db30e98a7d7ec90835db88ec4b32820efe2a9bdc2287e032eb6"}, + {file = "yarl-1.25.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d781294bb815ecb5ea57ff6bbf8038e0a31a95fdf3e1788f66e0dc100d64b58"}, + {file = "yarl-1.25.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e12c538e00e7c1b286a07061046b90e8124e6a9793efae2c70db6a4aad07faad"}, + {file = "yarl-1.25.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7e4de3ac4adbad3d0bc7c6f4360a7dbff5de2f15e3b723be3198074e17fd9c40"}, + {file = "yarl-1.25.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:419f392a1da624877975709e3864dfe833af6cc7671b39318086d456e288380c"}, + {file = "yarl-1.25.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6f117789d22dce188e5754e8bc65b7e6ebf8cb73963b9fa761f672a5883769d"}, + {file = "yarl-1.25.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:80e47012e730da131c9f059c80936783f9659aae22dc31c03c0595590d11ed54"}, + {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e80f557716fd765439577131e526b8942ffc2c07bdbc5e39fa62f660ba1e963f"}, + {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f61964f235a43738bfac50da46fc4254943a7eea3051aeb0b6fc7c992c29fadc"}, + {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e546fe1d4a93ebc2910f0d768baff19faa09843ab3f2036a67ed6e69fae4419d"}, + {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:cce0727fd5ac04d372fa9bbfde9febc2bcf209aadfcf0468e45dec72719895d1"}, + {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af4ea5b37403ef4e30f3927eaed540db942bde01d8d3ff083527c0704d1c9c68"}, + {file = "yarl-1.25.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:68782fdb4027b8d1eee25ec35e9a6db05e863b899eb0310b3a33b6c3fef55707"}, + {file = "yarl-1.25.1-cp312-cp312-win_amd64.whl", hash = "sha256:7d575b54cb3863ef9bc290ea4b009999d55dc237326131e4853cf33e888fee03"}, + {file = "yarl-1.25.1-cp312-cp312-win_arm64.whl", hash = "sha256:bc3ac7bf569f6b64dad04dd7808c7872dae8a97df657856eac05e9b7e3614a85"}, + {file = "yarl-1.25.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:25868beca8b6765f8f7d0e11fe6dd7c66dd4b0793b9500286d20cc92352126a5"}, + {file = "yarl-1.25.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:10b2fd95332f0d716d5eee3c9fb2ce8eada19082de7fee83d32e37992fd75c26"}, + {file = "yarl-1.25.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0f12afda4eea8c8994a76d4df1875c765194f5fbe8a9d197929ea303caee29ec"}, + {file = "yarl-1.25.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:14b79a30a93a3ce2e8832603fd0ab780ada281b0ba5110b519a634f2d7d7d1fc"}, + {file = "yarl-1.25.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4bd6340d20ae2c7ca719b87b426e808e90743b676d05d4c26c4fb5ca71f41184"}, + {file = "yarl-1.25.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:126a2533570c554719ca40a1288fdee1700b6bc82e7131aa69fa85252d92e651"}, + {file = "yarl-1.25.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a3faadac7d812ddac258feb57b9846b60c1b437c4f4b9ad42595c6f6fe4390df"}, + {file = "yarl-1.25.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be80550d9bfe83d9b62398a37081a90434e6df2d978ec345c3d2820de6beddab"}, + {file = "yarl-1.25.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e07595c7d6f4db270ceede356a1bd1c07a34f1c26f958d1ed0cd7b48e0d2bba3"}, + {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eb96ed1ae6c7d072d60840c0434aef07a2df611812810807fbc54263a6053e9a"}, + {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3feb99222553a8cbedfa52c2f59dd84c3f50d5b582c728d522caf8d72769a54b"}, + {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a2ed0ba415ccdf08f14bf544cb78346d0f76086707ffee24921a2c84dbf1305a"}, + {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2b49375d22299b0a834c2bca72f39aaecc270d96fb24c30424899676f487b22a"}, + {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ef74070ac553c59eb4f04258722066d6c6135b7baa03b2e9f2da65c096e96d98"}, + {file = "yarl-1.25.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0a66db89ea473abeac4b70523cafd94db3772380e565f9d28af7a179b7af71fa"}, + {file = "yarl-1.25.1-cp313-cp313-win_amd64.whl", hash = "sha256:1f51020b2eb8a003c84925638ec63c21a750a4bddd3a22ec8eac6a742dadf1b9"}, + {file = "yarl-1.25.1-cp313-cp313-win_arm64.whl", hash = "sha256:b10dd0557ba422715b5206b3743192135a6022acca8baec51aa127d0a75db8fe"}, + {file = "yarl-1.25.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:a9ca696eb02e5c02a8afd872ada510eba9b7fe6e68b9572c2e9a9b1941e31e2e"}, + {file = "yarl-1.25.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a5877f2255aab518ebe528289037699201d5dc5f045f2396cb30aa02db22f57f"}, + {file = "yarl-1.25.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7a5c3115595995779ee21f2567035793911c3802a43c74f3fbb0314929ec67ac"}, + {file = "yarl-1.25.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77e5099b99b37f3cf79c246998ca9f7313a78054cd1809ec46bc1afad47e1c4c"}, + {file = "yarl-1.25.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6efaf45df6a849cef613a03a94c845647456662f85438c886bb67a9c027c8c2c"}, + {file = "yarl-1.25.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d5f90e44653c4e0f78501ed9bb7d3fce835a8d62b7c6ed0cb16557534087e743"}, + {file = "yarl-1.25.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:632da579b2d879f6bad20f2cfa35ded1efe2f4f77f8abb26a6234a5b236acd2f"}, + {file = "yarl-1.25.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:30eec96e8a91bd588ce897c9543f6d5d8d34b28fbcba28a4dedf20ebeae9fe57"}, + {file = "yarl-1.25.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:12b6bc4906e11f5e1a1cdcb12296e7afbd366c783cc8073403cd2fb74334e453"}, + {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9d6ed3d17bccce4c05343e1ca8da13bc5c02c812a4e7282ddd05e8769322d3fc"}, + {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:f38a70074041d3b7e138e452799f5174198bae5bd5ab2000917badf403908c5f"}, + {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca89e4e21854ed27ec753297dde84b16c9f8e53b14a4866fb44457d643c19f8"}, + {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:1ab7618921a93767387a4b83776f751588f5b5ae9bb5bc96620e2e2e00bca868"}, + {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:0ae12ff2b805fa02c4dab838005caef735e39986322698c48588d3beacb65c62"}, + {file = "yarl-1.25.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:90c30ed53546da833c700115c0064c22120d1b1560f474699fd31f22dd668233"}, + {file = "yarl-1.25.1-cp314-cp314-win_amd64.whl", hash = "sha256:acfa7e22aa6c6e7a5996a41d275bfa01efa7ea56ab890590280e9063e2cf5c1b"}, + {file = "yarl-1.25.1-cp314-cp314-win_arm64.whl", hash = "sha256:8e7d98cdbb6d71e726f7d525952867096053d1f290dd4e3c50d7d313a136f414"}, + {file = "yarl-1.25.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d21f0fa80a02d05299207eeaafef345d812ace96d5306e4ef265e1d419a615fa"}, + {file = "yarl-1.25.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17c9877a89fb6e2bca6f9087eb24cd7fb434653946ef5075e470d23d49b52287"}, + {file = "yarl-1.25.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:29273edf1530e397bd07cb784db1fbe0d2590b77569f2e24679a9c0a2d763b94"}, + {file = "yarl-1.25.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7abffdf37af1cec6a2ad69b827aa84320db5894791bc8ed932dc93fb274b7e9"}, + {file = "yarl-1.25.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2239a02249d9326655419e0168a28ca9008938eaab31dc29fc875c217927a6c0"}, + {file = "yarl-1.25.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:664ec6a520b74a1df2810666eb67695fcb77fa663e6ea0a25aaf2e529cb24dfa"}, + {file = "yarl-1.25.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4f1c91f5a5980a937ff8e238e98e6897e1ad74a4b1e2c0d68c73b5ffbb3f5c0b"}, + {file = "yarl-1.25.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c88edaec8c349ad4c5ad4c486a3defcc4b80ceb2f074436ffa0a87caf5e76a6"}, + {file = "yarl-1.25.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:35dcbea443fafb3eece757ad4e514560ddeb6c34cfae1582c620d7b293d7feee"}, + {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:882569ff613758cac762a457a5d72d6e211b28d4bcfea89d1d71ea942b02eac0"}, + {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d0f1489233a254bb3643d2f05de7d59019254d81daeca6b9162fe9edef57e0c7"}, + {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f41753a76f4f63927d03a0d8ba8f5ce0f2083bec29a8cfaccc55371b1564b96b"}, + {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8fb0eb4955adf0579001581f2f71a126e8781ba61bcd120f127b0401163c6c2d"}, + {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a1e32763e641a1566507d90a8d3b19bfc3cc04a9d4e5ae3e32189874ed4b58a3"}, + {file = "yarl-1.25.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65b5b2066651b7432d389e9799d979c703bcc6ef44266bb8153ef54e91e4aab3"}, + {file = "yarl-1.25.1-cp314-cp314t-win_amd64.whl", hash = "sha256:734f6e5400352ac4254456003d462866c684703570929cff7a7bde015d0cb371"}, + {file = "yarl-1.25.1-cp314-cp314t-win_arm64.whl", hash = "sha256:287e99ff5aa4dc1c7630bfc683ded6f106d756c99dec432a2d7f197a784f51c6"}, + {file = "yarl-1.25.1-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:9b1bdaae98bc016825dd3c9d8ee1832f829b3341f9cc6ebd1a1b0a7fef7367cc"}, + {file = "yarl-1.25.1-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:e7011b8fb8c4054bf0c12e5edc6cd83778b0028e99ce59b18586ed036f92cfdc"}, + {file = "yarl-1.25.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:f074e8d4aa0a5798920ddb6de3d08b228c614ff3724c3e8bd7577f4bafea867b"}, + {file = "yarl-1.25.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d42e7e3ca399555578b4d617e3a6ecf13371b3743a115995fa010c7bf341459"}, + {file = "yarl-1.25.1-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aa4ed3dd308548f9e707d9caaf005d2d7f8c1e7868f858dfeb47fe76e16b391d"}, + {file = "yarl-1.25.1-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42a66563d8cc056ee32e6191e05097a7b2b3bc302e0bc3133daf8710eb18bd26"}, + {file = "yarl-1.25.1-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:98d370568f393215d605304cdb77b3d5539bd192c75b623c7304c42c8d6d8273"}, + {file = "yarl-1.25.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23bf5b403c879a54964e0feac7285688e04bb220074878d737d331522da0a5bf"}, + {file = "yarl-1.25.1-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d45673badd08456d0340e9364eddafe1c53a9d2896424294de4d7dd71ad3ee57"}, + {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:0136d640dfa9b0523853e411430a99f8a91eca85774c6420285a33b755bc6de3"}, + {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:59ba3a6e1aa8cfe5adf4bd270fd965db21955401b7ca6f1696010c55ed4daec2"}, + {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:87796fedc3ba97ec14fab55acb48584276e6c1e4c1e89c422bda62c838e754a9"}, + {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:bd0912757081f89b107d6c00b2ff8a194401b0b87eadcf4481de2b865a8fd44f"}, + {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:b51c159a9794633f5e0db7ecec7b2b6e3734eca1f5d17dc989ff3552a43ff78b"}, + {file = "yarl-1.25.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:319e070a01db9920fb63761843f96a104c8e2b9427266731810dc1e22595b17c"}, + {file = "yarl-1.25.1-cp315-cp315-win_amd64.whl", hash = "sha256:a2059a2d891bd156bc5184e7ab7a56e78a84dfcfdeac8c501b552533ad1c36ee"}, + {file = "yarl-1.25.1-cp315-cp315-win_arm64.whl", hash = "sha256:a78b50b4f7918a3de71105d5c0b93bbc57bb8339a4d03a9dfd449f9068e76f3d"}, + {file = "yarl-1.25.1-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:b5402a340723fa7da00b5cff987ddab61276be6d11251ea71ae02bcac54890d8"}, + {file = "yarl-1.25.1-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:eda19ea5ee88742f47a2340816e6f2d40b53bed3ab5b69794769f36af9f35bb4"}, + {file = "yarl-1.25.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:75baa6cf9b6d1c52f3e111a130e202fd8cf0a5b3a066c3f73d615e885092e4ec"}, + {file = "yarl-1.25.1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbcef5a9119ef653653132cccaf999b30a0af6f33bb0a4ba80bec30056868487"}, + {file = "yarl-1.25.1-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7efc9f082dfed77c316edffa9deb52888e1bc6789171887cc1f68e06d65465c8"}, + {file = "yarl-1.25.1-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fe01645169a2112aa1d4ebc3e4c5f029c5c8f97adfc32e5d37c993b39a994d75"}, + {file = "yarl-1.25.1-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1c557dfd5e3db046053a0bdc72261ade790ebe8e2c7a41b36b0ca1f14cb95f3"}, + {file = "yarl-1.25.1-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ce4d6ccafb33d39bd78444612d14938ead674c25702ded2ee9c54a47735d225"}, + {file = "yarl-1.25.1-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:80a063f8297fc796296f00f100be520f209b23dc98f93ce8eba6ee7122598209"}, + {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:7cb414a73e21a7ab58254926073f2930cb22f5b4314ea4260a687e2b3fd4dce3"}, + {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:85a18376073f8a39aa07be34f9fc77e2869aa72c55c441efdd2cf79a0407504d"}, + {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:77716e245c90f058466a05e6a465bb8600f767a8f4b18b4d40f3aff958e5f73c"}, + {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:1e80dcf1446e1b080b1932b0d103c464a04112f5bc31f0f983ad418172063cde"}, + {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:bdc8d8b8c22e9e43ac68316b5e6cf083dec537f4ec213cb4aa967b583bc3fa64"}, + {file = "yarl-1.25.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:dfbf531053a0935f2e871bcd4753f90313688772ff8c017f5ea402e315a78c1f"}, + {file = "yarl-1.25.1-cp315-cp315t-win_amd64.whl", hash = "sha256:b13b88747769537f3d32e89e3a735da10c0a9e35d7322928c701b5f93d3afffd"}, + {file = "yarl-1.25.1-cp315-cp315t-win_arm64.whl", hash = "sha256:783dd1467083f4d3f7722ad6a313f24c173e7571372738fcb7a6e6d1ba48df25"}, + {file = "yarl-1.25.1-py3-none-any.whl", hash = "sha256:681c758b0490f9e96b78e5fa8e8dc6e648e9185bb6eaebe73183c33ea0c445f3"}, + {file = "yarl-1.25.1.tar.gz", hash = "sha256:03dd38de09bc213e9a8b29761eec33ee1d5318dac0e49d8af36e4d27830e23a7"}, ] [package.dependencies] diff --git a/pyproject.toml b/pyproject.toml index 1889c81..8f73fac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,12 @@ [project] name = "newscatcher-catchall-sdk" dynamic = ["version"] +license = "MIT" +license-files = ["LICENSE"] [tool.poetry] name = "newscatcher-catchall-sdk" -version = "3.1.1" +version = "4.0.0" description = "" readme = "README.md" authors = [] @@ -26,8 +28,7 @@ classifiers = [ "Operating System :: POSIX :: Linux", "Operating System :: Microsoft :: Windows", "Topic :: Software Development :: Libraries :: Python Modules", - "Typing :: Typed", - "License :: OSI Approved :: MIT License" + "Typing :: Typed" ] packages = [ { include = "newscatcher_catchall", from = "src"} diff --git a/reference.md b/reference.md index cf68a33..c8e0fec 100644 --- a/reference.md +++ b/reference.md @@ -431,7 +431,7 @@ Job processing mode. **connected_dataset_ids:** `typing.Optional[typing.List[str]]` -Dataset IDs to connect to the job. When provided, this enables Company Watchlist mode — the job returns only events relevant to companies in the connected datasets. To set the minimum relevance threshold, use `ed_score_min`. +Dataset IDs to connect to the job. When provided, this enables Company Monitors mode — the job returns only events relevant to companies in the connected datasets. To set the minimum relevance threshold, use `ed_score_min`. The dataset must have `latest_status: ready` before the job is submitted. Submitting with a non-existent or inaccessible dataset ID returns `400`. @@ -471,7 +471,7 @@ Only valid when `connected_dataset_ids` is set; otherwise ignored. Records where **fetch_all_watchlist_news:** `typing.Optional[bool]` -When true, retrieves all news for connected Company Watchlist entities +When true, retrieves all news for connected Company Monitors entities without topic filtering. Requires connected_dataset_ids to be set. @@ -493,6 +493,20 @@ connected_dataset_ids is set.
+**source_groups:** `typing.Optional[typing.List[str]]` + +Slugs of source groups to scope fetching to their curated domain allowlists. + +Source groups are named domain lists maintained by NewsCatcher (for example "Top 100 US Finance"). Retrieve the groups available to your organization with [List source groups](https://www.newscatcherapi.com/docs/web-search-api/api-reference/jobs/list-source-groups). + +Domains are resolved when the job runs, so a group's current membership always applies. Maximum 20 groups per job. An unknown or inaccessible slug is rejected at submit time. + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -901,8 +915,7 @@ client.jobs.delete_job(
-## Monitors -
client.monitors.list_monitors(...) -> ListMonitorsResponseDto +
client.jobs.list_source_groups(...) -> ListSourceGroupsResponseDto
@@ -914,7 +927,15 @@ client.jobs.delete_job(
-Returns all monitors created by the authenticated user. +Returns a paginated list of source groups visible to your organization. + +A source group is a named, curated domain allowlist maintained by NewsCatcher — for +example "Top 100 US Finance". Pass a group's `slug` in `source_groups` when creating +a job to scope article fetching to that group's domains, instead of maintaining a +long domain list yourself. + +The response covers public groups plus any restricted groups your organization has +been granted access to. Each entry returns `slug`, `name`, and `description`.
@@ -937,7 +958,87 @@ client = CatchAllApi( environment=CatchAllApiEnvironment.DEFAULT, ) -client.monitors.list_monitors( +client.jobs.list_source_groups() + +``` + +
+ + + +#### ⚙️ Parameters + +
+
+ +
+
+ +**page:** `typing.Optional[int]` — Page number to retrieve. + +
+
+ +
+
+ +**page_size:** `typing.Optional[int]` — Number of source groups per page. + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + + + +
+ +## Event Monitors +
client.event_monitors.list_monitors(...) -> ListMonitorsResponseDto +
+
+ +#### 📝 Description + +
+
+ +
+
+ +Returns all event monitors created by the authenticated user. +
+
+
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from newscatcher_catchall import CatchAllApi +from newscatcher_catchall.environment import CatchAllApiEnvironment + +client = CatchAllApi( + api_key="", + environment=CatchAllApiEnvironment.DEFAULT, +) + +client.event_monitors.list_monitors( project_id="60a85db4-78ec-4b78-876a-bc7d9cdadd04", ) @@ -1007,7 +1108,7 @@ client.monitors.list_monitors(
-
client.monitors.create_monitor(...) -> CreateMonitorResponseDto +
client.event_monitors.create_monitor(...) -> CreateMonitorResponseDto
@@ -1019,7 +1120,7 @@ client.monitors.list_monitors(
-Create a scheduled monitor based on a reference job. +Create a scheduled event monitor based on a reference job.
@@ -1042,7 +1143,7 @@ client = CatchAllApi( environment=CatchAllApiEnvironment.DEFAULT, ) -client.monitors.create_monitor( +client.event_monitors.create_monitor( reference_job_id="5f0c9087-85cb-4917-b3c7-e5a5eff73a0c", schedule="every day at 12 PM", timezone="UTC", @@ -1071,7 +1172,7 @@ client.monitors.create_monitor( Job ID to use as template for scheduled runs. Defines the query, validators, and enrichments used for each scheduled run. -If [`backfill`](https://www.newscatcherapi.com/docs/web-search-api/api-reference/monitors/create-monitor#body-backfill) is true, the job's `end_date` must be within the last 7 days. +If [`backfill`](https://www.newscatcherapi.com/docs/web-search-api/api-reference/event-monitors/create-monitor#body-backfill) is true, the job's `end_date` must be within the last 7 days.
@@ -1079,7 +1180,7 @@ If [`backfill`](https://www.newscatcherapi.com/docs/web-search-api/api-reference
-**schedule:** `str` — Monitor schedule in plain text format. Minimum frequency depends on your plan. +**schedule:** `str` — Event monitor schedule in plain text format. Minimum frequency depends on your plan.
@@ -1104,7 +1205,7 @@ If the schedule includes a timezone abbreviation (for example, `"every day at 9a IDs of centralized webhooks to notify on each run completion. Passing IDs here is equivalent to calling `POST /catchAll/webhooks/{webhook_id}/resources` for each ID after creation. -Maximum 5 per monitor. +Maximum 5 per event monitor. @@ -1112,7 +1213,7 @@ Maximum 5 per monitor.
-**limit:** `typing.Optional[int]` — Maximum number of records per monitor run. If not provided, defaults to the plan limit. +**limit:** `typing.Optional[int]` — Maximum number of records per event monitor run. If not provided, defaults to the plan limit.
@@ -1132,7 +1233,7 @@ If false, no gap filling occurs and the first run uses the current cron window o
-**project_id:** `typing.Optional[str]` — Project to assign this monitor to. The monitor appears in the project's resource list after creation. +**project_id:** `typing.Optional[str]` — Project to assign this event monitor to. The event monitor appears in the project's resource list after creation.
@@ -1152,7 +1253,7 @@ If false, no gap filling occurs and the first run uses the current cron window o
-
client.monitors.pull_monitor_results(...) -> PullMonitorResponseDto +
client.event_monitors.pull_monitor_results(...) -> PullMonitorResponseDto
@@ -1164,7 +1265,7 @@ If false, no gap filling occurs and the first run uses the current cron window o
-Retrieve aggregated results from all jobs executed by a monitor. +Retrieve aggregated results from all jobs executed by an event monitor.
@@ -1187,7 +1288,7 @@ client = CatchAllApi( environment=CatchAllApiEnvironment.DEFAULT, ) -client.monitors.pull_monitor_results( +client.event_monitors.pull_monitor_results( monitor_id="monitor_id", ) @@ -1205,7 +1306,7 @@ client.monitors.pull_monitor_results(
-**monitor_id:** `str` — Monitor identifier. +**monitor_id:** `str` — Event monitor identifier.
@@ -1225,7 +1326,7 @@ client.monitors.pull_monitor_results(
-
client.monitors.pull_monitor_results_csv(...) -> str +
client.event_monitors.pull_monitor_results_csv(...) -> str
@@ -1239,7 +1340,7 @@ client.monitors.pull_monitor_results( Returns the most recent run's records as a CSV download. One row per record, with enrichment fields as columns and citations as a JSON column. -If the monitor's reference job used connected entity datasets, connected entities are split into `event_associated_entities` and `mention_entities` JSON columns. When no entity dataset was used, those two columns are omitted from the export entirely. +If the event monitor's reference job used connected entity datasets, connected entities are split into `event_associated_entities` and `mention_entities` JSON columns. When no entity dataset was used, those two columns are omitted from the export entirely.
@@ -1262,7 +1363,7 @@ client = CatchAllApi( environment=CatchAllApiEnvironment.DEFAULT, ) -client.monitors.pull_monitor_results_csv( +client.event_monitors.pull_monitor_results_csv( monitor_id="monitor_id", ) @@ -1280,7 +1381,7 @@ client.monitors.pull_monitor_results_csv(
-**monitor_id:** `str` — Monitor identifier. +**monitor_id:** `str` — Event monitor identifier.
@@ -1300,7 +1401,7 @@ client.monitors.pull_monitor_results_csv(
-
client.monitors.list_monitor_jobs(...) -> ListMonitorJobsResponse +
client.event_monitors.list_monitor_jobs(...) -> ListMonitorJobsResponse
@@ -1312,7 +1413,7 @@ client.monitors.pull_monitor_results_csv(
-Return all jobs executed by a monitor. +Return all jobs executed by an event monitor.
@@ -1335,7 +1436,7 @@ client = CatchAllApi( environment=CatchAllApiEnvironment.DEFAULT, ) -client.monitors.list_monitor_jobs( +client.event_monitors.list_monitor_jobs( monitor_id="monitor_id", ) @@ -1353,7 +1454,7 @@ client.monitors.list_monitor_jobs(
-**monitor_id:** `str` — Monitor identifier. +**monitor_id:** `str` — Event monitor identifier.
@@ -1381,7 +1482,7 @@ client.monitors.list_monitor_jobs(
-
client.monitors.get_monitor_status_history(...) -> MonitorStatusHistoryResponseDto +
client.event_monitors.get_monitor_status_history(...) -> MonitorStatusHistoryResponseDto
@@ -1393,7 +1494,7 @@ client.monitors.list_monitor_jobs(
-Returns the full execution history of a monitor as a list of status entries, ordered from newest to oldest. +Returns the full execution history of an event monitor as a list of status entries, ordered from newest to oldest.
@@ -1416,7 +1517,7 @@ client = CatchAllApi( environment=CatchAllApiEnvironment.DEFAULT, ) -client.monitors.get_monitor_status_history( +client.event_monitors.get_monitor_status_history( monitor_id="monitor_id", ) @@ -1434,7 +1535,7 @@ client.monitors.get_monitor_status_history(
-**monitor_id:** `str` — Monitor identifier. +**monitor_id:** `str` — Event monitor identifier.
@@ -1454,7 +1555,7 @@ client.monitors.get_monitor_status_history(
-
client.monitors.enable_monitor(...) -> EnableMonitorResponse +
client.event_monitors.enable_monitor(...) -> EnableMonitorResponse
@@ -1466,7 +1567,7 @@ client.monitors.get_monitor_status_history(
-Resume scheduled job execution for a monitor. +Resume scheduled job execution for an event monitor.
@@ -1489,7 +1590,7 @@ client = CatchAllApi( environment=CatchAllApiEnvironment.DEFAULT, ) -client.monitors.enable_monitor( +client.event_monitors.enable_monitor( monitor_id="monitor_id", backfill=True, ) @@ -1508,7 +1609,7 @@ client.monitors.enable_monitor(
-**monitor_id:** `str` — Monitor identifier. +**monitor_id:** `str` — Event monitor identifier.
@@ -1540,7 +1641,7 @@ If false, no gap filling occurs and the first run uses the current cron window o
-
client.monitors.disable_monitor(...) -> DisableMonitorResponse +
client.event_monitors.disable_monitor(...) -> DisableMonitorResponse
@@ -1552,7 +1653,7 @@ If false, no gap filling occurs and the first run uses the current cron window o
-Stop scheduled job execution for a monitor. +Stop scheduled job execution for an event monitor.
@@ -1575,7 +1676,7 @@ client = CatchAllApi( environment=CatchAllApiEnvironment.DEFAULT, ) -client.monitors.disable_monitor( +client.event_monitors.disable_monitor( monitor_id="monitor_id", ) @@ -1593,7 +1694,7 @@ client.monitors.disable_monitor(
-**monitor_id:** `str` — Monitor identifier. +**monitor_id:** `str` — Event monitor identifier.
@@ -1613,7 +1714,7 @@ client.monitors.disable_monitor(
-
client.monitors.delete_monitor(...) -> DeleteMonitorResponseDto +
client.event_monitors.delete_monitor(...) -> DeleteMonitorResponseDto
@@ -1625,14 +1726,14 @@ client.monitors.disable_monitor(
-Soft-deletes a monitor. The monitor is flagged as deleted, stops +Soft-deletes an event monitor. The event monitor is flagged as deleted, stops executing scheduled jobs immediately, and no longer appears in list results. -Only the monitor owner can delete a monitor. Returns `404` if the -monitor is not found or does not belong to the authenticated user. +Only the event monitor owner can delete an event monitor. Returns `404` if the +event monitor is not found or does not belong to the authenticated user. -Deleting an already-deleted monitor returns `200`. +Deleting an already-deleted event monitor returns `200`.
@@ -1655,7 +1756,7 @@ client = CatchAllApi( environment=CatchAllApiEnvironment.DEFAULT, ) -client.monitors.delete_monitor( +client.event_monitors.delete_monitor( monitor_id="monitor_id", ) @@ -1673,7 +1774,7 @@ client.monitors.delete_monitor(
-**monitor_id:** `str` — Monitor identifier. +**monitor_id:** `str` — Event monitor identifier.
@@ -1693,7 +1794,7 @@ client.monitors.delete_monitor(
-
client.monitors.update_monitor(...) -> UpdateMonitorResponseDto +
client.event_monitors.update_monitor(...) -> UpdateMonitorResponseDto
@@ -1705,7 +1806,12 @@ client.monitors.delete_monitor(
-Update the webhook configuration for an existing monitor. +Update the webhook assignments, record limit, or schedule of an existing +event monitor. Omitted fields are left unchanged. + +Passing `schedule` replaces the event monitor's current schedule. The new +schedule takes effect from the next scheduler reload, and the old schedule +stops firing. The reference job cannot be changed.
@@ -1728,7 +1834,7 @@ client = CatchAllApi( environment=CatchAllApiEnvironment.DEFAULT, ) -client.monitors.update_monitor( +client.event_monitors.update_monitor( monitor_id="monitor_id", webhook_ids=[ "a1b2c3d4-e5f6-7890-abcd-ef1234567890" @@ -1749,7 +1855,7 @@ client.monitors.update_monitor(
-**monitor_id:** `str` — Monitor identifier. +**monitor_id:** `str` — Event monitor identifier.
@@ -1759,7 +1865,7 @@ client.monitors.update_monitor( **webhook_ids:** `typing.Optional[typing.List[str]]` -Updated list of centralized webhook IDs for this monitor. +Updated list of centralized webhook IDs for this event monitor. Replaces all existing webhook assignments. Pass an empty array `[]` to clear all assignments. Omit to leave existing assignments unchanged. @@ -1769,7 +1875,34 @@ Replaces all existing webhook assignments. Pass an empty array `[]` to clear all
-**limit:** `typing.Optional[int]` — Updated maximum number of records per monitor run. +**limit:** `typing.Optional[int]` — Updated maximum number of records per event monitor run. + +
+
+ +
+
+ +**schedule:** `typing.Optional[str]` + +New natural-language schedule that replaces the event monitor's current +schedule. Examples: `every day at 9 AM`, `every Monday at 6 PM EST`. + +Omit to keep the current schedule. The new schedule takes effect from the +next scheduler reload, and the old schedule stops firing. Returns `422` if +the text can't be parsed or runs would be spaced too closely. + +
+
+ +
+
+ +**timezone:** `typing.Optional[str]` + +IANA timezone for the new schedule (for example, `America/New_York`). +A timezone included in the `schedule` text takes precedence. Ignored if +`schedule` is not set.
@@ -1825,7 +1958,9 @@ client = CatchAllApi( environment=CatchAllApiEnvironment.DEFAULT, ) -client.webhooks.list_webhooks() +client.webhooks.list_webhooks( + project_id="60a85db4-78ec-4b78-876a-bc7d9cdadd04", +) ``` @@ -1865,6 +2000,14 @@ client.webhooks.list_webhooks()
+**project_id:** `typing.Optional[str]` — Filter results to resources belonging to this project. + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -2137,7 +2280,7 @@ client.webhooks.get_webhook( Permanently deletes a webhook and removes all resource assignments. -Assigned jobs and monitors no longer trigger delivery to this webhook. This operation cannot be undone. +Assigned jobs and event monitors no longer trigger delivery to this webhook. This operation cannot be undone.
@@ -2367,7 +2510,7 @@ client.webhooks.update_webhook( Sends a test HTTP request to the webhook URL using the webhook's configured method, headers, and auth. Returns the response from the target endpoint. -Use this to verify URL reachability and authentication before attaching the webhook to a live job or monitor. +Use this to verify URL reachability and authentication before attaching the webhook to a live job or event monitor.
@@ -2552,7 +2695,7 @@ client.webhooks.list_webhook_resources(
-Attaches a job, monitor, or monitor group to the webhook. When the +Attaches a job, event monitor, or event monitor group to the webhook. When the resource completes, the webhook receives a delivery. A single webhook can be assigned to multiple resources. Each resource @@ -2847,7 +2990,7 @@ client.webhooks.list_webhooks_for_resource(
Manually dispatches a webhook delivery for a resource on demand, without -waiting for the next job or monitor cycle. +waiting for the next job or event monitor cycle. Use this to re-deliver results after a failed delivery, replay a specific job's results, or validate a webhook against live data. The webhook must @@ -3081,6 +3224,7 @@ client = CatchAllApi( client.entities.list_entities( search="NewsCatcher", + project_id="60a85db4-78ec-4b78-876a-bc7d9cdadd04", ) ``` @@ -3153,6 +3297,14 @@ client.entities.list_entities(
+**project_id:** `typing.Optional[str]` — Filter results to resources belonging to this project. + +
+
+ +
+
+ **request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
@@ -4984,7 +5136,7 @@ client.projects.delete_project( **delete_resources:** `typing.Optional[bool]` -If true, permanently deletes all resources (jobs, monitors, datasets, monitor groups) assigned to the project. If false, the project is deleted and its resources are unassigned but not deleted. +If true, permanently deletes all resources (jobs, event monitors, datasets, event monitor groups) assigned to the project. If false, the project is deleted and its resources are unassigned but not deleted. Webhooks are never deleted by either setting — they are only detached from the project. diff --git a/src/newscatcher_catchall/__init__.py b/src/newscatcher_catchall/__init__.py index f4c86fc..8652d0c 100644 --- a/src/newscatcher_catchall/__init__.py +++ b/src/newscatcher_catchall/__init__.py @@ -61,6 +61,7 @@ EntityType, EntityValidationErrorBody, Error, + EventTags, FormatterConfigDto, GetPlanLimitsResponseDto, GetWebhookResponseDto, @@ -70,6 +71,7 @@ JobStep, Limit, ListMonitorsResponseDto, + ListSourceGroupsResponseDto, ListUserJobsResponseDto, ListWebhookResourcesResponseDto, ListWebhooksResponseDto, @@ -110,6 +112,7 @@ SharingInfoPermission, SkippedRow, SortOrder, + SourceGroupRef, StartDate, StatusResponseDto, SubmitResponseDto, @@ -140,19 +143,19 @@ WebhookType, ) from .errors import BadRequestError, ForbiddenError, NotFoundError, UnauthorizedError, UnprocessableEntityError - from . import datasets, entities, jobs, meta, monitors, projects, webhooks + from . import datasets, entities, event_monitors, jobs, meta, projects, webhooks from ._default_clients import DefaultAioHttpClient, DefaultAsyncHttpxClient from .client import AsyncCatchAllApi, CatchAllApi from .environment import CatchAllApiEnvironment - from .jobs import GetUserJobsRequestMode, SubmitRequestDtoMode - from .meta import GetVersionResponse, HealthCheckResponse - from .monitors import ( + from .event_monitors import ( DisableMonitorResponse, EnableMonitorResponse, ListMonitorJobsRequestSort, ListMonitorJobsResponse, ListMonitorJobsResponseSortOrder, ) + from .jobs import GetUserJobsRequestMode, SubmitRequestDtoMode + from .meta import GetVersionResponse, HealthCheckResponse from .version import __version__ from .webhooks import ( CreateWebhookRequestDtoAuth, @@ -217,8 +220,8 @@ "DeliveryHistoryResponseDto": ".types", "DeliveryMode": ".types", "DeliveryStatus": ".types", - "DisableMonitorResponse": ".monitors", - "EnableMonitorResponse": ".monitors", + "DisableMonitorResponse": ".event_monitors", + "EnableMonitorResponse": ".event_monitors", "EndDate": ".types", "EnrichmentSchema": ".types", "EnrichmentType": ".types", @@ -231,6 +234,7 @@ "EntityType": ".types", "EntityValidationErrorBody": ".types", "Error": ".types", + "EventTags": ".types", "ForbiddenError": ".errors", "FormatterConfigDto": ".types", "GetPlanLimitsResponseDto": ".types", @@ -243,10 +247,11 @@ "IssueType": ".types", "JobStep": ".types", "Limit": ".types", - "ListMonitorJobsRequestSort": ".monitors", - "ListMonitorJobsResponse": ".monitors", - "ListMonitorJobsResponseSortOrder": ".monitors", + "ListMonitorJobsRequestSort": ".event_monitors", + "ListMonitorJobsResponse": ".event_monitors", + "ListMonitorJobsResponseSortOrder": ".event_monitors", "ListMonitorsResponseDto": ".types", + "ListSourceGroupsResponseDto": ".types", "ListUserJobsResponseDto": ".types", "ListWebhookResourcesResponseDto": ".types", "ListWebhooksResponseDto": ".types", @@ -288,6 +293,7 @@ "SharingInfoPermission": ".types", "SkippedRow": ".types", "SortOrder": ".types", + "SourceGroupRef": ".types", "StartDate": ".types", "StatusResponseDto": ".types", "SubmitRequestDtoMode": ".jobs", @@ -326,9 +332,9 @@ "__version__": ".version", "datasets": ".datasets", "entities": ".entities", + "event_monitors": ".event_monitors", "jobs": ".jobs", "meta": ".meta", - "monitors": ".monitors", "projects": ".projects", "webhooks": ".webhooks", } @@ -422,6 +428,7 @@ def __dir__(): "EntityType", "EntityValidationErrorBody", "Error", + "EventTags", "ForbiddenError", "FormatterConfigDto", "GetPlanLimitsResponseDto", @@ -438,6 +445,7 @@ def __dir__(): "ListMonitorJobsResponse", "ListMonitorJobsResponseSortOrder", "ListMonitorsResponseDto", + "ListSourceGroupsResponseDto", "ListUserJobsResponseDto", "ListWebhookResourcesResponseDto", "ListWebhooksResponseDto", @@ -479,6 +487,7 @@ def __dir__(): "SharingInfoPermission", "SkippedRow", "SortOrder", + "SourceGroupRef", "StartDate", "StatusResponseDto", "SubmitRequestDtoMode", @@ -517,9 +526,9 @@ def __dir__(): "__version__", "datasets", "entities", + "event_monitors", "jobs", "meta", - "monitors", "projects", "webhooks", ] diff --git a/src/newscatcher_catchall/client.py b/src/newscatcher_catchall/client.py index 8721155..ff20455 100644 --- a/src/newscatcher_catchall/client.py +++ b/src/newscatcher_catchall/client.py @@ -12,9 +12,9 @@ if typing.TYPE_CHECKING: from .datasets.client import AsyncDatasetsClient, DatasetsClient from .entities.client import AsyncEntitiesClient, EntitiesClient + from .event_monitors.client import AsyncEventMonitorsClient, EventMonitorsClient from .jobs.client import AsyncJobsClient, JobsClient from .meta.client import AsyncMetaClient, MetaClient - from .monitors.client import AsyncMonitorsClient, MonitorsClient from .projects.client import AsyncProjectsClient, ProjectsClient from .webhooks.client import AsyncWebhooksClient, WebhooksClient @@ -104,7 +104,7 @@ def __init__( logging=logging, ) self._jobs: typing.Optional[JobsClient] = None - self._monitors: typing.Optional[MonitorsClient] = None + self._event_monitors: typing.Optional[EventMonitorsClient] = None self._webhooks: typing.Optional[WebhooksClient] = None self._entities: typing.Optional[EntitiesClient] = None self._datasets: typing.Optional[DatasetsClient] = None @@ -120,12 +120,12 @@ def jobs(self): return self._jobs @property - def monitors(self): - if self._monitors is None: - from .monitors.client import MonitorsClient # noqa: E402 + def event_monitors(self): + if self._event_monitors is None: + from .event_monitors.client import EventMonitorsClient # noqa: E402 - self._monitors = MonitorsClient(client_wrapper=self._client_wrapper) - return self._monitors + self._event_monitors = EventMonitorsClient(client_wrapper=self._client_wrapper) + return self._event_monitors @property def webhooks(self): @@ -269,7 +269,7 @@ def __init__( logging=logging, ) self._jobs: typing.Optional[AsyncJobsClient] = None - self._monitors: typing.Optional[AsyncMonitorsClient] = None + self._event_monitors: typing.Optional[AsyncEventMonitorsClient] = None self._webhooks: typing.Optional[AsyncWebhooksClient] = None self._entities: typing.Optional[AsyncEntitiesClient] = None self._datasets: typing.Optional[AsyncDatasetsClient] = None @@ -285,12 +285,12 @@ def jobs(self): return self._jobs @property - def monitors(self): - if self._monitors is None: - from .monitors.client import AsyncMonitorsClient # noqa: E402 + def event_monitors(self): + if self._event_monitors is None: + from .event_monitors.client import AsyncEventMonitorsClient # noqa: E402 - self._monitors = AsyncMonitorsClient(client_wrapper=self._client_wrapper) - return self._monitors + self._event_monitors = AsyncEventMonitorsClient(client_wrapper=self._client_wrapper) + return self._event_monitors @property def webhooks(self): diff --git a/src/newscatcher_catchall/core/client_wrapper.py b/src/newscatcher_catchall/core/client_wrapper.py index f5165e4..27bd471 100644 --- a/src/newscatcher_catchall/core/client_wrapper.py +++ b/src/newscatcher_catchall/core/client_wrapper.py @@ -33,12 +33,12 @@ def get_headers(self) -> typing.Dict[str, str]: import platform headers: typing.Dict[str, str] = { - "User-Agent": "newscatcher-catchall-sdk/3.1.1", + "User-Agent": "newscatcher-catchall-sdk/0.0.0-fern-placeholder", "X-Fern-Language": "Python", "X-Fern-Runtime": f"python/{platform.python_version()}", "X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}", "X-Fern-SDK-Name": "newscatcher-catchall-sdk", - "X-Fern-SDK-Version": "3.1.1", + "X-Fern-SDK-Version": "4.0.0", **(self.get_custom_headers() or {}), } headers["x-api-key"] = self.api_key diff --git a/src/newscatcher_catchall/core/http_client.py b/src/newscatcher_catchall/core/http_client.py index 409d267..3e5a786 100644 --- a/src/newscatcher_catchall/core/http_client.py +++ b/src/newscatcher_catchall/core/http_client.py @@ -272,7 +272,16 @@ def get_request_body( data: typing.Optional[typing.Any], request_options: typing.Optional[RequestOptions], omit: typing.Optional[typing.Any], + optional_body: bool = False, ) -> typing.Tuple[typing.Optional[typing.Any], typing.Optional[typing.Any]]: + # A whole body left at the sentinel was never passed by the caller, so it is absent + # rather than empty: the request carries no content and no `Content-Type`. + if omit is not None: + if json is omit: + json = None + if data is omit: + data = None + json_body = None data_body = None if data is not None: @@ -288,14 +297,36 @@ def get_request_body( # Only collapse empty dict to None when the body was not explicitly provided # and there are no additional body parameters. This preserves explicit empty # bodies (e.g., when an endpoint has a request body type but all fields are optional). - if json_body == {} and json is None and not has_additional_body_parameters: + # `optional_body` marks an endpoint whose body the API does not require, where a body + # that ends up empty means the caller passed none of its properties, so the request is + # sent with no content and no `Content-Type`. + if json_body == {} and (json is None or optional_body) and not has_additional_body_parameters: json_body = None - if data_body == {} and data is None and not has_additional_body_parameters: + if data_body == {} and (data is None or optional_body) and not has_additional_body_parameters: data_body = None return json_body, data_body +def drop_content_type_without_body( + headers: typing.Dict[str, typing.Any], + *, + json_body: typing.Optional[typing.Any], + data_body: typing.Optional[typing.Any], + optional_body: bool, +) -> typing.Dict[str, typing.Any]: + """Strip ``Content-Type`` from a request that carries no body. + + ``get_request_body`` drops the body of an ``optional_body`` endpoint when the caller + supplied none of it, but the endpoint still passes the content type it would have used. + A request that sends nothing must not advertise a media type, so a server that branches + on the header sees a bodyless call for what it is. + """ + if not optional_body or json_body is not None or data_body is not None: + return headers + return {key: value for key, value in headers.items() if key.lower() != "content-type"} + + class HttpClient: def __init__( self, @@ -343,6 +374,7 @@ def request( request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + optional_body: bool = False, force_multipart: typing.Optional[bool] = None, ) -> httpx.Response: base_url = self.get_base_url(base_url) @@ -355,7 +387,9 @@ def request( ) timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT - json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit) + json_body, data_body = get_request_body( + json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body + ) request_files: typing.Optional[RequestFiles] = ( convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit)) @@ -398,6 +432,9 @@ def request( } ) ) + _request_headers = drop_content_type_without_body( + _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body + ) if self.logger.is_debug(): self.logger.debug( @@ -506,6 +543,7 @@ def stream( request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + optional_body: bool = False, force_multipart: typing.Optional[bool] = None, ) -> typing.Iterator[httpx.Response]: base_url = self.get_base_url(base_url) @@ -527,7 +565,9 @@ def stream( if (request_files is None or len(request_files) == 0) and force_multipart: request_files = FORCE_MULTIPART - json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit) + json_body, data_body = get_request_body( + json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body + ) data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) @@ -561,6 +601,9 @@ def stream( } ) ) + _request_headers = drop_content_type_without_body( + _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body + ) if self.logger.is_debug(): self.logger.debug( @@ -638,6 +681,7 @@ async def request( request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + optional_body: bool = False, force_multipart: typing.Optional[bool] = None, ) -> httpx.Response: base_url = self.get_base_url(base_url) @@ -659,7 +703,9 @@ async def request( if (request_files is None or len(request_files) == 0) and force_multipart: request_files = FORCE_MULTIPART - json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit) + json_body, data_body = get_request_body( + json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body + ) data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) @@ -696,6 +742,9 @@ async def request( } ) ) + _request_headers = drop_content_type_without_body( + _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body + ) if self.logger.is_debug(): self.logger.debug( @@ -804,6 +853,7 @@ async def stream( request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + optional_body: bool = False, force_multipart: typing.Optional[bool] = None, ) -> typing.AsyncIterator[httpx.Response]: base_url = self.get_base_url(base_url) @@ -825,7 +875,9 @@ async def stream( if (request_files is None or len(request_files) == 0) and force_multipart: request_files = FORCE_MULTIPART - json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit) + json_body, data_body = get_request_body( + json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body + ) data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) @@ -862,6 +914,9 @@ async def stream( } ) ) + _request_headers = drop_content_type_without_body( + _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body + ) if self.logger.is_debug(): self.logger.debug( diff --git a/src/newscatcher_catchall/core/http_response.py b/src/newscatcher_catchall/core/http_response.py index 00bb109..9aa1e18 100644 --- a/src/newscatcher_catchall/core/http_response.py +++ b/src/newscatcher_catchall/core/http_response.py @@ -24,6 +24,10 @@ def headers(self) -> Dict[str, str]: def status_code(self) -> int: return self._response.status_code + @property + def response(self) -> httpx.Response: + return self._response + class HttpResponse(Generic[T], BaseHttpResponse): """HTTP response wrapper that exposes response headers and data.""" diff --git a/src/newscatcher_catchall/core/pydantic_utilities.py b/src/newscatcher_catchall/core/pydantic_utilities.py index 6587f5e..70816b9 100644 --- a/src/newscatcher_catchall/core/pydantic_utilities.py +++ b/src/newscatcher_catchall/core/pydantic_utilities.py @@ -5,6 +5,7 @@ import inspect import json import logging +import weakref from collections import defaultdict from dataclasses import asdict from typing import ( @@ -184,6 +185,58 @@ def _get_type_adapter(type_: Type[Any]) -> Any: return adapter +_field_alias_cache: "weakref.WeakKeyDictionary[type, Tuple[Dict[str, str], Tuple[str, ...]]]" = ( + weakref.WeakKeyDictionary() +) + + +def _get_field_aliases(model: type) -> Tuple[Dict[str, str], Tuple[str, ...]]: + """ + Map of field name to Pydantic alias for the fields whose alias differs from their name, together with the + keys that are ambiguous (an alias of one field and the name of another). Computed once per model class. + """ + cached = _field_alias_cache.get(model) + if cached is None: + fields: Mapping[str, Any] = ( + getattr(model, "model_fields", {}) if IS_PYDANTIC_V2 else getattr(model, "__fields__", {}) + ) + name_to_alias: Dict[str, str] = {} + for name, field in fields.items(): + alias = getattr(field, "alias", None) + if alias is not None and alias != name: + name_to_alias[name] = alias + cached = (name_to_alias, tuple(alias for alias in name_to_alias.values() if alias in fields)) + _field_alias_cache[model] = cached + return cached + + +def _coerce_keys_to_aliases(model: type, data: Any) -> Any: + """ + Accept Python field names in input by rewriting them to their Pydantic aliases, + while avoiding silent collisions when a key could refer to multiple fields. + """ + if not isinstance(data, Mapping): + return data + + name_to_alias, ambiguous_keys = _get_field_aliases(model) + for key in ambiguous_keys: + if key in data and name_to_alias.get(key, key) not in data: + raise ValueError( + f"Ambiguous input key '{key}': it is both a field name and an alias. " + "Provide the explicit alias key to disambiguate." + ) + + if not name_to_alias or not any(name in data for name in name_to_alias): + return data if isinstance(data, dict) else dict(data) + + rewritten: Dict[str, Any] = dict(data) + for name, alias in name_to_alias.items(): + if name in data and alias not in rewritten: + rewritten[alias] = rewritten.pop(name) + + return rewritten + + def parse_obj_as(type_: Type[T], object_: Any) -> T: # convert_and_respect_annotation_metadata is required for TypedDict aliasing. # @@ -193,20 +246,7 @@ def parse_obj_as(type_: Type[T], object_: Any) -> T: # - If the model encodes aliasing only via FieldMetadata annotations, then we MUST pre-dealias because Pydantic # will not recognize those aliases during validation. if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel): - has_pydantic_aliases = False - if IS_PYDANTIC_V2: - for field_name, field_info in getattr(type_, "model_fields", {}).items(): # type: ignore[attr-defined] - alias = getattr(field_info, "alias", None) - if alias is not None and alias != field_name: - has_pydantic_aliases = True - break - else: - for field in getattr(type_, "__fields__", {}).values(): - alias = getattr(field, "alias", None) - name = getattr(field, "name", None) - if alias is not None and name is not None and alias != name: - has_pydantic_aliases = True - break + has_pydantic_aliases = bool(_get_field_aliases(type_)[0]) dealiased_object = ( object_ @@ -239,39 +279,7 @@ class UniversalBaseModel(pydantic.BaseModel): @pydantic.model_validator(mode="before") # type: ignore[attr-defined] @classmethod def _coerce_field_names_to_aliases(cls, data: Any) -> Any: - """ - Accept Python field names in input by rewriting them to their Pydantic aliases, - while avoiding silent collisions when a key could refer to multiple fields. - """ - if not isinstance(data, Mapping): - return data - - fields = getattr(cls, "model_fields", {}) # type: ignore[attr-defined] - name_to_alias: Dict[str, str] = {} - alias_to_name: Dict[str, str] = {} - - for name, field_info in fields.items(): - alias = getattr(field_info, "alias", None) or name - name_to_alias[name] = alias - if alias != name: - alias_to_name[alias] = name - - # Detect ambiguous keys: a key that is an alias for one field and a name for another. - ambiguous_keys = set(alias_to_name.keys()).intersection(set(name_to_alias.keys())) - for key in ambiguous_keys: - if key in data and name_to_alias[key] not in data: - raise ValueError( - f"Ambiguous input key '{key}': it is both a field name and an alias. " - "Provide the explicit alias key to disambiguate." - ) - - original_keys = set(data.keys()) - rewritten: Dict[str, Any] = dict(data) - for name, alias in name_to_alias.items(): - if alias != name and name in original_keys and alias not in rewritten: - rewritten[alias] = rewritten.pop(name) - - return rewritten + return _coerce_keys_to_aliases(cls, data) @pydantic.model_serializer(mode="plain", when_used="json") # type: ignore[attr-defined] def serialize_model(self) -> Any: # type: ignore[name-defined] @@ -287,37 +295,7 @@ class Config: @pydantic.root_validator(pre=True) def _coerce_field_names_to_aliases(cls, values: Any) -> Any: - """ - Pydantic v1 equivalent of _coerce_field_names_to_aliases. - """ - if not isinstance(values, Mapping): - return values - - fields = getattr(cls, "__fields__", {}) - name_to_alias: Dict[str, str] = {} - alias_to_name: Dict[str, str] = {} - - for name, field in fields.items(): - alias = getattr(field, "alias", None) or name - name_to_alias[name] = alias - if alias != name: - alias_to_name[alias] = name - - ambiguous_keys = set(alias_to_name.keys()).intersection(set(name_to_alias.keys())) - for key in ambiguous_keys: - if key in values and name_to_alias[key] not in values: - raise ValueError( - f"Ambiguous input key '{key}': it is both a field name and an alias. " - "Provide the explicit alias key to disambiguate." - ) - - original_keys = set(values.keys()) - rewritten: Dict[str, Any] = dict(values) - for name, alias in name_to_alias.items(): - if alias != name and name in original_keys and alias not in rewritten: - rewritten[alias] = rewritten.pop(name) - - return rewritten + return _coerce_keys_to_aliases(cls, values) # type: ignore[arg-type] @classmethod def model_construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model": diff --git a/src/newscatcher_catchall/datasets/raw_client.py b/src/newscatcher_catchall/datasets/raw_client.py index 27ed31d..9f8e19a 100644 --- a/src/newscatcher_catchall/datasets/raw_client.py +++ b/src/newscatcher_catchall/datasets/raw_client.py @@ -14,6 +14,7 @@ from ..errors.bad_request_error import BadRequestError from ..errors.forbidden_error import ForbiddenError from ..errors.not_found_error import NotFoundError +from ..errors.unauthorized_error import UnauthorizedError from ..errors.unprocessable_entity_error import UnprocessableEntityError from ..types.create_dataset_csv_response import CreateDatasetCsvResponse from ..types.dataset_entity_list_response import DatasetEntityListResponse @@ -113,6 +114,17 @@ def list_datasets( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -207,6 +219,17 @@ def create_dataset( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -303,6 +326,17 @@ def create_dataset_from_csv( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -368,6 +402,17 @@ def get_dataset( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -427,6 +472,17 @@ def delete_dataset( try: if 200 <= _response.status_code < 300: return HttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -511,6 +567,17 @@ def update_dataset( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -601,6 +668,17 @@ def add_entities_to_dataset( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -691,6 +769,17 @@ def remove_entities_from_dataset( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -807,6 +896,17 @@ def list_entities_in_dataset( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -883,6 +983,17 @@ def get_dataset_status_history( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -959,6 +1070,17 @@ def upload_csv_to_dataset( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1078,6 +1200,17 @@ async def list_datasets( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1172,6 +1305,17 @@ async def create_dataset( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1268,6 +1412,17 @@ async def create_dataset_from_csv( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1333,6 +1488,17 @@ async def get_dataset( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1392,6 +1558,17 @@ async def delete_dataset( try: if 200 <= _response.status_code < 300: return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1476,6 +1653,17 @@ async def update_dataset( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1566,6 +1754,17 @@ async def add_entities_to_dataset( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1656,6 +1855,17 @@ async def remove_entities_from_dataset( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1772,6 +1982,17 @@ async def list_entities_in_dataset( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1848,6 +2069,17 @@ async def get_dataset_status_history( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1924,6 +2156,17 @@ async def upload_csv_to_dataset( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), diff --git a/src/newscatcher_catchall/entities/client.py b/src/newscatcher_catchall/entities/client.py index dedf3d2..a100e85 100644 --- a/src/newscatcher_catchall/entities/client.py +++ b/src/newscatcher_catchall/entities/client.py @@ -45,6 +45,7 @@ def list_entities( entity_type: typing.Optional[EntityType] = None, sort_by: typing.Optional[EntitySortBy] = None, sort_order: typing.Optional[SortOrder] = None, + project_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> EntityListResponse: """ @@ -69,6 +70,9 @@ def list_entities( sort_order : typing.Optional[SortOrder] + project_id : typing.Optional[str] + Filter results to resources belonging to this project. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -86,6 +90,7 @@ def list_entities( ) client.entities.list_entities( search="NewsCatcher", + project_id="60a85db4-78ec-4b78-876a-bc7d9cdadd04", ) """ _response = self._raw_client.list_entities( @@ -96,6 +101,7 @@ def list_entities( entity_type=entity_type, sort_by=sort_by, sort_order=sort_order, + project_id=project_id, request_options=request_options, ) return _response.data @@ -126,7 +132,7 @@ def create_entity( entity_type : typing.Optional[EntityType] description : typing.Optional[str] - Free-text description of the entity used for disambiguation when similar names exist. See [Writing effective descriptions](https://www.newscatcherapi.com/docs/web-search-api/concepts/company-search#writing-effective-descriptions) for guidance on improving matching quality. + Free-text description of the entity used for disambiguation when similar names exist. See [Writing effective descriptions](https://www.newscatcherapi.com/docs/web-search-api/concepts/company-monitors#writing-effective-descriptions) for guidance on improving matching quality. external_entity_id : typing.Optional[str] Optional external identifier for this entity. Free-form string, not enforced as unique. Use it to store your own CRM, data warehouse, or internal database ID so you can join CatchAll results back to your systems. @@ -402,6 +408,7 @@ async def list_entities( entity_type: typing.Optional[EntityType] = None, sort_by: typing.Optional[EntitySortBy] = None, sort_order: typing.Optional[SortOrder] = None, + project_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> EntityListResponse: """ @@ -426,6 +433,9 @@ async def list_entities( sort_order : typing.Optional[SortOrder] + project_id : typing.Optional[str] + Filter results to resources belonging to this project. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -448,6 +458,7 @@ async def list_entities( async def main() -> None: await client.entities.list_entities( search="NewsCatcher", + project_id="60a85db4-78ec-4b78-876a-bc7d9cdadd04", ) @@ -461,6 +472,7 @@ async def main() -> None: entity_type=entity_type, sort_by=sort_by, sort_order=sort_order, + project_id=project_id, request_options=request_options, ) return _response.data @@ -491,7 +503,7 @@ async def create_entity( entity_type : typing.Optional[EntityType] description : typing.Optional[str] - Free-text description of the entity used for disambiguation when similar names exist. See [Writing effective descriptions](https://www.newscatcherapi.com/docs/web-search-api/concepts/company-search#writing-effective-descriptions) for guidance on improving matching quality. + Free-text description of the entity used for disambiguation when similar names exist. See [Writing effective descriptions](https://www.newscatcherapi.com/docs/web-search-api/concepts/company-monitors#writing-effective-descriptions) for guidance on improving matching quality. external_entity_id : typing.Optional[str] Optional external identifier for this entity. Free-form string, not enforced as unique. Use it to store your own CRM, data warehouse, or internal database ID so you can join CatchAll results back to your systems. diff --git a/src/newscatcher_catchall/entities/raw_client.py b/src/newscatcher_catchall/entities/raw_client.py index 2188aac..62d7182 100644 --- a/src/newscatcher_catchall/entities/raw_client.py +++ b/src/newscatcher_catchall/entities/raw_client.py @@ -14,6 +14,8 @@ from ..errors.bad_request_error import BadRequestError from ..errors.forbidden_error import ForbiddenError from ..errors.not_found_error import NotFoundError +from ..errors.unauthorized_error import UnauthorizedError +from ..errors.unprocessable_entity_error import UnprocessableEntityError from ..types.additional_attributes import AdditionalAttributes from ..types.create_entities_batch_response import CreateEntitiesBatchResponse from ..types.create_entity_request import CreateEntityRequest @@ -25,6 +27,7 @@ from ..types.entity_type import EntityType from ..types.error import Error from ..types.sort_order import SortOrder +from ..types.validation_error_response import ValidationErrorResponse from pydantic import ValidationError # this is used as the default value for optional parameters @@ -45,6 +48,7 @@ def list_entities( entity_type: typing.Optional[EntityType] = None, sort_by: typing.Optional[EntitySortBy] = None, sort_order: typing.Optional[SortOrder] = None, + project_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[EntityListResponse]: """ @@ -69,6 +73,9 @@ def list_entities( sort_order : typing.Optional[SortOrder] + project_id : typing.Optional[str] + Filter results to resources belonging to this project. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -88,6 +95,7 @@ def list_entities( "entity_type": entity_type, "sort_by": sort_by, "sort_order": sort_order, + "project_id": project_id, }, request_options=request_options, ) @@ -101,6 +109,17 @@ def list_entities( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -112,6 +131,28 @@ def list_entities( ), ), ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 422: + raise UnprocessableEntityError( + headers=dict(_response.headers), + body=typing.cast( + ValidationErrorResponse, + parse_obj_as( + type_=ValidationErrorResponse, # type: ignore + object_=_response.json(), + ), + ), + ) _response_json = _response.json() except JSONDecodeError: raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) @@ -147,7 +188,7 @@ def create_entity( entity_type : typing.Optional[EntityType] description : typing.Optional[str] - Free-text description of the entity used for disambiguation when similar names exist. See [Writing effective descriptions](https://www.newscatcherapi.com/docs/web-search-api/concepts/company-search#writing-effective-descriptions) for guidance on improving matching quality. + Free-text description of the entity used for disambiguation when similar names exist. See [Writing effective descriptions](https://www.newscatcherapi.com/docs/web-search-api/concepts/company-monitors#writing-effective-descriptions) for guidance on improving matching quality. external_entity_id : typing.Optional[str] Optional external identifier for this entity. Free-form string, not enforced as unique. Use it to store your own CRM, data warehouse, or internal database ID so you can join CatchAll results back to your systems. @@ -198,6 +239,17 @@ def create_entity( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -277,6 +329,17 @@ def create_entities_batch( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -331,6 +394,17 @@ def get_entity( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -389,6 +463,17 @@ def delete_entity( try: if 200 <= _response.status_code < 300: return HttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -495,6 +580,17 @@ def update_entity( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -541,6 +637,7 @@ async def list_entities( entity_type: typing.Optional[EntityType] = None, sort_by: typing.Optional[EntitySortBy] = None, sort_order: typing.Optional[SortOrder] = None, + project_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[EntityListResponse]: """ @@ -565,6 +662,9 @@ async def list_entities( sort_order : typing.Optional[SortOrder] + project_id : typing.Optional[str] + Filter results to resources belonging to this project. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -584,6 +684,7 @@ async def list_entities( "entity_type": entity_type, "sort_by": sort_by, "sort_order": sort_order, + "project_id": project_id, }, request_options=request_options, ) @@ -597,6 +698,17 @@ async def list_entities( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -608,6 +720,28 @@ async def list_entities( ), ), ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 422: + raise UnprocessableEntityError( + headers=dict(_response.headers), + body=typing.cast( + ValidationErrorResponse, + parse_obj_as( + type_=ValidationErrorResponse, # type: ignore + object_=_response.json(), + ), + ), + ) _response_json = _response.json() except JSONDecodeError: raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) @@ -643,7 +777,7 @@ async def create_entity( entity_type : typing.Optional[EntityType] description : typing.Optional[str] - Free-text description of the entity used for disambiguation when similar names exist. See [Writing effective descriptions](https://www.newscatcherapi.com/docs/web-search-api/concepts/company-search#writing-effective-descriptions) for guidance on improving matching quality. + Free-text description of the entity used for disambiguation when similar names exist. See [Writing effective descriptions](https://www.newscatcherapi.com/docs/web-search-api/concepts/company-monitors#writing-effective-descriptions) for guidance on improving matching quality. external_entity_id : typing.Optional[str] Optional external identifier for this entity. Free-form string, not enforced as unique. Use it to store your own CRM, data warehouse, or internal database ID so you can join CatchAll results back to your systems. @@ -694,6 +828,17 @@ async def create_entity( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -773,6 +918,17 @@ async def create_entities_batch( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -827,6 +983,17 @@ async def get_entity( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -885,6 +1052,17 @@ async def delete_entity( try: if 200 <= _response.status_code < 300: return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -991,6 +1169,17 @@ async def update_entity( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), diff --git a/src/newscatcher_catchall/monitors/__init__.py b/src/newscatcher_catchall/event_monitors/__init__.py similarity index 100% rename from src/newscatcher_catchall/monitors/__init__.py rename to src/newscatcher_catchall/event_monitors/__init__.py diff --git a/src/newscatcher_catchall/monitors/client.py b/src/newscatcher_catchall/event_monitors/client.py similarity index 73% rename from src/newscatcher_catchall/monitors/client.py rename to src/newscatcher_catchall/event_monitors/client.py index 199f4b9..0106b1f 100644 --- a/src/newscatcher_catchall/monitors/client.py +++ b/src/newscatcher_catchall/event_monitors/client.py @@ -11,7 +11,7 @@ from ..types.ownership_filter import OwnershipFilter from ..types.pull_monitor_response_dto import PullMonitorResponseDto from ..types.update_monitor_response_dto import UpdateMonitorResponseDto -from .raw_client import AsyncRawMonitorsClient, RawMonitorsClient +from .raw_client import AsyncRawEventMonitorsClient, RawEventMonitorsClient from .types.disable_monitor_response import DisableMonitorResponse from .types.enable_monitor_response import EnableMonitorResponse from .types.list_monitor_jobs_request_sort import ListMonitorJobsRequestSort @@ -21,18 +21,18 @@ OMIT = typing.cast(typing.Any, ...) -class MonitorsClient: +class EventMonitorsClient: def __init__(self, *, client_wrapper: SyncClientWrapper): - self._raw_client = RawMonitorsClient(client_wrapper=client_wrapper) + self._raw_client = RawEventMonitorsClient(client_wrapper=client_wrapper) @property - def with_raw_response(self) -> RawMonitorsClient: + def with_raw_response(self) -> RawEventMonitorsClient: """ Retrieves a raw implementation of this client that returns raw responses. Returns ------- - RawMonitorsClient + RawEventMonitorsClient """ return self._raw_client @@ -47,7 +47,7 @@ def list_monitors( request_options: typing.Optional[RequestOptions] = None, ) -> ListMonitorsResponseDto: """ - Returns all monitors created by the authenticated user. + Returns all event monitors created by the authenticated user. Parameters ---------- @@ -71,7 +71,7 @@ def list_monitors( Returns ------- ListMonitorsResponseDto - List of user monitors + List of user event monitors Examples -------- @@ -80,7 +80,7 @@ def list_monitors( client = CatchAllApi( api_key="YOUR_API_KEY", ) - client.monitors.list_monitors( + client.event_monitors.list_monitors( project_id="60a85db4-78ec-4b78-876a-bc7d9cdadd04", ) """ @@ -107,17 +107,17 @@ def create_monitor( request_options: typing.Optional[RequestOptions] = None, ) -> CreateMonitorResponseDto: """ - Create a scheduled monitor based on a reference job. + Create a scheduled event monitor based on a reference job. Parameters ---------- reference_job_id : str Job ID to use as template for scheduled runs. Defines the query, validators, and enrichments used for each scheduled run. - If [`backfill`](https://www.newscatcherapi.com/docs/web-search-api/api-reference/monitors/create-monitor#body-backfill) is true, the job's `end_date` must be within the last 7 days. + If [`backfill`](https://www.newscatcherapi.com/docs/web-search-api/api-reference/event-monitors/create-monitor#body-backfill) is true, the job's `end_date` must be within the last 7 days. schedule : str - Monitor schedule in plain text format. Minimum frequency depends on your plan. + Event monitor schedule in plain text format. Minimum frequency depends on your plan. timezone : typing.Optional[str] The IANA timezone identifier used as the fallback when the `schedule` string does not include an explicit timezone. @@ -128,10 +128,10 @@ def create_monitor( IDs of centralized webhooks to notify on each run completion. Passing IDs here is equivalent to calling `POST /catchAll/webhooks/{webhook_id}/resources` for each ID after creation. - Maximum 5 per monitor. + Maximum 5 per event monitor. limit : typing.Optional[int] - Maximum number of records per monitor run. If not provided, defaults to the plan limit. + Maximum number of records per event monitor run. If not provided, defaults to the plan limit. backfill : typing.Optional[bool] If true, fills the data gap between the reference job's `end_date` and the first scheduled run. The reference job's `end_date` must be within the last 7 days. @@ -139,7 +139,7 @@ def create_monitor( If false, no gap filling occurs and the first run uses the current cron window only — the reference job's age does not matter. project_id : typing.Optional[str] - Project to assign this monitor to. The monitor appears in the project's resource list after creation. + Project to assign this event monitor to. The event monitor appears in the project's resource list after creation. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -147,7 +147,7 @@ def create_monitor( Returns ------- CreateMonitorResponseDto - Monitor created successfully + Event monitor created successfully Examples -------- @@ -156,7 +156,7 @@ def create_monitor( client = CatchAllApi( api_key="YOUR_API_KEY", ) - client.monitors.create_monitor( + client.event_monitors.create_monitor( reference_job_id="5f0c9087-85cb-4917-b3c7-e5a5eff73a0c", schedule="every day at 12 PM", timezone="UTC", @@ -181,12 +181,12 @@ def pull_monitor_results( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> PullMonitorResponseDto: """ - Retrieve aggregated results from all jobs executed by a monitor. + Retrieve aggregated results from all jobs executed by an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -194,7 +194,7 @@ def pull_monitor_results( Returns ------- PullMonitorResponseDto - Monitor results retrieved successfully + Event monitor results retrieved successfully Examples -------- @@ -203,7 +203,7 @@ def pull_monitor_results( client = CatchAllApi( api_key="YOUR_API_KEY", ) - client.monitors.pull_monitor_results( + client.event_monitors.pull_monitor_results( monitor_id="monitor_id", ) """ @@ -216,12 +216,12 @@ def pull_monitor_results_csv( """ Returns the most recent run's records as a CSV download. One row per record, with enrichment fields as columns and citations as a JSON column. - If the monitor's reference job used connected entity datasets, connected entities are split into `event_associated_entities` and `mention_entities` JSON columns. When no entity dataset was used, those two columns are omitted from the export entirely. + If the event monitor's reference job used connected entity datasets, connected entities are split into `event_associated_entities` and `mention_entities` JSON columns. When no entity dataset was used, those two columns are omitted from the export entirely. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -229,7 +229,7 @@ def pull_monitor_results_csv( Returns ------- str - CSV export of the latest monitor run. + CSV export of the latest event monitor run. Examples -------- @@ -238,7 +238,7 @@ def pull_monitor_results_csv( client = CatchAllApi( api_key="YOUR_API_KEY", ) - client.monitors.pull_monitor_results_csv( + client.event_monitors.pull_monitor_results_csv( monitor_id="monitor_id", ) """ @@ -253,12 +253,12 @@ def list_monitor_jobs( request_options: typing.Optional[RequestOptions] = None, ) -> ListMonitorJobsResponse: """ - Return all jobs executed by a monitor. + Return all jobs executed by an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. sort : typing.Optional[ListMonitorJobsRequestSort] Sort by start_date (asc or desc). @@ -269,7 +269,7 @@ def list_monitor_jobs( Returns ------- ListMonitorJobsResponse - List of monitor jobs + List of event monitor jobs Examples -------- @@ -278,7 +278,7 @@ def list_monitor_jobs( client = CatchAllApi( api_key="YOUR_API_KEY", ) - client.monitors.list_monitor_jobs( + client.event_monitors.list_monitor_jobs( monitor_id="monitor_id", ) """ @@ -289,12 +289,12 @@ def get_monitor_status_history( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> MonitorStatusHistoryResponseDto: """ - Returns the full execution history of a monitor as a list of status entries, ordered from newest to oldest. + Returns the full execution history of an event monitor as a list of status entries, ordered from newest to oldest. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -302,7 +302,7 @@ def get_monitor_status_history( Returns ------- MonitorStatusHistoryResponseDto - Monitor status history retrieved successfully. + Event monitor status history retrieved successfully. Examples -------- @@ -311,7 +311,7 @@ def get_monitor_status_history( client = CatchAllApi( api_key="YOUR_API_KEY", ) - client.monitors.get_monitor_status_history( + client.event_monitors.get_monitor_status_history( monitor_id="monitor_id", ) """ @@ -326,12 +326,12 @@ def enable_monitor( request_options: typing.Optional[RequestOptions] = None, ) -> EnableMonitorResponse: """ - Resume scheduled job execution for a monitor. + Resume scheduled job execution for an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. backfill : typing.Optional[bool] If true, fills the data gap between the last job's `end_date` and the first scheduled run after enabling. The last job's `end_date` must be within the last 7 days. @@ -344,7 +344,7 @@ def enable_monitor( Returns ------- EnableMonitorResponse - Monitor enabled successfully + Event monitor enabled successfully Examples -------- @@ -353,7 +353,7 @@ def enable_monitor( client = CatchAllApi( api_key="YOUR_API_KEY", ) - client.monitors.enable_monitor( + client.event_monitors.enable_monitor( monitor_id="monitor_id", backfill=True, ) @@ -365,12 +365,12 @@ def disable_monitor( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> DisableMonitorResponse: """ - Stop scheduled job execution for a monitor. + Stop scheduled job execution for an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -378,7 +378,7 @@ def disable_monitor( Returns ------- DisableMonitorResponse - Monitor disabled successfully + Event monitor disabled successfully Examples -------- @@ -387,7 +387,7 @@ def disable_monitor( client = CatchAllApi( api_key="YOUR_API_KEY", ) - client.monitors.disable_monitor( + client.event_monitors.disable_monitor( monitor_id="monitor_id", ) """ @@ -398,19 +398,19 @@ def delete_monitor( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> DeleteMonitorResponseDto: """ - Soft-deletes a monitor. The monitor is flagged as deleted, stops + Soft-deletes an event monitor. The event monitor is flagged as deleted, stops executing scheduled jobs immediately, and no longer appears in list results. - Only the monitor owner can delete a monitor. Returns `404` if the - monitor is not found or does not belong to the authenticated user. + Only the event monitor owner can delete an event monitor. Returns `404` if the + event monitor is not found or does not belong to the authenticated user. - Deleting an already-deleted monitor returns `200`. + Deleting an already-deleted event monitor returns `200`. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -418,7 +418,7 @@ def delete_monitor( Returns ------- DeleteMonitorResponseDto - Monitor deleted successfully (or already deleted). + Event monitor deleted successfully (or already deleted). Examples -------- @@ -427,7 +427,7 @@ def delete_monitor( client = CatchAllApi( api_key="YOUR_API_KEY", ) - client.monitors.delete_monitor( + client.event_monitors.delete_monitor( monitor_id="monitor_id", ) """ @@ -440,23 +440,43 @@ def update_monitor( *, webhook_ids: typing.Optional[typing.Sequence[str]] = OMIT, limit: typing.Optional[int] = OMIT, + schedule: typing.Optional[str] = OMIT, + timezone: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> UpdateMonitorResponseDto: """ - Update the webhook configuration for an existing monitor. + Update the webhook assignments, record limit, or schedule of an existing + event monitor. Omitted fields are left unchanged. + + Passing `schedule` replaces the event monitor's current schedule. The new + schedule takes effect from the next scheduler reload, and the old schedule + stops firing. The reference job cannot be changed. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. webhook_ids : typing.Optional[typing.Sequence[str]] - Updated list of centralized webhook IDs for this monitor. + Updated list of centralized webhook IDs for this event monitor. Replaces all existing webhook assignments. Pass an empty array `[]` to clear all assignments. Omit to leave existing assignments unchanged. limit : typing.Optional[int] - Updated maximum number of records per monitor run. + Updated maximum number of records per event monitor run. + + schedule : typing.Optional[str] + New natural-language schedule that replaces the event monitor's current + schedule. Examples: `every day at 9 AM`, `every Monday at 6 PM EST`. + + Omit to keep the current schedule. The new schedule takes effect from the + next scheduler reload, and the old schedule stops firing. Returns `422` if + the text can't be parsed or runs would be spaced too closely. + + timezone : typing.Optional[str] + IANA timezone for the new schedule (for example, `America/New_York`). + A timezone included in the `schedule` text takes precedence. Ignored if + `schedule` is not set. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -464,7 +484,7 @@ def update_monitor( Returns ------- UpdateMonitorResponseDto - Monitor updated successfully + Event monitor updated successfully Examples -------- @@ -473,29 +493,34 @@ def update_monitor( client = CatchAllApi( api_key="YOUR_API_KEY", ) - client.monitors.update_monitor( + client.event_monitors.update_monitor( monitor_id="monitor_id", webhook_ids=["a1b2c3d4-e5f6-7890-abcd-ef1234567890"], ) """ _response = self._raw_client.update_monitor( - monitor_id, webhook_ids=webhook_ids, limit=limit, request_options=request_options + monitor_id, + webhook_ids=webhook_ids, + limit=limit, + schedule=schedule, + timezone=timezone, + request_options=request_options, ) return _response.data -class AsyncMonitorsClient: +class AsyncEventMonitorsClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._raw_client = AsyncRawMonitorsClient(client_wrapper=client_wrapper) + self._raw_client = AsyncRawEventMonitorsClient(client_wrapper=client_wrapper) @property - def with_raw_response(self) -> AsyncRawMonitorsClient: + def with_raw_response(self) -> AsyncRawEventMonitorsClient: """ Retrieves a raw implementation of this client that returns raw responses. Returns ------- - AsyncRawMonitorsClient + AsyncRawEventMonitorsClient """ return self._raw_client @@ -510,7 +535,7 @@ async def list_monitors( request_options: typing.Optional[RequestOptions] = None, ) -> ListMonitorsResponseDto: """ - Returns all monitors created by the authenticated user. + Returns all event monitors created by the authenticated user. Parameters ---------- @@ -534,7 +559,7 @@ async def list_monitors( Returns ------- ListMonitorsResponseDto - List of user monitors + List of user event monitors Examples -------- @@ -548,7 +573,7 @@ async def list_monitors( async def main() -> None: - await client.monitors.list_monitors( + await client.event_monitors.list_monitors( project_id="60a85db4-78ec-4b78-876a-bc7d9cdadd04", ) @@ -578,17 +603,17 @@ async def create_monitor( request_options: typing.Optional[RequestOptions] = None, ) -> CreateMonitorResponseDto: """ - Create a scheduled monitor based on a reference job. + Create a scheduled event monitor based on a reference job. Parameters ---------- reference_job_id : str Job ID to use as template for scheduled runs. Defines the query, validators, and enrichments used for each scheduled run. - If [`backfill`](https://www.newscatcherapi.com/docs/web-search-api/api-reference/monitors/create-monitor#body-backfill) is true, the job's `end_date` must be within the last 7 days. + If [`backfill`](https://www.newscatcherapi.com/docs/web-search-api/api-reference/event-monitors/create-monitor#body-backfill) is true, the job's `end_date` must be within the last 7 days. schedule : str - Monitor schedule in plain text format. Minimum frequency depends on your plan. + Event monitor schedule in plain text format. Minimum frequency depends on your plan. timezone : typing.Optional[str] The IANA timezone identifier used as the fallback when the `schedule` string does not include an explicit timezone. @@ -599,10 +624,10 @@ async def create_monitor( IDs of centralized webhooks to notify on each run completion. Passing IDs here is equivalent to calling `POST /catchAll/webhooks/{webhook_id}/resources` for each ID after creation. - Maximum 5 per monitor. + Maximum 5 per event monitor. limit : typing.Optional[int] - Maximum number of records per monitor run. If not provided, defaults to the plan limit. + Maximum number of records per event monitor run. If not provided, defaults to the plan limit. backfill : typing.Optional[bool] If true, fills the data gap between the reference job's `end_date` and the first scheduled run. The reference job's `end_date` must be within the last 7 days. @@ -610,7 +635,7 @@ async def create_monitor( If false, no gap filling occurs and the first run uses the current cron window only — the reference job's age does not matter. project_id : typing.Optional[str] - Project to assign this monitor to. The monitor appears in the project's resource list after creation. + Project to assign this event monitor to. The event monitor appears in the project's resource list after creation. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -618,7 +643,7 @@ async def create_monitor( Returns ------- CreateMonitorResponseDto - Monitor created successfully + Event monitor created successfully Examples -------- @@ -632,7 +657,7 @@ async def create_monitor( async def main() -> None: - await client.monitors.create_monitor( + await client.event_monitors.create_monitor( reference_job_id="5f0c9087-85cb-4917-b3c7-e5a5eff73a0c", schedule="every day at 12 PM", timezone="UTC", @@ -660,12 +685,12 @@ async def pull_monitor_results( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> PullMonitorResponseDto: """ - Retrieve aggregated results from all jobs executed by a monitor. + Retrieve aggregated results from all jobs executed by an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -673,7 +698,7 @@ async def pull_monitor_results( Returns ------- PullMonitorResponseDto - Monitor results retrieved successfully + Event monitor results retrieved successfully Examples -------- @@ -687,7 +712,7 @@ async def pull_monitor_results( async def main() -> None: - await client.monitors.pull_monitor_results( + await client.event_monitors.pull_monitor_results( monitor_id="monitor_id", ) @@ -703,12 +728,12 @@ async def pull_monitor_results_csv( """ Returns the most recent run's records as a CSV download. One row per record, with enrichment fields as columns and citations as a JSON column. - If the monitor's reference job used connected entity datasets, connected entities are split into `event_associated_entities` and `mention_entities` JSON columns. When no entity dataset was used, those two columns are omitted from the export entirely. + If the event monitor's reference job used connected entity datasets, connected entities are split into `event_associated_entities` and `mention_entities` JSON columns. When no entity dataset was used, those two columns are omitted from the export entirely. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -716,7 +741,7 @@ async def pull_monitor_results_csv( Returns ------- str - CSV export of the latest monitor run. + CSV export of the latest event monitor run. Examples -------- @@ -730,7 +755,7 @@ async def pull_monitor_results_csv( async def main() -> None: - await client.monitors.pull_monitor_results_csv( + await client.event_monitors.pull_monitor_results_csv( monitor_id="monitor_id", ) @@ -748,12 +773,12 @@ async def list_monitor_jobs( request_options: typing.Optional[RequestOptions] = None, ) -> ListMonitorJobsResponse: """ - Return all jobs executed by a monitor. + Return all jobs executed by an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. sort : typing.Optional[ListMonitorJobsRequestSort] Sort by start_date (asc or desc). @@ -764,7 +789,7 @@ async def list_monitor_jobs( Returns ------- ListMonitorJobsResponse - List of monitor jobs + List of event monitor jobs Examples -------- @@ -778,7 +803,7 @@ async def list_monitor_jobs( async def main() -> None: - await client.monitors.list_monitor_jobs( + await client.event_monitors.list_monitor_jobs( monitor_id="monitor_id", ) @@ -792,12 +817,12 @@ async def get_monitor_status_history( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> MonitorStatusHistoryResponseDto: """ - Returns the full execution history of a monitor as a list of status entries, ordered from newest to oldest. + Returns the full execution history of an event monitor as a list of status entries, ordered from newest to oldest. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -805,7 +830,7 @@ async def get_monitor_status_history( Returns ------- MonitorStatusHistoryResponseDto - Monitor status history retrieved successfully. + Event monitor status history retrieved successfully. Examples -------- @@ -819,7 +844,7 @@ async def get_monitor_status_history( async def main() -> None: - await client.monitors.get_monitor_status_history( + await client.event_monitors.get_monitor_status_history( monitor_id="monitor_id", ) @@ -837,12 +862,12 @@ async def enable_monitor( request_options: typing.Optional[RequestOptions] = None, ) -> EnableMonitorResponse: """ - Resume scheduled job execution for a monitor. + Resume scheduled job execution for an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. backfill : typing.Optional[bool] If true, fills the data gap between the last job's `end_date` and the first scheduled run after enabling. The last job's `end_date` must be within the last 7 days. @@ -855,7 +880,7 @@ async def enable_monitor( Returns ------- EnableMonitorResponse - Monitor enabled successfully + Event monitor enabled successfully Examples -------- @@ -869,7 +894,7 @@ async def enable_monitor( async def main() -> None: - await client.monitors.enable_monitor( + await client.event_monitors.enable_monitor( monitor_id="monitor_id", backfill=True, ) @@ -886,12 +911,12 @@ async def disable_monitor( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> DisableMonitorResponse: """ - Stop scheduled job execution for a monitor. + Stop scheduled job execution for an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -899,7 +924,7 @@ async def disable_monitor( Returns ------- DisableMonitorResponse - Monitor disabled successfully + Event monitor disabled successfully Examples -------- @@ -913,7 +938,7 @@ async def disable_monitor( async def main() -> None: - await client.monitors.disable_monitor( + await client.event_monitors.disable_monitor( monitor_id="monitor_id", ) @@ -927,19 +952,19 @@ async def delete_monitor( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> DeleteMonitorResponseDto: """ - Soft-deletes a monitor. The monitor is flagged as deleted, stops + Soft-deletes an event monitor. The event monitor is flagged as deleted, stops executing scheduled jobs immediately, and no longer appears in list results. - Only the monitor owner can delete a monitor. Returns `404` if the - monitor is not found or does not belong to the authenticated user. + Only the event monitor owner can delete an event monitor. Returns `404` if the + event monitor is not found or does not belong to the authenticated user. - Deleting an already-deleted monitor returns `200`. + Deleting an already-deleted event monitor returns `200`. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -947,7 +972,7 @@ async def delete_monitor( Returns ------- DeleteMonitorResponseDto - Monitor deleted successfully (or already deleted). + Event monitor deleted successfully (or already deleted). Examples -------- @@ -961,7 +986,7 @@ async def delete_monitor( async def main() -> None: - await client.monitors.delete_monitor( + await client.event_monitors.delete_monitor( monitor_id="monitor_id", ) @@ -977,23 +1002,43 @@ async def update_monitor( *, webhook_ids: typing.Optional[typing.Sequence[str]] = OMIT, limit: typing.Optional[int] = OMIT, + schedule: typing.Optional[str] = OMIT, + timezone: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> UpdateMonitorResponseDto: """ - Update the webhook configuration for an existing monitor. + Update the webhook assignments, record limit, or schedule of an existing + event monitor. Omitted fields are left unchanged. + + Passing `schedule` replaces the event monitor's current schedule. The new + schedule takes effect from the next scheduler reload, and the old schedule + stops firing. The reference job cannot be changed. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. webhook_ids : typing.Optional[typing.Sequence[str]] - Updated list of centralized webhook IDs for this monitor. + Updated list of centralized webhook IDs for this event monitor. Replaces all existing webhook assignments. Pass an empty array `[]` to clear all assignments. Omit to leave existing assignments unchanged. limit : typing.Optional[int] - Updated maximum number of records per monitor run. + Updated maximum number of records per event monitor run. + + schedule : typing.Optional[str] + New natural-language schedule that replaces the event monitor's current + schedule. Examples: `every day at 9 AM`, `every Monday at 6 PM EST`. + + Omit to keep the current schedule. The new schedule takes effect from the + next scheduler reload, and the old schedule stops firing. Returns `422` if + the text can't be parsed or runs would be spaced too closely. + + timezone : typing.Optional[str] + IANA timezone for the new schedule (for example, `America/New_York`). + A timezone included in the `schedule` text takes precedence. Ignored if + `schedule` is not set. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1001,7 +1046,7 @@ async def update_monitor( Returns ------- UpdateMonitorResponseDto - Monitor updated successfully + Event monitor updated successfully Examples -------- @@ -1015,7 +1060,7 @@ async def update_monitor( async def main() -> None: - await client.monitors.update_monitor( + await client.event_monitors.update_monitor( monitor_id="monitor_id", webhook_ids=["a1b2c3d4-e5f6-7890-abcd-ef1234567890"], ) @@ -1024,6 +1069,11 @@ async def main() -> None: asyncio.run(main()) """ _response = await self._raw_client.update_monitor( - monitor_id, webhook_ids=webhook_ids, limit=limit, request_options=request_options + monitor_id, + webhook_ids=webhook_ids, + limit=limit, + schedule=schedule, + timezone=timezone, + request_options=request_options, ) return _response.data diff --git a/src/newscatcher_catchall/monitors/raw_client.py b/src/newscatcher_catchall/event_monitors/raw_client.py similarity index 80% rename from src/newscatcher_catchall/monitors/raw_client.py rename to src/newscatcher_catchall/event_monitors/raw_client.py index 3cf5a87..f80f88f 100644 --- a/src/newscatcher_catchall/monitors/raw_client.py +++ b/src/newscatcher_catchall/event_monitors/raw_client.py @@ -33,7 +33,7 @@ OMIT = typing.cast(typing.Any, ...) -class RawMonitorsClient: +class RawEventMonitorsClient: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper @@ -48,7 +48,7 @@ def list_monitors( request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[ListMonitorsResponseDto]: """ - Returns all monitors created by the authenticated user. + Returns all event monitors created by the authenticated user. Parameters ---------- @@ -72,7 +72,7 @@ def list_monitors( Returns ------- HttpResponse[ListMonitorsResponseDto] - List of user monitors + List of user event monitors """ _response = self._client_wrapper.httpx_client.request( "catchAll/monitors", @@ -96,6 +96,17 @@ def list_monitors( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -140,17 +151,17 @@ def create_monitor( request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[CreateMonitorResponseDto]: """ - Create a scheduled monitor based on a reference job. + Create a scheduled event monitor based on a reference job. Parameters ---------- reference_job_id : str Job ID to use as template for scheduled runs. Defines the query, validators, and enrichments used for each scheduled run. - If [`backfill`](https://www.newscatcherapi.com/docs/web-search-api/api-reference/monitors/create-monitor#body-backfill) is true, the job's `end_date` must be within the last 7 days. + If [`backfill`](https://www.newscatcherapi.com/docs/web-search-api/api-reference/event-monitors/create-monitor#body-backfill) is true, the job's `end_date` must be within the last 7 days. schedule : str - Monitor schedule in plain text format. Minimum frequency depends on your plan. + Event monitor schedule in plain text format. Minimum frequency depends on your plan. timezone : typing.Optional[str] The IANA timezone identifier used as the fallback when the `schedule` string does not include an explicit timezone. @@ -161,10 +172,10 @@ def create_monitor( IDs of centralized webhooks to notify on each run completion. Passing IDs here is equivalent to calling `POST /catchAll/webhooks/{webhook_id}/resources` for each ID after creation. - Maximum 5 per monitor. + Maximum 5 per event monitor. limit : typing.Optional[int] - Maximum number of records per monitor run. If not provided, defaults to the plan limit. + Maximum number of records per event monitor run. If not provided, defaults to the plan limit. backfill : typing.Optional[bool] If true, fills the data gap between the reference job's `end_date` and the first scheduled run. The reference job's `end_date` must be within the last 7 days. @@ -172,7 +183,7 @@ def create_monitor( If false, no gap filling occurs and the first run uses the current cron window only — the reference job's age does not matter. project_id : typing.Optional[str] - Project to assign this monitor to. The monitor appears in the project's resource list after creation. + Project to assign this event monitor to. The event monitor appears in the project's resource list after creation. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -180,7 +191,7 @@ def create_monitor( Returns ------- HttpResponse[CreateMonitorResponseDto] - Monitor created successfully + Event monitor created successfully """ _response = self._client_wrapper.httpx_client.request( "catchAll/monitors/create", @@ -210,6 +221,17 @@ def create_monitor( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 422: raise UnprocessableEntityError( headers=dict(_response.headers), @@ -234,12 +256,12 @@ def pull_monitor_results( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[PullMonitorResponseDto]: """ - Retrieve aggregated results from all jobs executed by a monitor. + Retrieve aggregated results from all jobs executed by an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -247,7 +269,7 @@ def pull_monitor_results( Returns ------- HttpResponse[PullMonitorResponseDto] - Monitor results retrieved successfully + Event monitor results retrieved successfully """ _response = self._client_wrapper.httpx_client.request( f"catchAll/monitors/pull/{encode_path_param(monitor_id)}", @@ -264,6 +286,17 @@ def pull_monitor_results( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 404: raise NotFoundError( headers=dict(_response.headers), @@ -301,12 +334,12 @@ def pull_monitor_results_csv( """ Returns the most recent run's records as a CSV download. One row per record, with enrichment fields as columns and citations as a JSON column. - If the monitor's reference job used connected entity datasets, connected entities are split into `event_associated_entities` and `mention_entities` JSON columns. When no entity dataset was used, those two columns are omitted from the export entirely. + If the event monitor's reference job used connected entity datasets, connected entities are split into `event_associated_entities` and `mention_entities` JSON columns. When no entity dataset was used, those two columns are omitted from the export entirely. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -314,7 +347,7 @@ def pull_monitor_results_csv( Returns ------- HttpResponse[str] - CSV export of the latest monitor run. + CSV export of the latest event monitor run. """ _response = self._client_wrapper.httpx_client.request( f"catchAll/monitors/pull/{encode_path_param(monitor_id)}/csv", @@ -324,6 +357,17 @@ def pull_monitor_results_csv( try: if 200 <= _response.status_code < 300: return HttpResponse(response=_response, data=_response.text) # type: ignore + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -363,12 +407,12 @@ def list_monitor_jobs( request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[ListMonitorJobsResponse]: """ - Return all jobs executed by a monitor. + Return all jobs executed by an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. sort : typing.Optional[ListMonitorJobsRequestSort] Sort by start_date (asc or desc). @@ -379,7 +423,7 @@ def list_monitor_jobs( Returns ------- HttpResponse[ListMonitorJobsResponse] - List of monitor jobs + List of event monitor jobs """ _response = self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}/jobs", @@ -399,6 +443,17 @@ def list_monitor_jobs( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 404: raise NotFoundError( headers=dict(_response.headers), @@ -434,12 +489,12 @@ def get_monitor_status_history( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[MonitorStatusHistoryResponseDto]: """ - Returns the full execution history of a monitor as a list of status entries, ordered from newest to oldest. + Returns the full execution history of an event monitor as a list of status entries, ordered from newest to oldest. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -447,7 +502,7 @@ def get_monitor_status_history( Returns ------- HttpResponse[MonitorStatusHistoryResponseDto] - Monitor status history retrieved successfully. + Event monitor status history retrieved successfully. """ _response = self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}/status", @@ -503,12 +558,12 @@ def enable_monitor( request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[EnableMonitorResponse]: """ - Resume scheduled job execution for a monitor. + Resume scheduled job execution for an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. backfill : typing.Optional[bool] If true, fills the data gap between the last job's `end_date` and the first scheduled run after enabling. The last job's `end_date` must be within the last 7 days. @@ -521,7 +576,7 @@ def enable_monitor( Returns ------- HttpResponse[EnableMonitorResponse] - Monitor enabled successfully + Event monitor enabled successfully """ _response = self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}/enable", @@ -545,6 +600,17 @@ def enable_monitor( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -591,12 +657,12 @@ def disable_monitor( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[DisableMonitorResponse]: """ - Stop scheduled job execution for a monitor. + Stop scheduled job execution for an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -604,7 +670,7 @@ def disable_monitor( Returns ------- HttpResponse[DisableMonitorResponse] - Monitor disabled successfully + Event monitor disabled successfully """ _response = self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}/disable", @@ -621,6 +687,17 @@ def disable_monitor( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -667,19 +744,19 @@ def delete_monitor( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> HttpResponse[DeleteMonitorResponseDto]: """ - Soft-deletes a monitor. The monitor is flagged as deleted, stops + Soft-deletes an event monitor. The event monitor is flagged as deleted, stops executing scheduled jobs immediately, and no longer appears in list results. - Only the monitor owner can delete a monitor. Returns `404` if the - monitor is not found or does not belong to the authenticated user. + Only the event monitor owner can delete an event monitor. Returns `404` if the + event monitor is not found or does not belong to the authenticated user. - Deleting an already-deleted monitor returns `200`. + Deleting an already-deleted event monitor returns `200`. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -687,7 +764,7 @@ def delete_monitor( Returns ------- HttpResponse[DeleteMonitorResponseDto] - Monitor deleted successfully (or already deleted). + Event monitor deleted successfully (or already deleted). """ _response = self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}", @@ -741,23 +818,43 @@ def update_monitor( *, webhook_ids: typing.Optional[typing.Sequence[str]] = OMIT, limit: typing.Optional[int] = OMIT, + schedule: typing.Optional[str] = OMIT, + timezone: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[UpdateMonitorResponseDto]: """ - Update the webhook configuration for an existing monitor. + Update the webhook assignments, record limit, or schedule of an existing + event monitor. Omitted fields are left unchanged. + + Passing `schedule` replaces the event monitor's current schedule. The new + schedule takes effect from the next scheduler reload, and the old schedule + stops firing. The reference job cannot be changed. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. webhook_ids : typing.Optional[typing.Sequence[str]] - Updated list of centralized webhook IDs for this monitor. + Updated list of centralized webhook IDs for this event monitor. Replaces all existing webhook assignments. Pass an empty array `[]` to clear all assignments. Omit to leave existing assignments unchanged. limit : typing.Optional[int] - Updated maximum number of records per monitor run. + Updated maximum number of records per event monitor run. + + schedule : typing.Optional[str] + New natural-language schedule that replaces the event monitor's current + schedule. Examples: `every day at 9 AM`, `every Monday at 6 PM EST`. + + Omit to keep the current schedule. The new schedule takes effect from the + next scheduler reload, and the old schedule stops firing. Returns `422` if + the text can't be parsed or runs would be spaced too closely. + + timezone : typing.Optional[str] + IANA timezone for the new schedule (for example, `America/New_York`). + A timezone included in the `schedule` text takes precedence. Ignored if + `schedule` is not set. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -765,7 +862,7 @@ def update_monitor( Returns ------- HttpResponse[UpdateMonitorResponseDto] - Monitor updated successfully + Event monitor updated successfully """ _response = self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}", @@ -773,6 +870,8 @@ def update_monitor( json={ "webhook_ids": webhook_ids, "limit": limit, + "schedule": schedule, + "timezone": timezone, }, headers={ "content-type": "application/json", @@ -790,6 +889,17 @@ def update_monitor( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -833,7 +943,7 @@ def update_monitor( raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) -class AsyncRawMonitorsClient: +class AsyncRawEventMonitorsClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper @@ -848,7 +958,7 @@ async def list_monitors( request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[ListMonitorsResponseDto]: """ - Returns all monitors created by the authenticated user. + Returns all event monitors created by the authenticated user. Parameters ---------- @@ -872,7 +982,7 @@ async def list_monitors( Returns ------- AsyncHttpResponse[ListMonitorsResponseDto] - List of user monitors + List of user event monitors """ _response = await self._client_wrapper.httpx_client.request( "catchAll/monitors", @@ -896,6 +1006,17 @@ async def list_monitors( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -940,17 +1061,17 @@ async def create_monitor( request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[CreateMonitorResponseDto]: """ - Create a scheduled monitor based on a reference job. + Create a scheduled event monitor based on a reference job. Parameters ---------- reference_job_id : str Job ID to use as template for scheduled runs. Defines the query, validators, and enrichments used for each scheduled run. - If [`backfill`](https://www.newscatcherapi.com/docs/web-search-api/api-reference/monitors/create-monitor#body-backfill) is true, the job's `end_date` must be within the last 7 days. + If [`backfill`](https://www.newscatcherapi.com/docs/web-search-api/api-reference/event-monitors/create-monitor#body-backfill) is true, the job's `end_date` must be within the last 7 days. schedule : str - Monitor schedule in plain text format. Minimum frequency depends on your plan. + Event monitor schedule in plain text format. Minimum frequency depends on your plan. timezone : typing.Optional[str] The IANA timezone identifier used as the fallback when the `schedule` string does not include an explicit timezone. @@ -961,10 +1082,10 @@ async def create_monitor( IDs of centralized webhooks to notify on each run completion. Passing IDs here is equivalent to calling `POST /catchAll/webhooks/{webhook_id}/resources` for each ID after creation. - Maximum 5 per monitor. + Maximum 5 per event monitor. limit : typing.Optional[int] - Maximum number of records per monitor run. If not provided, defaults to the plan limit. + Maximum number of records per event monitor run. If not provided, defaults to the plan limit. backfill : typing.Optional[bool] If true, fills the data gap between the reference job's `end_date` and the first scheduled run. The reference job's `end_date` must be within the last 7 days. @@ -972,7 +1093,7 @@ async def create_monitor( If false, no gap filling occurs and the first run uses the current cron window only — the reference job's age does not matter. project_id : typing.Optional[str] - Project to assign this monitor to. The monitor appears in the project's resource list after creation. + Project to assign this event monitor to. The event monitor appears in the project's resource list after creation. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -980,7 +1101,7 @@ async def create_monitor( Returns ------- AsyncHttpResponse[CreateMonitorResponseDto] - Monitor created successfully + Event monitor created successfully """ _response = await self._client_wrapper.httpx_client.request( "catchAll/monitors/create", @@ -1010,6 +1131,17 @@ async def create_monitor( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 422: raise UnprocessableEntityError( headers=dict(_response.headers), @@ -1034,12 +1166,12 @@ async def pull_monitor_results( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[PullMonitorResponseDto]: """ - Retrieve aggregated results from all jobs executed by a monitor. + Retrieve aggregated results from all jobs executed by an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1047,7 +1179,7 @@ async def pull_monitor_results( Returns ------- AsyncHttpResponse[PullMonitorResponseDto] - Monitor results retrieved successfully + Event monitor results retrieved successfully """ _response = await self._client_wrapper.httpx_client.request( f"catchAll/monitors/pull/{encode_path_param(monitor_id)}", @@ -1064,6 +1196,17 @@ async def pull_monitor_results( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 404: raise NotFoundError( headers=dict(_response.headers), @@ -1101,12 +1244,12 @@ async def pull_monitor_results_csv( """ Returns the most recent run's records as a CSV download. One row per record, with enrichment fields as columns and citations as a JSON column. - If the monitor's reference job used connected entity datasets, connected entities are split into `event_associated_entities` and `mention_entities` JSON columns. When no entity dataset was used, those two columns are omitted from the export entirely. + If the event monitor's reference job used connected entity datasets, connected entities are split into `event_associated_entities` and `mention_entities` JSON columns. When no entity dataset was used, those two columns are omitted from the export entirely. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1114,7 +1257,7 @@ async def pull_monitor_results_csv( Returns ------- AsyncHttpResponse[str] - CSV export of the latest monitor run. + CSV export of the latest event monitor run. """ _response = await self._client_wrapper.httpx_client.request( f"catchAll/monitors/pull/{encode_path_param(monitor_id)}/csv", @@ -1124,6 +1267,17 @@ async def pull_monitor_results_csv( try: if 200 <= _response.status_code < 300: return AsyncHttpResponse(response=_response, data=_response.text) # type: ignore + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1163,12 +1317,12 @@ async def list_monitor_jobs( request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[ListMonitorJobsResponse]: """ - Return all jobs executed by a monitor. + Return all jobs executed by an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. sort : typing.Optional[ListMonitorJobsRequestSort] Sort by start_date (asc or desc). @@ -1179,7 +1333,7 @@ async def list_monitor_jobs( Returns ------- AsyncHttpResponse[ListMonitorJobsResponse] - List of monitor jobs + List of event monitor jobs """ _response = await self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}/jobs", @@ -1199,6 +1353,17 @@ async def list_monitor_jobs( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 404: raise NotFoundError( headers=dict(_response.headers), @@ -1234,12 +1399,12 @@ async def get_monitor_status_history( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[MonitorStatusHistoryResponseDto]: """ - Returns the full execution history of a monitor as a list of status entries, ordered from newest to oldest. + Returns the full execution history of an event monitor as a list of status entries, ordered from newest to oldest. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1247,7 +1412,7 @@ async def get_monitor_status_history( Returns ------- AsyncHttpResponse[MonitorStatusHistoryResponseDto] - Monitor status history retrieved successfully. + Event monitor status history retrieved successfully. """ _response = await self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}/status", @@ -1303,12 +1468,12 @@ async def enable_monitor( request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[EnableMonitorResponse]: """ - Resume scheduled job execution for a monitor. + Resume scheduled job execution for an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. backfill : typing.Optional[bool] If true, fills the data gap between the last job's `end_date` and the first scheduled run after enabling. The last job's `end_date` must be within the last 7 days. @@ -1321,7 +1486,7 @@ async def enable_monitor( Returns ------- AsyncHttpResponse[EnableMonitorResponse] - Monitor enabled successfully + Event monitor enabled successfully """ _response = await self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}/enable", @@ -1345,6 +1510,17 @@ async def enable_monitor( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1391,12 +1567,12 @@ async def disable_monitor( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[DisableMonitorResponse]: """ - Stop scheduled job execution for a monitor. + Stop scheduled job execution for an event monitor. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1404,7 +1580,7 @@ async def disable_monitor( Returns ------- AsyncHttpResponse[DisableMonitorResponse] - Monitor disabled successfully + Event monitor disabled successfully """ _response = await self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}/disable", @@ -1421,6 +1597,17 @@ async def disable_monitor( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1467,19 +1654,19 @@ async def delete_monitor( self, monitor_id: str, *, request_options: typing.Optional[RequestOptions] = None ) -> AsyncHttpResponse[DeleteMonitorResponseDto]: """ - Soft-deletes a monitor. The monitor is flagged as deleted, stops + Soft-deletes an event monitor. The event monitor is flagged as deleted, stops executing scheduled jobs immediately, and no longer appears in list results. - Only the monitor owner can delete a monitor. Returns `404` if the - monitor is not found or does not belong to the authenticated user. + Only the event monitor owner can delete an event monitor. Returns `404` if the + event monitor is not found or does not belong to the authenticated user. - Deleting an already-deleted monitor returns `200`. + Deleting an already-deleted event monitor returns `200`. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1487,7 +1674,7 @@ async def delete_monitor( Returns ------- AsyncHttpResponse[DeleteMonitorResponseDto] - Monitor deleted successfully (or already deleted). + Event monitor deleted successfully (or already deleted). """ _response = await self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}", @@ -1541,23 +1728,43 @@ async def update_monitor( *, webhook_ids: typing.Optional[typing.Sequence[str]] = OMIT, limit: typing.Optional[int] = OMIT, + schedule: typing.Optional[str] = OMIT, + timezone: typing.Optional[str] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[UpdateMonitorResponseDto]: """ - Update the webhook configuration for an existing monitor. + Update the webhook assignments, record limit, or schedule of an existing + event monitor. Omitted fields are left unchanged. + + Passing `schedule` replaces the event monitor's current schedule. The new + schedule takes effect from the next scheduler reload, and the old schedule + stops firing. The reference job cannot be changed. Parameters ---------- monitor_id : str - Monitor identifier. + Event monitor identifier. webhook_ids : typing.Optional[typing.Sequence[str]] - Updated list of centralized webhook IDs for this monitor. + Updated list of centralized webhook IDs for this event monitor. Replaces all existing webhook assignments. Pass an empty array `[]` to clear all assignments. Omit to leave existing assignments unchanged. limit : typing.Optional[int] - Updated maximum number of records per monitor run. + Updated maximum number of records per event monitor run. + + schedule : typing.Optional[str] + New natural-language schedule that replaces the event monitor's current + schedule. Examples: `every day at 9 AM`, `every Monday at 6 PM EST`. + + Omit to keep the current schedule. The new schedule takes effect from the + next scheduler reload, and the old schedule stops firing. Returns `422` if + the text can't be parsed or runs would be spaced too closely. + + timezone : typing.Optional[str] + IANA timezone for the new schedule (for example, `America/New_York`). + A timezone included in the `schedule` text takes precedence. Ignored if + `schedule` is not set. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1565,7 +1772,7 @@ async def update_monitor( Returns ------- AsyncHttpResponse[UpdateMonitorResponseDto] - Monitor updated successfully + Event monitor updated successfully """ _response = await self._client_wrapper.httpx_client.request( f"catchAll/monitors/{encode_path_param(monitor_id)}", @@ -1573,6 +1780,8 @@ async def update_monitor( json={ "webhook_ids": webhook_ids, "limit": limit, + "schedule": schedule, + "timezone": timezone, }, headers={ "content-type": "application/json", @@ -1590,6 +1799,17 @@ async def update_monitor( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), diff --git a/src/newscatcher_catchall/monitors/types/__init__.py b/src/newscatcher_catchall/event_monitors/types/__init__.py similarity index 100% rename from src/newscatcher_catchall/monitors/types/__init__.py rename to src/newscatcher_catchall/event_monitors/types/__init__.py diff --git a/src/newscatcher_catchall/monitors/types/disable_monitor_response.py b/src/newscatcher_catchall/event_monitors/types/disable_monitor_response.py similarity index 95% rename from src/newscatcher_catchall/monitors/types/disable_monitor_response.py rename to src/newscatcher_catchall/event_monitors/types/disable_monitor_response.py index b9769cf..7d0e222 100644 --- a/src/newscatcher_catchall/monitors/types/disable_monitor_response.py +++ b/src/newscatcher_catchall/event_monitors/types/disable_monitor_response.py @@ -19,7 +19,7 @@ class DisableMonitorResponse(UniversalBaseModel): monitor_id: str = pydantic.Field() """ - ID of the disabled monitor. + ID of the disabled event monitor. """ if IS_PYDANTIC_V2: diff --git a/src/newscatcher_catchall/monitors/types/enable_monitor_response.py b/src/newscatcher_catchall/event_monitors/types/enable_monitor_response.py similarity index 95% rename from src/newscatcher_catchall/monitors/types/enable_monitor_response.py rename to src/newscatcher_catchall/event_monitors/types/enable_monitor_response.py index d87d0d1..b1ac1ca 100644 --- a/src/newscatcher_catchall/monitors/types/enable_monitor_response.py +++ b/src/newscatcher_catchall/event_monitors/types/enable_monitor_response.py @@ -19,7 +19,7 @@ class EnableMonitorResponse(UniversalBaseModel): monitor_id: str = pydantic.Field() """ - ID of the enabled monitor. + ID of the enabled event monitor. """ if IS_PYDANTIC_V2: diff --git a/src/newscatcher_catchall/monitors/types/list_monitor_jobs_request_sort.py b/src/newscatcher_catchall/event_monitors/types/list_monitor_jobs_request_sort.py similarity index 100% rename from src/newscatcher_catchall/monitors/types/list_monitor_jobs_request_sort.py rename to src/newscatcher_catchall/event_monitors/types/list_monitor_jobs_request_sort.py diff --git a/src/newscatcher_catchall/monitors/types/list_monitor_jobs_response.py b/src/newscatcher_catchall/event_monitors/types/list_monitor_jobs_response.py similarity index 87% rename from src/newscatcher_catchall/monitors/types/list_monitor_jobs_response.py rename to src/newscatcher_catchall/event_monitors/types/list_monitor_jobs_response.py index b8106f6..344b6ea 100644 --- a/src/newscatcher_catchall/monitors/types/list_monitor_jobs_response.py +++ b/src/newscatcher_catchall/event_monitors/types/list_monitor_jobs_response.py @@ -11,7 +11,7 @@ class ListMonitorJobsResponse(UniversalBaseModel): monitor_id: str = pydantic.Field() """ - Monitor identifier. + Event monitor identifier. """ sort_order: ListMonitorJobsResponseSortOrder = pydantic.Field() @@ -21,12 +21,12 @@ class ListMonitorJobsResponse(UniversalBaseModel): total_jobs: int = pydantic.Field() """ - Total number of jobs for this monitor. + Total number of jobs for this event monitor. """ jobs: typing.List[MonitorJobItem] = pydantic.Field() """ - Array of job executions for this monitor. + Array of job executions for this event monitor. """ if IS_PYDANTIC_V2: diff --git a/src/newscatcher_catchall/monitors/types/list_monitor_jobs_response_sort_order.py b/src/newscatcher_catchall/event_monitors/types/list_monitor_jobs_response_sort_order.py similarity index 100% rename from src/newscatcher_catchall/monitors/types/list_monitor_jobs_response_sort_order.py rename to src/newscatcher_catchall/event_monitors/types/list_monitor_jobs_response_sort_order.py diff --git a/src/newscatcher_catchall/jobs/client.py b/src/newscatcher_catchall/jobs/client.py index 5e41716..168a2f2 100644 --- a/src/newscatcher_catchall/jobs/client.py +++ b/src/newscatcher_catchall/jobs/client.py @@ -12,6 +12,7 @@ from ..types.entity_association_type import EntityAssociationType from ..types.initialize_response_dto import InitializeResponseDto from ..types.limit import Limit +from ..types.list_source_groups_response_dto import ListSourceGroupsResponseDto from ..types.list_user_jobs_response_dto import ListUserJobsResponseDto from ..types.ownership_filter import OwnershipFilter from ..types.pull_job_response_dto import PullJobResponseDto @@ -213,6 +214,7 @@ def create_job( webhook_ids: typing.Optional[typing.Sequence[str]] = OMIT, fetch_all_watchlist_news: typing.Optional[bool] = OMIT, ed_association_type: typing.Optional[EntityAssociationType] = OMIT, + source_groups: typing.Optional[typing.Sequence[str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> SubmitResponseDto: """ @@ -251,7 +253,7 @@ def create_job( - `lite`: Lightweight extraction with faster processing. Returns titles and citations only. connected_dataset_ids : typing.Optional[typing.Sequence[str]] - Dataset IDs to connect to the job. When provided, this enables Company Watchlist mode — the job returns only events relevant to companies in the connected datasets. To set the minimum relevance threshold, use `ed_score_min`. + Dataset IDs to connect to the job. When provided, this enables Company Monitors mode — the job returns only events relevant to companies in the connected datasets. To set the minimum relevance threshold, use `ed_score_min`. The dataset must have `latest_status: ready` before the job is submitted. Submitting with a non-existent or inaccessible dataset ID returns `400`. @@ -267,7 +269,7 @@ def create_job( IDs of webhooks to notify when the job completes. Maximum 5 per job. fetch_all_watchlist_news : typing.Optional[bool] - When true, retrieves all news for connected Company Watchlist entities + When true, retrieves all news for connected Company Monitors entities without topic filtering. Requires connected_dataset_ids to be set. ed_association_type : typing.Optional[EntityAssociationType] @@ -276,6 +278,13 @@ def create_job( where the entity is merely referenced. Only relevant when connected_dataset_ids is set. + source_groups : typing.Optional[typing.Sequence[str]] + Slugs of source groups to scope fetching to their curated domain allowlists. + + Source groups are named domain lists maintained by NewsCatcher (for example "Top 100 US Finance"). Retrieve the groups available to your organization with [List source groups](https://www.newscatcherapi.com/docs/web-search-api/api-reference/jobs/list-source-groups). + + Domains are resolved when the job runs, so a group's current membership always applies. Maximum 20 groups per job. An unknown or inaccessible slug is rejected at submit time. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -321,6 +330,7 @@ def create_job( webhook_ids=webhook_ids, fetch_all_watchlist_news=fetch_all_watchlist_news, ed_association_type=ed_association_type, + source_groups=source_groups, request_options=request_options, ) return _response.data @@ -515,6 +525,52 @@ def delete_job( _response = self._raw_client.delete_job(job_id, request_options=request_options) return _response.data + def list_source_groups( + self, + *, + page: typing.Optional[int] = None, + page_size: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ListSourceGroupsResponseDto: + """ + Returns a paginated list of source groups visible to your organization. + + A source group is a named, curated domain allowlist maintained by NewsCatcher — for + example "Top 100 US Finance". Pass a group's `slug` in `source_groups` when creating + a job to scope article fetching to that group's domains, instead of maintaining a + long domain list yourself. + + The response covers public groups plus any restricted groups your organization has + been granted access to. Each entry returns `slug`, `name`, and `description`. + + Parameters + ---------- + page : typing.Optional[int] + Page number to retrieve. + + page_size : typing.Optional[int] + Number of source groups per page. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ListSourceGroupsResponseDto + Source groups retrieved successfully. + + Examples + -------- + from newscatcher_catchall import CatchAllApi + + client = CatchAllApi( + api_key="YOUR_API_KEY", + ) + client.jobs.list_source_groups() + """ + _response = self._raw_client.list_source_groups(page=page, page_size=page_size, request_options=request_options) + return _response.data + class AsyncJobsClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): @@ -724,6 +780,7 @@ async def create_job( webhook_ids: typing.Optional[typing.Sequence[str]] = OMIT, fetch_all_watchlist_news: typing.Optional[bool] = OMIT, ed_association_type: typing.Optional[EntityAssociationType] = OMIT, + source_groups: typing.Optional[typing.Sequence[str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> SubmitResponseDto: """ @@ -762,7 +819,7 @@ async def create_job( - `lite`: Lightweight extraction with faster processing. Returns titles and citations only. connected_dataset_ids : typing.Optional[typing.Sequence[str]] - Dataset IDs to connect to the job. When provided, this enables Company Watchlist mode — the job returns only events relevant to companies in the connected datasets. To set the minimum relevance threshold, use `ed_score_min`. + Dataset IDs to connect to the job. When provided, this enables Company Monitors mode — the job returns only events relevant to companies in the connected datasets. To set the minimum relevance threshold, use `ed_score_min`. The dataset must have `latest_status: ready` before the job is submitted. Submitting with a non-existent or inaccessible dataset ID returns `400`. @@ -778,7 +835,7 @@ async def create_job( IDs of webhooks to notify when the job completes. Maximum 5 per job. fetch_all_watchlist_news : typing.Optional[bool] - When true, retrieves all news for connected Company Watchlist entities + When true, retrieves all news for connected Company Monitors entities without topic filtering. Requires connected_dataset_ids to be set. ed_association_type : typing.Optional[EntityAssociationType] @@ -787,6 +844,13 @@ async def create_job( where the entity is merely referenced. Only relevant when connected_dataset_ids is set. + source_groups : typing.Optional[typing.Sequence[str]] + Slugs of source groups to scope fetching to their curated domain allowlists. + + Source groups are named domain lists maintained by NewsCatcher (for example "Top 100 US Finance"). Retrieve the groups available to your organization with [List source groups](https://www.newscatcherapi.com/docs/web-search-api/api-reference/jobs/list-source-groups). + + Domains are resolved when the job runs, so a group's current membership always applies. Maximum 20 groups per job. An unknown or inaccessible slug is rejected at submit time. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -839,6 +903,7 @@ async def main() -> None: webhook_ids=webhook_ids, fetch_all_watchlist_news=fetch_all_watchlist_news, ed_association_type=ed_association_type, + source_groups=source_groups, request_options=request_options, ) return _response.data @@ -1074,3 +1139,59 @@ async def main() -> None: """ _response = await self._raw_client.delete_job(job_id, request_options=request_options) return _response.data + + async def list_source_groups( + self, + *, + page: typing.Optional[int] = None, + page_size: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ListSourceGroupsResponseDto: + """ + Returns a paginated list of source groups visible to your organization. + + A source group is a named, curated domain allowlist maintained by NewsCatcher — for + example "Top 100 US Finance". Pass a group's `slug` in `source_groups` when creating + a job to scope article fetching to that group's domains, instead of maintaining a + long domain list yourself. + + The response covers public groups plus any restricted groups your organization has + been granted access to. Each entry returns `slug`, `name`, and `description`. + + Parameters + ---------- + page : typing.Optional[int] + Page number to retrieve. + + page_size : typing.Optional[int] + Number of source groups per page. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ListSourceGroupsResponseDto + Source groups retrieved successfully. + + Examples + -------- + import asyncio + + from newscatcher_catchall import AsyncCatchAllApi + + client = AsyncCatchAllApi( + api_key="YOUR_API_KEY", + ) + + + async def main() -> None: + await client.jobs.list_source_groups() + + + asyncio.run(main()) + """ + _response = await self._raw_client.list_source_groups( + page=page, page_size=page_size, request_options=request_options + ) + return _response.data diff --git a/src/newscatcher_catchall/jobs/raw_client.py b/src/newscatcher_catchall/jobs/raw_client.py index dd5a500..d9f15db 100644 --- a/src/newscatcher_catchall/jobs/raw_client.py +++ b/src/newscatcher_catchall/jobs/raw_client.py @@ -25,6 +25,7 @@ from ..types.error import Error from ..types.initialize_response_dto import InitializeResponseDto from ..types.limit import Limit +from ..types.list_source_groups_response_dto import ListSourceGroupsResponseDto from ..types.list_user_jobs_response_dto import ListUserJobsResponseDto from ..types.ownership_filter import OwnershipFilter from ..types.pull_job_response_dto import PullJobResponseDto @@ -111,6 +112,17 @@ def get_user_jobs( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -174,6 +186,17 @@ def validate_query( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -263,6 +286,17 @@ def initialize( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -311,6 +345,7 @@ def create_job( webhook_ids: typing.Optional[typing.Sequence[str]] = OMIT, fetch_all_watchlist_news: typing.Optional[bool] = OMIT, ed_association_type: typing.Optional[EntityAssociationType] = OMIT, + source_groups: typing.Optional[typing.Sequence[str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[SubmitResponseDto]: """ @@ -349,7 +384,7 @@ def create_job( - `lite`: Lightweight extraction with faster processing. Returns titles and citations only. connected_dataset_ids : typing.Optional[typing.Sequence[str]] - Dataset IDs to connect to the job. When provided, this enables Company Watchlist mode — the job returns only events relevant to companies in the connected datasets. To set the minimum relevance threshold, use `ed_score_min`. + Dataset IDs to connect to the job. When provided, this enables Company Monitors mode — the job returns only events relevant to companies in the connected datasets. To set the minimum relevance threshold, use `ed_score_min`. The dataset must have `latest_status: ready` before the job is submitted. Submitting with a non-existent or inaccessible dataset ID returns `400`. @@ -365,7 +400,7 @@ def create_job( IDs of webhooks to notify when the job completes. Maximum 5 per job. fetch_all_watchlist_news : typing.Optional[bool] - When true, retrieves all news for connected Company Watchlist entities + When true, retrieves all news for connected Company Monitors entities without topic filtering. Requires connected_dataset_ids to be set. ed_association_type : typing.Optional[EntityAssociationType] @@ -374,6 +409,13 @@ def create_job( where the entity is merely referenced. Only relevant when connected_dataset_ids is set. + source_groups : typing.Optional[typing.Sequence[str]] + Slugs of source groups to scope fetching to their curated domain allowlists. + + Source groups are named domain lists maintained by NewsCatcher (for example "Top 100 US Finance"). Retrieve the groups available to your organization with [List source groups](https://www.newscatcherapi.com/docs/web-search-api/api-reference/jobs/list-source-groups). + + Domains are resolved when the job runs, so a group's current membership always applies. Maximum 20 groups per job. An unknown or inaccessible slug is rejected at submit time. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -404,6 +446,7 @@ def create_job( "webhook_ids": webhook_ids, "fetch_all_watchlist_news": fetch_all_watchlist_news, "ed_association_type": ed_association_type, + "source_groups": source_groups, }, headers={ "content-type": "application/json", @@ -432,6 +475,17 @@ def create_job( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -497,6 +551,17 @@ def get_job_status( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -577,6 +642,17 @@ def get_job_results( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -637,6 +713,17 @@ def get_job_results_csv( try: if 200 <= _response.status_code < 300: return HttpResponse(response=_response, data=_response.text) # type: ignore + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -728,6 +815,17 @@ def continue_job( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -828,6 +926,90 @@ def delete_job( ) raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + def list_source_groups( + self, + *, + page: typing.Optional[int] = None, + page_size: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ListSourceGroupsResponseDto]: + """ + Returns a paginated list of source groups visible to your organization. + + A source group is a named, curated domain allowlist maintained by NewsCatcher — for + example "Top 100 US Finance". Pass a group's `slug` in `source_groups` when creating + a job to scope article fetching to that group's domains, instead of maintaining a + long domain list yourself. + + The response covers public groups plus any restricted groups your organization has + been granted access to. Each entry returns `slug`, `name`, and `description`. + + Parameters + ---------- + page : typing.Optional[int] + Page number to retrieve. + + page_size : typing.Optional[int] + Number of source groups per page. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ListSourceGroupsResponseDto] + Source groups retrieved successfully. + """ + _response = self._client_wrapper.httpx_client.request( + "catchAll/source-groups", + method="GET", + params={ + "page": page, + "page_size": page_size, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ListSourceGroupsResponseDto, + parse_obj_as( + type_=ListSourceGroupsResponseDto, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 422: + raise UnprocessableEntityError( + headers=dict(_response.headers), + body=typing.cast( + ValidationErrorResponse, + parse_obj_as( + type_=ValidationErrorResponse, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + class AsyncRawJobsClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): @@ -897,6 +1079,17 @@ async def get_user_jobs( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -960,6 +1153,17 @@ async def validate_query( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1049,6 +1253,17 @@ async def initialize( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1097,6 +1312,7 @@ async def create_job( webhook_ids: typing.Optional[typing.Sequence[str]] = OMIT, fetch_all_watchlist_news: typing.Optional[bool] = OMIT, ed_association_type: typing.Optional[EntityAssociationType] = OMIT, + source_groups: typing.Optional[typing.Sequence[str]] = OMIT, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[SubmitResponseDto]: """ @@ -1135,7 +1351,7 @@ async def create_job( - `lite`: Lightweight extraction with faster processing. Returns titles and citations only. connected_dataset_ids : typing.Optional[typing.Sequence[str]] - Dataset IDs to connect to the job. When provided, this enables Company Watchlist mode — the job returns only events relevant to companies in the connected datasets. To set the minimum relevance threshold, use `ed_score_min`. + Dataset IDs to connect to the job. When provided, this enables Company Monitors mode — the job returns only events relevant to companies in the connected datasets. To set the minimum relevance threshold, use `ed_score_min`. The dataset must have `latest_status: ready` before the job is submitted. Submitting with a non-existent or inaccessible dataset ID returns `400`. @@ -1151,7 +1367,7 @@ async def create_job( IDs of webhooks to notify when the job completes. Maximum 5 per job. fetch_all_watchlist_news : typing.Optional[bool] - When true, retrieves all news for connected Company Watchlist entities + When true, retrieves all news for connected Company Monitors entities without topic filtering. Requires connected_dataset_ids to be set. ed_association_type : typing.Optional[EntityAssociationType] @@ -1160,6 +1376,13 @@ async def create_job( where the entity is merely referenced. Only relevant when connected_dataset_ids is set. + source_groups : typing.Optional[typing.Sequence[str]] + Slugs of source groups to scope fetching to their curated domain allowlists. + + Source groups are named domain lists maintained by NewsCatcher (for example "Top 100 US Finance"). Retrieve the groups available to your organization with [List source groups](https://www.newscatcherapi.com/docs/web-search-api/api-reference/jobs/list-source-groups). + + Domains are resolved when the job runs, so a group's current membership always applies. Maximum 20 groups per job. An unknown or inaccessible slug is rejected at submit time. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1190,6 +1413,7 @@ async def create_job( "webhook_ids": webhook_ids, "fetch_all_watchlist_news": fetch_all_watchlist_news, "ed_association_type": ed_association_type, + "source_groups": source_groups, }, headers={ "content-type": "application/json", @@ -1218,6 +1442,17 @@ async def create_job( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1283,6 +1518,17 @@ async def get_job_status( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1363,6 +1609,17 @@ async def get_job_results( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1423,6 +1680,17 @@ async def get_job_results_csv( try: if 200 <= _response.status_code < 300: return AsyncHttpResponse(response=_response, data=_response.text) # type: ignore + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1514,6 +1782,17 @@ async def continue_job( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1613,3 +1892,87 @@ async def delete_job( status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e ) raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + async def list_source_groups( + self, + *, + page: typing.Optional[int] = None, + page_size: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ListSourceGroupsResponseDto]: + """ + Returns a paginated list of source groups visible to your organization. + + A source group is a named, curated domain allowlist maintained by NewsCatcher — for + example "Top 100 US Finance". Pass a group's `slug` in `source_groups` when creating + a job to scope article fetching to that group's domains, instead of maintaining a + long domain list yourself. + + The response covers public groups plus any restricted groups your organization has + been granted access to. Each entry returns `slug`, `name`, and `description`. + + Parameters + ---------- + page : typing.Optional[int] + Page number to retrieve. + + page_size : typing.Optional[int] + Number of source groups per page. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ListSourceGroupsResponseDto] + Source groups retrieved successfully. + """ + _response = await self._client_wrapper.httpx_client.request( + "catchAll/source-groups", + method="GET", + params={ + "page": page, + "page_size": page_size, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ListSourceGroupsResponseDto, + parse_obj_as( + type_=ListSourceGroupsResponseDto, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 422: + raise UnprocessableEntityError( + headers=dict(_response.headers), + body=typing.cast( + ValidationErrorResponse, + parse_obj_as( + type_=ValidationErrorResponse, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text) + except ValidationError as e: + raise ParsingError( + status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e + ) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) diff --git a/src/newscatcher_catchall/meta/raw_client.py b/src/newscatcher_catchall/meta/raw_client.py index 607b704..162a078 100644 --- a/src/newscatcher_catchall/meta/raw_client.py +++ b/src/newscatcher_catchall/meta/raw_client.py @@ -10,6 +10,7 @@ from ..core.pydantic_utilities import parse_obj_as from ..core.request_options import RequestOptions from ..errors.forbidden_error import ForbiddenError +from ..errors.unauthorized_error import UnauthorizedError from ..types.error import Error from ..types.get_plan_limits_response_dto import GetPlanLimitsResponseDto from .types.get_version_response import GetVersionResponse @@ -132,6 +133,17 @@ def get_plan_limits( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -268,6 +280,17 @@ async def get_plan_limits( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), diff --git a/src/newscatcher_catchall/projects/client.py b/src/newscatcher_catchall/projects/client.py index 63c96f0..d1460d5 100644 --- a/src/newscatcher_catchall/projects/client.py +++ b/src/newscatcher_catchall/projects/client.py @@ -177,7 +177,7 @@ def delete_project( Unique project identifier. delete_resources : typing.Optional[bool] - If true, permanently deletes all resources (jobs, monitors, datasets, monitor groups) assigned to the project. If false, the project is deleted and its resources are unassigned but not deleted. + If true, permanently deletes all resources (jobs, event monitors, datasets, event monitor groups) assigned to the project. If false, the project is deleted and its resources are unassigned but not deleted. Webhooks are never deleted by either setting — they are only detached from the project. @@ -614,7 +614,7 @@ async def delete_project( Unique project identifier. delete_resources : typing.Optional[bool] - If true, permanently deletes all resources (jobs, monitors, datasets, monitor groups) assigned to the project. If false, the project is deleted and its resources are unassigned but not deleted. + If true, permanently deletes all resources (jobs, event monitors, datasets, event monitor groups) assigned to the project. If false, the project is deleted and its resources are unassigned but not deleted. Webhooks are never deleted by either setting — they are only detached from the project. diff --git a/src/newscatcher_catchall/projects/raw_client.py b/src/newscatcher_catchall/projects/raw_client.py index 5516394..fd10079 100644 --- a/src/newscatcher_catchall/projects/raw_client.py +++ b/src/newscatcher_catchall/projects/raw_client.py @@ -14,6 +14,7 @@ from ..errors.bad_request_error import BadRequestError from ..errors.forbidden_error import ForbiddenError from ..errors.not_found_error import NotFoundError +from ..errors.unauthorized_error import UnauthorizedError from ..errors.unprocessable_entity_error import UnprocessableEntityError from ..types.add_resource_response_dto import AddResourceResponseDto from ..types.create_project_response_dto import CreateProjectResponseDto @@ -92,6 +93,17 @@ def list_projects( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -172,6 +184,17 @@ def create_project( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -237,6 +260,17 @@ def get_project( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -286,7 +320,7 @@ def delete_project( Unique project identifier. delete_resources : typing.Optional[bool] - If true, permanently deletes all resources (jobs, monitors, datasets, monitor groups) assigned to the project. If false, the project is deleted and its resources are unassigned but not deleted. + If true, permanently deletes all resources (jobs, event monitors, datasets, event monitor groups) assigned to the project. If false, the project is deleted and its resources are unassigned but not deleted. Webhooks are never deleted by either setting — they are only detached from the project. @@ -308,6 +342,17 @@ def delete_project( try: if 200 <= _response.status_code < 300: return HttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -392,6 +437,17 @@ def update_project( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -470,6 +526,17 @@ def get_project_overview( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -554,6 +621,17 @@ def list_project_resources( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -657,6 +735,17 @@ def add_resource_to_project( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -733,6 +822,17 @@ def remove_resource_from_project( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -823,6 +923,17 @@ async def list_projects( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -903,6 +1014,17 @@ async def create_project( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -968,6 +1090,17 @@ async def get_project( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1017,7 +1150,7 @@ async def delete_project( Unique project identifier. delete_resources : typing.Optional[bool] - If true, permanently deletes all resources (jobs, monitors, datasets, monitor groups) assigned to the project. If false, the project is deleted and its resources are unassigned but not deleted. + If true, permanently deletes all resources (jobs, event monitors, datasets, event monitor groups) assigned to the project. If false, the project is deleted and its resources are unassigned but not deleted. Webhooks are never deleted by either setting — they are only detached from the project. @@ -1039,6 +1172,17 @@ async def delete_project( try: if 200 <= _response.status_code < 300: return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1123,6 +1267,17 @@ async def update_project( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1201,6 +1356,17 @@ async def get_project_overview( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1285,6 +1451,17 @@ async def list_project_resources( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1388,6 +1565,17 @@ async def add_resource_to_project( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1464,6 +1652,17 @@ async def remove_resource_from_project( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), diff --git a/src/newscatcher_catchall/types/__init__.py b/src/newscatcher_catchall/types/__init__.py index 578c103..0018b87 100644 --- a/src/newscatcher_catchall/types/__init__.py +++ b/src/newscatcher_catchall/types/__init__.py @@ -62,6 +62,7 @@ from .entity_type import EntityType from .entity_validation_error_body import EntityValidationErrorBody from .error import Error + from .event_tags import EventTags from .formatter_config_dto import FormatterConfigDto from .get_plan_limits_response_dto import GetPlanLimitsResponseDto from .get_webhook_response_dto import GetWebhookResponseDto @@ -71,6 +72,7 @@ from .job_step import JobStep from .limit import Limit from .list_monitors_response_dto import ListMonitorsResponseDto + from .list_source_groups_response_dto import ListSourceGroupsResponseDto from .list_user_jobs_response_dto import ListUserJobsResponseDto from .list_webhook_resources_response_dto import ListWebhookResourcesResponseDto from .list_webhooks_response_dto import ListWebhooksResponseDto @@ -111,6 +113,7 @@ from .sharing_info_permission import SharingInfoPermission from .skipped_row import SkippedRow from .sort_order import SortOrder + from .source_group_ref import SourceGroupRef from .start_date import StartDate from .status_response_dto import StatusResponseDto from .submit_response_dto import SubmitResponseDto @@ -196,6 +199,7 @@ "EntityType": ".entity_type", "EntityValidationErrorBody": ".entity_validation_error_body", "Error": ".error", + "EventTags": ".event_tags", "FormatterConfigDto": ".formatter_config_dto", "GetPlanLimitsResponseDto": ".get_plan_limits_response_dto", "GetWebhookResponseDto": ".get_webhook_response_dto", @@ -205,6 +209,7 @@ "JobStep": ".job_step", "Limit": ".limit", "ListMonitorsResponseDto": ".list_monitors_response_dto", + "ListSourceGroupsResponseDto": ".list_source_groups_response_dto", "ListUserJobsResponseDto": ".list_user_jobs_response_dto", "ListWebhookResourcesResponseDto": ".list_webhook_resources_response_dto", "ListWebhooksResponseDto": ".list_webhooks_response_dto", @@ -245,6 +250,7 @@ "SharingInfoPermission": ".sharing_info_permission", "SkippedRow": ".skipped_row", "SortOrder": ".sort_order", + "SourceGroupRef": ".source_group_ref", "StartDate": ".start_date", "StatusResponseDto": ".status_response_dto", "SubmitResponseDto": ".submit_response_dto", @@ -352,6 +358,7 @@ def __dir__(): "EntityType", "EntityValidationErrorBody", "Error", + "EventTags", "FormatterConfigDto", "GetPlanLimitsResponseDto", "GetWebhookResponseDto", @@ -361,6 +368,7 @@ def __dir__(): "JobStep", "Limit", "ListMonitorsResponseDto", + "ListSourceGroupsResponseDto", "ListUserJobsResponseDto", "ListWebhookResourcesResponseDto", "ListWebhooksResponseDto", @@ -401,6 +409,7 @@ def __dir__(): "SharingInfoPermission", "SkippedRow", "SortOrder", + "SourceGroupRef", "StartDate", "StatusResponseDto", "SubmitResponseDto", diff --git a/src/newscatcher_catchall/types/base_record.py b/src/newscatcher_catchall/types/base_record.py index 5b312b1..9eec670 100644 --- a/src/newscatcher_catchall/types/base_record.py +++ b/src/newscatcher_catchall/types/base_record.py @@ -24,7 +24,7 @@ class BaseRecord(UniversalBaseModel): **Note:** The system always includes the `enrichment_confidence` field within the `enrichment` object, regardless of whether enrichments are generated or specified by you. - For integration guidance, see [Dynamic schemas](https://www.newscatcherapi.com/docs/web-search-api/guides-and-concepts/dynamic-schemas) + For integration guidance, see [Dynamic schemas](https://www.newscatcherapi.com/docs/web-search-api/concepts/dynamic-schemas) """ if IS_PYDANTIC_V2: diff --git a/src/newscatcher_catchall/types/base_record_enrichment.py b/src/newscatcher_catchall/types/base_record_enrichment.py index b36c077..63e25c8 100644 --- a/src/newscatcher_catchall/types/base_record_enrichment.py +++ b/src/newscatcher_catchall/types/base_record_enrichment.py @@ -13,7 +13,7 @@ class BaseRecordEnrichment(UniversalBaseModel): **Note:** The system always includes the `enrichment_confidence` field within the `enrichment` object, regardless of whether enrichments are generated or specified by you. - For integration guidance, see [Dynamic schemas](https://www.newscatcherapi.com/docs/web-search-api/guides-and-concepts/dynamic-schemas) + For integration guidance, see [Dynamic schemas](https://www.newscatcherapi.com/docs/web-search-api/concepts/dynamic-schemas) """ enrichment_confidence: typing.Optional[BaseRecordEnrichmentEnrichmentConfidence] = pydantic.Field(default=None) diff --git a/src/newscatcher_catchall/types/connected_dataset.py b/src/newscatcher_catchall/types/connected_dataset.py index 82f0ba5..55f4a9b 100644 --- a/src/newscatcher_catchall/types/connected_dataset.py +++ b/src/newscatcher_catchall/types/connected_dataset.py @@ -8,7 +8,7 @@ class ConnectedDataset(UniversalBaseModel): """ - A dataset used to narrow the retrieval scope of a job or monitor, returned with its identifier and name. + A dataset used to narrow the retrieval scope of a job or event monitor, returned with its identifier and name. """ id: str = pydantic.Field() diff --git a/src/newscatcher_catchall/types/connected_entity.py b/src/newscatcher_catchall/types/connected_entity.py index f5f68f4..a810cb4 100644 --- a/src/newscatcher_catchall/types/connected_entity.py +++ b/src/newscatcher_catchall/types/connected_entity.py @@ -9,7 +9,7 @@ class ConnectedEntity(UniversalBaseModel): """ - A company entity matched to a record in a Company Watchlist job, with a relevance score and explanation. + A company entity matched to a record in a Company Monitors job, with a relevance score and explanation. Only entities with `ed_score` ≥ 1 appear in results. Entities scored 0 are filtered out before the response is returned. When `ed_score_min` is set at submission time, entities below that threshold are excluded. """ diff --git a/src/newscatcher_catchall/types/create_entity_request.py b/src/newscatcher_catchall/types/create_entity_request.py index b5f92fd..97c8722 100644 --- a/src/newscatcher_catchall/types/create_entity_request.py +++ b/src/newscatcher_catchall/types/create_entity_request.py @@ -24,7 +24,7 @@ class CreateEntityRequest(UniversalBaseModel): entity_type: typing.Optional[EntityType] = None description: typing.Optional[str] = pydantic.Field(default=None) """ - Free-text description of the entity used for disambiguation when similar names exist. See [Writing effective descriptions](https://www.newscatcherapi.com/docs/web-search-api/concepts/company-search#writing-effective-descriptions) for guidance on improving matching quality. + Free-text description of the entity used for disambiguation when similar names exist. See [Writing effective descriptions](https://www.newscatcherapi.com/docs/web-search-api/concepts/company-monitors#writing-effective-descriptions) for guidance on improving matching quality. """ external_entity_id: typing.Optional[str] = pydantic.Field(default=None) diff --git a/src/newscatcher_catchall/types/create_monitor_response_dto.py b/src/newscatcher_catchall/types/create_monitor_response_dto.py index 4ca8f67..6079574 100644 --- a/src/newscatcher_catchall/types/create_monitor_response_dto.py +++ b/src/newscatcher_catchall/types/create_monitor_response_dto.py @@ -9,7 +9,7 @@ class CreateMonitorResponseDto(UniversalBaseModel): monitor_id: typing.Optional[str] = pydantic.Field(default=None) """ - Monitor ID if successful, null if error. + Event monitor ID if successful, null if error. """ status: str = pydantic.Field() diff --git a/src/newscatcher_catchall/types/delete_monitor_response_dto.py b/src/newscatcher_catchall/types/delete_monitor_response_dto.py index b30b7c9..f3c7032 100644 --- a/src/newscatcher_catchall/types/delete_monitor_response_dto.py +++ b/src/newscatcher_catchall/types/delete_monitor_response_dto.py @@ -19,7 +19,7 @@ class DeleteMonitorResponseDto(UniversalBaseModel): monitor_id: typing.Optional[str] = pydantic.Field(default=None) """ - ID of the deleted monitor. `null` on failure. + ID of the deleted event monitor. `null` on failure. """ if IS_PYDANTIC_V2: diff --git a/src/newscatcher_catchall/types/delivery_history_item_dto.py b/src/newscatcher_catchall/types/delivery_history_item_dto.py index 41aca71..a028a8d 100644 --- a/src/newscatcher_catchall/types/delivery_history_item_dto.py +++ b/src/newscatcher_catchall/types/delivery_history_item_dto.py @@ -32,7 +32,7 @@ class DeliveryHistoryItemDto(UniversalBaseModel): additional_info: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(default=None) """ - Extra context about the triggering event, such as job query or monitor schedule. + Extra context about the triggering event, such as job query or event monitor schedule. """ status_code: int = pydantic.Field() diff --git a/src/newscatcher_catchall/types/event_tags.py b/src/newscatcher_catchall/types/event_tags.py new file mode 100644 index 0000000..4fcbe2b --- /dev/null +++ b/src/newscatcher_catchall/types/event_tags.py @@ -0,0 +1,37 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class EventTags(UniversalBaseModel): + """ + Fixed-taxonomy classification of the event described by a record. + + Tagging is additive: it never filters or removes records. A record the classifier + cannot place is still returned, with `unclassifiable` or `other_sector` in place of + a taxonomy value. + """ + + event_type: typing.Optional[str] = pydantic.Field(default=None) + """ + Taxonomy path describing what happened, drawn from a fixed vocabulary. + `unclassifiable` when no path fits. + """ + + sector: typing.Optional[str] = pydantic.Field(default=None) + """ + Industry sector the event belongs to, drawn from a fixed vocabulary. + `other_sector` when no sector fits. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/newscatcher_catchall/types/list_monitors_response_dto.py b/src/newscatcher_catchall/types/list_monitors_response_dto.py index 1828dcb..ddc4aa8 100644 --- a/src/newscatcher_catchall/types/list_monitors_response_dto.py +++ b/src/newscatcher_catchall/types/list_monitors_response_dto.py @@ -10,7 +10,7 @@ class ListMonitorsResponseDto(UniversalBaseModel): total: int = pydantic.Field() """ - Total number of monitors for this user. + Total number of event monitors for this user. """ page: int = pydantic.Field() @@ -20,7 +20,7 @@ class ListMonitorsResponseDto(UniversalBaseModel): page_size: int = pydantic.Field() """ - Number of monitors per page. + Number of event monitors per page. """ total_pages: int = pydantic.Field() @@ -30,7 +30,7 @@ class ListMonitorsResponseDto(UniversalBaseModel): monitors: typing.List[MonitorListItemDto] = pydantic.Field() """ - Array of monitor summaries. + Array of event monitor summaries. """ if IS_PYDANTIC_V2: diff --git a/src/newscatcher_catchall/types/list_source_groups_response_dto.py b/src/newscatcher_catchall/types/list_source_groups_response_dto.py new file mode 100644 index 0000000..35dfb3c --- /dev/null +++ b/src/newscatcher_catchall/types/list_source_groups_response_dto.py @@ -0,0 +1,38 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .source_group_ref import SourceGroupRef + + +class ListSourceGroupsResponseDto(UniversalBaseModel): + source_groups: typing.List[SourceGroupRef] = pydantic.Field() + """ + Source groups visible to your organization. + """ + + total: int = pydantic.Field() + """ + Total number of source groups available to your organization. + """ + + page: int = pydantic.Field() + """ + The current page number. + """ + + page_size: int = pydantic.Field() + """ + The number of source groups per page. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/newscatcher_catchall/types/monitor_citation.py b/src/newscatcher_catchall/types/monitor_citation.py index 074087f..ee9239b 100644 --- a/src/newscatcher_catchall/types/monitor_citation.py +++ b/src/newscatcher_catchall/types/monitor_citation.py @@ -10,7 +10,7 @@ class MonitorCitation(Citation): """ - Citation with monitor-specific metadata. Used in monitor results and webhook payloads. + Citation with event monitor-specific metadata. Used in event monitor results and webhook payloads. Extends base citation with tracking information for job_id and timestamps. """ diff --git a/src/newscatcher_catchall/types/monitor_job_item.py b/src/newscatcher_catchall/types/monitor_job_item.py index 6277e83..7f4642c 100644 --- a/src/newscatcher_catchall/types/monitor_job_item.py +++ b/src/newscatcher_catchall/types/monitor_job_item.py @@ -15,12 +15,12 @@ class MonitorJobItem(UniversalBaseModel): start_date: dt.datetime = pydantic.Field() """ - Start of the data collection time window for this job execution (based on monitor schedule) in ISO 8601 format with UTC timezone. + Start of the data collection time window for this job execution (based on event monitor schedule) in ISO 8601 format with UTC timezone. """ end_date: dt.datetime = pydantic.Field() """ - End of the data collection time window for this job execution (based on monitor schedule) in ISO 8601 format with UTC timezone. + End of the data collection time window for this job execution (based on event monitor schedule) in ISO 8601 format with UTC timezone. """ if IS_PYDANTIC_V2: diff --git a/src/newscatcher_catchall/types/monitor_list_item_dto.py b/src/newscatcher_catchall/types/monitor_list_item_dto.py index 89be2f2..14a2934 100644 --- a/src/newscatcher_catchall/types/monitor_list_item_dto.py +++ b/src/newscatcher_catchall/types/monitor_list_item_dto.py @@ -12,12 +12,12 @@ class MonitorListItemDto(UniversalBaseModel): monitor_id: str = pydantic.Field() """ - Monitor identifier. + Event monitor identifier. """ reference_job_id: str = pydantic.Field() """ - Job identifier used as a reference for this monitor. + Job identifier used as a reference for this event monitor. """ reference_job_query: str = pydantic.Field() @@ -27,17 +27,17 @@ class MonitorListItemDto(UniversalBaseModel): enabled: bool = pydantic.Field() """ - True if the monitor is currently active; false otherwise. + True if the event monitor is currently active; false otherwise. """ schedule: typing.Optional[str] = pydantic.Field(default=None) """ - Cron expression for monitor schedule. + Cron expression for event monitor schedule. """ schedule_human_readable: typing.Optional[str] = pydantic.Field(default=None) """ - The monitor schedule in a plain text format. + The event monitor schedule in a plain text format. """ timezone: typing.Optional[str] = pydantic.Field(default=None) @@ -47,22 +47,22 @@ class MonitorListItemDto(UniversalBaseModel): created_at: typing.Optional[dt.datetime] = pydantic.Field(default=None) """ - The date when the monitor was created. + The date when the event monitor was created. """ webhook: typing.Optional[WebhookDto] = pydantic.Field(default=None) """ - Webhook configuration for this monitor, or null if not set. + Webhook configuration for this event monitor, or null if not set. """ user_key: typing.Optional[str] = pydantic.Field(default=None) """ - Masked API key associated with this monitor. + Masked API key associated with this event monitor. """ sharing_info: typing.Optional[SharingInfo] = pydantic.Field(default=None) """ - Present when this monitor was shared with the authenticated user. Omitted when the user owns the monitor. + Present when this event monitor was shared with the authenticated user. Omitted when the user owns the event monitor. """ if IS_PYDANTIC_V2: diff --git a/src/newscatcher_catchall/types/monitor_record.py b/src/newscatcher_catchall/types/monitor_record.py index 0449771..0491c1a 100644 --- a/src/newscatcher_catchall/types/monitor_record.py +++ b/src/newscatcher_catchall/types/monitor_record.py @@ -11,24 +11,24 @@ class MonitorRecord(BaseRecord): """ - Record with monitor-specific metadata. Used in monitor results and webhook payloads. + Record with event monitor-specific metadata. Used in event monitor results and webhook payloads. Includes timestamps tracking when records were added and updated, and citations include job tracking. """ citations: typing.List[MonitorCitation] = pydantic.Field() """ - Source documents with monitor-specific metadata (job_id, added_on timestamps). + Source documents with event monitor-specific metadata (job_id, added_on timestamps). """ added_on: typing.Optional[dt.datetime] = pydantic.Field(default=None) """ - The date when this record was first added to monitor results in ISO 8601 format with UTC timezone. + The date when this record was first added to event monitor results in ISO 8601 format with UTC timezone. """ updated_on: typing.Optional[dt.datetime] = pydantic.Field(default=None) """ - The date when this record was last updated in monitor results in ISO 8601 format with UTC timezone. + The date when this record was last updated in event monitor results in ISO 8601 format with UTC timezone. """ if IS_PYDANTIC_V2: diff --git a/src/newscatcher_catchall/types/monitor_status_entry.py b/src/newscatcher_catchall/types/monitor_status_entry.py index 8d4f7c6..9a442fe 100644 --- a/src/newscatcher_catchall/types/monitor_status_entry.py +++ b/src/newscatcher_catchall/types/monitor_status_entry.py @@ -13,9 +13,9 @@ class MonitorStatusEntry(UniversalBaseModel): """ Type of lifecycle event. - - `created`: Monitor was created. - - `enable`: Monitor was enabled. - - `disable`: Monitor was disabled. + - `created`: Event monitor was created. + - `enable`: Event monitor was enabled. + - `disable`: Event monitor was disabled. - `scheduled`: A job was triggered for execution. `additional_information` contains `job_id`, `start_date`, and `end_date`. @@ -54,7 +54,7 @@ class MonitorStatusEntry(UniversalBaseModel): } } ``` - The `webhook` key is only present if the monitor has a webhook configured. + The `webhook` key is only present if the event monitor has a webhook configured. """ if IS_PYDANTIC_V2: diff --git a/src/newscatcher_catchall/types/monitor_status_history_response_dto.py b/src/newscatcher_catchall/types/monitor_status_history_response_dto.py index c8891fd..d6a81f9 100644 --- a/src/newscatcher_catchall/types/monitor_status_history_response_dto.py +++ b/src/newscatcher_catchall/types/monitor_status_history_response_dto.py @@ -20,7 +20,7 @@ class MonitorStatusHistoryResponseDto(UniversalBaseModel): monitor_id: typing.Optional[str] = pydantic.Field(default=None) """ - Monitor identifier. `null` on failure. + Event monitor identifier. `null` on failure. """ total_statuses: typing.Optional[int] = pydantic.Field(default=None) diff --git a/src/newscatcher_catchall/types/pull_job_response_dto.py b/src/newscatcher_catchall/types/pull_job_response_dto.py index b9da2e5..0073a56 100644 --- a/src/newscatcher_catchall/types/pull_job_response_dto.py +++ b/src/newscatcher_catchall/types/pull_job_response_dto.py @@ -9,6 +9,7 @@ from .pull_job_response_dto_mode import PullJobResponseDtoMode from .record import Record from .sharing_info import SharingInfo +from .source_group_ref import SourceGroupRef class PullJobResponseDto(UniversalBaseModel): @@ -100,6 +101,12 @@ class PullJobResponseDto(UniversalBaseModel): Datasets used to narrow retrieval scope, each with `id` and `name`. """ + source_groups: typing.Optional[typing.List[SourceGroupRef]] = pydantic.Field(default=None) + """ + Source groups attached to this job, each with `slug`, `name`, and `description`. + `null` when the job was not scoped to any source group. + """ + is_all_news_query: typing.Optional[bool] = pydantic.Field(default=None) """ True when the query was submitted as an all-news (watchlist-generic) query. diff --git a/src/newscatcher_catchall/types/pull_monitor_response_dto.py b/src/newscatcher_catchall/types/pull_monitor_response_dto.py index 12d58a7..26e39d4 100644 --- a/src/newscatcher_catchall/types/pull_monitor_response_dto.py +++ b/src/newscatcher_catchall/types/pull_monitor_response_dto.py @@ -13,12 +13,12 @@ class PullMonitorResponseDto(UniversalBaseModel): monitor_id: str = pydantic.Field() """ - Unique identifier for the monitor. + Unique identifier for the event monitor. """ cron_expression: typing.Optional[str] = pydantic.Field(default=None) """ - The cron expression for a monitor schedule parsed from the text schedule you provide. + The cron expression for an event monitor schedule parsed from the text schedule you provide. Standard cron format (minute hour day month day-of-week). """ @@ -31,27 +31,27 @@ class PullMonitorResponseDto(UniversalBaseModel): reference_job: ReferenceJob run_info: typing.Optional[PullMonitorResponseDtoRunInfo] = pydantic.Field(default=None) """ - Execution time range for this monitor. + Execution time range for this event monitor. """ records: typing.Optional[int] = pydantic.Field(default=None) """ - Total number of records collected across all monitor jobs. + Total number of records collected across all event monitor jobs. """ status: str = pydantic.Field() """ - Current monitor status or error message if monitor creation failed. + Current event monitor status or error message if event monitor creation failed. """ all_records: typing.Optional[typing.List[MonitorRecord]] = pydantic.Field(default=None) """ - Aggregated records from all jobs executed by this monitor. Each record includes structured data extracted from web sources with citations. + Aggregated records from all jobs executed by this event monitor. Each record includes structured data extracted from web sources with citations. """ limit: typing.Optional[int] = pydantic.Field(default=None) """ - Record limit applied to this monitor's jobs. + Record limit applied to this event monitor's jobs. """ connected_datasets: typing.Optional[typing.List[ConnectedDataset]] = pydantic.Field(default=None) diff --git a/src/newscatcher_catchall/types/pull_monitor_response_dto_run_info.py b/src/newscatcher_catchall/types/pull_monitor_response_dto_run_info.py index e439b16..28270d2 100644 --- a/src/newscatcher_catchall/types/pull_monitor_response_dto_run_info.py +++ b/src/newscatcher_catchall/types/pull_monitor_response_dto_run_info.py @@ -9,7 +9,7 @@ class PullMonitorResponseDtoRunInfo(UniversalBaseModel): """ - Execution time range for this monitor. + Execution time range for this event monitor. """ first_run: typing.Optional[dt.datetime] = pydantic.Field(default=None) diff --git a/src/newscatcher_catchall/types/record.py b/src/newscatcher_catchall/types/record.py index 01df0fd..ab9828e 100644 --- a/src/newscatcher_catchall/types/record.py +++ b/src/newscatcher_catchall/types/record.py @@ -7,6 +7,7 @@ from .base_record import BaseRecord from .citation import Citation from .connected_entity import ConnectedEntity +from .event_tags import EventTags class Record(BaseRecord): @@ -21,6 +22,15 @@ class Record(BaseRecord): Only present when the job was submitted with `connected_dataset_ids`. """ + tags: typing.Optional[EventTags] = pydantic.Field(default=None) + """ + Fixed-taxonomy classification of the event, as `event_type` and `sector`. + + Only present for all-news watchlist jobs — those submitted with + `fetch_all_watchlist_news: true`, which the job pull response reports as + `is_all_news_query: true`. Absent or `null` for every other job. + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/newscatcher_catchall/types/reference_job.py b/src/newscatcher_catchall/types/reference_job.py index ec4e28e..94c4c84 100644 --- a/src/newscatcher_catchall/types/reference_job.py +++ b/src/newscatcher_catchall/types/reference_job.py @@ -4,6 +4,7 @@ import pydantic from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .source_group_ref import SourceGroupRef class ReferenceJob(UniversalBaseModel): @@ -17,6 +18,12 @@ class ReferenceJob(UniversalBaseModel): Context provided with the reference job query. """ + source_groups: typing.Optional[typing.List[SourceGroupRef]] = pydantic.Field(default=None) + """ + Source groups attached to the reference job, each with `slug`, `name`, and + `description`. `null` when the reference job was not scoped to any source group. + """ + if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 else: diff --git a/src/newscatcher_catchall/types/source_group_ref.py b/src/newscatcher_catchall/types/source_group_ref.py new file mode 100644 index 0000000..53a7d75 --- /dev/null +++ b/src/newscatcher_catchall/types/source_group_ref.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class SourceGroupRef(UniversalBaseModel): + """ + A source group attached to a job, returned with its slug, name, and description. + + Source groups are curated domain allowlists maintained by NewsCatcher. Attach one + to a job with `source_groups` on job creation to scope fetching to its domains. + """ + + slug: str = pydantic.Field() + """ + Stable identifier for the source group. This is the value you pass in + `source_groups` when creating a job. + """ + + name: str = pydantic.Field() + """ + Human-readable name of the source group. + """ + + description: typing.Optional[str] = pydantic.Field(default=None) + """ + What the group covers, when set. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/src/newscatcher_catchall/types/update_monitor_response_dto.py b/src/newscatcher_catchall/types/update_monitor_response_dto.py index a2dd5ad..bfacf49 100644 --- a/src/newscatcher_catchall/types/update_monitor_response_dto.py +++ b/src/newscatcher_catchall/types/update_monitor_response_dto.py @@ -9,7 +9,7 @@ class UpdateMonitorResponseDto(UniversalBaseModel): monitor_id: str = pydantic.Field() """ - Monitor identifier. + Event monitor identifier. """ status: str = pydantic.Field() diff --git a/src/newscatcher_catchall/types/webhook_payload.py b/src/newscatcher_catchall/types/webhook_payload.py index fa57e07..61d1b65 100644 --- a/src/newscatcher_catchall/types/webhook_payload.py +++ b/src/newscatcher_catchall/types/webhook_payload.py @@ -10,19 +10,19 @@ class WebhookPayload(UniversalBaseModel): """ - **First execution:** The initial webhook after monitor creation includes all records from the reference job, providing immediate access to collected data. + **First execution:** The initial webhook after event monitor creation includes all records from the reference job, providing immediate access to collected data. **Subsequent executions:** Only new records (after deduplication) are included. """ monitor_id: typing.Optional[str] = pydantic.Field(default=None) """ - Monitor identifier. + Event monitor identifier. """ reference_job_id: typing.Optional[str] = pydantic.Field(default=None) """ - Reference job used as template for this monitor. + Reference job used as template for this event monitor. """ latest_job_id: typing.Optional[str] = pydantic.Field(default=None) @@ -37,7 +37,7 @@ class WebhookPayload(UniversalBaseModel): jobs_processed: typing.Optional[int] = pydantic.Field(default=None) """ - Total number of jobs executed by this monitor. + Total number of jobs executed by this event monitor. """ updated_at: typing.Optional[dt.datetime] = pydantic.Field(default=None) @@ -47,7 +47,7 @@ class WebhookPayload(UniversalBaseModel): cron_expression: typing.Optional[str] = pydantic.Field(default=None) """ - Cron expression defining the monitor schedule. + Cron expression defining the event monitor schedule. """ timezone: typing.Optional[str] = pydantic.Field(default=None) @@ -57,7 +57,7 @@ class WebhookPayload(UniversalBaseModel): records: typing.Optional[typing.List[MonitorRecord]] = pydantic.Field(default=None) """ - Array of new records from the latest job execution (includes monitor-specific fields like added_on, updated_on). + Array of new records from the latest job execution (includes event monitor-specific fields like added_on, updated_on). """ if IS_PYDANTIC_V2: diff --git a/src/newscatcher_catchall/webhooks/client.py b/src/newscatcher_catchall/webhooks/client.py index 636e0c4..b95758f 100644 --- a/src/newscatcher_catchall/webhooks/client.py +++ b/src/newscatcher_catchall/webhooks/client.py @@ -46,6 +46,7 @@ def list_webhooks( page: typing.Optional[int] = None, page_size: typing.Optional[int] = None, search: typing.Optional[str] = None, + project_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> ListWebhooksResponseDto: """ @@ -62,6 +63,9 @@ def list_webhooks( search : typing.Optional[str] Filter results by text (case-insensitive substring match). + project_id : typing.Optional[str] + Filter results to resources belonging to this project. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -77,10 +81,12 @@ def list_webhooks( client = CatchAllApi( api_key="YOUR_API_KEY", ) - client.webhooks.list_webhooks() + client.webhooks.list_webhooks( + project_id="60a85db4-78ec-4b78-876a-bc7d9cdadd04", + ) """ _response = self._raw_client.list_webhooks( - page=page, page_size=page_size, search=search, request_options=request_options + page=page, page_size=page_size, search=search, project_id=project_id, request_options=request_options ) return _response.data @@ -224,7 +230,7 @@ def delete_webhook(self, webhook_id: str, *, request_options: typing.Optional[Re """ Permanently deletes a webhook and removes all resource assignments. - Assigned jobs and monitors no longer trigger delivery to this webhook. This operation cannot be undone. + Assigned jobs and event monitors no longer trigger delivery to this webhook. This operation cannot be undone. Parameters ---------- @@ -350,7 +356,7 @@ def test_webhook( """ Sends a test HTTP request to the webhook URL using the webhook's configured method, headers, and auth. Returns the response from the target endpoint. - Use this to verify URL reachability and authentication before attaching the webhook to a live job or monitor. + Use this to verify URL reachability and authentication before attaching the webhook to a live job or event monitor. Parameters ---------- @@ -442,7 +448,7 @@ def assign_webhook_resource( request_options: typing.Optional[RequestOptions] = None, ) -> AssignWebhookResourceResponseDto: """ - Attaches a job, monitor, or monitor group to the webhook. When the + Attaches a job, event monitor, or event monitor group to the webhook. When the resource completes, the webhook receives a delivery. A single webhook can be assigned to multiple resources. Each resource @@ -603,7 +609,7 @@ def trigger_webhook( ) -> None: """ Manually dispatches a webhook delivery for a resource on demand, without - waiting for the next job or monitor cycle. + waiting for the next job or event monitor cycle. Use this to re-deliver results after a failed delivery, replay a specific job's results, or validate a webhook against live data. The webhook must @@ -729,6 +735,7 @@ async def list_webhooks( page: typing.Optional[int] = None, page_size: typing.Optional[int] = None, search: typing.Optional[str] = None, + project_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> ListWebhooksResponseDto: """ @@ -745,6 +752,9 @@ async def list_webhooks( search : typing.Optional[str] Filter results by text (case-insensitive substring match). + project_id : typing.Optional[str] + Filter results to resources belonging to this project. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -765,13 +775,15 @@ async def list_webhooks( async def main() -> None: - await client.webhooks.list_webhooks() + await client.webhooks.list_webhooks( + project_id="60a85db4-78ec-4b78-876a-bc7d9cdadd04", + ) asyncio.run(main()) """ _response = await self._raw_client.list_webhooks( - page=page, page_size=page_size, search=search, request_options=request_options + page=page, page_size=page_size, search=search, project_id=project_id, request_options=request_options ) return _response.data @@ -931,7 +943,7 @@ async def delete_webhook(self, webhook_id: str, *, request_options: typing.Optio """ Permanently deletes a webhook and removes all resource assignments. - Assigned jobs and monitors no longer trigger delivery to this webhook. This operation cannot be undone. + Assigned jobs and event monitors no longer trigger delivery to this webhook. This operation cannot be undone. Parameters ---------- @@ -1073,7 +1085,7 @@ async def test_webhook( """ Sends a test HTTP request to the webhook URL using the webhook's configured method, headers, and auth. Returns the response from the target endpoint. - Use this to verify URL reachability and authentication before attaching the webhook to a live job or monitor. + Use this to verify URL reachability and authentication before attaching the webhook to a live job or event monitor. Parameters ---------- @@ -1181,7 +1193,7 @@ async def assign_webhook_resource( request_options: typing.Optional[RequestOptions] = None, ) -> AssignWebhookResourceResponseDto: """ - Attaches a job, monitor, or monitor group to the webhook. When the + Attaches a job, event monitor, or event monitor group to the webhook. When the resource completes, the webhook receives a delivery. A single webhook can be assigned to multiple resources. Each resource @@ -1366,7 +1378,7 @@ async def trigger_webhook( ) -> None: """ Manually dispatches a webhook delivery for a resource on demand, without - waiting for the next job or monitor cycle. + waiting for the next job or event monitor cycle. Use this to re-deliver results after a failed delivery, replay a specific job's results, or validate a webhook against live data. The webhook must diff --git a/src/newscatcher_catchall/webhooks/raw_client.py b/src/newscatcher_catchall/webhooks/raw_client.py index 407a624..0c8a15e 100644 --- a/src/newscatcher_catchall/webhooks/raw_client.py +++ b/src/newscatcher_catchall/webhooks/raw_client.py @@ -14,6 +14,7 @@ from ..errors.bad_request_error import BadRequestError from ..errors.forbidden_error import ForbiddenError from ..errors.not_found_error import NotFoundError +from ..errors.unauthorized_error import UnauthorizedError from ..errors.unprocessable_entity_error import UnprocessableEntityError from ..types.assign_webhook_resource_response_dto import AssignWebhookResourceResponseDto from ..types.create_webhook_response_dto import CreateWebhookResponseDto @@ -48,6 +49,7 @@ def list_webhooks( page: typing.Optional[int] = None, page_size: typing.Optional[int] = None, search: typing.Optional[str] = None, + project_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[ListWebhooksResponseDto]: """ @@ -64,6 +66,9 @@ def list_webhooks( search : typing.Optional[str] Filter results by text (case-insensitive substring match). + project_id : typing.Optional[str] + Filter results to resources belonging to this project. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -79,6 +84,7 @@ def list_webhooks( "page": page, "page_size": page_size, "search": search, + "project_id": project_id, }, request_options=request_options, ) @@ -92,6 +98,17 @@ def list_webhooks( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -103,6 +120,17 @@ def list_webhooks( ), ), ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 422: raise UnprocessableEntityError( headers=dict(_response.headers), @@ -231,6 +259,17 @@ def create_webhook( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -307,6 +346,17 @@ def get_webhook( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -355,7 +405,7 @@ def delete_webhook( """ Permanently deletes a webhook and removes all resource assignments. - Assigned jobs and monitors no longer trigger delivery to this webhook. This operation cannot be undone. + Assigned jobs and event monitors no longer trigger delivery to this webhook. This operation cannot be undone. Parameters ---------- @@ -377,6 +427,17 @@ def delete_webhook( try: if 200 <= _response.status_code < 300: return HttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -502,6 +563,17 @@ def update_webhook( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -554,7 +626,7 @@ def test_webhook( """ Sends a test HTTP request to the webhook URL using the webhook's configured method, headers, and auth. Returns the response from the target endpoint. - Use this to verify URL reachability and authentication before attaching the webhook to a live job or monitor. + Use this to verify URL reachability and authentication before attaching the webhook to a live job or event monitor. Parameters ---------- @@ -595,6 +667,17 @@ def test_webhook( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -690,6 +773,17 @@ def list_webhook_resources( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -741,7 +835,7 @@ def assign_webhook_resource( request_options: typing.Optional[RequestOptions] = None, ) -> HttpResponse[AssignWebhookResourceResponseDto]: """ - Attaches a job, monitor, or monitor group to the webhook. When the + Attaches a job, event monitor, or event monitor group to the webhook. When the resource completes, the webhook receives a delivery. A single webhook can be assigned to multiple resources. Each resource @@ -800,6 +894,17 @@ def assign_webhook_resource( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -880,6 +985,17 @@ def remove_webhook_resource( try: if 200 <= _response.status_code < 300: return HttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -968,6 +1084,17 @@ def list_webhooks_for_resource( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1021,7 +1148,7 @@ def trigger_webhook( ) -> HttpResponse[None]: """ Manually dispatches a webhook delivery for a resource on demand, without - waiting for the next job or monitor cycle. + waiting for the next job or event monitor cycle. Use this to re-deliver results after a failed delivery, replay a specific job's results, or validate a webhook against live data. The webhook must @@ -1061,6 +1188,17 @@ def trigger_webhook( try: if 200 <= _response.status_code < 300: return HttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1160,6 +1298,17 @@ def get_webhook_delivery_history( ), ) return HttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1213,6 +1362,7 @@ async def list_webhooks( page: typing.Optional[int] = None, page_size: typing.Optional[int] = None, search: typing.Optional[str] = None, + project_id: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[ListWebhooksResponseDto]: """ @@ -1229,6 +1379,9 @@ async def list_webhooks( search : typing.Optional[str] Filter results by text (case-insensitive substring match). + project_id : typing.Optional[str] + Filter results to resources belonging to this project. + request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -1244,6 +1397,7 @@ async def list_webhooks( "page": page, "page_size": page_size, "search": search, + "project_id": project_id, }, request_options=request_options, ) @@ -1257,6 +1411,17 @@ async def list_webhooks( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1268,6 +1433,17 @@ async def list_webhooks( ), ), ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 422: raise UnprocessableEntityError( headers=dict(_response.headers), @@ -1396,6 +1572,17 @@ async def create_webhook( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1472,6 +1659,17 @@ async def get_webhook( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1520,7 +1718,7 @@ async def delete_webhook( """ Permanently deletes a webhook and removes all resource assignments. - Assigned jobs and monitors no longer trigger delivery to this webhook. This operation cannot be undone. + Assigned jobs and event monitors no longer trigger delivery to this webhook. This operation cannot be undone. Parameters ---------- @@ -1542,6 +1740,17 @@ async def delete_webhook( try: if 200 <= _response.status_code < 300: return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1667,6 +1876,17 @@ async def update_webhook( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1719,7 +1939,7 @@ async def test_webhook( """ Sends a test HTTP request to the webhook URL using the webhook's configured method, headers, and auth. Returns the response from the target endpoint. - Use this to verify URL reachability and authentication before attaching the webhook to a live job or monitor. + Use this to verify URL reachability and authentication before attaching the webhook to a live job or event monitor. Parameters ---------- @@ -1760,6 +1980,17 @@ async def test_webhook( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1855,6 +2086,17 @@ async def list_webhook_resources( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -1906,7 +2148,7 @@ async def assign_webhook_resource( request_options: typing.Optional[RequestOptions] = None, ) -> AsyncHttpResponse[AssignWebhookResourceResponseDto]: """ - Attaches a job, monitor, or monitor group to the webhook. When the + Attaches a job, event monitor, or event monitor group to the webhook. When the resource completes, the webhook receives a delivery. A single webhook can be assigned to multiple resources. Each resource @@ -1965,6 +2207,17 @@ async def assign_webhook_resource( ), ), ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -2045,6 +2298,17 @@ async def remove_webhook_resource( try: if 200 <= _response.status_code < 300: return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -2133,6 +2397,17 @@ async def list_webhooks_for_resource( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -2186,7 +2461,7 @@ async def trigger_webhook( ) -> AsyncHttpResponse[None]: """ Manually dispatches a webhook delivery for a resource on demand, without - waiting for the next job or monitor cycle. + waiting for the next job or event monitor cycle. Use this to re-deliver results after a failed delivery, replay a specific job's results, or validate a webhook against live data. The webhook must @@ -2226,6 +2501,17 @@ async def trigger_webhook( try: if 200 <= _response.status_code < 300: return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), @@ -2325,6 +2611,17 @@ async def get_webhook_delivery_history( ), ) return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + Error, + parse_obj_as( + type_=Error, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise ForbiddenError( headers=dict(_response.headers), diff --git a/tests/utils/test_http_client.py b/tests/utils/test_http_client.py index 7634cc0..d120206 100644 --- a/tests/utils/test_http_client.py +++ b/tests/utils/test_http_client.py @@ -11,6 +11,7 @@ HttpClient, _build_url, _should_retry, + drop_content_type_without_body, get_request_body, remove_none_from_dict, ) @@ -121,6 +122,67 @@ def test_explicit_empty_json_body_is_preserved() -> None: assert data_body2 == {} +def test_omitted_body_sends_no_content() -> None: + """A body left at the sentinel was never passed, so nothing is sent. + + This is how an endpoint whose body may be omitted stays bodyless, as opposed to + sending an empty ``{}``. An explicit ``None`` still reaches the wire as ``null``. + """ + omit = cast(Any, ...) + unrelated_request_options: RequestOptions = {"max_retries": 3} + + json_body, data_body = get_request_body(json=omit, data=None, request_options=unrelated_request_options, omit=omit) + assert json_body is None + assert data_body is None + + json_body2, data_body2 = get_request_body( + json=None, data=omit, request_options=unrelated_request_options, omit=omit + ) + assert json_body2 is None + assert data_body2 is None + + # an explicitly passed body is untouched + json_body3, _ = get_request_body(json={"hello": "world"}, data=None, request_options=None, omit=omit) + assert json_body3 == {"hello": "world"} + + +def test_optional_body_sends_no_content_when_every_property_is_omitted() -> None: + """An endpoint that inlines an omittable body sends nothing once every property is omitted. + + The body reaches the client as a dict of sentinels rather than as a single argument, so + ``optional_body`` is what tells the client that an empty result means "no body at all". + """ + omit = cast(Any, ...) + + json_body, data_body = get_request_body( + json={"amount": omit, "source": omit}, data=None, request_options=None, omit=omit, optional_body=True + ) + assert json_body is None + assert data_body is None + + # a body the API requires still goes out as `{}` + required_json_body, _ = get_request_body( + json={"amount": omit, "source": omit}, data=None, request_options=None, omit=omit + ) + assert required_json_body == {} + + # a property the caller did pass keeps the body + populated_json_body, _ = get_request_body( + json={"amount": 1, "source": omit}, data=None, request_options=None, omit=omit, optional_body=True + ) + assert populated_json_body == {"amount": 1} + + # additional body parameters keep the body, since the caller asked for them + with_additional_body_parameters, _ = get_request_body( + json={"amount": omit}, + data=None, + request_options={"additional_body_parameters": {"custom": "value"}}, + omit=omit, + optional_body=True, + ) + assert with_additional_body_parameters == {"custom": "value"} + + def test_json_body_preserves_none_values() -> None: """Test that JSON bodies preserve None values (they become JSON null).""" json_body, data_body = get_request_body( @@ -672,28 +734,20 @@ def _make_response(status_code: int) -> httpx.Response: return httpx.Response(status_code=status_code, content=b"") -@pytest.mark.parametrize( - "status_code", - [408, 409, 429, 500, 501, 502, 503, 504, 599], -) +RETRYABLE_STATUS_CODES = [408, 409, 429, 500, 501, 502, 503, 504, 599] +NON_RETRYABLE_STATUS_CODES = [200, 201, 301, 400, 401, 403, 404] + + +@pytest.mark.parametrize("status_code", RETRYABLE_STATUS_CODES) def test_should_retry_retryable_status_codes(status_code: int) -> None: - """Legacy mode: retries on 408, 409, 429, and all >= 500.""" assert _should_retry(_make_response(status_code)) is True -@pytest.mark.parametrize( - "status_code", - [200, 201, 301, 400, 401, 403, 404], -) +@pytest.mark.parametrize("status_code", NON_RETRYABLE_STATUS_CODES) def test_should_not_retry_non_retryable_status_codes(status_code: int) -> None: assert _should_retry(_make_response(status_code)) is False -def test_should_retry_599_upper_boundary() -> None: - """Legacy mode retries on >= 500, which includes 599.""" - assert _should_retry(_make_response(599)) is True - - # --------------------------------------------------------------------------- # RequestOptions timeout resolution tests (timeout / deprecated timeout_in_seconds) # --------------------------------------------------------------------------- @@ -759,3 +813,33 @@ async def test_async_request_options_timeout_takes_precedence() -> None: ) await http_client.request(path="/test", method="GET", request_options={"timeout": 30, "timeout_in_seconds": 45}) assert dummy_client.last_request_kwargs["timeout"] == 30 + + +def test_drop_content_type_without_body_omits_header_for_bodyless_optional_call() -> None: + """An optional-body endpoint the caller left empty must not advertise a media type. + + `get_request_body` drops the body, but the endpoint still hands over the content type it + would have used, so a server that branches on the header would see a JSON request carrying + nothing at all. + """ + headers = {"content-type": "application/json", "authorization": "Bearer x"} + + assert drop_content_type_without_body(headers, json_body=None, data_body=None, optional_body=True) == { + "authorization": "Bearer x" + } + + +def test_drop_content_type_without_body_keeps_header_when_a_body_is_sent() -> None: + headers = {"content-type": "application/json"} + + assert ( + drop_content_type_without_body(headers, json_body={"amount": 60}, data_body=None, optional_body=True) == headers + ) + assert drop_content_type_without_body(headers, json_body=None, data_body="raw", optional_body=True) == headers + + +def test_drop_content_type_without_body_leaves_required_body_endpoints_alone() -> None: + """Without the opt-in, an endpoint keeps the header it has always sent.""" + headers = {"Content-Type": "application/json"} + + assert drop_content_type_without_body(headers, json_body=None, data_body=None, optional_body=False) == headers