From 11f39b24bc9e564a80d54331575210b1a6907df8 Mon Sep 17 00:00:00 2001 From: "fern-api[bot]" <115122769+fern-api[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:22:49 +0000 Subject: [PATCH] SDK regeneration --- .fern/metadata.json | 7 +- README.md | 10 +- poetry.lock | 103 ++--- pyproject.toml | 5 +- src/pipedream/accounts/client.py | 30 -- src/pipedream/actions/client.py | 34 +- src/pipedream/actions/raw_client.py | 4 +- src/pipedream/app_categories/client.py | 12 - src/pipedream/apps/client.py | 12 - src/pipedream/client.py | 39 +- src/pipedream/components/client.py | 28 +- src/pipedream/components/raw_client.py | 4 +- src/pipedream/core/client_wrapper.py | 8 +- src/pipedream/core/http_client.py | 216 ++++++---- src/pipedream/core/http_response.py | 6 +- src/pipedream/core/jsonable_encoder.py | 8 + src/pipedream/core/pydantic_utilities.py | 304 ++++++++++++- src/pipedream/deployed_triggers/client.py | 54 --- src/pipedream/file_stash/client.py | 6 - src/pipedream/oauth_tokens/client.py | 10 +- src/pipedream/oauth_tokens/raw_client.py | 4 +- src/pipedream/projects/client.py | 42 -- src/pipedream/tokens/client.py | 12 - src/pipedream/triggers/client.py | 34 +- src/pipedream/triggers/raw_client.py | 4 +- src/pipedream/types/__init__.py | 6 + src/pipedream/types/backend_client_opts.py | 2 +- src/pipedream/types/configurable_prop.py | 402 +++++++++++++----- .../configurable_prop_airtable_base_id.py | 9 +- .../configurable_prop_airtable_field_id.py | 9 +- .../configurable_prop_airtable_table_id.py | 9 +- .../configurable_prop_airtable_view_id.py | 9 +- .../types/configurable_prop_alert.py | 2 +- .../types/configurable_prop_apphook.py | 22 +- src/pipedream/types/configurable_prop_base.py | 59 +-- .../configurable_prop_discord_channel.py | 9 +- ...configurable_prop_discord_channel_array.py | 11 +- src/pipedream/types/configurable_prop_http.py | 11 +- .../types/configure_prop_response.py | 10 +- .../types/configured_prop_value_app.py | 4 +- .../types/configured_prop_value_sql.py | 13 +- src/pipedream/types/connect_usage.py | 51 +++ src/pipedream/types/connect_usage_response.py | 24 ++ src/pipedream/types/dynamic_props.py | 9 +- src/pipedream/types/http_request_body.py | 4 +- src/pipedream/types/page_info.py | 23 +- src/pipedream/types/prop_option_nested.py | 2 +- src/pipedream/types/proxy_response_binary.py | 2 +- src/pipedream/types/reload_props_response.py | 6 +- src/pipedream/types/timer_interval.py | 9 +- src/pipedream/types/tool_annotations.py | 57 +-- src/pipedream/usage/__init__.py | 4 + src/pipedream/usage/client.py | 122 ++++++ src/pipedream/usage/raw_client.py | 159 +++++++ src/pipedream/users/client.py | 6 - tests/utils/test_http_client.py | 203 ++++++++- 56 files changed, 1584 insertions(+), 680 deletions(-) create mode 100644 src/pipedream/types/connect_usage.py create mode 100644 src/pipedream/types/connect_usage_response.py create mode 100644 src/pipedream/usage/__init__.py create mode 100644 src/pipedream/usage/client.py create mode 100644 src/pipedream/usage/raw_client.py diff --git a/.fern/metadata.json b/.fern/metadata.json index e8e81e2..928e059 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -1,7 +1,7 @@ { - "cliVersion": "3.5.0", + "cliVersion": "3.65.1", "generatorName": "fernapi/fern-python-sdk", - "generatorVersion": "4.45.0", + "generatorVersion": "4.54.4", "generatorConfig": { "client": { "class_name": "Client", @@ -9,5 +9,6 @@ "exported_class_name": "Pipedream", "exported_filename": "pipedream.py" } - } + }, + "sdkVersion": "1.1.4" } \ No newline at end of file diff --git a/README.md b/README.md index 3df45ed..300cfa8 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,6 @@ from pipedream import Pipedream client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.actions.run( id="id", @@ -61,9 +58,6 @@ from pipedream import AsyncPipedream client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -101,9 +95,6 @@ from pipedream import Pipedream client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) response = client.apps.list( after="after", @@ -165,6 +156,7 @@ client = Pipedream( ) response = client.actions.with_raw_response.run(...) print(response.headers) # access the response headers +print(response.status_code) # access the response status code print(response.data) # access the underlying object pager = client.apps.list(...) print(pager.response) # access the typed response for the first page diff --git a/poetry.lock b/poetry.lock index 9decbf8..2f8666b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,13 +38,13 @@ trio = ["trio (>=0.26.1)"] [[package]] name = "certifi" -version = "2025.11.12" +version = "2026.1.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" files = [ - {file = "certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b"}, - {file = "certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316"}, + {file = "certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c"}, + {file = "certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120"}, ] [[package]] @@ -236,13 +236,13 @@ files = [ [[package]] name = "packaging" -version = "25.0" +version = "26.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, - {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, + {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, + {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, ] [[package]] @@ -517,53 +517,58 @@ files = [ [[package]] name = "tomli" -version = "2.3.0" +version = "2.4.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45"}, - {file = "tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba"}, - {file = "tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf"}, - {file = "tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441"}, - {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845"}, - {file = "tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c"}, - {file = "tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456"}, - {file = "tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be"}, - {file = "tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac"}, - {file = "tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22"}, - {file = "tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f"}, - {file = "tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52"}, - {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8"}, - {file = "tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6"}, - {file = "tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876"}, - {file = "tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878"}, - {file = "tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b"}, - {file = "tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae"}, - {file = "tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b"}, - {file = "tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf"}, - {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f"}, - {file = "tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05"}, - {file = "tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606"}, - {file = "tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999"}, - {file = "tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e"}, - {file = "tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3"}, - {file = "tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc"}, - {file = "tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0"}, - {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879"}, - {file = "tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005"}, - {file = "tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463"}, - {file = "tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8"}, - {file = "tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77"}, - {file = "tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf"}, - {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530"}, - {file = "tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b"}, - {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67"}, - {file = "tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f"}, - {file = "tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0"}, - {file = "tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba"}, - {file = "tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b"}, - {file = "tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549"}, + {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"}, + {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576"}, + {file = "tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a"}, + {file = "tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa"}, + {file = "tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51"}, + {file = "tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729"}, + {file = "tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da"}, + {file = "tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f"}, + {file = "tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86"}, + {file = "tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87"}, + {file = "tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8"}, + {file = "tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776"}, + {file = "tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475"}, + {file = "tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b"}, + {file = "tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087"}, + {file = "tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd"}, + {file = "tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4"}, + {file = "tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a"}, + {file = "tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 30a012f..bc6086f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ dynamic = ["version"] [tool.poetry] name = "pipedream" -version = "1.1.3" +version = "1.1.4" description = "" readme = "README.md" authors = [] @@ -19,6 +19,9 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", diff --git a/src/pipedream/accounts/client.py b/src/pipedream/accounts/client.py index 79d552f..3ffbd23 100644 --- a/src/pipedream/accounts/client.py +++ b/src/pipedream/accounts/client.py @@ -79,9 +79,6 @@ def list( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) response = client.accounts.list( external_user_id="external_user_id", @@ -156,9 +153,6 @@ def create( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.accounts.create( external_user_id="external_user_id", @@ -210,9 +204,6 @@ def retrieve( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.accounts.retrieve( account_id="account_id", @@ -245,9 +236,6 @@ def delete(self, account_id: str, *, request_options: typing.Optional[RequestOpt client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.accounts.delete( account_id="account_id", @@ -277,9 +265,6 @@ def delete_by_app(self, app_id: str, *, request_options: typing.Optional[Request client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.accounts.delete_by_app( app_id="app_id", @@ -357,9 +342,6 @@ async def list( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -443,9 +425,6 @@ async def create( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -505,9 +484,6 @@ async def retrieve( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -548,9 +524,6 @@ async def delete(self, account_id: str, *, request_options: typing.Optional[Requ client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -588,9 +561,6 @@ async def delete_by_app(self, app_id: str, *, request_options: typing.Optional[R client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/src/pipedream/actions/client.py b/src/pipedream/actions/client.py index 14e4eaa..b2debbd 100644 --- a/src/pipedream/actions/client.py +++ b/src/pipedream/actions/client.py @@ -74,7 +74,7 @@ def list( Returns ------- SyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission Examples -------- @@ -82,9 +82,6 @@ def list( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) response = client.actions.list( after="after", @@ -136,9 +133,6 @@ def retrieve( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.actions.retrieve( component_id="component_id", @@ -211,9 +205,6 @@ def configure_prop( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.actions.configure_prop( id="id", @@ -283,9 +274,6 @@ def reload_props( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.actions.reload_props( id="id", @@ -349,9 +337,6 @@ def run( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.actions.run( id="id", @@ -425,7 +410,7 @@ async def list( Returns ------- AsyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission Examples -------- @@ -435,9 +420,6 @@ async def list( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -498,9 +480,6 @@ async def retrieve( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -581,9 +560,6 @@ async def configure_prop( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -661,9 +637,6 @@ async def reload_props( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -735,9 +708,6 @@ async def run( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/src/pipedream/actions/raw_client.py b/src/pipedream/actions/raw_client.py index c8a464d..028cf72 100644 --- a/src/pipedream/actions/raw_client.py +++ b/src/pipedream/actions/raw_client.py @@ -71,7 +71,7 @@ def list( Returns ------- SyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission """ _response = self._client_wrapper.httpx_client.request( f"v1/connect/{jsonable_encoder(self._client_wrapper._project_id)}/actions", @@ -523,7 +523,7 @@ async def list( Returns ------- AsyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission """ _response = await self._client_wrapper.httpx_client.request( f"v1/connect/{jsonable_encoder(self._client_wrapper._project_id)}/actions", diff --git a/src/pipedream/app_categories/client.py b/src/pipedream/app_categories/client.py index 93cebd8..b66dd78 100644 --- a/src/pipedream/app_categories/client.py +++ b/src/pipedream/app_categories/client.py @@ -44,9 +44,6 @@ def list(self, *, request_options: typing.Optional[RequestOptions] = None) -> Li client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.app_categories.list() """ @@ -76,9 +73,6 @@ def retrieve(self, id: str, *, request_options: typing.Optional[RequestOptions] client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.app_categories.retrieve( id="id", @@ -125,9 +119,6 @@ async def list(self, *, request_options: typing.Optional[RequestOptions] = None) client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -167,9 +158,6 @@ async def retrieve( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/src/pipedream/apps/client.py b/src/pipedream/apps/client.py index 1d56cbf..4115c7b 100644 --- a/src/pipedream/apps/client.py +++ b/src/pipedream/apps/client.py @@ -92,9 +92,6 @@ def list( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) response = client.apps.list( after="after", @@ -150,9 +147,6 @@ def retrieve(self, app_id: str, *, request_options: typing.Optional[RequestOptio client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.apps.retrieve( app_id="app_id", @@ -243,9 +237,6 @@ async def list( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -310,9 +301,6 @@ async def retrieve(self, app_id: str, *, request_options: typing.Optional[Reques client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/src/pipedream/client.py b/src/pipedream/client.py index 0dd370e..1e3f499 100644 --- a/src/pipedream/client.py +++ b/src/pipedream/client.py @@ -6,11 +6,11 @@ import typing import httpx -from .types.project_environment import ProjectEnvironment from .core.api_error import ApiError from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper from .core.oauth_token_provider import AsyncOAuthTokenProvider, OAuthTokenProvider from .environment import PipedreamEnvironment +from .types.project_environment import ProjectEnvironment if typing.TYPE_CHECKING: from .accounts.client import AccountsClient, AsyncAccountsClient @@ -25,6 +25,7 @@ from .proxy.client import AsyncProxyClient, ProxyClient from .tokens.client import AsyncTokensClient, TokensClient from .triggers.client import AsyncTriggersClient, TriggersClient + from .usage.client import AsyncUsageClient, UsageClient from .users.client import AsyncUsersClient, UsersClient @@ -76,9 +77,6 @@ class Client: client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) # or ... @@ -99,6 +97,7 @@ def __init__( environment: PipedreamEnvironment = PipedreamEnvironment.PROD, project_id: str, project_environment: typing.Optional[ProjectEnvironment] = os.getenv("PIPEDREAM_PROJECT_ENVIRONMENT"), + headers: typing.Optional[typing.Dict[str, str]] = None, timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, httpx_client: typing.Optional[httpx.Client] = None, @@ -113,6 +112,7 @@ def __init__( environment: PipedreamEnvironment = PipedreamEnvironment.PROD, project_id: str, project_environment: typing.Optional[ProjectEnvironment] = os.getenv("PIPEDREAM_PROJECT_ENVIRONMENT"), + headers: typing.Optional[typing.Dict[str, str]] = None, timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, httpx_client: typing.Optional[httpx.Client] = None, @@ -125,6 +125,7 @@ def __init__( environment: PipedreamEnvironment = PipedreamEnvironment.PROD, project_id: str, project_environment: typing.Optional[ProjectEnvironment] = os.getenv("PIPEDREAM_PROJECT_ENVIRONMENT"), + headers: typing.Optional[typing.Dict[str, str]] = None, client_id: typing.Optional[str] = os.getenv("PIPEDREAM_CLIENT_ID"), client_secret: typing.Optional[str] = os.getenv("PIPEDREAM_CLIENT_SECRET"), token: typing.Optional[typing.Callable[[], str]] = None, @@ -141,6 +142,7 @@ def __init__( base_url=_get_base_url(base_url=base_url, environment=environment), project_id=project_id, project_environment=project_environment, + headers=headers, httpx_client=httpx_client if httpx_client is not None else httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects) @@ -157,6 +159,7 @@ def __init__( base_url=_get_base_url(base_url=base_url, environment=environment), project_id=project_id, project_environment=project_environment, + headers=headers, httpx_client=httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects) if follow_redirects is not None else httpx.Client(timeout=_defaulted_timeout), @@ -167,6 +170,7 @@ def __init__( base_url=_get_base_url(base_url=base_url, environment=environment), project_id=project_id, project_environment=project_environment, + headers=headers, token=_token_getter_override if _token_getter_override is not None else oauth_token_provider.get_token, httpx_client=httpx_client if httpx_client is not None @@ -191,6 +195,7 @@ def __init__( self._file_stash: typing.Optional[FileStashClient] = None self._proxy: typing.Optional[ProxyClient] = None self._tokens: typing.Optional[TokensClient] = None + self._usage: typing.Optional[UsageClient] = None self._oauth_tokens: typing.Optional[OauthTokensClient] = None @property @@ -289,6 +294,14 @@ def tokens(self): self._tokens = TokensClient(client_wrapper=self._client_wrapper) return self._tokens + @property + def usage(self): + if self._usage is None: + from .usage.client import UsageClient # noqa: E402 + + self._usage = UsageClient(client_wrapper=self._client_wrapper) + return self._usage + @property def oauth_tokens(self): if self._oauth_tokens is None: @@ -346,9 +359,6 @@ class AsyncClient: client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) # or ... @@ -369,6 +379,7 @@ def __init__( environment: PipedreamEnvironment = PipedreamEnvironment.PROD, project_id: str, project_environment: typing.Optional[ProjectEnvironment] = os.getenv("PIPEDREAM_PROJECT_ENVIRONMENT"), + headers: typing.Optional[typing.Dict[str, str]] = None, timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, httpx_client: typing.Optional[httpx.AsyncClient] = None, @@ -383,6 +394,7 @@ def __init__( environment: PipedreamEnvironment = PipedreamEnvironment.PROD, project_id: str, project_environment: typing.Optional[ProjectEnvironment] = os.getenv("PIPEDREAM_PROJECT_ENVIRONMENT"), + headers: typing.Optional[typing.Dict[str, str]] = None, timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, httpx_client: typing.Optional[httpx.AsyncClient] = None, @@ -395,6 +407,7 @@ def __init__( environment: PipedreamEnvironment = PipedreamEnvironment.PROD, project_id: str, project_environment: typing.Optional[ProjectEnvironment] = os.getenv("PIPEDREAM_PROJECT_ENVIRONMENT"), + headers: typing.Optional[typing.Dict[str, str]] = None, client_id: typing.Optional[str] = os.getenv("PIPEDREAM_CLIENT_ID"), client_secret: typing.Optional[str] = os.getenv("PIPEDREAM_CLIENT_SECRET"), token: typing.Optional[typing.Callable[[], str]] = None, @@ -411,6 +424,7 @@ def __init__( base_url=_get_base_url(base_url=base_url, environment=environment), project_id=project_id, project_environment=project_environment, + headers=headers, httpx_client=httpx_client if httpx_client is not None else httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects) @@ -427,6 +441,7 @@ def __init__( base_url=_get_base_url(base_url=base_url, environment=environment), project_id=project_id, project_environment=project_environment, + headers=headers, httpx_client=httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects) if follow_redirects is not None else httpx.AsyncClient(timeout=_defaulted_timeout), @@ -437,6 +452,7 @@ def __init__( base_url=_get_base_url(base_url=base_url, environment=environment), project_id=project_id, project_environment=project_environment, + headers=headers, token=_token_getter_override, async_token=oauth_token_provider.get_token, httpx_client=httpx_client @@ -462,6 +478,7 @@ def __init__( self._file_stash: typing.Optional[AsyncFileStashClient] = None self._proxy: typing.Optional[AsyncProxyClient] = None self._tokens: typing.Optional[AsyncTokensClient] = None + self._usage: typing.Optional[AsyncUsageClient] = None self._oauth_tokens: typing.Optional[AsyncOauthTokensClient] = None @property @@ -560,6 +577,14 @@ def tokens(self): self._tokens = AsyncTokensClient(client_wrapper=self._client_wrapper) return self._tokens + @property + def usage(self): + if self._usage is None: + from .usage.client import AsyncUsageClient # noqa: E402 + + self._usage = AsyncUsageClient(client_wrapper=self._client_wrapper) + return self._usage + @property def oauth_tokens(self): if self._oauth_tokens is None: diff --git a/src/pipedream/components/client.py b/src/pipedream/components/client.py index 1e8afde..8b2f545 100644 --- a/src/pipedream/components/client.py +++ b/src/pipedream/components/client.py @@ -77,7 +77,7 @@ def list( Returns ------- SyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission Examples -------- @@ -85,9 +85,6 @@ def list( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) response = client.components.list( after="after", @@ -147,9 +144,6 @@ def retrieve( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.components.retrieve( component_id="component_id", @@ -222,9 +216,6 @@ def configure_prop( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.components.configure_prop( id="id", @@ -294,9 +285,6 @@ def reload_props( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.components.reload_props( id="id", @@ -374,7 +362,7 @@ async def list( Returns ------- AsyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission Examples -------- @@ -384,9 +372,6 @@ async def list( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -455,9 +440,6 @@ async def retrieve( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -538,9 +520,6 @@ async def configure_prop( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -618,9 +597,6 @@ async def reload_props( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/src/pipedream/components/raw_client.py b/src/pipedream/components/raw_client.py index 8209c3d..b3e39bf 100644 --- a/src/pipedream/components/raw_client.py +++ b/src/pipedream/components/raw_client.py @@ -74,7 +74,7 @@ def list( Returns ------- SyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission """ _response = self._client_wrapper.httpx_client.request( f"v1/connect/{jsonable_encoder(self._client_wrapper._project_id)}/components", @@ -445,7 +445,7 @@ async def list( Returns ------- AsyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission """ _response = await self._client_wrapper.httpx_client.request( f"v1/connect/{jsonable_encoder(self._client_wrapper._project_id)}/components", diff --git a/src/pipedream/core/client_wrapper.py b/src/pipedream/core/client_wrapper.py index b1967dd..f68e360 100644 --- a/src/pipedream/core/client_wrapper.py +++ b/src/pipedream/core/client_wrapper.py @@ -26,11 +26,15 @@ def __init__( self._timeout = timeout def get_headers(self) -> typing.Dict[str, str]: + import platform + headers: typing.Dict[str, str] = { - "User-Agent": "pipedream/1.1.3", + "User-Agent": "pipedream/1.1.4", "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": "pipedream", - "X-Fern-SDK-Version": "1.1.3", + "X-Fern-SDK-Version": "1.1.4", **(self.get_custom_headers() or {}), } if self._project_environment is not None: diff --git a/src/pipedream/core/http_client.py b/src/pipedream/core/http_client.py index f4a7c07..7c6c936 100644 --- a/src/pipedream/core/http_client.py +++ b/src/pipedream/core/http_client.py @@ -5,7 +5,6 @@ import re import time import typing -import urllib.parse from contextlib import asynccontextmanager, contextmanager from random import random @@ -123,6 +122,30 @@ def _should_retry(response: httpx.Response) -> bool: return response.status_code >= 500 or response.status_code in retryable_400s +def _build_url(base_url: str, path: typing.Optional[str]) -> str: + """ + Build a full URL by joining a base URL with a path. + + This function correctly handles base URLs that contain path prefixes (e.g., tenant-based URLs) + by using string concatenation instead of urllib.parse.urljoin(), which would incorrectly + strip path components when the path starts with '/'. + + Example: + >>> _build_url("https://cloud.example.com/org/tenant/api", "/users") + 'https://cloud.example.com/org/tenant/api/users' + + Args: + base_url: The base URL, which may contain path prefixes. + path: The path to append. Can be None or empty string. + + Returns: + The full URL with base_url and path properly joined. + """ + if not path: + return base_url + return f"{base_url.rstrip('/')}/{path.lstrip('/')}" + + def _maybe_filter_none_from_multipart_data( data: typing.Optional[typing.Any], request_files: typing.Optional[RequestFiles], @@ -192,8 +215,19 @@ def get_request_body( # If both data and json are None, we send json data in the event extra properties are specified json_body = maybe_filter_request_body(json, request_options, omit) - # If you have an empty JSON body, you should just send None - return (json_body if json_body != {} else None), data_body if data_body != {} else None + has_additional_body_parameters = bool( + request_options is not None and request_options.get("additional_body_parameters") + ) + + # 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: + json_body = None + if data_body == {} and data is None and not has_additional_body_parameters: + data_body = None + + return json_body, data_body class HttpClient: @@ -237,7 +271,7 @@ def request( ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 2, + retries: int = 0, omit: typing.Optional[typing.Any] = None, force_multipart: typing.Optional[bool] = None, ) -> httpx.Response: @@ -261,9 +295,29 @@ def request( data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( + remove_none_from_dict( + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) or {} + if request_options is not None + else {} + ), + }, + omit, + ) + ) + ) + ) + response = self.httpx_client.request( method=method, - url=urllib.parse.urljoin(f"{base_url}/", path), + url=_build_url(base_url, path), headers=jsonable_encoder( remove_none_from_dict( { @@ -273,23 +327,7 @@ def request( } ) ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get("additional_query_parameters", {}) or {} - if request_options is not None - else {} - ), - }, - omit, - ) - ) - ) - ), + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, @@ -297,9 +335,9 @@ def request( timeout=timeout, ) - max_retries: int = request_options.get("max_retries", 0) if request_options is not None else 0 + max_retries: int = request_options.get("max_retries", 2) if request_options is not None else 2 if _should_retry(response=response): - if max_retries > retries: + if retries < max_retries: time.sleep(_retry_timeout(response=response, retries=retries)) return self.request( path=path, @@ -336,7 +374,7 @@ def stream( ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 2, + retries: int = 0, omit: typing.Optional[typing.Any] = None, force_multipart: typing.Optional[bool] = None, ) -> typing.Iterator[httpx.Response]: @@ -360,9 +398,29 @@ def stream( data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart) + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( + remove_none_from_dict( + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) + if request_options is not None + else {} + ), + }, + omit, + ) + ) + ) + ) + with self.httpx_client.stream( method=method, - url=urllib.parse.urljoin(f"{base_url}/", path), + url=_build_url(base_url, path), headers=jsonable_encoder( remove_none_from_dict( { @@ -372,23 +430,7 @@ def stream( } ) ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get("additional_query_parameters", {}) - if request_options is not None - else {} - ), - }, - omit, - ) - ) - ) - ), + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, @@ -446,7 +488,7 @@ async def request( ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 2, + retries: int = 0, omit: typing.Optional[typing.Any] = None, force_multipart: typing.Optional[bool] = None, ) -> httpx.Response: @@ -473,10 +515,30 @@ async def request( # Get headers (supports async token providers) _headers = await self._get_headers() + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( + remove_none_from_dict( + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) or {} + if request_options is not None + else {} + ), + }, + omit, + ) + ) + ) + ) + # Add the input to each of these and do None-safety checks response = await self.httpx_client.request( method=method, - url=urllib.parse.urljoin(f"{base_url}/", path), + url=_build_url(base_url, path), headers=jsonable_encoder( remove_none_from_dict( { @@ -486,23 +548,7 @@ async def request( } ) ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get("additional_query_parameters", {}) or {} - if request_options is not None - else {} - ), - }, - omit, - ) - ) - ) - ), + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, @@ -510,9 +556,9 @@ async def request( timeout=timeout, ) - max_retries: int = request_options.get("max_retries", 0) if request_options is not None else 0 + max_retries: int = request_options.get("max_retries", 2) if request_options is not None else 2 if _should_retry(response=response): - if max_retries > retries: + if retries < max_retries: await asyncio.sleep(_retry_timeout(response=response, retries=retries)) return await self.request( path=path, @@ -548,7 +594,7 @@ async def stream( ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, - retries: int = 2, + retries: int = 0, omit: typing.Optional[typing.Any] = None, force_multipart: typing.Optional[bool] = None, ) -> typing.AsyncIterator[httpx.Response]: @@ -575,9 +621,29 @@ async def stream( # Get headers (supports async token providers) _headers = await self._get_headers() + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( + remove_none_from_dict( + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) + if request_options is not None + else {} + ), + }, + omit=omit, + ) + ) + ) + ) + async with self.httpx_client.stream( method=method, - url=urllib.parse.urljoin(f"{base_url}/", path), + url=_build_url(base_url, path), headers=jsonable_encoder( remove_none_from_dict( { @@ -587,23 +653,7 @@ async def stream( } ) ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get("additional_query_parameters", {}) - if request_options is not None - else {} - ), - }, - omit=omit, - ) - ) - ) - ), + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, diff --git a/src/pipedream/core/http_response.py b/src/pipedream/core/http_response.py index 2479747..00bb109 100644 --- a/src/pipedream/core/http_response.py +++ b/src/pipedream/core/http_response.py @@ -9,7 +9,7 @@ class BaseHttpResponse: - """Minimalist HTTP response wrapper that exposes response headers.""" + """Minimalist HTTP response wrapper that exposes response headers and status code.""" _response: httpx.Response @@ -20,6 +20,10 @@ def __init__(self, response: httpx.Response): def headers(self) -> Dict[str, str]: return dict(self._response.headers) + @property + def status_code(self) -> int: + return self._response.status_code + class HttpResponse(Generic[T], BaseHttpResponse): """HTTP response wrapper that exposes response headers and data.""" diff --git a/src/pipedream/core/jsonable_encoder.py b/src/pipedream/core/jsonable_encoder.py index afee366..f8beaea 100644 --- a/src/pipedream/core/jsonable_encoder.py +++ b/src/pipedream/core/jsonable_encoder.py @@ -30,6 +30,10 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None) -> Any: custom_encoder = custom_encoder or {} + # Generated SDKs use Ellipsis (`...`) as the sentinel value for "OMIT". + # OMIT values should be excluded from serialized payloads. + if obj is Ellipsis: + return None if custom_encoder: if type(obj) in custom_encoder: return custom_encoder[type(obj)](obj) @@ -70,6 +74,8 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any] allowed_keys = set(obj.keys()) for key, value in obj.items(): if key in allowed_keys: + if value is Ellipsis: + continue encoded_key = jsonable_encoder(key, custom_encoder=custom_encoder) encoded_value = jsonable_encoder(value, custom_encoder=custom_encoder) encoded_dict[encoded_key] = encoded_value @@ -77,6 +83,8 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any] if isinstance(obj, (list, set, frozenset, GeneratorType, tuple)): encoded_list = [] for item in obj: + if item is Ellipsis: + continue encoded_list.append(jsonable_encoder(item, custom_encoder=custom_encoder)) return encoded_list diff --git a/src/pipedream/core/pydantic_utilities.py b/src/pipedream/core/pydantic_utilities.py index 185e5c4..789081b 100644 --- a/src/pipedream/core/pydantic_utilities.py +++ b/src/pipedream/core/pydantic_utilities.py @@ -2,10 +2,35 @@ # nopycln: file import datetime as dt +import inspect +import json +import logging from collections import defaultdict -from typing import Any, Callable, ClassVar, Dict, List, Mapping, Optional, Set, Tuple, Type, TypeVar, Union, cast +from dataclasses import asdict +from typing import ( + TYPE_CHECKING, + Any, + Callable, + ClassVar, + Dict, + List, + Mapping, + Optional, + Set, + Tuple, + Type, + TypeVar, + Union, + cast, +) import pydantic +import typing_extensions + +_logger = logging.getLogger(__name__) + +if TYPE_CHECKING: + from .http_sse._models import ServerSentEvent IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.") @@ -36,8 +61,212 @@ Model = TypeVar("Model", bound=pydantic.BaseModel) +def _get_discriminator_and_variants(type_: Type[Any]) -> Tuple[Optional[str], Optional[List[Type[Any]]]]: + """ + Extract the discriminator field name and union variants from a discriminated union type. + Supports Annotated[Union[...], Field(discriminator=...)] patterns. + Returns (discriminator, variants) or (None, None) if not a discriminated union. + """ + origin = typing_extensions.get_origin(type_) + + if origin is typing_extensions.Annotated: + args = typing_extensions.get_args(type_) + if len(args) >= 2: + inner_type = args[0] + # Check annotations for discriminator + discriminator = None + for annotation in args[1:]: + if hasattr(annotation, "discriminator"): + discriminator = getattr(annotation, "discriminator", None) + break + + if discriminator: + inner_origin = typing_extensions.get_origin(inner_type) + if inner_origin is Union: + variants = list(typing_extensions.get_args(inner_type)) + return discriminator, variants + return None, None + + +def _get_field_annotation(model: Type[Any], field_name: str) -> Optional[Type[Any]]: + """Get the type annotation of a field from a Pydantic model.""" + if IS_PYDANTIC_V2: + fields = getattr(model, "model_fields", {}) + field_info = fields.get(field_name) + if field_info: + return cast(Optional[Type[Any]], field_info.annotation) + else: + fields = getattr(model, "__fields__", {}) + field_info = fields.get(field_name) + if field_info: + return cast(Optional[Type[Any]], field_info.outer_type_) + return None + + +def _find_variant_by_discriminator( + variants: List[Type[Any]], + discriminator: str, + discriminator_value: Any, +) -> Optional[Type[Any]]: + """Find the union variant that matches the discriminator value.""" + for variant in variants: + if not (inspect.isclass(variant) and issubclass(variant, pydantic.BaseModel)): + continue + + disc_annotation = _get_field_annotation(variant, discriminator) + if disc_annotation and is_literal_type(disc_annotation): + literal_args = get_args(disc_annotation) + if literal_args and literal_args[0] == discriminator_value: + return variant + return None + + +def _is_string_type(type_: Type[Any]) -> bool: + """Check if a type is str or Optional[str].""" + if type_ is str: + return True + + origin = typing_extensions.get_origin(type_) + if origin is Union: + args = typing_extensions.get_args(type_) + # Optional[str] = Union[str, None] + non_none_args = [a for a in args if a is not type(None)] + if len(non_none_args) == 1 and non_none_args[0] is str: + return True + + return False + + +def parse_sse_obj(sse: "ServerSentEvent", type_: Type[T]) -> T: + """ + Parse a ServerSentEvent into the appropriate type. + + Handles two scenarios based on where the discriminator field is located: + + 1. Data-level discrimination: The discriminator (e.g., 'type') is inside the 'data' payload. + The union describes the data content, not the SSE envelope. + -> Returns: json.loads(data) parsed into the type + + Example: ChatStreamResponse with discriminator='type' + Input: ServerSentEvent(event="message", data='{"type": "content-delta", ...}', id="") + Output: ContentDeltaEvent (parsed from data, SSE envelope stripped) + + 2. Event-level discrimination: The discriminator (e.g., 'event') is at the SSE event level. + The union describes the full SSE event structure. + -> Returns: SSE envelope with 'data' field JSON-parsed only if the variant expects non-string + + Example: JobStreamResponse with discriminator='event' + Input: ServerSentEvent(event="ERROR", data='{"code": "FAILED", ...}', id="123") + Output: JobStreamResponse_Error with data as ErrorData object + + But for variants where data is str (like STATUS_UPDATE): + Input: ServerSentEvent(event="STATUS_UPDATE", data='{"status": "processing"}', id="1") + Output: JobStreamResponse_StatusUpdate with data as string (not parsed) + + Args: + sse: The ServerSentEvent object to parse + type_: The target discriminated union type + + Returns: + The parsed object of type T + + Note: + This function is only available in SDK contexts where http_sse module exists. + """ + sse_event = asdict(sse) + discriminator, variants = _get_discriminator_and_variants(type_) + + if discriminator is None or variants is None: + # Not a discriminated union - parse the data field as JSON + data_value = sse_event.get("data") + if isinstance(data_value, str) and data_value: + try: + parsed_data = json.loads(data_value) + return parse_obj_as(type_, parsed_data) + except json.JSONDecodeError as e: + _logger.warning( + "Failed to parse SSE data field as JSON: %s, data: %s", + e, + data_value[:100] if len(data_value) > 100 else data_value, + ) + return parse_obj_as(type_, sse_event) + + data_value = sse_event.get("data") + + # Check if discriminator is at the top level (event-level discrimination) + if discriminator in sse_event: + # Case 2: Event-level discrimination + # Find the matching variant to check if 'data' field needs JSON parsing + disc_value = sse_event.get(discriminator) + matching_variant = _find_variant_by_discriminator(variants, discriminator, disc_value) + + if matching_variant is not None: + # Check what type the variant expects for 'data' + data_type = _get_field_annotation(matching_variant, "data") + if data_type is not None and not _is_string_type(data_type): + # Variant expects non-string data - parse JSON + if isinstance(data_value, str) and data_value: + try: + parsed_data = json.loads(data_value) + new_object = dict(sse_event) + new_object["data"] = parsed_data + return parse_obj_as(type_, new_object) + except json.JSONDecodeError as e: + _logger.warning( + "Failed to parse SSE data field as JSON for event-level discrimination: %s, data: %s", + e, + data_value[:100] if len(data_value) > 100 else data_value, + ) + # Either no matching variant, data is string type, or JSON parse failed + return parse_obj_as(type_, sse_event) + + else: + # Case 1: Data-level discrimination + # The discriminator is inside the data payload - extract and parse data only + if isinstance(data_value, str) and data_value: + try: + parsed_data = json.loads(data_value) + return parse_obj_as(type_, parsed_data) + except json.JSONDecodeError as e: + _logger.warning( + "Failed to parse SSE data field as JSON for data-level discrimination: %s, data: %s", + e, + data_value[:100] if len(data_value) > 100 else data_value, + ) + return parse_obj_as(type_, sse_event) + + def parse_obj_as(type_: Type[T], object_: Any) -> T: - dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read") + # convert_and_respect_annotation_metadata is required for TypedDict aliasing. + # + # For Pydantic models, whether we should pre-dealias depends on how the model encodes aliasing: + # - If the model uses real Pydantic aliases (pydantic.Field(alias=...)), then we must pass wire keys through + # unchanged so Pydantic can validate them. + # - 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 + + dealiased_object = ( + object_ + if has_pydantic_aliases + else convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read") + ) + else: + dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read") if IS_PYDANTIC_V2: adapter = pydantic.TypeAdapter(type_) # type: ignore[attr-defined] return adapter.validate_python(dealiased_object) @@ -59,6 +288,43 @@ class UniversalBaseModel(pydantic.BaseModel): protected_namespaces=(), ) + @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 + @pydantic.model_serializer(mode="plain", when_used="json") # type: ignore[attr-defined] def serialize_model(self) -> Any: # type: ignore[name-defined] serialized = self.dict() # type: ignore[attr-defined] @@ -71,6 +337,40 @@ class Config: smart_union = True json_encoders = {dt.datetime: serialize_datetime} + @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 + @classmethod def model_construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model": dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read") diff --git a/src/pipedream/deployed_triggers/client.py b/src/pipedream/deployed_triggers/client.py index 08dbc65..eab3da5 100644 --- a/src/pipedream/deployed_triggers/client.py +++ b/src/pipedream/deployed_triggers/client.py @@ -77,9 +77,6 @@ def list( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) response = client.deployed_triggers.list( after="after", @@ -130,9 +127,6 @@ def retrieve( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.deployed_triggers.retrieve( trigger_id="trigger_id", @@ -190,9 +184,6 @@ def update( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.deployed_triggers.update( trigger_id="trigger_id", @@ -244,9 +235,6 @@ def delete( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.deployed_triggers.delete( trigger_id="trigger_id", @@ -297,9 +285,6 @@ def list_events( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.deployed_triggers.list_events( trigger_id="trigger_id", @@ -339,9 +324,6 @@ def list_workflows( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.deployed_triggers.list_workflows( trigger_id="trigger_id", @@ -388,9 +370,6 @@ def update_workflows( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.deployed_triggers.update_workflows( trigger_id="trigger_id", @@ -430,9 +409,6 @@ def list_webhooks( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.deployed_triggers.list_webhooks( trigger_id="trigger_id", @@ -479,9 +455,6 @@ def update_webhooks( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.deployed_triggers.update_webhooks( trigger_id="trigger_id", @@ -556,9 +529,6 @@ async def list( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -618,9 +588,6 @@ async def retrieve( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -686,9 +653,6 @@ async def update( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -748,9 +712,6 @@ async def delete( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -809,9 +770,6 @@ async def list_events( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -859,9 +817,6 @@ async def list_workflows( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -916,9 +871,6 @@ async def update_workflows( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -966,9 +918,6 @@ async def list_webhooks( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -1023,9 +972,6 @@ async def update_webhooks( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/src/pipedream/file_stash/client.py b/src/pipedream/file_stash/client.py index f0469a8..8dcac90 100644 --- a/src/pipedream/file_stash/client.py +++ b/src/pipedream/file_stash/client.py @@ -46,9 +46,6 @@ def download_file( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.file_stash.download_file( s_3_key="s3_key", @@ -99,9 +96,6 @@ async def download_file( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/src/pipedream/oauth_tokens/client.py b/src/pipedream/oauth_tokens/client.py index 3dca46c..4e6acd4 100644 --- a/src/pipedream/oauth_tokens/client.py +++ b/src/pipedream/oauth_tokens/client.py @@ -44,7 +44,7 @@ def create( client_secret : str scope : typing.Optional[str] - Optional space-separated scopes for the access token. Defaults to '*'. + Optional space-separated scopes for the access token. Defaults to `*`. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -60,9 +60,6 @@ def create( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.oauth_tokens.create( client_id="client_id", @@ -108,7 +105,7 @@ async def create( client_secret : str scope : typing.Optional[str] - Optional space-separated scopes for the access token. Defaults to '*'. + Optional space-separated scopes for the access token. Defaults to `*`. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -126,9 +123,6 @@ async def create( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/src/pipedream/oauth_tokens/raw_client.py b/src/pipedream/oauth_tokens/raw_client.py index 30fa1b7..4f0e054 100644 --- a/src/pipedream/oauth_tokens/raw_client.py +++ b/src/pipedream/oauth_tokens/raw_client.py @@ -36,7 +36,7 @@ def create( client_secret : str scope : typing.Optional[str] - Optional space-separated scopes for the access token. Defaults to '*'. + Optional space-separated scopes for the access token. Defaults to `*`. request_options : typing.Optional[RequestOptions] Request-specific configuration. @@ -99,7 +99,7 @@ async def create( client_secret : str scope : typing.Optional[str] - Optional space-separated scopes for the access token. Defaults to '*'. + Optional space-separated scopes for the access token. Defaults to `*`. request_options : typing.Optional[RequestOptions] Request-specific configuration. diff --git a/src/pipedream/projects/client.py b/src/pipedream/projects/client.py index 1469544..38d0e45 100644 --- a/src/pipedream/projects/client.py +++ b/src/pipedream/projects/client.py @@ -69,9 +69,6 @@ def list( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) response = client.projects.list( after="after", @@ -127,9 +124,6 @@ def create( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.projects.create( name="name", @@ -167,9 +161,6 @@ def retrieve(self, project_id: str, *, request_options: typing.Optional[RequestO client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.projects.retrieve( project_id="project_id", @@ -200,9 +191,6 @@ def delete(self, project_id: str, *, request_options: typing.Optional[RequestOpt client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.projects.delete( project_id="project_id", @@ -255,9 +243,6 @@ def update( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.projects.update( project_id="project_id", @@ -300,9 +285,6 @@ def update_logo( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.projects.update_logo( project_id="project_id", @@ -332,9 +314,6 @@ def retrieve_info(self, *, request_options: typing.Optional[RequestOptions] = No client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.projects.retrieve_info() """ @@ -399,9 +378,6 @@ async def list( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -468,9 +444,6 @@ async def create( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -516,9 +489,6 @@ async def retrieve(self, project_id: str, *, request_options: typing.Optional[Re client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -557,9 +527,6 @@ async def delete(self, project_id: str, *, request_options: typing.Optional[Requ client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -620,9 +587,6 @@ async def update( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -673,9 +637,6 @@ async def update_logo( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -713,9 +674,6 @@ async def retrieve_info(self, *, request_options: typing.Optional[RequestOptions client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/src/pipedream/tokens/client.py b/src/pipedream/tokens/client.py index f37eccf..52f1505 100644 --- a/src/pipedream/tokens/client.py +++ b/src/pipedream/tokens/client.py @@ -72,9 +72,6 @@ def create( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.tokens.create( external_user_id="external_user_id", @@ -125,9 +122,6 @@ def validate( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.tokens.validate( ctok="ctok", @@ -202,9 +196,6 @@ async def create( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -263,9 +254,6 @@ async def validate( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/src/pipedream/triggers/client.py b/src/pipedream/triggers/client.py index 6c578cd..9bb4bef 100644 --- a/src/pipedream/triggers/client.py +++ b/src/pipedream/triggers/client.py @@ -73,7 +73,7 @@ def list( Returns ------- SyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission Examples -------- @@ -81,9 +81,6 @@ def list( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) response = client.triggers.list( after="after", @@ -135,9 +132,6 @@ def retrieve( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.triggers.retrieve( component_id="component_id", @@ -210,9 +204,6 @@ def configure_prop( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.triggers.configure_prop( id="id", @@ -282,9 +273,6 @@ def reload_props( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.triggers.reload_props( id="id", @@ -357,9 +345,6 @@ def deploy( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.triggers.deploy( id="id", @@ -435,7 +420,7 @@ async def list( Returns ------- AsyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission Examples -------- @@ -445,9 +430,6 @@ async def list( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -508,9 +490,6 @@ async def retrieve( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -591,9 +570,6 @@ async def configure_prop( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -671,9 +647,6 @@ async def reload_props( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) @@ -754,9 +727,6 @@ async def deploy( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/src/pipedream/triggers/raw_client.py b/src/pipedream/triggers/raw_client.py index 85171f1..92e9a65 100644 --- a/src/pipedream/triggers/raw_client.py +++ b/src/pipedream/triggers/raw_client.py @@ -71,7 +71,7 @@ def list( Returns ------- SyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission """ _response = self._client_wrapper.httpx_client.request( f"v1/connect/{jsonable_encoder(self._client_wrapper._project_id)}/triggers", @@ -533,7 +533,7 @@ async def list( Returns ------- AsyncPager[Component, GetComponentsResponse] - behaves like registry=all + returns public + private without permission """ _response = await self._client_wrapper.httpx_client.request( f"v1/connect/{jsonable_encoder(self._client_wrapper._project_id)}/triggers", diff --git a/src/pipedream/types/__init__.py b/src/pipedream/types/__init__.py index 51f6712..b7173bb 100644 --- a/src/pipedream/types/__init__.py +++ b/src/pipedream/types/__init__.py @@ -95,6 +95,8 @@ from .configured_prop_value_string_array import ConfiguredPropValueStringArray from .configured_props import ConfiguredProps from .connect_token import ConnectToken + from .connect_usage import ConnectUsage + from .connect_usage_response import ConnectUsageResponse from .create_o_auth_token_response import CreateOAuthTokenResponse from .create_token_response import CreateTokenResponse from .delete_trigger_opts import DeleteTriggerOpts @@ -240,6 +242,8 @@ "ConfiguredPropValueStringArray": ".configured_prop_value_string_array", "ConfiguredProps": ".configured_props", "ConnectToken": ".connect_token", + "ConnectUsage": ".connect_usage", + "ConnectUsageResponse": ".connect_usage_response", "CreateOAuthTokenResponse": ".create_o_auth_token_response", "CreateTokenResponse": ".create_token_response", "DeleteTriggerOpts": ".delete_trigger_opts", @@ -412,6 +416,8 @@ def __dir__(): "ConfiguredPropValueStringArray", "ConfiguredProps", "ConnectToken", + "ConnectUsage", + "ConnectUsageResponse", "CreateOAuthTokenResponse", "CreateTokenResponse", "DeleteTriggerOpts", diff --git a/src/pipedream/types/backend_client_opts.py b/src/pipedream/types/backend_client_opts.py index 8c0ee71..87bed03 100644 --- a/src/pipedream/types/backend_client_opts.py +++ b/src/pipedream/types/backend_client_opts.py @@ -28,7 +28,7 @@ class BackendClientOpts(UniversalBaseModel): scope: typing.Optional[str] = pydantic.Field(default=None) """ - Optional space-separated scopes for the access token. Defaults to '*'. + Optional space-separated scopes for the access token. Defaults to `*`. """ if IS_PYDANTIC_V2: diff --git a/src/pipedream/types/configurable_prop.py b/src/pipedream/types/configurable_prop.py index 2f88533..85ae9ef 100644 --- a/src/pipedream/types/configurable_prop.py +++ b/src/pipedream/types/configurable_prop.py @@ -37,7 +37,7 @@ class ConfigurableProp_Alert(UniversalBaseModel): type: typing.Literal["alert"] = "alert" alert_type: typing_extensions.Annotated[ - typing.Optional[ConfigurablePropAlertType], FieldMetadata(alias="alertType") + typing.Optional[ConfigurablePropAlertType], FieldMetadata(alias="alertType"), pydantic.Field(alias="alertType") ] = None content: str name: str @@ -46,10 +46,18 @@ class ConfigurableProp_Alert(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -75,10 +83,18 @@ class ConfigurableProp_Any(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -103,10 +119,18 @@ class ConfigurableProp_App(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -132,10 +156,18 @@ class ConfigurableProp_Boolean(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -159,10 +191,18 @@ class ConfigurableProp_DataStore(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -186,10 +226,18 @@ class ConfigurableProp_Dir(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -216,10 +264,18 @@ class ConfigurableProp_InterfaceTimer(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -237,10 +293,10 @@ class ConfigurableProp_InterfaceApphook(UniversalBaseModel): """ type: typing.Literal["$.interface.apphook"] = "$.interface.apphook" - app_prop: typing_extensions.Annotated[str, FieldMetadata(alias="appProp")] - event_names: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="eventNames")] = ( - None - ) + app_prop: typing_extensions.Annotated[str, FieldMetadata(alias="appProp"), pydantic.Field(alias="appProp")] + event_names: typing_extensions.Annotated[ + typing.Optional[typing.List[str]], FieldMetadata(alias="eventNames"), pydantic.Field(alias="eventNames") + ] = None remote: typing.Optional[bool] = None static: typing.Optional[typing.List[typing.Any]] = None name: str @@ -249,10 +305,18 @@ class ConfigurableProp_InterfaceApphook(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -280,10 +344,18 @@ class ConfigurableProp_IntegerArray(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -301,17 +373,27 @@ class ConfigurableProp_InterfaceHttp(UniversalBaseModel): """ type: typing.Literal["$.interface.http"] = "$.interface.http" - custom_response: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="customResponse")] = None + custom_response: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="customResponse"), pydantic.Field(alias="customResponse") + ] = None name: str label: typing.Optional[str] = None description: typing.Optional[str] = None optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -336,10 +418,18 @@ class ConfigurableProp_HttpRequest(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -363,10 +453,18 @@ class ConfigurableProp_ServiceDb(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -393,10 +491,18 @@ class ConfigurableProp_Sql(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -414,17 +520,25 @@ class ConfigurableProp_AirtableBaseId(UniversalBaseModel): """ type: typing.Literal["$.airtable.baseId"] = "$.airtable.baseId" - app_prop: typing_extensions.Annotated[str, FieldMetadata(alias="appProp")] + app_prop: typing_extensions.Annotated[str, FieldMetadata(alias="appProp"), pydantic.Field(alias="appProp")] name: str label: typing.Optional[str] = None description: typing.Optional[str] = None optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -442,17 +556,27 @@ class ConfigurableProp_AirtableTableId(UniversalBaseModel): """ type: typing.Literal["$.airtable.tableId"] = "$.airtable.tableId" - base_id_prop: typing_extensions.Annotated[str, FieldMetadata(alias="baseIdProp")] + base_id_prop: typing_extensions.Annotated[ + str, FieldMetadata(alias="baseIdProp"), pydantic.Field(alias="baseIdProp") + ] name: str label: typing.Optional[str] = None description: typing.Optional[str] = None optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -470,17 +594,27 @@ class ConfigurableProp_AirtableViewId(UniversalBaseModel): """ type: typing.Literal["$.airtable.viewId"] = "$.airtable.viewId" - table_id_prop: typing_extensions.Annotated[str, FieldMetadata(alias="tableIdProp")] + table_id_prop: typing_extensions.Annotated[ + str, FieldMetadata(alias="tableIdProp"), pydantic.Field(alias="tableIdProp") + ] name: str label: typing.Optional[str] = None description: typing.Optional[str] = None optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -498,17 +632,27 @@ class ConfigurableProp_AirtableFieldId(UniversalBaseModel): """ type: typing.Literal["$.airtable.fieldId"] = "$.airtable.fieldId" - table_id_prop: typing_extensions.Annotated[str, FieldMetadata(alias="tableIdProp")] + table_id_prop: typing_extensions.Annotated[ + str, FieldMetadata(alias="tableIdProp"), pydantic.Field(alias="tableIdProp") + ] name: str label: typing.Optional[str] = None description: typing.Optional[str] = None optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -526,17 +670,25 @@ class ConfigurableProp_DiscordChannel(UniversalBaseModel): """ type: typing.Literal["$.discord.channel"] = "$.discord.channel" - app_prop: typing_extensions.Annotated[str, FieldMetadata(alias="appProp")] + app_prop: typing_extensions.Annotated[str, FieldMetadata(alias="appProp"), pydantic.Field(alias="appProp")] name: str label: typing.Optional[str] = None description: typing.Optional[str] = None optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -554,17 +706,27 @@ class ConfigurableProp_DiscordChannelArray(UniversalBaseModel): """ type: typing.Literal["$.discord.channel[]"] = "$.discord.channel[]" - app_prop: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="appProp")] = None + app_prop: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="appProp"), pydantic.Field(alias="appProp") + ] = None name: str label: typing.Optional[str] = None description: typing.Optional[str] = None optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -592,10 +754,18 @@ class ConfigurableProp_Integer(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -621,10 +791,18 @@ class ConfigurableProp_Object(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -651,10 +829,18 @@ class ConfigurableProp_String(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 @@ -681,10 +867,18 @@ class ConfigurableProp_StringArray(UniversalBaseModel): optional: typing.Optional[bool] = None disabled: typing.Optional[bool] = None hidden: typing.Optional[bool] = None - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = None - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = None - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = None - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = None + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="remoteOptions"), pydantic.Field(alias="remoteOptions") + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="useQuery"), pydantic.Field(alias="useQuery") + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="reloadProps"), pydantic.Field(alias="reloadProps") + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withLabel"), pydantic.Field(alias="withLabel") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/configurable_prop_airtable_base_id.py b/src/pipedream/types/configurable_prop_airtable_base_id.py index 322ca16..dbecf66 100644 --- a/src/pipedream/types/configurable_prop_airtable_base_id.py +++ b/src/pipedream/types/configurable_prop_airtable_base_id.py @@ -10,10 +10,11 @@ class ConfigurablePropAirtableBaseId(ConfigurablePropBase): - app_prop: typing_extensions.Annotated[str, FieldMetadata(alias="appProp")] = pydantic.Field() - """ - The name of the app prop that provides Airtable authentication - """ + app_prop: typing_extensions.Annotated[ + str, + FieldMetadata(alias="appProp"), + pydantic.Field(alias="appProp", description="The name of the app prop that provides Airtable authentication"), + ] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/configurable_prop_airtable_field_id.py b/src/pipedream/types/configurable_prop_airtable_field_id.py index a2fa882..57b1768 100644 --- a/src/pipedream/types/configurable_prop_airtable_field_id.py +++ b/src/pipedream/types/configurable_prop_airtable_field_id.py @@ -10,10 +10,11 @@ class ConfigurablePropAirtableFieldId(ConfigurablePropBase): - table_id_prop: typing_extensions.Annotated[str, FieldMetadata(alias="tableIdProp")] = pydantic.Field() - """ - The name of the prop that provides the Airtable table ID - """ + table_id_prop: typing_extensions.Annotated[ + str, + FieldMetadata(alias="tableIdProp"), + pydantic.Field(alias="tableIdProp", description="The name of the prop that provides the Airtable table ID"), + ] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/configurable_prop_airtable_table_id.py b/src/pipedream/types/configurable_prop_airtable_table_id.py index a6be428..4bd65d2 100644 --- a/src/pipedream/types/configurable_prop_airtable_table_id.py +++ b/src/pipedream/types/configurable_prop_airtable_table_id.py @@ -10,10 +10,11 @@ class ConfigurablePropAirtableTableId(ConfigurablePropBase): - base_id_prop: typing_extensions.Annotated[str, FieldMetadata(alias="baseIdProp")] = pydantic.Field() - """ - The name of the prop that provides the Airtable base ID - """ + base_id_prop: typing_extensions.Annotated[ + str, + FieldMetadata(alias="baseIdProp"), + pydantic.Field(alias="baseIdProp", description="The name of the prop that provides the Airtable base ID"), + ] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/configurable_prop_airtable_view_id.py b/src/pipedream/types/configurable_prop_airtable_view_id.py index 7d265b8..016bb2c 100644 --- a/src/pipedream/types/configurable_prop_airtable_view_id.py +++ b/src/pipedream/types/configurable_prop_airtable_view_id.py @@ -10,10 +10,11 @@ class ConfigurablePropAirtableViewId(ConfigurablePropBase): - table_id_prop: typing_extensions.Annotated[str, FieldMetadata(alias="tableIdProp")] = pydantic.Field() - """ - The name of the prop that provides the Airtable table ID - """ + table_id_prop: typing_extensions.Annotated[ + str, + FieldMetadata(alias="tableIdProp"), + pydantic.Field(alias="tableIdProp", description="The name of the prop that provides the Airtable table ID"), + ] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/configurable_prop_alert.py b/src/pipedream/types/configurable_prop_alert.py index 0e5e5fd..306292d 100644 --- a/src/pipedream/types/configurable_prop_alert.py +++ b/src/pipedream/types/configurable_prop_alert.py @@ -12,7 +12,7 @@ class ConfigurablePropAlert(ConfigurablePropBase): alert_type: typing_extensions.Annotated[ - typing.Optional[ConfigurablePropAlertType], FieldMetadata(alias="alertType") + typing.Optional[ConfigurablePropAlertType], FieldMetadata(alias="alertType"), pydantic.Field(alias="alertType") ] = None content: str = pydantic.Field() """ diff --git a/src/pipedream/types/configurable_prop_apphook.py b/src/pipedream/types/configurable_prop_apphook.py index 7847505..9b12b95 100644 --- a/src/pipedream/types/configurable_prop_apphook.py +++ b/src/pipedream/types/configurable_prop_apphook.py @@ -10,18 +10,16 @@ class ConfigurablePropApphook(ConfigurablePropBase): - app_prop: typing_extensions.Annotated[str, FieldMetadata(alias="appProp")] = pydantic.Field() - """ - The name of the app prop that this apphook depends on - """ - - event_names: typing_extensions.Annotated[typing.Optional[typing.List[str]], FieldMetadata(alias="eventNames")] = ( - pydantic.Field(default=None) - ) - """ - List of event names to listen for - """ - + app_prop: typing_extensions.Annotated[ + str, + FieldMetadata(alias="appProp"), + pydantic.Field(alias="appProp", description="The name of the app prop that this apphook depends on"), + ] + event_names: typing_extensions.Annotated[ + typing.Optional[typing.List[str]], + FieldMetadata(alias="eventNames"), + pydantic.Field(alias="eventNames", description="List of event names to listen for"), + ] = None remote: typing.Optional[bool] = pydantic.Field(default=None) """ Whether this apphook is remote diff --git a/src/pipedream/types/configurable_prop_base.py b/src/pipedream/types/configurable_prop_base.py index d0ccb3e..93921b4 100644 --- a/src/pipedream/types/configurable_prop_base.py +++ b/src/pipedream/types/configurable_prop_base.py @@ -43,33 +43,38 @@ class ConfigurablePropBase(UniversalBaseModel): If true, should not expose this prop to the user """ - remote_options: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="remoteOptions")] = ( - pydantic.Field(default=None) - ) - """ - If true, call `configureComponent` for this prop to load remote options. It is safe, and preferred, given a returned list of { label: string; value: any } objects to set the prop value to { __lv: { label: string; value: any } }. This way, on load, you can access label for the value without necessarily reloading these options - """ - - use_query: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="useQuery")] = pydantic.Field( - default=None - ) - """ - If true, calls to `configureComponent` for this prop support receiving a `query` parameter to filter remote options - """ - - reload_props: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="reloadProps")] = ( - pydantic.Field(default=None) - ) - """ - If true, after setting a value for this prop, a call to `reloadComponentProps` is required as the component has dynamic configurable props dependent on this one - """ - - with_label: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="withLabel")] = pydantic.Field( - default=None - ) - """ - If true, you must save the configured prop value as a "label-value" object which should look like: { __lv: { label: string; value: any } } because the execution needs to access the label - """ + remote_options: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="remoteOptions"), + pydantic.Field( + alias="remoteOptions", + description="If true, call `configureComponent` for this prop to load remote options. It is safe, and preferred, given a returned list of { label: string; value: any } objects to set the prop value to { __lv: { label: string; value: any } }. This way, on load, you can access label for the value without necessarily reloading these options", + ), + ] = None + use_query: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="useQuery"), + pydantic.Field( + alias="useQuery", + description="If true, calls to `configureComponent` for this prop support receiving a `query` parameter to filter remote options", + ), + ] = None + reload_props: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="reloadProps"), + pydantic.Field( + alias="reloadProps", + description="If true, after setting a value for this prop, a call to `reloadComponentProps` is required as the component has dynamic configurable props dependent on this one", + ), + ] = None + with_label: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="withLabel"), + pydantic.Field( + alias="withLabel", + description='If true, you must save the configured prop value as a "label-value" object which should look like: { __lv: { label: string; value: any } } because the execution needs to access the label', + ), + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/configurable_prop_discord_channel.py b/src/pipedream/types/configurable_prop_discord_channel.py index e8c025f..38a6edd 100644 --- a/src/pipedream/types/configurable_prop_discord_channel.py +++ b/src/pipedream/types/configurable_prop_discord_channel.py @@ -10,10 +10,11 @@ class ConfigurablePropDiscordChannel(ConfigurablePropBase): - app_prop: typing_extensions.Annotated[str, FieldMetadata(alias="appProp")] = pydantic.Field() - """ - The name of the app prop that provides Discord authentication - """ + app_prop: typing_extensions.Annotated[ + str, + FieldMetadata(alias="appProp"), + pydantic.Field(alias="appProp", description="The name of the app prop that provides Discord authentication"), + ] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/configurable_prop_discord_channel_array.py b/src/pipedream/types/configurable_prop_discord_channel_array.py index 7c5af21..11d6e11 100644 --- a/src/pipedream/types/configurable_prop_discord_channel_array.py +++ b/src/pipedream/types/configurable_prop_discord_channel_array.py @@ -10,12 +10,11 @@ class ConfigurablePropDiscordChannelArray(ConfigurablePropBase): - app_prop: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="appProp")] = pydantic.Field( - default=None - ) - """ - The name of the app prop that provides Discord authentication - """ + app_prop: typing_extensions.Annotated[ + typing.Optional[str], + FieldMetadata(alias="appProp"), + pydantic.Field(alias="appProp", description="The name of the app prop that provides Discord authentication"), + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/configurable_prop_http.py b/src/pipedream/types/configurable_prop_http.py index c9276b6..6a49c4d 100644 --- a/src/pipedream/types/configurable_prop_http.py +++ b/src/pipedream/types/configurable_prop_http.py @@ -10,12 +10,11 @@ class ConfigurablePropHttp(ConfigurablePropBase): - custom_response: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="customResponse")] = ( - pydantic.Field(default=None) - ) - """ - Whether this HTTP interface allows custom responses - """ + custom_response: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="customResponse"), + pydantic.Field(alias="customResponse", description="Whether this HTTP interface allows custom responses"), + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/configure_prop_response.py b/src/pipedream/types/configure_prop_response.py index 54ad6c5..70e5300 100644 --- a/src/pipedream/types/configure_prop_response.py +++ b/src/pipedream/types/configure_prop_response.py @@ -17,12 +17,10 @@ class ConfigurePropResponse(UniversalBaseModel): options: typing.Optional[ConfigurePropOptions] = None string_options: typing_extensions.Annotated[ - typing.Optional[typing.List[str]], FieldMetadata(alias="stringOptions") - ] = pydantic.Field(default=None) - """ - Available options for the configured prop - """ - + typing.Optional[typing.List[str]], + FieldMetadata(alias="stringOptions"), + pydantic.Field(alias="stringOptions", description="Available options for the configured prop"), + ] = None observations: typing.Optional[typing.List[Observation]] = None context: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(default=None) """ diff --git a/src/pipedream/types/configured_prop_value_app.py b/src/pipedream/types/configured_prop_value_app.py index acafb83..4aaf2db 100644 --- a/src/pipedream/types/configured_prop_value_app.py +++ b/src/pipedream/types/configured_prop_value_app.py @@ -10,7 +10,9 @@ class ConfiguredPropValueApp(UniversalBaseModel): - auth_provision_id: typing_extensions.Annotated[AccountId, FieldMetadata(alias="authProvisionId")] + auth_provision_id: typing_extensions.Annotated[ + AccountId, FieldMetadata(alias="authProvisionId"), pydantic.Field(alias="authProvisionId") + ] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/configured_prop_value_sql.py b/src/pipedream/types/configured_prop_value_sql.py index 81eb9ad..2020b30 100644 --- a/src/pipedream/types/configured_prop_value_sql.py +++ b/src/pipedream/types/configured_prop_value_sql.py @@ -24,12 +24,13 @@ class ConfiguredPropValueSql(UniversalBaseModel): The list of parameters for the prepared statement """ - use_prepared_statements: typing_extensions.Annotated[bool, FieldMetadata(alias="usePreparedStatements")] = ( - pydantic.Field() - ) - """ - Whether to use prepared statements for the query or not - """ + use_prepared_statements: typing_extensions.Annotated[ + bool, + FieldMetadata(alias="usePreparedStatements"), + pydantic.Field( + alias="usePreparedStatements", description="Whether to use prepared statements for the query or not" + ), + ] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/connect_usage.py b/src/pipedream/types/connect_usage.py new file mode 100644 index 0000000..9f70e87 --- /dev/null +++ b/src/pipedream/types/connect_usage.py @@ -0,0 +1,51 @@ +# 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 ConnectUsage(UniversalBaseModel): + """ + Connect usage record + """ + + credits_used: int = pydantic.Field() + """ + Total Connect credits used + """ + + action_run_credits_used: typing.Optional[int] = pydantic.Field(default=None) + """ + Credits used when running Connect actions + """ + + proxy_credits_used: typing.Optional[int] = pydantic.Field(default=None) + """ + Credits used by Connect proxy requests + """ + + source_emit_credits_used: typing.Optional[int] = pydantic.Field(default=None) + """ + Credits used by Connect source event emissions + """ + + usage_start_ts: int = pydantic.Field() + """ + Usage window start timestamp (seconds) + """ + + usage_end_ts: int = pydantic.Field() + """ + Usage window end timestamp (seconds) + """ + + 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/pipedream/types/connect_usage_response.py b/src/pipedream/types/connect_usage_response.py new file mode 100644 index 0000000..c5e1c15 --- /dev/null +++ b/src/pipedream/types/connect_usage_response.py @@ -0,0 +1,24 @@ +# 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 .connect_usage import ConnectUsage + + +class ConnectUsageResponse(UniversalBaseModel): + """ + Connect usage records for a time window + """ + + data: typing.List[ConnectUsage] + + 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/pipedream/types/dynamic_props.py b/src/pipedream/types/dynamic_props.py index e5b93ba..8c80452 100644 --- a/src/pipedream/types/dynamic_props.py +++ b/src/pipedream/types/dynamic_props.py @@ -20,11 +20,10 @@ class DynamicProps(UniversalBaseModel): """ configurable_props: typing_extensions.Annotated[ - typing.Optional[typing.List[ConfigurableProp]], FieldMetadata(alias="configurableProps") - ] = pydantic.Field(default=None) - """ - The updated configurable properties - """ + typing.Optional[typing.List[ConfigurableProp]], + FieldMetadata(alias="configurableProps"), + pydantic.Field(alias="configurableProps", description="The updated configurable properties"), + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/http_request_body.py b/src/pipedream/types/http_request_body.py index fe1fcde..3f5a006 100644 --- a/src/pipedream/types/http_request_body.py +++ b/src/pipedream/types/http_request_body.py @@ -17,7 +17,9 @@ class HttpRequestBody(UniversalBaseModel): """ type: typing.Optional[HttpRequestBodyType] = None - content_type: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="contentType")] = None + content_type: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="contentType"), pydantic.Field(alias="contentType") + ] = None fields: typing.Optional[typing.List[HttpRequestField]] = None mode: typing.Optional[HttpRequestBodyMode] = None raw: typing.Optional[str] = None diff --git a/src/pipedream/types/page_info.py b/src/pipedream/types/page_info.py index 3cd0148..bbf3fef 100644 --- a/src/pipedream/types/page_info.py +++ b/src/pipedream/types/page_info.py @@ -7,10 +7,25 @@ class PageInfo(UniversalBaseModel): - count: typing.Optional[int] = None - total_count: typing.Optional[int] = None - start_cursor: typing.Optional[str] = None - end_cursor: typing.Optional[str] = None + count: typing.Optional[int] = pydantic.Field(default=None) + """ + Number of items returned + """ + + total_count: typing.Optional[int] = pydantic.Field(default=None) + """ + Total number of items + """ + + start_cursor: typing.Optional[str] = pydantic.Field(default=None) + """ + Used to fetch the previous page of items + """ + + end_cursor: typing.Optional[str] = pydantic.Field(default=None) + """ + Used to fetch the next page of items + """ if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/prop_option_nested.py b/src/pipedream/types/prop_option_nested.py index 806bf7c..0305616 100644 --- a/src/pipedream/types/prop_option_nested.py +++ b/src/pipedream/types/prop_option_nested.py @@ -14,7 +14,7 @@ class PropOptionNested(UniversalBaseModel): A configuration option for a component's prop (nested under `__lv`) """ - lv: typing_extensions.Annotated[PropOption, FieldMetadata(alias="__lv")] + lv: typing_extensions.Annotated[PropOption, FieldMetadata(alias="__lv"), pydantic.Field(alias="__lv")] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/proxy_response_binary.py b/src/pipedream/types/proxy_response_binary.py index e799429..da2f3e8 100644 --- a/src/pipedream/types/proxy_response_binary.py +++ b/src/pipedream/types/proxy_response_binary.py @@ -1,3 +1,3 @@ # This file was auto-generated by Fern from our API Definition. -ProxyResponseBinary = str +ProxyResponseBinary = bytes diff --git a/src/pipedream/types/reload_props_response.py b/src/pipedream/types/reload_props_response.py index 6a138c5..017a707 100644 --- a/src/pipedream/types/reload_props_response.py +++ b/src/pipedream/types/reload_props_response.py @@ -21,9 +21,9 @@ class ReloadPropsResponse(UniversalBaseModel): Any errors that occurred during configuration """ - dynamic_props: typing_extensions.Annotated[typing.Optional[DynamicProps], FieldMetadata(alias="dynamicProps")] = ( - None - ) + dynamic_props: typing_extensions.Annotated[ + typing.Optional[DynamicProps], FieldMetadata(alias="dynamicProps"), pydantic.Field(alias="dynamicProps") + ] = None if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/timer_interval.py b/src/pipedream/types/timer_interval.py index 36981c8..58cf141 100644 --- a/src/pipedream/types/timer_interval.py +++ b/src/pipedream/types/timer_interval.py @@ -13,10 +13,11 @@ class TimerInterval(UniversalBaseModel): Timer configuration using interval in seconds """ - interval_seconds: typing_extensions.Annotated[int, FieldMetadata(alias="intervalSeconds")] = pydantic.Field() - """ - Interval in seconds for timer execution - """ + interval_seconds: typing_extensions.Annotated[ + int, + FieldMetadata(alias="intervalSeconds"), + pydantic.Field(alias="intervalSeconds", description="Interval in seconds for timer execution"), + ] if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/pipedream/types/tool_annotations.py b/src/pipedream/types/tool_annotations.py index a66f513..dcada6f 100644 --- a/src/pipedream/types/tool_annotations.py +++ b/src/pipedream/types/tool_annotations.py @@ -13,34 +13,35 @@ class ToolAnnotations(UniversalBaseModel): Optional properties describing component behavior """ - destructive_hint: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="destructiveHint")] = ( - pydantic.Field(default=None) - ) - """ - If true, the component may perform destructive updates to its environment. If false, the component performs only additive updates. - """ - - idempotent_hint: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="idempotentHint")] = ( - pydantic.Field(default=None) - ) - """ - If true, calling the component repeatedly with the same arguments will have no additional effect on the its environment. - """ - - open_world_hint: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="openWorldHint")] = ( - pydantic.Field(default=None) - ) - """ - If true, this component may interact with an “open world” of external entities. If false, the component's domain of interaction is closed. For example, the world of a web search component is open, whereas that of a memory component is not. - """ - - read_only_hint: typing_extensions.Annotated[typing.Optional[bool], FieldMetadata(alias="readOnlyHint")] = ( - pydantic.Field(default=None) - ) - """ - If true, the component does not modify its environment. - """ - + destructive_hint: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="destructiveHint"), + pydantic.Field( + alias="destructiveHint", + description="If true, the component may perform destructive updates to its environment. If false, the component performs only additive updates.", + ), + ] = None + idempotent_hint: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="idempotentHint"), + pydantic.Field( + alias="idempotentHint", + description="If true, calling the component repeatedly with the same arguments will have no additional effect on the its environment.", + ), + ] = None + open_world_hint: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="openWorldHint"), + pydantic.Field( + alias="openWorldHint", + description="If true, this component may interact with an “open world” of external entities. If false, the component's domain of interaction is closed. For example, the world of a web search component is open, whereas that of a memory component is not.", + ), + ] = None + read_only_hint: typing_extensions.Annotated[ + typing.Optional[bool], + FieldMetadata(alias="readOnlyHint"), + pydantic.Field(alias="readOnlyHint", description="If true, the component does not modify its environment."), + ] = None title: typing.Optional[str] = pydantic.Field(default=None) """ A human-readable title for the component. diff --git a/src/pipedream/usage/__init__.py b/src/pipedream/usage/__init__.py new file mode 100644 index 0000000..5cde020 --- /dev/null +++ b/src/pipedream/usage/__init__.py @@ -0,0 +1,4 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + diff --git a/src/pipedream/usage/client.py b/src/pipedream/usage/client.py new file mode 100644 index 0000000..925486d --- /dev/null +++ b/src/pipedream/usage/client.py @@ -0,0 +1,122 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from ..types.connect_usage_response import ConnectUsageResponse +from .raw_client import AsyncRawUsageClient, RawUsageClient + + +class UsageClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawUsageClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawUsageClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawUsageClient + """ + return self._raw_client + + def list( + self, *, start_ts: int, end_ts: int, request_options: typing.Optional[RequestOptions] = None + ) -> ConnectUsageResponse: + """ + Retrieve Connect usage records for a time window + + Parameters + ---------- + start_ts : int + Usage window start timestamp (seconds) + + end_ts : int + Usage window end timestamp (seconds) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ConnectUsageResponse + usage records listed + + Examples + -------- + from pipedream import Pipedream + + client = Pipedream( + project_id="YOUR_PROJECT_ID", + ) + client.usage.list( + start_ts=1, + end_ts=1, + ) + """ + _response = self._raw_client.list(start_ts=start_ts, end_ts=end_ts, request_options=request_options) + return _response.data + + +class AsyncUsageClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawUsageClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawUsageClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawUsageClient + """ + return self._raw_client + + async def list( + self, *, start_ts: int, end_ts: int, request_options: typing.Optional[RequestOptions] = None + ) -> ConnectUsageResponse: + """ + Retrieve Connect usage records for a time window + + Parameters + ---------- + start_ts : int + Usage window start timestamp (seconds) + + end_ts : int + Usage window end timestamp (seconds) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ConnectUsageResponse + usage records listed + + Examples + -------- + import asyncio + + from pipedream import AsyncPipedream + + client = AsyncPipedream( + project_id="YOUR_PROJECT_ID", + ) + + + async def main() -> None: + await client.usage.list( + start_ts=1, + end_ts=1, + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.list(start_ts=start_ts, end_ts=end_ts, request_options=request_options) + return _response.data diff --git a/src/pipedream/usage/raw_client.py b/src/pipedream/usage/raw_client.py new file mode 100644 index 0000000..8a07c9a --- /dev/null +++ b/src/pipedream/usage/raw_client.py @@ -0,0 +1,159 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from ..errors.bad_request_error import BadRequestError +from ..errors.too_many_requests_error import TooManyRequestsError +from ..types.connect_usage_response import ConnectUsageResponse + + +class RawUsageClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def list( + self, *, start_ts: int, end_ts: int, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[ConnectUsageResponse]: + """ + Retrieve Connect usage records for a time window + + Parameters + ---------- + start_ts : int + Usage window start timestamp (seconds) + + end_ts : int + Usage window end timestamp (seconds) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ConnectUsageResponse] + usage records listed + """ + _response = self._client_wrapper.httpx_client.request( + "v1/connect/usage", + method="GET", + params={ + "start_ts": start_ts, + "end_ts": end_ts, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ConnectUsageResponse, + parse_obj_as( + type_=ConnectUsageResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # 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) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) + + +class AsyncRawUsageClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list( + self, *, start_ts: int, end_ts: int, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[ConnectUsageResponse]: + """ + Retrieve Connect usage records for a time window + + Parameters + ---------- + start_ts : int + Usage window start timestamp (seconds) + + end_ts : int + Usage window end timestamp (seconds) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ConnectUsageResponse] + usage records listed + """ + _response = await self._client_wrapper.httpx_client.request( + "v1/connect/usage", + method="GET", + params={ + "start_ts": start_ts, + "end_ts": end_ts, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ConnectUsageResponse, + parse_obj_as( + type_=ConnectUsageResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise BadRequestError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 429: + raise TooManyRequestsError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # 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) + raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json) diff --git a/src/pipedream/users/client.py b/src/pipedream/users/client.py index b597a38..dbb1d0a 100644 --- a/src/pipedream/users/client.py +++ b/src/pipedream/users/client.py @@ -45,9 +45,6 @@ def delete_external_user( client = Pipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) client.users.delete_external_user( external_user_id="external_user_id", @@ -97,9 +94,6 @@ async def delete_external_user( client = AsyncPipedream( project_id="YOUR_PROJECT_ID", - project_environment="YOUR_PROJECT_ENVIRONMENT", - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", ) diff --git a/tests/utils/test_http_client.py b/tests/utils/test_http_client.py index 50f2759..3576329 100644 --- a/tests/utils/test_http_client.py +++ b/tests/utils/test_http_client.py @@ -1,9 +1,49 @@ # This file was auto-generated by Fern from our API Definition. -from pipedream.core.http_client import get_request_body, remove_none_from_dict +from typing import Any, Dict + +import pytest + +from pipedream.core.http_client import ( + AsyncHttpClient, + HttpClient, + _build_url, + get_request_body, + remove_none_from_dict, +) from pipedream.core.request_options import RequestOptions +# Stub clients for testing HttpClient and AsyncHttpClient +class _DummySyncClient: + """A minimal stub for httpx.Client that records request arguments.""" + + def __init__(self) -> None: + self.last_request_kwargs: Dict[str, Any] = {} + + def request(self, **kwargs: Any) -> "_DummyResponse": + self.last_request_kwargs = kwargs + return _DummyResponse() + + +class _DummyAsyncClient: + """A minimal stub for httpx.AsyncClient that records request arguments.""" + + def __init__(self) -> None: + self.last_request_kwargs: Dict[str, Any] = {} + + async def request(self, **kwargs: Any) -> "_DummyResponse": + self.last_request_kwargs = kwargs + return _DummyResponse() + + +class _DummyResponse: + """A minimal stub for httpx.Response.""" + + status_code = 200 + headers: Dict[str, str] = {} + + def get_request_options() -> RequestOptions: return {"additional_body_parameters": {"see you": "later"}} @@ -52,17 +92,30 @@ def test_get_none_request_body() -> None: def test_get_empty_json_request_body() -> None: + """Test that implicit empty bodies (json=None) are collapsed to None.""" unrelated_request_options: RequestOptions = {"max_retries": 3} json_body, data_body = get_request_body(json=None, data=None, request_options=unrelated_request_options, omit=None) assert json_body is None assert data_body is None - json_body_extras, data_body_extras = get_request_body( - json={}, data=None, request_options=unrelated_request_options, omit=None - ) - assert json_body_extras is None - assert data_body_extras is None +def test_explicit_empty_json_body_is_preserved() -> None: + """Test that explicit empty bodies (json={}) are preserved and sent as {}. + + This is important for endpoints where the request body is required but all + fields are optional. The server expects valid JSON ({}) not an empty body. + """ + unrelated_request_options: RequestOptions = {"max_retries": 3} + + # Explicit json={} should be preserved + json_body, data_body = get_request_body(json={}, data=None, request_options=unrelated_request_options, omit=None) + assert json_body == {} + assert data_body is None + + # Explicit data={} should also be preserved + json_body2, data_body2 = get_request_body(json=None, data={}, request_options=unrelated_request_options, omit=None) + assert json_body2 is None + assert data_body2 == {} def test_json_body_preserves_none_values() -> None: @@ -107,3 +160,141 @@ def test_remove_none_from_dict_empty_dict() -> None: def test_remove_none_from_dict_all_none() -> None: """Test that remove_none_from_dict handles dict with all None values.""" assert remove_none_from_dict({"a": None, "b": None}) == {} + + +def test_http_client_does_not_pass_empty_params_list() -> None: + """Test that HttpClient passes params=None when params are empty. + + This prevents httpx from stripping existing query parameters from the URL, + which happens when params=[] or params={} is passed. + """ + dummy_client = _DummySyncClient() + http_client = HttpClient( + httpx_client=dummy_client, # type: ignore[arg-type] + base_timeout=lambda: None, + base_headers=lambda: {}, + base_url=lambda: "https://example.com", + ) + + # Use a path with query params (e.g., pagination cursor URL) + http_client.request( + path="resource?after=123", + method="GET", + params=None, + request_options=None, + ) + + # We care that httpx receives params=None, not [] or {} + assert "params" in dummy_client.last_request_kwargs + assert dummy_client.last_request_kwargs["params"] is None + + # Verify the query string in the URL is preserved + url = str(dummy_client.last_request_kwargs["url"]) + assert "after=123" in url, f"Expected query param 'after=123' in URL, got: {url}" + + +def test_http_client_passes_encoded_params_when_present() -> None: + """Test that HttpClient passes encoded params when params are provided.""" + dummy_client = _DummySyncClient() + http_client = HttpClient( + httpx_client=dummy_client, # type: ignore[arg-type] + base_timeout=lambda: None, + base_headers=lambda: {}, + base_url=lambda: "https://example.com/resource", + ) + + http_client.request( + path="", + method="GET", + params={"after": "456"}, + request_options=None, + ) + + params = dummy_client.last_request_kwargs["params"] + # For a simple dict, encode_query should give a single (key, value) tuple + assert params == [("after", "456")] + + +@pytest.mark.asyncio +async def test_async_http_client_does_not_pass_empty_params_list() -> None: + """Test that AsyncHttpClient passes params=None when params are empty. + + This prevents httpx from stripping existing query parameters from the URL, + which happens when params=[] or params={} is passed. + """ + dummy_client = _DummyAsyncClient() + http_client = AsyncHttpClient( + httpx_client=dummy_client, # type: ignore[arg-type] + base_timeout=lambda: None, + base_headers=lambda: {}, + base_url=lambda: "https://example.com", + async_base_headers=None, + ) + + # Use a path with query params (e.g., pagination cursor URL) + await http_client.request( + path="resource?after=123", + method="GET", + params=None, + request_options=None, + ) + + # We care that httpx receives params=None, not [] or {} + assert "params" in dummy_client.last_request_kwargs + assert dummy_client.last_request_kwargs["params"] is None + + # Verify the query string in the URL is preserved + url = str(dummy_client.last_request_kwargs["url"]) + assert "after=123" in url, f"Expected query param 'after=123' in URL, got: {url}" + + +@pytest.mark.asyncio +async def test_async_http_client_passes_encoded_params_when_present() -> None: + """Test that AsyncHttpClient passes encoded params when params are provided.""" + dummy_client = _DummyAsyncClient() + http_client = AsyncHttpClient( + httpx_client=dummy_client, # type: ignore[arg-type] + base_timeout=lambda: None, + base_headers=lambda: {}, + base_url=lambda: "https://example.com/resource", + async_base_headers=None, + ) + + await http_client.request( + path="", + method="GET", + params={"after": "456"}, + request_options=None, + ) + + params = dummy_client.last_request_kwargs["params"] + # For a simple dict, encode_query should give a single (key, value) tuple + assert params == [("after", "456")] + + +def test_basic_url_joining() -> None: + """Test basic URL joining with a simple base URL and path.""" + result = _build_url("https://api.example.com", "/users") + assert result == "https://api.example.com/users" + + +def test_basic_url_joining_trailing_slash() -> None: + """Test basic URL joining with a simple base URL and path.""" + result = _build_url("https://api.example.com/", "/users") + assert result == "https://api.example.com/users" + + +def test_preserves_base_url_path_prefix() -> None: + """Test that path prefixes in base URL are preserved. + + This is the critical bug fix - urllib.parse.urljoin() would strip + the path prefix when the path starts with '/'. + """ + result = _build_url("https://cloud.example.com/org/tenant/api", "/users") + assert result == "https://cloud.example.com/org/tenant/api/users" + + +def test_preserves_base_url_path_prefix_trailing_slash() -> None: + """Test that path prefixes in base URL are preserved.""" + result = _build_url("https://cloud.example.com/org/tenant/api/", "/users") + assert result == "https://cloud.example.com/org/tenant/api/users"