From 48e933b32fcc2620bb4f850f41f57865dfa2e9cf Mon Sep 17 00:00:00 2001 From: Bindi Pankhudi Date: Thu, 15 Feb 2024 14:07:05 -0800 Subject: [PATCH 01/43] AirbyteLib: Fix no-such-table-error (#35311) Co-authored-by: Bindi Pankhudi Co-authored-by: Aaron Steers --- airbyte-lib/airbyte_lib/_processors.py | 17 +- airbyte-lib/examples/run_github.py | 4 +- airbyte-lib/poetry.lock | 439 +++++++++--------- airbyte-lib/pyproject.toml | 2 + .../fixtures/source-test/source_test/run.py | 15 + .../test_source_test_fixture.py | 93 ++-- 6 files changed, 324 insertions(+), 246 deletions(-) diff --git a/airbyte-lib/airbyte_lib/_processors.py b/airbyte-lib/airbyte_lib/_processors.py index 1b51e6df8ee7..e879d22214e0 100644 --- a/airbyte-lib/airbyte_lib/_processors.py +++ b/airbyte-lib/airbyte_lib/_processors.py @@ -45,6 +45,7 @@ DEFAULT_BATCH_SIZE = 10_000 +DEBUG_MODE = False # Set to True to enable additional debug logging. class BatchHandle: @@ -60,6 +61,7 @@ class RecordProcessor(abc.ABC): config_class: type[CacheConfigBase] skip_finalize_step: bool = False + _expected_streams: set[str] def __init__( self, @@ -109,6 +111,7 @@ def register_source( incoming_source_catalog=incoming_source_catalog, incoming_stream_names=stream_names, ) + self._expected_streams = stream_names @property def _streams_with_data(self) -> set[str]: @@ -203,12 +206,18 @@ def process_airbyte_messages( # Type.LOG, Type.TRACE, Type.CONTROL, etc. pass + # Add empty streams to the dictionary, so we create a destination table for it + for stream_name in self._expected_streams: + if stream_name not in stream_batches: + if DEBUG_MODE: + print(f"Stream {stream_name} has no data") + stream_batches[stream_name] = [] + # We are at the end of the stream. Process whatever else is queued. for stream_name, stream_batch in stream_batches.items(): - if stream_batch: - record_batch = pa.Table.from_pylist(stream_batch) - self._process_batch(stream_name, record_batch) - progress.log_batch_written(stream_name, len(stream_batch)) + record_batch = pa.Table.from_pylist(stream_batch) + self._process_batch(stream_name, record_batch) + progress.log_batch_written(stream_name, len(stream_batch)) # Finalize any pending batches for stream_name in list(self._pending_batches.keys()): diff --git a/airbyte-lib/examples/run_github.py b/airbyte-lib/examples/run_github.py index 3faf22b60e19..253e1275a541 100644 --- a/airbyte-lib/examples/run_github.py +++ b/airbyte-lib/examples/run_github.py @@ -19,12 +19,12 @@ source = ab.get_source("source-github") source.set_config( { - "repositories": ["airbytehq/quickstarts"], + "repositories": ["airbytehq/airbyte-lib-private-beta"], "credentials": {"personal_access_token": GITHUB_TOKEN}, } ) source.check() -source.select_streams(["issues", "pull_requests", "commits", "collaborators"]) +source.select_streams(["issues", "pull_requests", "commits", "collaborators", "deployments"]) result = source.read(cache=ab.new_local_cache("github")) print(result.processed_records) diff --git a/airbyte-lib/poetry.lock b/airbyte-lib/poetry.lock index b4ca0726238c..86d14143870c 100644 --- a/airbyte-lib/poetry.lock +++ b/airbyte-lib/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "airbyte-cdk" @@ -53,13 +53,13 @@ pydantic = ">=1.9.2,<2.0.0" [[package]] name = "airbyte-source-faker" -version = "6.0.0" +version = "6.0.1" description = "Source implementation for fake but realistic looking data." optional = false python-versions = "*" files = [ - {file = "airbyte-source-faker-6.0.0.tar.gz", hash = "sha256:60c68980527b66f1ffa31e4e13c406233b6d9cfcb2a6acc23ebd827cd2532181"}, - {file = "airbyte_source_faker-6.0.0-py3-none-any.whl", hash = "sha256:d92265c5be31a8d2ac66e7ed40cbe134d62acbb63adbc05789697cf64784e5b7"}, + {file = "airbyte-source-faker-6.0.1.tar.gz", hash = "sha256:8173a48551fbfe0eb6e9c331fec650fa490f283736aef0d58e2f14e55f8cf90a"}, + {file = "airbyte_source_faker-6.0.1-py3-none-any.whl", hash = "sha256:622cd123589218cffe69755727addfe85873d7563002cf8d5f949586604e0d9f"}, ] [package.dependencies] @@ -438,50 +438,58 @@ files = [ [[package]] name = "duckdb" -version = "0.9.2" -description = "DuckDB embedded database" +version = "0.10.0" +description = "DuckDB in-process database" optional = false python-versions = ">=3.7.0" files = [ - {file = "duckdb-0.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aadcea5160c586704c03a8a796c06a8afffbefefb1986601104a60cb0bfdb5ab"}, - {file = "duckdb-0.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:08215f17147ed83cbec972175d9882387366de2ed36c21cbe4add04b39a5bcb4"}, - {file = "duckdb-0.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee6c2a8aba6850abef5e1be9dbc04b8e72a5b2c2b67f77892317a21fae868fe7"}, - {file = "duckdb-0.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ff49f3da9399900fd58b5acd0bb8bfad22c5147584ad2427a78d937e11ec9d0"}, - {file = "duckdb-0.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5ac5baf8597efd2bfa75f984654afcabcd698342d59b0e265a0bc6f267b3f0"}, - {file = "duckdb-0.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:81c6df905589a1023a27e9712edb5b724566587ef280a0c66a7ec07c8083623b"}, - {file = "duckdb-0.9.2-cp310-cp310-win32.whl", hash = "sha256:a298cd1d821c81d0dec8a60878c4b38c1adea04a9675fb6306c8f9083bbf314d"}, - {file = "duckdb-0.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:492a69cd60b6cb4f671b51893884cdc5efc4c3b2eb76057a007d2a2295427173"}, - {file = "duckdb-0.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:061a9ea809811d6e3025c5de31bc40e0302cfb08c08feefa574a6491e882e7e8"}, - {file = "duckdb-0.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a43f93be768af39f604b7b9b48891f9177c9282a408051209101ff80f7450d8f"}, - {file = "duckdb-0.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac29c8c8f56fff5a681f7bf61711ccb9325c5329e64f23cb7ff31781d7b50773"}, - {file = "duckdb-0.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b14d98d26bab139114f62ade81350a5342f60a168d94b27ed2c706838f949eda"}, - {file = "duckdb-0.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:796a995299878913e765b28cc2b14c8e44fae2f54ab41a9ee668c18449f5f833"}, - {file = "duckdb-0.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6cb64ccfb72c11ec9c41b3cb6181b6fd33deccceda530e94e1c362af5f810ba1"}, - {file = "duckdb-0.9.2-cp311-cp311-win32.whl", hash = "sha256:930740cb7b2cd9e79946e1d3a8f66e15dc5849d4eaeff75c8788d0983b9256a5"}, - {file = "duckdb-0.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:c28f13c45006fd525001b2011cdf91fa216530e9751779651e66edc0e446be50"}, - {file = "duckdb-0.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fbce7bbcb4ba7d99fcec84cec08db40bc0dd9342c6c11930ce708817741faeeb"}, - {file = "duckdb-0.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15a82109a9e69b1891f0999749f9e3265f550032470f51432f944a37cfdc908b"}, - {file = "duckdb-0.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9490fb9a35eb74af40db5569d90df8a04a6f09ed9a8c9caa024998c40e2506aa"}, - {file = "duckdb-0.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:696d5c6dee86c1a491ea15b74aafe34ad2b62dcd46ad7e03b1d00111ca1a8c68"}, - {file = "duckdb-0.9.2-cp37-cp37m-win32.whl", hash = "sha256:4f0935300bdf8b7631ddfc838f36a858c1323696d8c8a2cecbd416bddf6b0631"}, - {file = "duckdb-0.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:0aab900f7510e4d2613263865570203ddfa2631858c7eb8cbed091af6ceb597f"}, - {file = "duckdb-0.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7d8130ed6a0c9421b135d0743705ea95b9a745852977717504e45722c112bf7a"}, - {file = "duckdb-0.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:974e5de0294f88a1a837378f1f83330395801e9246f4e88ed3bfc8ada65dcbee"}, - {file = "duckdb-0.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4fbc297b602ef17e579bb3190c94d19c5002422b55814421a0fc11299c0c1100"}, - {file = "duckdb-0.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dd58a0d84a424924a35b3772419f8cd78a01c626be3147e4934d7a035a8ad68"}, - {file = "duckdb-0.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11a1194a582c80dfb57565daa06141727e415ff5d17e022dc5f31888a5423d33"}, - {file = "duckdb-0.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:be45d08541002a9338e568dca67ab4f20c0277f8f58a73dfc1435c5b4297c996"}, - {file = "duckdb-0.9.2-cp38-cp38-win32.whl", hash = "sha256:dd6f88aeb7fc0bfecaca633629ff5c986ac966fe3b7dcec0b2c48632fd550ba2"}, - {file = "duckdb-0.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:28100c4a6a04e69aa0f4a6670a6d3d67a65f0337246a0c1a429f3f28f3c40b9a"}, - {file = "duckdb-0.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7ae5bf0b6ad4278e46e933e51473b86b4b932dbc54ff097610e5b482dd125552"}, - {file = "duckdb-0.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e5d0bb845a80aa48ed1fd1d2d285dd352e96dc97f8efced2a7429437ccd1fe1f"}, - {file = "duckdb-0.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ce262d74a52500d10888110dfd6715989926ec936918c232dcbaddb78fc55b4"}, - {file = "duckdb-0.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6935240da090a7f7d2666f6d0a5e45ff85715244171ca4e6576060a7f4a1200e"}, - {file = "duckdb-0.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5cfb93e73911696a98b9479299d19cfbc21dd05bb7ab11a923a903f86b4d06e"}, - {file = "duckdb-0.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:64e3bc01751f31e7572d2716c3e8da8fe785f1cdc5be329100818d223002213f"}, - {file = "duckdb-0.9.2-cp39-cp39-win32.whl", hash = "sha256:6e5b80f46487636368e31b61461940e3999986359a78660a50dfdd17dd72017c"}, - {file = "duckdb-0.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:e6142a220180dbeea4f341708bd5f9501c5c962ce7ef47c1cadf5e8810b4cb13"}, - {file = "duckdb-0.9.2.tar.gz", hash = "sha256:3843afeab7c3fc4a4c0b53686a4cc1d9cdbdadcbb468d60fef910355ecafd447"}, + {file = "duckdb-0.10.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bd0ffb3fddef0f72a150e4d76e10942a84a1a0447d10907df1621b90d6668060"}, + {file = "duckdb-0.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f3d709d5c7c1a12b5e10d0b05fa916c670cd2b50178e3696faa0cc16048a1745"}, + {file = "duckdb-0.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9114aa22ec5d591a20ce5184be90f49d8e5b5348ceaab21e102c54560d07a5f8"}, + {file = "duckdb-0.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a37877efadf39caf7cadde0f430fedf762751b9c54750c821e2f1316705a21"}, + {file = "duckdb-0.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87cbc9e1d9c3fc9f14307bea757f99f15f46843c0ab13a6061354410824ed41f"}, + {file = "duckdb-0.10.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f0bfec79fed387201550517d325dff4fad2705020bc139d936cab08b9e845662"}, + {file = "duckdb-0.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c5622134d2d9796b15e09de810e450859d4beb46d9b861357ec9ae40a61b775c"}, + {file = "duckdb-0.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:089ee8e831ccaef1b73fc89c43b661567175eed0115454880bafed5e35cda702"}, + {file = "duckdb-0.10.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a05af63747f1d7021995f0811c333dee7316cec3b06c0d3e4741b9bdb678dd21"}, + {file = "duckdb-0.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:072d6eba5d8a59e0069a8b5b4252fed8a21f9fe3f85a9129d186a39b3d0aea03"}, + {file = "duckdb-0.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a77b85668f59b919042832e4659538337f1c7f197123076c5311f1c9cf077df7"}, + {file = "duckdb-0.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96a666f1d2da65d03199a977aec246920920a5ea1da76b70ae02bd4fb1ffc48c"}, + {file = "duckdb-0.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ec76a4262b783628d26612d184834852d9c92fb203e91af789100c17e3d7173"}, + {file = "duckdb-0.10.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:009dd9d2cdbd3b061a9efbdfc79f2d1a8377bcf49f1e5f430138621f8c083a6c"}, + {file = "duckdb-0.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:878f06766088090dad4a2e5ee0081555242b2e8dcb29415ecc97e388cf0cf8d8"}, + {file = "duckdb-0.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:713ff0a1fb63a6d60f454acf67f31656549fb5d63f21ac68314e4f522daa1a89"}, + {file = "duckdb-0.10.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9c0ee450dfedfb52dd4957244e31820feef17228da31af6d052979450a80fd19"}, + {file = "duckdb-0.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ff79b2ea9994398b545c0d10601cd73565fbd09f8951b3d8003c7c5c0cebc7cb"}, + {file = "duckdb-0.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6bdf1aa71b924ef651062e6b8ff9981ad85bec89598294af8a072062c5717340"}, + {file = "duckdb-0.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0265bbc8216be3ced7b377ba8847128a3fc0ef99798a3c4557c1b88e3a01c23"}, + {file = "duckdb-0.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d418a315a07707a693bd985274c0f8c4dd77015d9ef5d8d3da4cc1942fd82e0"}, + {file = "duckdb-0.10.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2828475a292e68c71855190b818aded6bce7328f79e38c04a0c75f8f1c0ceef0"}, + {file = "duckdb-0.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c3aaeaae2eba97035c65f31ffdb18202c951337bf2b3d53d77ce1da8ae2ecf51"}, + {file = "duckdb-0.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:c51790aaaea97d8e4a58a114c371ed8d2c4e1ca7cbf29e3bdab6d8ccfc5afc1e"}, + {file = "duckdb-0.10.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8af1ae7cc77a12206b6c47ade191882cc8f49f750bb3e72bb86ac1d4fa89926a"}, + {file = "duckdb-0.10.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa4f7e8e8dc0e376aeb280b83f2584d0e25ec38985c27d19f3107b2edc4f4a97"}, + {file = "duckdb-0.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28ae942a79fad913defa912b56483cd7827a4e7721f4ce4bc9025b746ecb3c89"}, + {file = "duckdb-0.10.0-cp37-cp37m-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:01b57802898091455ca2a32c1335aac1e398da77c99e8a96a1e5de09f6a0add9"}, + {file = "duckdb-0.10.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:52e1ad4a55fa153d320c367046b9500578192e01c6d04308ba8b540441736f2c"}, + {file = "duckdb-0.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:904c47d04095af745e989c853f0bfc0776913dfc40dfbd2da7afdbbb5f67fed0"}, + {file = "duckdb-0.10.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:184ae7ea5874f3b8fa51ab0f1519bdd088a0b78c32080ee272b1d137e2c8fd9c"}, + {file = "duckdb-0.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd33982ecc9bac727a032d6cedced9f19033cbad56647147408891eb51a6cb37"}, + {file = "duckdb-0.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f59bf0949899105dd5f8864cb48139bfb78454a8c017b8258ba2b5e90acf7afc"}, + {file = "duckdb-0.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:395f3b18948001e35dceb48a4423d574e38656606d033eef375408b539e7b076"}, + {file = "duckdb-0.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b8eb2b803be7ee1df70435c33b03a4598cdaf676cd67ad782b288dcff65d781"}, + {file = "duckdb-0.10.0-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:31b2ddd331801064326c8e3587a4db8a31d02aef11332c168f45b3bd92effb41"}, + {file = "duckdb-0.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c8b89e76a041424b8c2026c5dc1f74b53fbbc6c6f650d563259885ab2e7d093d"}, + {file = "duckdb-0.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:79084a82f16c0a54f6bfb7ded5600400c2daa90eb0d83337d81a56924eaee5d4"}, + {file = "duckdb-0.10.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:79799b3a270dcd9070f677ba510f1e66b112df3068425691bac97c5e278929c7"}, + {file = "duckdb-0.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8fc394bfe3434920cdbcfbdd0ac3ba40902faa1dbda088db0ba44003a45318a"}, + {file = "duckdb-0.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c116605551b4abf5786243a59bcef02bd69cc51837d0c57cafaa68cdc428aa0c"}, + {file = "duckdb-0.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3191170c3b0a43b0c12644800326f5afdea00d5a4621d59dbbd0c1059139e140"}, + {file = "duckdb-0.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fee69a50eb93c72dc77e7ab1fabe0c38d21a52c5da44a86aa217081e38f9f1bd"}, + {file = "duckdb-0.10.0-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5f449e87dacb16b0d145dbe65fa6fdb5a55b2b6911a46d74876e445dd395bac"}, + {file = "duckdb-0.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4487d0df221b17ea4177ad08131bc606b35f25cfadf890987833055b9d10cdf6"}, + {file = "duckdb-0.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:c099ae2ff8fe939fda62da81704f91e2f92ac45e48dc0e37c679c9d243d01e65"}, + {file = "duckdb-0.10.0.tar.gz", hash = "sha256:c02bcc128002aa79e3c9d89b9de25e062d1096a8793bc0d7932317b7977f6845"}, ] [[package]] @@ -569,13 +577,13 @@ files = [ [[package]] name = "google-api-core" -version = "2.16.2" +version = "2.17.1" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.16.2.tar.gz", hash = "sha256:032d37b45d1d6bdaf68fb11ff621e2593263a239fa9246e2e94325f9c47876d2"}, - {file = "google_api_core-2.16.2-py3-none-any.whl", hash = "sha256:449ca0e3f14c179b4165b664256066c7861610f70b6ffe54bb01a04e9b466929"}, + {file = "google-api-core-2.17.1.tar.gz", hash = "sha256:9df18a1f87ee0df0bc4eea2770ebc4228392d8cc4066655b320e2cfccb15db95"}, + {file = "google_api_core-2.17.1-py3-none-any.whl", hash = "sha256:610c5b90092c360736baccf17bd3efbcb30dd380e7a6dc28a71059edb8bd0d8e"}, ] [package.dependencies] @@ -599,13 +607,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.27.0" +version = "2.28.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.27.0.tar.gz", hash = "sha256:e863a56ccc2d8efa83df7a80272601e43487fa9a728a376205c86c26aaefa821"}, - {file = "google_auth-2.27.0-py2.py3-none-any.whl", hash = "sha256:8e4bad367015430ff253fe49d500fdc3396c1a434db5740828c728e45bcce245"}, + {file = "google-auth-2.28.0.tar.gz", hash = "sha256:3cfc1b6e4e64797584fb53fc9bd0b7afa9b7c0dba2004fa7dcc9349e58cc3195"}, + {file = "google_auth-2.28.0-py2.py3-none-any.whl", hash = "sha256:7634d29dcd1e101f5226a23cbc4a0c6cda6394253bf80e281d9c5c6797869c53"}, ] [package.dependencies] @@ -1141,61 +1149,61 @@ files = [ [[package]] name = "orjson" -version = "3.9.13" +version = "3.9.14" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.8" files = [ - {file = "orjson-3.9.13-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:fa6b67f8bef277c2a4aadd548d58796854e7d760964126c3209b19bccc6a74f1"}, - {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b812417199eeb169c25f67815cfb66fd8de7ff098bf57d065e8c1943a7ba5c8f"}, - {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7ccd5bd222e5041069ad9d9868ab59e6dbc53ecde8d8c82b919954fbba43b46b"}, - {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaaf80957c38e9d3f796f355a80fad945e72cd745e6b64c210e635b7043b673e"}, - {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:60da7316131185d0110a1848e9ad15311e6c8938ee0b5be8cbd7261e1d80ee8f"}, - {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b98cd948372f0eb219bc309dee4633db1278687161e3280d9e693b6076951d2"}, - {file = "orjson-3.9.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3869d65561f10071d3e7f35ae58fd377056f67d7aaed5222f318390c3ad30339"}, - {file = "orjson-3.9.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43fd6036b16bb6742d03dae62f7bdf8214d06dea47e4353cde7e2bd1358d186f"}, - {file = "orjson-3.9.13-cp310-none-win32.whl", hash = "sha256:0d3ba9d88e20765335260d7b25547d7c571eee2b698200f97afa7d8c7cd668fc"}, - {file = "orjson-3.9.13-cp310-none-win_amd64.whl", hash = "sha256:6e47153db080f5e87e8ba638f1a8b18995eede6b0abb93964d58cf11bcea362f"}, - {file = "orjson-3.9.13-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4584e8eb727bc431baaf1bf97e35a1d8a0109c924ec847395673dfd5f4ef6d6f"}, - {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f37f0cdd026ef777a4336e599d8194c8357fc14760c2a5ddcfdf1965d45504b"}, - {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d714595d81efab11b42bccd119977d94b25d12d3a806851ff6bfd286a4bce960"}, - {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9171e8e1a1f221953e38e84ae0abffe8759002fd8968106ee379febbb5358b33"}, - {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ab9dbdec3f13f3ea6f937564ce21651844cfbf2725099f2f490426acf683c23"}, - {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:811ac076855e33e931549340288e0761873baf29276ad00f221709933c644330"}, - {file = "orjson-3.9.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:860d0f5b42d0c0afd73fa4177709f6e1b966ba691fcd72175affa902052a81d6"}, - {file = "orjson-3.9.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:838b898e8c1f26eb6b8d81b180981273f6f5110c76c22c384979aca854194f1b"}, - {file = "orjson-3.9.13-cp311-none-win32.whl", hash = "sha256:d3222db9df629ef3c3673124f2e05fb72bc4a320c117e953fec0d69dde82e36d"}, - {file = "orjson-3.9.13-cp311-none-win_amd64.whl", hash = "sha256:978117122ca4cc59b28af5322253017f6c5fc03dbdda78c7f4b94ae984c8dd43"}, - {file = "orjson-3.9.13-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:031df1026c7ea8303332d78711f180231e3ae8b564271fb748a03926587c5546"}, - {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fd9a2101d04e85086ea6198786a3f016e45475f800712e6833e14bf9ce2832f"}, - {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:446d9ad04204e79229ae19502daeea56479e55cbc32634655d886f5a39e91b44"}, - {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b57c0954a9fdd2b05b9cec0f5a12a0bdce5bf021a5b3b09323041613972481ab"}, - {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:266e55c83f81248f63cc93d11c5e3a53df49a5d2598fa9e9db5f99837a802d5d"}, - {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31372ba3a9fe8ad118e7d22fba46bbc18e89039e3bfa89db7bc8c18ee722dca8"}, - {file = "orjson-3.9.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3b0c4da61f39899561e08e571f54472a09fa71717d9797928af558175ae5243"}, - {file = "orjson-3.9.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cc03a35bfc71c8ebf96ce49b82c2a7be6af4b3cd3ac34166fdb42ac510bbfff"}, - {file = "orjson-3.9.13-cp312-none-win_amd64.whl", hash = "sha256:49b7e3fe861cb246361825d1a238f2584ed8ea21e714bf6bb17cebb86772e61c"}, - {file = "orjson-3.9.13-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:62e9a99879c4d5a04926ac2518a992134bfa00d546ea5a4cae4b9be454d35a22"}, - {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d92a3e835a5100f1d5b566fff79217eab92223ca31900dba733902a182a35ab0"}, - {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:23f21faf072ed3b60b5954686f98157e073f6a8068eaa58dbde83e87212eda84"}, - {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:828c502bb261588f7de897e06cb23c4b122997cb039d2014cb78e7dabe92ef0c"}, - {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16946d095212a3dec552572c5d9bca7afa40f3116ad49695a397be07d529f1fa"}, - {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3deadd8dc0e9ff844b5b656fa30a48dbee1c3b332d8278302dd9637f6b09f627"}, - {file = "orjson-3.9.13-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9b1b5adc5adf596c59dca57156b71ad301d73956f5bab4039b0e34dbf50b9fa0"}, - {file = "orjson-3.9.13-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ddc089315d030c54f0f03fb38286e2667c05009a78d659f108a8efcfbdf2e585"}, - {file = "orjson-3.9.13-cp38-none-win32.whl", hash = "sha256:ae77275a28667d9c82d4522b681504642055efa0368d73108511647c6499b31c"}, - {file = "orjson-3.9.13-cp38-none-win_amd64.whl", hash = "sha256:730385fdb99a21fce9bb84bb7fcbda72c88626facd74956bda712834b480729d"}, - {file = "orjson-3.9.13-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7e8e4a571d958910272af8d53a9cbe6599f9f5fd496a1bc51211183bb2072cbd"}, - {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfad553a36548262e7da0f3a7464270e13900b898800fb571a5d4b298c3f8356"}, - {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d691c44604941945b00e0a13b19a7d9c1a19511abadf0080f373e98fdeb6b31"}, - {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8c83718346de08d68b3cb1105c5d91e5fc39885d8610fdda16613d4e3941459"}, - {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ef57a53bfc2091a7cd50a640d9ae866bd7d92a5225a1bab6baa60ef62583f2"}, - {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9156b96afa38db71344522f5517077eaedf62fcd2c9148392ff93d801128809c"}, - {file = "orjson-3.9.13-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31fb66b41fb2c4c817d9610f0bc7d31345728d7b5295ac78b63603407432a2b2"}, - {file = "orjson-3.9.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8a730bf07feacb0863974e67b206b7c503a62199de1cece2eb0d4c233ec29c11"}, - {file = "orjson-3.9.13-cp39-none-win32.whl", hash = "sha256:5ef58869f3399acbbe013518d8b374ee9558659eef14bca0984f67cb1fbd3c37"}, - {file = "orjson-3.9.13-cp39-none-win_amd64.whl", hash = "sha256:9bcf56efdb83244cde070e82a69c0f03c47c235f0a5cb6c81d9da23af7fbaae4"}, - {file = "orjson-3.9.13.tar.gz", hash = "sha256:fc6bc65b0cf524ee042e0bc2912b9206ef242edfba7426cf95763e4af01f527a"}, + {file = "orjson-3.9.14-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:793f6c9448ab6eb7d4974b4dde3f230345c08ca6c7995330fbceeb43a5c8aa5e"}, + {file = "orjson-3.9.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6bc7928d161840096adc956703494b5c0193ede887346f028216cac0af87500"}, + {file = "orjson-3.9.14-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58b36f54da759602d8e2f7dad958752d453dfe2c7122767bc7f765e17dc59959"}, + {file = "orjson-3.9.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:abcda41ecdc950399c05eff761c3de91485d9a70d8227cb599ad3a66afe93bcc"}, + {file = "orjson-3.9.14-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df76ecd17b1b3627bddfd689faaf206380a1a38cc9f6c4075bd884eaedcf46c2"}, + {file = "orjson-3.9.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d450a8e0656efb5d0fcb062157b918ab02dcca73278975b4ee9ea49e2fcf5bd5"}, + {file = "orjson-3.9.14-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:95c03137b0cf66517c8baa65770507a756d3a89489d8ecf864ea92348e1beabe"}, + {file = "orjson-3.9.14-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20837e10835c98973673406d6798e10f821e7744520633811a5a3d809762d8cc"}, + {file = "orjson-3.9.14-cp310-none-win32.whl", hash = "sha256:1f7b6f3ef10ae8e3558abb729873d033dbb5843507c66b1c0767e32502ba96bb"}, + {file = "orjson-3.9.14-cp310-none-win_amd64.whl", hash = "sha256:ea890e6dc1711aeec0a33b8520e395c2f3d59ead5b4351a788e06bf95fc7ba81"}, + {file = "orjson-3.9.14-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c19009ff37f033c70acd04b636380379499dac2cba27ae7dfc24f304deabbc81"}, + {file = "orjson-3.9.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19cdea0664aec0b7f385be84986d4defd3334e9c3c799407686ee1c26f7b8251"}, + {file = "orjson-3.9.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:135d518f73787ce323b1a5e21fb854fe22258d7a8ae562b81a49d6c7f826f2a3"}, + {file = "orjson-3.9.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2cf1d0557c61c75e18cf7d69fb689b77896e95553e212c0cc64cf2087944b84"}, + {file = "orjson-3.9.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7c11667421df2d8b18b021223505dcc3ee51be518d54e4dc49161ac88ac2b87"}, + {file = "orjson-3.9.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eefc41ba42e75ed88bc396d8fe997beb20477f3e7efa000cd7a47eda452fbb2"}, + {file = "orjson-3.9.14-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:917311d6a64d1c327c0dfda1e41f3966a7fb72b11ca7aa2e7a68fcccc7db35d9"}, + {file = "orjson-3.9.14-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4dc1c132259b38d12c6587d190cd09cd76e3b5273ce71fe1372437b4cbc65f6f"}, + {file = "orjson-3.9.14-cp311-none-win32.whl", hash = "sha256:6f39a10408478f4c05736a74da63727a1ae0e83e3533d07b19443400fe8591ca"}, + {file = "orjson-3.9.14-cp311-none-win_amd64.whl", hash = "sha256:26280a7fcb62d8257f634c16acebc3bec626454f9ab13558bbf7883b9140760e"}, + {file = "orjson-3.9.14-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:08e722a8d06b13b67a51f247a24938d1a94b4b3862e40e0eef3b2e98c99cd04c"}, + {file = "orjson-3.9.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2591faa0c031cf3f57e5bce1461cfbd6160f3f66b5a72609a130924917cb07d"}, + {file = "orjson-3.9.14-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e2450d87dd7b4f277f4c5598faa8b49a0c197b91186c47a2c0b88e15531e4e3e"}, + {file = "orjson-3.9.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90903d2908158a2c9077a06f11e27545de610af690fb178fd3ba6b32492d4d1c"}, + {file = "orjson-3.9.14-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce6f095eef0026eae76fc212f20f786011ecf482fc7df2f4c272a8ae6dd7b1ef"}, + {file = "orjson-3.9.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:751250a31fef2bac05a2da2449aae7142075ea26139271f169af60456d8ad27a"}, + {file = "orjson-3.9.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9a1af21160a38ee8be3f4fcf24ee4b99e6184cadc7f915d599f073f478a94d2c"}, + {file = "orjson-3.9.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:449bf090b2aa4e019371d7511a6ea8a5a248139205c27d1834bb4b1e3c44d936"}, + {file = "orjson-3.9.14-cp312-none-win_amd64.whl", hash = "sha256:a603161318ff699784943e71f53899983b7dee571b4dd07c336437c9c5a272b0"}, + {file = "orjson-3.9.14-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:814f288c011efdf8f115c5ebcc1ab94b11da64b207722917e0ceb42f52ef30a3"}, + {file = "orjson-3.9.14-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a88cafb100af68af3b9b29b5ccd09fdf7a48c63327916c8c923a94c336d38dd3"}, + {file = "orjson-3.9.14-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ba3518b999f88882ade6686f1b71e207b52e23546e180499be5bbb63a2f9c6e6"}, + {file = "orjson-3.9.14-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:978f416bbff9da8d2091e3cf011c92da68b13f2c453dcc2e8109099b2a19d234"}, + {file = "orjson-3.9.14-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75fc593cf836f631153d0e21beaeb8d26e144445c73645889335c2247fcd71a0"}, + {file = "orjson-3.9.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d1528db3c7554f9d6eeb09df23cb80dd5177ec56eeb55cc5318826928de506"}, + {file = "orjson-3.9.14-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:7183cc68ee2113b19b0b8714221e5e3b07b3ba10ca2bb108d78fd49cefaae101"}, + {file = "orjson-3.9.14-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:df3266d54246cb56b8bb17fa908660d2a0f2e3f63fbc32451ffc1b1505051d07"}, + {file = "orjson-3.9.14-cp38-none-win32.whl", hash = "sha256:7913079b029e1b3501854c9a78ad938ed40d61fe09bebab3c93e60ff1301b189"}, + {file = "orjson-3.9.14-cp38-none-win_amd64.whl", hash = "sha256:29512eb925b620e5da2fd7585814485c67cc6ba4fe739a0a700c50467a8a8065"}, + {file = "orjson-3.9.14-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5bf597530544db27a8d76aced49cfc817ee9503e0a4ebf0109cd70331e7bbe0c"}, + {file = "orjson-3.9.14-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac650d49366fa41fe702e054cb560171a8634e2865537e91f09a8d05ea5b1d37"}, + {file = "orjson-3.9.14-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:236230433a9a4968ab895140514c308fdf9f607cb8bee178a04372b771123860"}, + {file = "orjson-3.9.14-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3014ccbda9be0b1b5f8ea895121df7e6524496b3908f4397ff02e923bcd8f6dd"}, + {file = "orjson-3.9.14-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ac0c7eae7ad3a223bde690565442f8a3d620056bd01196f191af8be58a5248e1"}, + {file = "orjson-3.9.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fca33fdd0b38839b01912c57546d4f412ba7bfa0faf9bf7453432219aec2df07"}, + {file = "orjson-3.9.14-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f75823cc1674a840a151e999a7dfa0d86c911150dd6f951d0736ee9d383bf415"}, + {file = "orjson-3.9.14-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f52ac2eb49e99e7373f62e2a68428c6946cda52ce89aa8fe9f890c7278e2d3a"}, + {file = "orjson-3.9.14-cp39-none-win32.whl", hash = "sha256:0572f174f50b673b7df78680fb52cd0087a8585a6d06d295a5f790568e1064c6"}, + {file = "orjson-3.9.14-cp39-none-win_amd64.whl", hash = "sha256:ab90c02cb264250b8a58cedcc72ed78a4a257d956c8d3c8bebe9751b818dfad8"}, + {file = "orjson-3.9.14.tar.gz", hash = "sha256:06fb40f8e49088ecaa02f1162581d39e2cf3fd9dbbfe411eb2284147c99bad79"}, ] [[package]] @@ -1916,6 +1924,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1923,8 +1932,16 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1941,6 +1958,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1948,6 +1966,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -2039,110 +2058,110 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "rpds-py" -version = "0.17.1" +version = "0.18.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.17.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4128980a14ed805e1b91a7ed551250282a8ddf8201a4e9f8f5b7e6225f54170d"}, - {file = "rpds_py-0.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ff1dcb8e8bc2261a088821b2595ef031c91d499a0c1b031c152d43fe0a6ecec8"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d65e6b4f1443048eb7e833c2accb4fa7ee67cc7d54f31b4f0555b474758bee55"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a71169d505af63bb4d20d23a8fbd4c6ce272e7bce6cc31f617152aa784436f29"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:436474f17733c7dca0fbf096d36ae65277e8645039df12a0fa52445ca494729d"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10162fe3f5f47c37ebf6d8ff5a2368508fe22007e3077bf25b9c7d803454d921"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:720215373a280f78a1814becb1312d4e4d1077b1202a56d2b0815e95ccb99ce9"}, - {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70fcc6c2906cfa5c6a552ba7ae2ce64b6c32f437d8f3f8eea49925b278a61453"}, - {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:91e5a8200e65aaac342a791272c564dffcf1281abd635d304d6c4e6b495f29dc"}, - {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:99f567dae93e10be2daaa896e07513dd4bf9c2ecf0576e0533ac36ba3b1d5394"}, - {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24e4900a6643f87058a27320f81336d527ccfe503984528edde4bb660c8c8d59"}, - {file = "rpds_py-0.17.1-cp310-none-win32.whl", hash = "sha256:0bfb09bf41fe7c51413f563373e5f537eaa653d7adc4830399d4e9bdc199959d"}, - {file = "rpds_py-0.17.1-cp310-none-win_amd64.whl", hash = "sha256:20de7b7179e2031a04042e85dc463a93a82bc177eeba5ddd13ff746325558aa6"}, - {file = "rpds_py-0.17.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:65dcf105c1943cba45d19207ef51b8bc46d232a381e94dd38719d52d3980015b"}, - {file = "rpds_py-0.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:01f58a7306b64e0a4fe042047dd2b7d411ee82e54240284bab63e325762c1147"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:071bc28c589b86bc6351a339114fb7a029f5cddbaca34103aa573eba7b482382"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae35e8e6801c5ab071b992cb2da958eee76340e6926ec693b5ff7d6381441745"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149c5cd24f729e3567b56e1795f74577aa3126c14c11e457bec1b1c90d212e38"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e796051f2070f47230c745d0a77a91088fbee2cc0502e9b796b9c6471983718c"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e820ee1004327609b28db8307acc27f5f2e9a0b185b2064c5f23e815f248f8"}, - {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1957a2ab607f9added64478a6982742eb29f109d89d065fa44e01691a20fc20a"}, - {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8587fd64c2a91c33cdc39d0cebdaf30e79491cc029a37fcd458ba863f8815383"}, - {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4dc889a9d8a34758d0fcc9ac86adb97bab3fb7f0c4d29794357eb147536483fd"}, - {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2953937f83820376b5979318840f3ee47477d94c17b940fe31d9458d79ae7eea"}, - {file = "rpds_py-0.17.1-cp311-none-win32.whl", hash = "sha256:1bfcad3109c1e5ba3cbe2f421614e70439f72897515a96c462ea657261b96518"}, - {file = "rpds_py-0.17.1-cp311-none-win_amd64.whl", hash = "sha256:99da0a4686ada4ed0f778120a0ea8d066de1a0a92ab0d13ae68492a437db78bf"}, - {file = "rpds_py-0.17.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1dc29db3900cb1bb40353772417800f29c3d078dbc8024fd64655a04ee3c4bdf"}, - {file = "rpds_py-0.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82ada4a8ed9e82e443fcef87e22a3eed3654dd3adf6e3b3a0deb70f03e86142a"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d36b2b59e8cc6e576f8f7b671e32f2ff43153f0ad6d0201250a7c07f25d570e"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3677fcca7fb728c86a78660c7fb1b07b69b281964673f486ae72860e13f512ad"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:516fb8c77805159e97a689e2f1c80655c7658f5af601c34ffdb916605598cda2"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df3b6f45ba4515632c5064e35ca7f31d51d13d1479673185ba8f9fefbbed58b9"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a967dd6afda7715d911c25a6ba1517975acd8d1092b2f326718725461a3d33f9"}, - {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dbbb95e6fc91ea3102505d111b327004d1c4ce98d56a4a02e82cd451f9f57140"}, - {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02866e060219514940342a1f84303a1ef7a1dad0ac311792fbbe19b521b489d2"}, - {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2528ff96d09f12e638695f3a2e0c609c7b84c6df7c5ae9bfeb9252b6fa686253"}, - {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd345a13ce06e94c753dab52f8e71e5252aec1e4f8022d24d56decd31e1b9b23"}, - {file = "rpds_py-0.17.1-cp312-none-win32.whl", hash = "sha256:2a792b2e1d3038daa83fa474d559acfd6dc1e3650ee93b2662ddc17dbff20ad1"}, - {file = "rpds_py-0.17.1-cp312-none-win_amd64.whl", hash = "sha256:292f7344a3301802e7c25c53792fae7d1593cb0e50964e7bcdcc5cf533d634e3"}, - {file = "rpds_py-0.17.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:8ffe53e1d8ef2520ebcf0c9fec15bb721da59e8ef283b6ff3079613b1e30513d"}, - {file = "rpds_py-0.17.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4341bd7579611cf50e7b20bb8c2e23512a3dc79de987a1f411cb458ab670eb90"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f4eb548daf4836e3b2c662033bfbfc551db58d30fd8fe660314f86bf8510b93"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b686f25377f9c006acbac63f61614416a6317133ab7fafe5de5f7dc8a06d42eb"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e21b76075c01d65d0f0f34302b5a7457d95721d5e0667aea65e5bb3ab415c25"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b86b21b348f7e5485fae740d845c65a880f5d1eda1e063bc59bef92d1f7d0c55"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f175e95a197f6a4059b50757a3dca33b32b61691bdbd22c29e8a8d21d3914cae"}, - {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1701fc54460ae2e5efc1dd6350eafd7a760f516df8dbe51d4a1c79d69472fbd4"}, - {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9051e3d2af8f55b42061603e29e744724cb5f65b128a491446cc029b3e2ea896"}, - {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:7450dbd659fed6dd41d1a7d47ed767e893ba402af8ae664c157c255ec6067fde"}, - {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5a024fa96d541fd7edaa0e9d904601c6445e95a729a2900c5aec6555fe921ed6"}, - {file = "rpds_py-0.17.1-cp38-none-win32.whl", hash = "sha256:da1ead63368c04a9bded7904757dfcae01eba0e0f9bc41d3d7f57ebf1c04015a"}, - {file = "rpds_py-0.17.1-cp38-none-win_amd64.whl", hash = "sha256:841320e1841bb53fada91c9725e766bb25009cfd4144e92298db296fb6c894fb"}, - {file = "rpds_py-0.17.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:f6c43b6f97209e370124baf2bf40bb1e8edc25311a158867eb1c3a5d449ebc7a"}, - {file = "rpds_py-0.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7d63ec01fe7c76c2dbb7e972fece45acbb8836e72682bde138e7e039906e2c"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81038ff87a4e04c22e1d81f947c6ac46f122e0c80460b9006e6517c4d842a6ec"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:810685321f4a304b2b55577c915bece4c4a06dfe38f6e62d9cc1d6ca8ee86b99"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:25f071737dae674ca8937a73d0f43f5a52e92c2d178330b4c0bb6ab05586ffa6"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa5bfb13f1e89151ade0eb812f7b0d7a4d643406caaad65ce1cbabe0a66d695f"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfe07308b311a8293a0d5ef4e61411c5c20f682db6b5e73de6c7c8824272c256"}, - {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a000133a90eea274a6f28adc3084643263b1e7c1a5a66eb0a0a7a36aa757ed74"}, - {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d0e8a6434a3fbf77d11448c9c25b2f25244226cfbec1a5159947cac5b8c5fa4"}, - {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:efa767c220d94aa4ac3a6dd3aeb986e9f229eaf5bce92d8b1b3018d06bed3772"}, - {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:dbc56680ecf585a384fbd93cd42bc82668b77cb525343170a2d86dafaed2a84b"}, - {file = "rpds_py-0.17.1-cp39-none-win32.whl", hash = "sha256:270987bc22e7e5a962b1094953ae901395e8c1e1e83ad016c5cfcfff75a15a3f"}, - {file = "rpds_py-0.17.1-cp39-none-win_amd64.whl", hash = "sha256:2a7b2f2f56a16a6d62e55354dd329d929560442bd92e87397b7a9586a32e3e76"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a3264e3e858de4fc601741498215835ff324ff2482fd4e4af61b46512dd7fc83"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f2f3b28b40fddcb6c1f1f6c88c6f3769cd933fa493ceb79da45968a21dccc920"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9584f8f52010295a4a417221861df9bea4c72d9632562b6e59b3c7b87a1522b7"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c64602e8be701c6cfe42064b71c84ce62ce66ddc6422c15463fd8127db3d8066"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:060f412230d5f19fc8c8b75f315931b408d8ebf56aec33ef4168d1b9e54200b1"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9412abdf0ba70faa6e2ee6c0cc62a8defb772e78860cef419865917d86c7342"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9737bdaa0ad33d34c0efc718741abaafce62fadae72c8b251df9b0c823c63b22"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9f0e4dc0f17dcea4ab9d13ac5c666b6b5337042b4d8f27e01b70fae41dd65c57"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1db228102ab9d1ff4c64148c96320d0be7044fa28bd865a9ce628ce98da5973d"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8bbd8e56f3ba25a7d0cf980fc42b34028848a53a0e36c9918550e0280b9d0b6"}, - {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:be22ae34d68544df293152b7e50895ba70d2a833ad9566932d750d3625918b82"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bf046179d011e6114daf12a534d874958b039342b347348a78b7cdf0dd9d6041"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:1a746a6d49665058a5896000e8d9d2f1a6acba8a03b389c1e4c06e11e0b7f40d"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0b8bf5b8db49d8fd40f54772a1dcf262e8be0ad2ab0206b5a2ec109c176c0a4"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7f4cb1f173385e8a39c29510dd11a78bf44e360fb75610594973f5ea141028b"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7fbd70cb8b54fe745301921b0816c08b6d917593429dfc437fd024b5ba713c58"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bdf1303df671179eaf2cb41e8515a07fc78d9d00f111eadbe3e14262f59c3d0"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad059a4bd14c45776600d223ec194e77db6c20255578bb5bcdd7c18fd169361"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3664d126d3388a887db44c2e293f87d500c4184ec43d5d14d2d2babdb4c64cad"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:698ea95a60c8b16b58be9d854c9f993c639f5c214cf9ba782eca53a8789d6b19"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:c3d2010656999b63e628a3c694f23020322b4178c450dc478558a2b6ef3cb9bb"}, - {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:938eab7323a736533f015e6069a7d53ef2dcc841e4e533b782c2bfb9fb12d84b"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e626b365293a2142a62b9a614e1f8e331b28f3ca57b9f05ebbf4cf2a0f0bdc5"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:380e0df2e9d5d5d339803cfc6d183a5442ad7ab3c63c2a0982e8c824566c5ccc"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b760a56e080a826c2e5af09002c1a037382ed21d03134eb6294812dda268c811"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5576ee2f3a309d2bb403ec292d5958ce03953b0e57a11d224c1f134feaf8c40f"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3c3461ebb4c4f1bbc70b15d20b565759f97a5aaf13af811fcefc892e9197ba"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:637b802f3f069a64436d432117a7e58fab414b4e27a7e81049817ae94de45d8d"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffee088ea9b593cc6160518ba9bd319b5475e5f3e578e4552d63818773c6f56a"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ac732390d529d8469b831949c78085b034bff67f584559340008d0f6041a049"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:93432e747fb07fa567ad9cc7aaadd6e29710e515aabf939dfbed8046041346c6"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:7b7d9ca34542099b4e185b3c2a2b2eda2e318a7dbde0b0d83357a6d4421b5296"}, - {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:0387ce69ba06e43df54e43968090f3626e231e4bc9150e4c3246947567695f68"}, - {file = "rpds_py-0.17.1.tar.gz", hash = "sha256:0210b2668f24c078307260bf88bdac9d6f1093635df5123789bfee4d8d7fc8e7"}, + {file = "rpds_py-0.18.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e"}, + {file = "rpds_py-0.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1"}, + {file = "rpds_py-0.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e"}, + {file = "rpds_py-0.18.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88"}, + {file = "rpds_py-0.18.0-cp310-none-win32.whl", hash = "sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337"}, + {file = "rpds_py-0.18.0-cp310-none-win_amd64.whl", hash = "sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66"}, + {file = "rpds_py-0.18.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4"}, + {file = "rpds_py-0.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5"}, + {file = "rpds_py-0.18.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b"}, + {file = "rpds_py-0.18.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836"}, + {file = "rpds_py-0.18.0-cp311-none-win32.whl", hash = "sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1"}, + {file = "rpds_py-0.18.0-cp311-none-win_amd64.whl", hash = "sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa"}, + {file = "rpds_py-0.18.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0"}, + {file = "rpds_py-0.18.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3"}, + {file = "rpds_py-0.18.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157"}, + {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496"}, + {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f"}, + {file = "rpds_py-0.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7"}, + {file = "rpds_py-0.18.0-cp312-none-win32.whl", hash = "sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98"}, + {file = "rpds_py-0.18.0-cp312-none-win_amd64.whl", hash = "sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec"}, + {file = "rpds_py-0.18.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e"}, + {file = "rpds_py-0.18.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d"}, + {file = "rpds_py-0.18.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c"}, + {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f"}, + {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c"}, + {file = "rpds_py-0.18.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594"}, + {file = "rpds_py-0.18.0-cp38-none-win32.whl", hash = "sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e"}, + {file = "rpds_py-0.18.0-cp38-none-win_amd64.whl", hash = "sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1"}, + {file = "rpds_py-0.18.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33"}, + {file = "rpds_py-0.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9"}, + {file = "rpds_py-0.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024"}, + {file = "rpds_py-0.18.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20"}, + {file = "rpds_py-0.18.0-cp39-none-win32.whl", hash = "sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7"}, + {file = "rpds_py-0.18.0-cp39-none-win_amd64.whl", hash = "sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984"}, + {file = "rpds_py-0.18.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da"}, + {file = "rpds_py-0.18.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432"}, + {file = "rpds_py-0.18.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f"}, + {file = "rpds_py-0.18.0.tar.gz", hash = "sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d"}, ] [[package]] @@ -2187,18 +2206,18 @@ files = [ [[package]] name = "setuptools" -version = "69.0.3" +version = "69.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, + {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -2471,13 +2490,13 @@ files = [ [[package]] name = "tzdata" -version = "2023.4" +version = "2024.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, - {file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [[package]] @@ -2665,4 +2684,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "71b8790d6cb735dfe4349431938c1a7db17cf3578007481626d8408990eedd29" +content-hash = "3b46151e994684f0953be1041a850ac8efcedea10632f8fa86aaaa6d20385174" diff --git a/airbyte-lib/pyproject.toml b/airbyte-lib/pyproject.toml index d1bdb3049c0c..8634bf4d1f3b 100644 --- a/airbyte-lib/pyproject.toml +++ b/airbyte-lib/pyproject.toml @@ -50,6 +50,7 @@ types-requests = "2.31.0.4" freezegun = "^1.4.0" airbyte-source-faker = "^6.0.0" viztracer = "^0.16.2" +tomli = "^2.0" [build-system] requires = ["poetry-core"] @@ -63,6 +64,7 @@ markers = [ [tool.ruff.pylint] max-args = 8 # Relaxed from default of 5 +max-branches = 15 # Relaxed from default of 12 [tool.ruff] target-version = "py39" diff --git a/airbyte-lib/tests/integration_tests/fixtures/source-test/source_test/run.py b/airbyte-lib/tests/integration_tests/fixtures/source-test/source_test/run.py index 213f94fd23a7..5f4ae3f1e939 100644 --- a/airbyte-lib/tests/integration_tests/fixtures/source-test/source_test/run.py +++ b/airbyte-lib/tests/integration_tests/fixtures/source-test/source_test/run.py @@ -35,6 +35,21 @@ }, }, }, + { + "name": "always-empty-stream", + "description": "This stream always emits zero records, to test handling of empty datasets.", + "supported_sync_modes": ["full_refresh", "incremental"], + "source_defined_cursor": False, + "json_schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "column1": {"type": "string"}, + "column2": {"type": "number"}, + "empty_column": {"type": "string"}, + }, + }, + }, ] }, } diff --git a/airbyte-lib/tests/integration_tests/test_source_test_fixture.py b/airbyte-lib/tests/integration_tests/test_source_test_fixture.py index dadc7b12da72..5e3a05e683a9 100644 --- a/airbyte-lib/tests/integration_tests/test_source_test_fixture.py +++ b/airbyte-lib/tests/integration_tests/test_source_test_fixture.py @@ -55,6 +55,7 @@ def expected_test_stream_data() -> dict[str, list[dict[str, str | int]]]: "stream2": [ {"column1": "value1", "column2": 1, "empty_column": None}, ], + "always-empty-stream": [], } def test_registry_get(): @@ -195,16 +196,20 @@ def test_file_write_and_cleanup() -> None: _ = source.read(cache_wo_cleanup) assert len(list(Path(temp_dir_1).glob("*.parquet"))) == 0, "Expected files to be cleaned up" - assert len(list(Path(temp_dir_2).glob("*.parquet"))) == 2, "Expected files to exist" + assert len(list(Path(temp_dir_2).glob("*.parquet"))) == 3, "Expected files to exist" def assert_cache_data(expected_test_stream_data: dict[str, list[dict[str, str | int]]], cache: SQLCacheBase, streams: list[str] = None): for stream_name in streams or expected_test_stream_data.keys(): - pd.testing.assert_frame_equal( - cache[stream_name].to_pandas(), - pd.DataFrame(expected_test_stream_data[stream_name]), - check_dtype=False, - ) + if len(cache[stream_name]) > 0: + pd.testing.assert_frame_equal( + cache[stream_name].to_pandas(), + pd.DataFrame(expected_test_stream_data[stream_name]), + check_dtype=False, + ) + else: + # stream is empty + assert len(expected_test_stream_data[stream_name]) == 0 # validate that the cache doesn't contain any other streams if streams: @@ -227,12 +232,13 @@ def test_read_result_mapping(): source = ab.get_source("source-test", config={"apiKey": "test"}) source.select_all_streams() result: ReadResult = source.read(ab.new_local_cache()) - assert len(result) == 2 + assert len(result) == 3 assert isinstance(result, Mapping) assert "stream1" in result assert "stream2" in result + assert "always-empty-stream" in result assert "stream3" not in result - assert result.keys() == {"stream1", "stream2"} + assert result.keys() == {"stream1", "stream2", "always-empty-stream"} def test_dataset_list_and_len(expected_test_stream_data): @@ -251,8 +257,9 @@ def test_dataset_list_and_len(expected_test_stream_data): assert isinstance(result, Mapping) assert "stream1" in result assert "stream2" in result + assert "always-empty-stream" in result assert "stream3" not in result - assert result.keys() == {"stream1", "stream2"} + assert result.keys() == {"stream1", "stream2", "always-empty-stream"} def test_read_from_cache(expected_test_stream_data: dict[str, list[dict[str, str | int]]]): @@ -330,11 +337,17 @@ def test_merge_streams_in_cache(expected_test_stream_data: dict[str, list[dict[s source.select_streams(["stream2"]) result = source.read(second_cache) + third_cache = ab.new_local_cache(cache_name) + source.select_streams(["always-empty-stream"]) + result = source.read(third_cache) + # Assert that the read result only contains stream2 with pytest.raises(KeyError): result["stream1"] + with pytest.raises(KeyError): + result["stream2"] - assert_cache_data(expected_test_stream_data, second_cache) + assert_cache_data(expected_test_stream_data, third_cache) def test_read_result_as_list(expected_test_stream_data: dict[str, list[dict[str, str | int]]]): @@ -346,8 +359,10 @@ def test_read_result_as_list(expected_test_stream_data: dict[str, list[dict[str, result: ReadResult = source.read(cache) stream_1_list = list(result["stream1"]) stream_2_list = list(result["stream2"]) + always_empty_stream_list = list(result["always-empty-stream"]) assert stream_1_list == expected_test_stream_data["stream1"] assert stream_2_list == expected_test_stream_data["stream2"] + assert always_empty_stream_list == expected_test_stream_data["always-empty-stream"] def test_get_records_result_as_list(expected_test_stream_data: dict[str, list[dict[str, str | int]]]): @@ -356,8 +371,10 @@ def test_get_records_result_as_list(expected_test_stream_data: dict[str, list[di stream_1_list = list(source.get_records("stream1")) stream_2_list = list(source.get_records("stream2")) + always_empty_stream_list = list(source.get_records("always-empty-stream")) assert stream_1_list == expected_test_stream_data["stream1"] assert stream_2_list == expected_test_stream_data["stream2"] + assert always_empty_stream_list == expected_test_stream_data["always-empty-stream"] @@ -380,11 +397,15 @@ def test_sync_with_merge_to_duckdb(expected_test_stream_data: dict[str, list[dic assert result.processed_records == 3 for stream_name, expected_data in expected_test_stream_data.items(): - pd.testing.assert_frame_equal( - result[stream_name].to_pandas(), - pd.DataFrame(expected_data), - check_dtype=False, - ) + if len(cache[stream_name]) > 0: + pd.testing.assert_frame_equal( + result[stream_name].to_pandas(), + pd.DataFrame(expected_data), + check_dtype=False, + ) + else: + # stream is empty + assert len(expected_test_stream_data[stream_name]) == 0 def test_cached_dataset( @@ -564,11 +585,15 @@ def test_sync_with_merge_to_postgres(new_pg_cache_config: PostgresCacheConfig, e assert result.processed_records == 3 for stream_name, expected_data in expected_test_stream_data.items(): - pd.testing.assert_frame_equal( - result[stream_name].to_pandas(), - pd.DataFrame(expected_data), - check_dtype=False, - ) + if len(cache[stream_name]) > 0: + pd.testing.assert_frame_equal( + result[stream_name].to_pandas(), + pd.DataFrame(expected_data), + check_dtype=False, + ) + else: + # stream is empty + assert len(expected_test_stream_data[stream_name]) == 0 def test_airbyte_lib_version() -> None: @@ -682,11 +707,15 @@ def test_sync_to_postgres(new_pg_cache_config: PostgresCacheConfig, expected_tes assert result.processed_records == 3 for stream_name, expected_data in expected_test_stream_data.items(): - pd.testing.assert_frame_equal( - result[stream_name].to_pandas(), - pd.DataFrame(expected_data), - check_dtype=False, - ) + if len(cache[stream_name]) > 0: + pd.testing.assert_frame_equal( + result[stream_name].to_pandas(), + pd.DataFrame(expected_data), + check_dtype=False, + ) + else: + # stream is empty + assert len(expected_test_stream_data[stream_name]) == 0 @pytest.mark.slow @pytest.mark.requires_creds @@ -700,11 +729,15 @@ def test_sync_to_snowflake(snowflake_config: SnowflakeCacheConfig, expected_test assert result.processed_records == 3 for stream_name, expected_data in expected_test_stream_data.items(): - pd.testing.assert_frame_equal( - result[stream_name].to_pandas(), - pd.DataFrame(expected_data), - check_dtype=False, - ) + if len(cache[stream_name]) > 0: + pd.testing.assert_frame_equal( + result[stream_name].to_pandas(), + pd.DataFrame(expected_data), + check_dtype=False, + ) + else: + # stream is empty + assert len(expected_test_stream_data[stream_name]) == 0 def test_sync_limited_streams(expected_test_stream_data): From 34ca0671c73a0e13e610013c9968c6959cc6e6c4 Mon Sep 17 00:00:00 2001 From: Edward Gao Date: Thu, 15 Feb 2024 14:35:25 -0800 Subject: [PATCH 02/43] =?UTF-8?q?=F0=9F=93=9D=20add=20instructions=20for?= =?UTF-8?q?=20soft=20reset=20(#35335)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core-concepts/typing-deduping.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/using-airbyte/core-concepts/typing-deduping.md b/docs/using-airbyte/core-concepts/typing-deduping.md index d0493b286653..eb606fc3e096 100644 --- a/docs/using-airbyte/core-concepts/typing-deduping.md +++ b/docs/using-airbyte/core-concepts/typing-deduping.md @@ -105,9 +105,9 @@ You also now see the following changes in Airbyte-provided columns: ## On final table re-creation -From time to time, Airbyte will drop and re-create the final table produced by a sync. This is done -as transitionally as possible, and should be invisible to most observers. This is done for a number -of reasons, including: +From time to time, Airbyte will drop and re-create the final table produced by a sync (sometimes +called a "soft reset"). This is done as transactionally as possible, and should be invisible to most +observers. This is done for a number of reasons, including: - **Schema Migrations** - Many destinations lack the ability to control column order, or cannot alter one data type to another. Re-creating the table allows Airbyte to strictly control the @@ -123,6 +123,18 @@ table outside of Airbyte could be lost during a sync. Many destinations provide wildcards to grant permissions to tables, which are better suited for this ELT process. We do not recommend altering the final tables (e.g. adding constraints) as it may cause issues with the sync. +### Manually triggering a final table re-creation + +In some cases, you need to manually run a soft reset - for example, if you accidentally delete some +records from the final table and want to repopulate them from the raw data. This can be done by: +1. Dropping the final table entirely (`DROP TABLE `) +1. Unsetting the raw table's `_airbyte_loaded_at` column + (`UPDATE airbyte_internal. SET _airbyte_loaded_at = NULL`) + 1. If you are using a nonstandard raw table schema, replace `airbyte_internal` with that schema. +1. And then running a sync. + +After the sync completes, your final table will be restored to its correct state. + ## Loading Data Incrementally to Final Tables :::note From 5c7e3b9d5db7542926d9de45bec172c782f96550 Mon Sep 17 00:00:00 2001 From: Xiaohan Song Date: Thu, 15 Feb 2024 15:31:18 -0800 Subject: [PATCH 03/43] [source-postgres] Add test for legacy version of postgres (#35329) --- .../CdcPostgresSourceLegacyCtidTest.java | 19 +++++++- .../postgres/CdcPostgresSourceTest.java | 45 ++++++++++++++++--- .../source/postgres/PostgresTestDatabase.java | 14 +++--- 3 files changed, 64 insertions(+), 14 deletions(-) diff --git a/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/CdcPostgresSourceLegacyCtidTest.java b/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/CdcPostgresSourceLegacyCtidTest.java index a6d7ecb4d970..53ae215c4da4 100644 --- a/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/CdcPostgresSourceLegacyCtidTest.java +++ b/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/CdcPostgresSourceLegacyCtidTest.java @@ -4,13 +4,28 @@ package io.airbyte.integrations.source.postgres; +import io.airbyte.integrations.source.postgres.PostgresTestDatabase.BaseImage; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Order; @Order(2) public class CdcPostgresSourceLegacyCtidTest extends CdcPostgresSourceTest { - protected static String getServerImageName() { - return "debezium/postgres:13-bullseye"; + @Override + protected void setBaseImage() { + this.postgresImage = BaseImage.POSTGRES_12; + } + + @Override + @Disabled("https://github.com/airbytehq/airbyte/issues/35267") + public void newTableSnapshotTest() { + + } + + @Override + @Disabled("https://github.com/airbytehq/airbyte/issues/35267") + public void syncShouldIncrementLSN() { + } } diff --git a/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/CdcPostgresSourceTest.java b/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/CdcPostgresSourceTest.java index 490cd4f3e400..551b81ac22f3 100644 --- a/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/CdcPostgresSourceTest.java +++ b/airbyte-integrations/connectors/source-postgres/src/test/java/io/airbyte/integrations/source/postgres/CdcPostgresSourceTest.java @@ -73,9 +73,16 @@ @Order(1) public class CdcPostgresSourceTest extends CdcSourceTest { + protected BaseImage postgresImage; + + protected void setBaseImage() { + this.postgresImage = getServerImage(); + } + @Override protected PostgresTestDatabase createTestDatabase() { - return PostgresTestDatabase.in(getServerImage(), ContainerModifier.CONF).withReplicationSlot(); + setBaseImage(); + return PostgresTestDatabase.in(this.postgresImage, ContainerModifier.CONF).withReplicationSlot(); } @Override @@ -101,6 +108,15 @@ protected void setup() { testdb.withPublicationForAllTables(); } + // For legacy Postgres we will call advanceLsn() after we retrieved target LSN, so that debezium + // would not drop any record. + // However, that might cause unexpected state and cause failure in the test. Thus we need to bypass + // some check if they are on legacy postgres + // versions. + private boolean isOnLegacyPostgres() { + return postgresImage.majorVersion < 15; + } + @Test void testDebugMode() { final JsonNode invalidDebugConfig = testdb.testConfigBuilder() @@ -196,7 +212,12 @@ private void assertStateTypes(final List stateMessages, fin if (Objects.isNull(sharedState)) { sharedState = global.getSharedState(); } else { - assertEquals(sharedState, global.getSharedState()); + // This validation is only true for versions on or after postgres 15. We execute + // EPHEMERAL_HEARTBEAT_CREATE_STATEMENTS for earlier versions of + // Postgres. See https://github.com/airbytehq/airbyte/pull/33605 for details. + if (!isOnLegacyPostgres()) { + assertEquals(sharedState, global.getSharedState()); + } } assertEquals(1, global.getStreamStates().size()); final AirbyteStreamState streamState = global.getStreamStates().get(0); @@ -324,7 +345,11 @@ public void testTwoStreamSync() throws Exception { if (Objects.isNull(sharedState)) { sharedState = global.getSharedState(); } else { - assertEquals(sharedState, global.getSharedState()); + // LSN will be advanced for postgres version before 15. See + // https://github.com/airbytehq/airbyte/pull/33605 + if (!isOnLegacyPostgres()) { + assertEquals(sharedState, global.getSharedState()); + } } if (Objects.isNull(firstStreamInState)) { @@ -755,7 +780,11 @@ protected void assertLsnPositionForSyncShouldIncrementLSN(final Long lsnPosition if (syncNumber == 1) { assertEquals(1, lsnPosition2.compareTo(lsnPosition1)); } else if (syncNumber == 2) { - assertEquals(0, lsnPosition2.compareTo(lsnPosition1)); + // Earlier Postgres version will advance lsn even if there is no sync records. See + // https://github.com/airbytehq/airbyte/pull/33605. + if (!isOnLegacyPostgres()) { + assertEquals(0, lsnPosition2.compareTo(lsnPosition1)); + } } else { throw new RuntimeException("Unknown sync number " + syncNumber); } @@ -791,7 +820,9 @@ protected void verifyCheckpointStatesByRecords() throws Exception { .toListAndClose(secondBatchIterator); assertEquals(recordsToCreate, extractRecordMessages(dataFromSecondBatch).size()); final List stateMessagesCDC = extractStateMessages(dataFromSecondBatch); - assertTrue(stateMessagesCDC.size() > 1, "Generated only the final state."); + if (!isOnLegacyPostgres()) { + assertTrue(stateMessagesCDC.size() > 1, "Generated only the final state."); + } assertEquals(stateMessagesCDC.size(), stateMessagesCDC.stream().distinct().count(), "There are duplicated states."); } @@ -830,7 +861,9 @@ protected void verifyCheckpointStatesBySeconds() throws Exception { assertEquals(recordsToCreate, extractRecordMessages(dataFromSecondBatch).size()); final List stateMessagesCDC = extractStateMessages(dataFromSecondBatch); - assertTrue(stateMessagesCDC.size() > 1, "Generated only the final state."); + if (!isOnLegacyPostgres()) { + assertTrue(stateMessagesCDC.size() > 1, "Generated only the final state."); + } assertEquals(stateMessagesCDC.size(), stateMessagesCDC.stream().distinct().count(), "There are duplicated states."); } diff --git a/airbyte-integrations/connectors/source-postgres/src/testFixtures/java/io/airbyte/integrations/source/postgres/PostgresTestDatabase.java b/airbyte-integrations/connectors/source-postgres/src/testFixtures/java/io/airbyte/integrations/source/postgres/PostgresTestDatabase.java index 155b649e96a8..a86dbd39c351 100644 --- a/airbyte-integrations/connectors/source-postgres/src/testFixtures/java/io/airbyte/integrations/source/postgres/PostgresTestDatabase.java +++ b/airbyte-integrations/connectors/source-postgres/src/testFixtures/java/io/airbyte/integrations/source/postgres/PostgresTestDatabase.java @@ -21,15 +21,17 @@ public class PostgresTestDatabase extends public static enum BaseImage { - POSTGRES_16("postgres:16-bullseye"), - POSTGRES_12("postgres:12-bullseye"), - POSTGRES_9("postgres:9-alpine"), - POSTGRES_SSL_DEV("marcosmarxm/postgres-ssl:dev"); + POSTGRES_16("postgres:16-bullseye", 16), + POSTGRES_12("postgres:12-bullseye", 12), + POSTGRES_9("postgres:9-alpine", 9), + POSTGRES_SSL_DEV("marcosmarxm/postgres-ssl:dev", 16); - private final String reference; + public final String reference; + public final int majorVersion; - private BaseImage(String reference) { + private BaseImage(String reference, int majorVersion) { this.reference = reference; + this.majorVersion = majorVersion; }; } From 9af2c1c66c93e50d4d86abaeb8d8a134d0deb10c Mon Sep 17 00:00:00 2001 From: "Roman Yermilov [GL]" <86300758+roman-yermilov-gl@users.noreply.github.com> Date: Fri, 16 Feb 2024 12:02:30 +0100 Subject: [PATCH 04/43] Source Klaviyo: added transform config for profile stream (#35336) --- airbyte-integrations/connectors/source-klaviyo/metadata.yaml | 2 +- .../connectors/source-klaviyo/source_klaviyo/streams.py | 3 +++ docs/integrations/sources/klaviyo.md | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/airbyte-integrations/connectors/source-klaviyo/metadata.yaml b/airbyte-integrations/connectors/source-klaviyo/metadata.yaml index e6ac692ff03a..c647833c8583 100644 --- a/airbyte-integrations/connectors/source-klaviyo/metadata.yaml +++ b/airbyte-integrations/connectors/source-klaviyo/metadata.yaml @@ -8,7 +8,7 @@ data: definitionId: 95e8cffd-b8c4-4039-968e-d32fb4a69bde connectorBuildOptions: baseImage: docker.io/airbyte/python-connector-base:1.1.0@sha256:bd98f6505c6764b1b5f99d3aedc23dfc9e9af631a62533f60eb32b1d3dbab20c - dockerImageTag: 2.1.2 + dockerImageTag: 2.1.3 dockerRepository: airbyte/source-klaviyo githubIssueLabel: source-klaviyo icon: klaviyo.svg diff --git a/airbyte-integrations/connectors/source-klaviyo/source_klaviyo/streams.py b/airbyte-integrations/connectors/source-klaviyo/source_klaviyo/streams.py index fcfd8fdf4423..5b7eca53a67b 100644 --- a/airbyte-integrations/connectors/source-klaviyo/source_klaviyo/streams.py +++ b/airbyte-integrations/connectors/source-klaviyo/source_klaviyo/streams.py @@ -12,6 +12,7 @@ from airbyte_cdk.sources.streams.availability_strategy import AvailabilityStrategy from airbyte_cdk.sources.streams.core import StreamData from airbyte_cdk.sources.streams.http import HttpStream +from airbyte_cdk.sources.utils.transform import TransformConfig, TypeTransformer from .availability_strategy import KlaviyoAvailabilityStrategy from .exceptions import KlaviyoBackoffError @@ -242,6 +243,8 @@ def read_records( class Profiles(IncrementalKlaviyoStream): """Docs: https://developers.klaviyo.com/en/v2023-02-22/reference/get_profiles""" + transformer: TypeTransformer = TypeTransformer(TransformConfig.DefaultSchemaNormalization) + cursor_field = "updated" api_revision = "2023-02-22" page_size = 100 diff --git a/docs/integrations/sources/klaviyo.md b/docs/integrations/sources/klaviyo.md index 23eeca5209c9..3f49f50eb0ca 100644 --- a/docs/integrations/sources/klaviyo.md +++ b/docs/integrations/sources/klaviyo.md @@ -63,7 +63,8 @@ The Klaviyo connector should not run into Klaviyo API limitations under normal u | Version | Date | Pull Request | Subject | | :------- | :--------- | :--------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | -| 2.1.2 | 2024-02-09 | [35088](https://github.com/airbytehq/airbyte/pull/35088) | Manage dependencies with Poetry. | +| `2.1.3` | 2024-02-15 | [35336](https://github.com/airbytehq/airbyte/pull/35336) | Added type transformer for the `profiles` stream. | +| `2.1.2` | 2024-02-09 | [35088](https://github.com/airbytehq/airbyte/pull/35088) | Manage dependencies with Poetry. | | `2.1.1` | 2024-02-07 | [34998](https://github.com/airbytehq/airbyte/pull/34998) | Add missing fields to stream schemas | | `2.1.0` | 2023-12-07 | [33237](https://github.com/airbytehq/airbyte/pull/33237) | Continue syncing streams even when one of the stream fails | | `2.0.2` | 2023-12-05 | [33099](https://github.com/airbytehq/airbyte/pull/33099) | Fix filtering for archived records stream | From b741045f500145bdb545b2a89238b40a79bf8a7d Mon Sep 17 00:00:00 2001 From: Daryna Ishchenko <80129833+darynaishchenko@users.noreply.github.com> Date: Fri, 16 Feb 2024 14:31:39 +0200 Subject: [PATCH 05/43] :hospital: Source Hubspot: updated marketing emails schema and expected records (#35328) --- .../integration_tests/expected_records.jsonl | 78 +++++++++---------- .../connectors/source-hubspot/metadata.yaml | 2 +- .../schemas/marketing_emails.json | 12 +++ docs/integrations/sources/hubspot.md | 3 +- 4 files changed, 54 insertions(+), 41 deletions(-) diff --git a/airbyte-integrations/connectors/source-hubspot/integration_tests/expected_records.jsonl b/airbyte-integrations/connectors/source-hubspot/integration_tests/expected_records.jsonl index b115f38f7911..091e59551fdb 100644 --- a/airbyte-integrations/connectors/source-hubspot/integration_tests/expected_records.jsonl +++ b/airbyte-integrations/connectors/source-hubspot/integration_tests/expected_records.jsonl @@ -1,22 +1,22 @@ {"stream": "campaigns", "data": {"id": 243851494, "lastUpdatedTime": 1675121674226, "appId": 113, "appName": "Batch", "contentId": 100523515217, "subject": "test", "name": "test", "counters": {"dropped": 1}, "lastProcessingFinishedAt": 1675121674000, "lastProcessingStartedAt": 1675121671000, "lastProcessingStateChangeAt": 1675121674000, "numIncluded": 1, "processingState": "DONE", "type": "BATCH_EMAIL", "counters_dropped": 1}, "emitted_at": 1697714185530} {"stream": "campaigns", "data": {"id": 115429485, "lastUpdatedTime": 1615506409286, "appId": 113, "appName": "Batch", "contentId": 42931043849, "subject": "Test subj", "name": "Test subj", "counters": {"processed": 1, "deferred": 1, "mta_dropped": 1, "dropped": 3, "sent": 0}, "lastProcessingFinishedAt": 1615504712000, "lastProcessingStartedAt": 1615504687000, "lastProcessingStateChangeAt": 1615504712000, "numIncluded": 3, "processingState": "DONE", "type": "BATCH_EMAIL", "counters_processed": 1, "counters_deferred": 1, "counters_mta_dropped": 1, "counters_dropped": 3, "counters_sent": 0}, "emitted_at": 1697714185763} -{"stream": "companies", "data": {"id": "4992593519", "properties": {"about_us": null, "address": null, "address2": null, "annualrevenue": null, "city": "San Francisco", "closedate": null, "closedate_timestamp_earliest_value_a2a17e6e": null, "country": "United States", "createdate": "2020-12-10T07:58:09.554000+00:00", "custom_company_property": null, "days_to_close": null, "description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "domain": "airbyte.io", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "facebook_company_page": null, "facebookfans": null, "first_contact_createdate": null, "first_contact_createdate_timestamp_earliest_value_78b50eea": null, "first_conversion_date": null, "first_conversion_date_timestamp_earliest_value_61f58f2c": null, "first_conversion_event_name": null, "first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "first_deal_created_date": "2021-05-21T10:17:06.028000+00:00", "founded_year": "2020", "googleplus_page": null, "hs_additional_domains": null, "hs_all_accessible_team_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_first_timestamp": null, "hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "hs_analytics_latest_source": null, "hs_analytics_latest_source_data_1": null, "hs_analytics_latest_source_data_2": null, "hs_analytics_latest_source_timestamp": null, "hs_analytics_num_page_views": null, "hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "hs_analytics_num_visits": null, "hs_analytics_num_visits_cardinality_sum_53d952a6": null, "hs_analytics_source": null, "hs_analytics_source_data_1": null, "hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "hs_analytics_source_data_2": null, "hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "hs_annual_revenue_currency_code": "USD", "hs_avatar_filemanager_key": null, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_date_entered_customer": null, "hs_date_entered_evangelist": null, "hs_date_entered_lead": null, "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": "2021-05-21T10:17:28.964000+00:00", "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": null, "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": null, "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_ideal_customer_profile": null, "hs_is_target_account": null, "hs_last_booked_meeting_date": null, "hs_last_logged_call_date": null, "hs_last_open_task_date": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": "2023-01-26T11:45:49.817000+00:00", "hs_latest_createdate_of_active_subscriptions": null, "hs_latest_meeting_activity": null, "hs_lead_status": null, "hs_merged_object_ids": null, "hs_num_blockers": null, "hs_num_child_companies": 0, "hs_num_contacts_with_buying_roles": null, "hs_num_decision_makers": null, "hs_num_open_deals": 1, "hs_object_id": 4992593519, "hs_object_source": "CONTACTS", "hs_object_source_id": "CRM_UI", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_parent_company_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": null, "hs_predictivecontactscore_v2": null, "hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_target_account": null, "hs_target_account_probability": 0.5476861596107483, "hs_target_account_recommendation_snooze_time": null, "hs_target_account_recommendation_state": null, "hs_time_in_customer": null, "hs_time_in_evangelist": null, "hs_time_in_lead": null, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": 85639946626, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": null, "hs_total_deal_value": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2020-12-10T07:58:09.554000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "hubspotscore": null, "industry": null, "is_public": false, "lifecyclestage": "opportunity", "linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "name": "Airbyte test1", "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_contacts": 0, "num_associated_deals": 1, "num_contacted_notes": null, "num_conversion_events": null, "num_conversion_events_cardinality_sum_d095f14b": null, "num_notes": null, "numberofemployees": 200, "phone": "+1 415-307-4864", "recent_conversion_date": null, "recent_conversion_date_timestamp_latest_value_72856da1": null, "recent_conversion_event_name": null, "recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "recent_deal_amount": null, "recent_deal_close_date": null, "state": "CA", "timezone": "America/Los_Angeles", "total_money_raised": null, "total_revenue": null, "twitterbio": null, "twitterfollowers": null, "twitterhandle": "AirbyteHQ", "type": null, "web_technologies": "slack;segment;google_tag_manager;greenhouse;google_analytics;intercom;piwik;google_apps;hubspot;facebook_advertiser", "website": "airbyte.io", "zip": "94114"}, "createdAt": "2020-12-10T07:58:09.554Z", "updatedAt": "2023-01-26T11:45:49.817Z", "archived": false, "properties_about_us": null, "properties_address": null, "properties_address2": null, "properties_annualrevenue": null, "properties_city": "San Francisco", "properties_closedate": null, "properties_closedate_timestamp_earliest_value_a2a17e6e": null, "properties_country": "United States", "properties_createdate": "2020-12-10T07:58:09.554000+00:00", "properties_custom_company_property": null, "properties_days_to_close": null, "properties_description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_domain": "airbyte.io", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_facebook_company_page": null, "properties_facebookfans": null, "properties_first_contact_createdate": null, "properties_first_contact_createdate_timestamp_earliest_value_78b50eea": null, "properties_first_conversion_date": null, "properties_first_conversion_date_timestamp_earliest_value_61f58f2c": null, "properties_first_conversion_event_name": null, "properties_first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "properties_first_deal_created_date": "2021-05-21T10:17:06.028000+00:00", "properties_founded_year": "2020", "properties_googleplus_page": null, "properties_hs_additional_domains": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_first_timestamp": null, "properties_hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "properties_hs_analytics_latest_source": null, "properties_hs_analytics_latest_source_data_1": null, "properties_hs_analytics_latest_source_data_2": null, "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_num_page_views": null, "properties_hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "properties_hs_analytics_num_visits": null, "properties_hs_analytics_num_visits_cardinality_sum_53d952a6": null, "properties_hs_analytics_source": null, "properties_hs_analytics_source_data_1": null, "properties_hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "properties_hs_analytics_source_data_2": null, "properties_hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "properties_hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "properties_hs_annual_revenue_currency_code": "USD", "properties_hs_avatar_filemanager_key": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_date_entered_customer": null, "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": null, "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": "2021-05-21T10:17:28.964000+00:00", "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": null, "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": null, "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_ideal_customer_profile": null, "properties_hs_is_target_account": null, "properties_hs_last_booked_meeting_date": null, "properties_hs_last_logged_call_date": null, "properties_hs_last_open_task_date": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": "2023-01-26T11:45:49.817000+00:00", "properties_hs_latest_createdate_of_active_subscriptions": null, "properties_hs_latest_meeting_activity": null, "properties_hs_lead_status": null, "properties_hs_merged_object_ids": null, "properties_hs_num_blockers": null, "properties_hs_num_child_companies": 0, "properties_hs_num_contacts_with_buying_roles": null, "properties_hs_num_decision_makers": null, "properties_hs_num_open_deals": 1, "properties_hs_object_id": 4992593519, "properties_hs_object_source": "CONTACTS", "properties_hs_object_source_id": "CRM_UI", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_parent_company_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": null, "properties_hs_predictivecontactscore_v2": null, "properties_hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_target_account": null, "properties_hs_target_account_probability": 0.5476861596107483, "properties_hs_target_account_recommendation_snooze_time": null, "properties_hs_target_account_recommendation_state": null, "properties_hs_time_in_customer": null, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": null, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": 85639946626, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": null, "properties_hs_total_deal_value": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2020-12-10T07:58:09.554000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": null, "properties_is_public": false, "properties_lifecyclestage": "opportunity", "properties_linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "properties_linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_name": "Airbyte test1", "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_associated_deals": 1, "properties_num_contacted_notes": null, "properties_num_conversion_events": null, "properties_num_conversion_events_cardinality_sum_d095f14b": null, "properties_num_notes": null, "properties_numberofemployees": 200, "properties_phone": "+1 415-307-4864", "properties_recent_conversion_date": null, "properties_recent_conversion_date_timestamp_latest_value_72856da1": null, "properties_recent_conversion_event_name": null, "properties_recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "properties_recent_deal_amount": null, "properties_recent_deal_close_date": null, "properties_state": "CA", "properties_timezone": "America/Los_Angeles", "properties_total_money_raised": null, "properties_total_revenue": null, "properties_twitterbio": null, "properties_twitterfollowers": null, "properties_twitterhandle": "AirbyteHQ", "properties_type": null, "properties_web_technologies": "slack;segment;google_tag_manager;greenhouse;google_analytics;intercom;piwik;google_apps;hubspot;facebook_advertiser", "properties_website": "airbyte.io", "properties_zip": "94114"}, "emitted_at": 1707232195717} -{"stream": "companies", "data": {"id": "5000526215", "properties": {"about_us": null, "address": null, "address2": null, "annualrevenue": 10000000, "city": "San Francisco", "closedate": "2023-04-04T15:00:58.081000+00:00", "closedate_timestamp_earliest_value_a2a17e6e": null, "country": "United States", "createdate": "2020-12-11T01:27:40.002000+00:00", "custom_company_property": null, "days_to_close": 844, "description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "domain": "dataline.io", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "facebook_company_page": null, "facebookfans": null, "first_contact_createdate": "2020-12-11T01:29:50.116000+00:00", "first_contact_createdate_timestamp_earliest_value_78b50eea": null, "first_conversion_date": null, "first_conversion_date_timestamp_earliest_value_61f58f2c": null, "first_conversion_event_name": null, "first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "first_deal_created_date": "2021-01-13T10:30:42.221000+00:00", "founded_year": "2020", "googleplus_page": null, "hs_additional_domains": null, "hs_all_accessible_team_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_first_timestamp": "2020-12-11T01:29:50.116000+00:00", "hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "hs_analytics_latest_source": "OFFLINE", "hs_analytics_latest_source_data_1": "CONTACTS", "hs_analytics_latest_source_data_2": "CRM_UI", "hs_analytics_latest_source_timestamp": "2020-12-11T01:29:50.153000+00:00", "hs_analytics_num_page_views": 0, "hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "hs_analytics_num_visits": 0, "hs_analytics_num_visits_cardinality_sum_53d952a6": null, "hs_analytics_source": "OFFLINE", "hs_analytics_source_data_1": "CONTACTS", "hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "hs_analytics_source_data_2": "CRM_UI", "hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "hs_annual_revenue_currency_code": "USD", "hs_avatar_filemanager_key": null, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_date_entered_customer": "2023-04-04T15:00:58.081000+00:00", "hs_date_entered_evangelist": null, "hs_date_entered_lead": null, "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": "2021-02-23T20:21:06.027000+00:00", "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": null, "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": "2023-04-04T15:00:58.081000+00:00", "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_ideal_customer_profile": null, "hs_is_target_account": null, "hs_last_booked_meeting_date": "2024-02-06T10:15:00+00:00", "hs_last_logged_call_date": null, "hs_last_open_task_date": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": "2024-02-06T10:15:05.376000+00:00", "hs_latest_createdate_of_active_subscriptions": null, "hs_latest_meeting_activity": "2024-02-06T10:15:00+00:00", "hs_lead_status": null, "hs_merged_object_ids": "5183403213", "hs_num_blockers": 0, "hs_num_child_companies": 0, "hs_num_contacts_with_buying_roles": 0, "hs_num_decision_makers": 0, "hs_num_open_deals": 2, "hs_object_id": 5000526215, "hs_object_source": "CONTACTS", "hs_object_source_id": "CRM_UI", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_parent_company_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": "companies-lifecycle-pipeline", "hs_predictivecontactscore_v2": 0.3, "hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_target_account": null, "hs_target_account_probability": 0.4857041537761688, "hs_target_account_recommendation_snooze_time": null, "hs_target_account_recommendation_state": null, "hs_time_in_customer": 26611737514, "hs_time_in_evangelist": null, "hs_time_in_lead": null, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": 66508792054, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": null, "hs_total_deal_value": 60010, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2020-12-11T01:27:40.002000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "hubspotscore": null, "industry": "COMPUTER_SOFTWARE", "is_public": false, "lifecyclestage": "customer", "linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "name": "Dataline", "notes_last_contacted": "2024-02-06T10:15:00+00:00", "notes_last_updated": "2024-02-06T10:15:00+00:00", "notes_next_activity_date": null, "num_associated_contacts": 1, "num_associated_deals": 3, "num_contacted_notes": 2, "num_conversion_events": null, "num_conversion_events_cardinality_sum_d095f14b": null, "num_notes": 2, "numberofemployees": 50, "phone": "", "recent_conversion_date": null, "recent_conversion_date_timestamp_latest_value_72856da1": null, "recent_conversion_event_name": null, "recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "recent_deal_amount": 60000, "recent_deal_close_date": "2023-04-04T14:59:45.103000+00:00", "state": "CA", "timezone": "", "total_money_raised": null, "total_revenue": 60000, "twitterbio": null, "twitterfollowers": null, "twitterhandle": "AirbyteHQ", "type": null, "web_technologies": "slack;segment;google_tag_manager;cloud_flare;google_analytics;intercom;lever;google_apps", "website": "dataline.io", "zip": ""}, "createdAt": "2020-12-11T01:27:40.002Z", "updatedAt": "2024-02-06T10:15:05.376Z", "archived": false, "contacts": ["151", "151"], "properties_about_us": null, "properties_address": null, "properties_address2": null, "properties_annualrevenue": 10000000, "properties_city": "San Francisco", "properties_closedate": "2023-04-04T15:00:58.081000+00:00", "properties_closedate_timestamp_earliest_value_a2a17e6e": null, "properties_country": "United States", "properties_createdate": "2020-12-11T01:27:40.002000+00:00", "properties_custom_company_property": null, "properties_days_to_close": 844, "properties_description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_domain": "dataline.io", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_facebook_company_page": null, "properties_facebookfans": null, "properties_first_contact_createdate": "2020-12-11T01:29:50.116000+00:00", "properties_first_contact_createdate_timestamp_earliest_value_78b50eea": null, "properties_first_conversion_date": null, "properties_first_conversion_date_timestamp_earliest_value_61f58f2c": null, "properties_first_conversion_event_name": null, "properties_first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "properties_first_deal_created_date": "2021-01-13T10:30:42.221000+00:00", "properties_founded_year": "2020", "properties_googleplus_page": null, "properties_hs_additional_domains": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_first_timestamp": "2020-12-11T01:29:50.116000+00:00", "properties_hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "properties_hs_analytics_latest_source": "OFFLINE", "properties_hs_analytics_latest_source_data_1": "CONTACTS", "properties_hs_analytics_latest_source_data_2": "CRM_UI", "properties_hs_analytics_latest_source_timestamp": "2020-12-11T01:29:50.153000+00:00", "properties_hs_analytics_num_page_views": 0, "properties_hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "properties_hs_analytics_num_visits": 0, "properties_hs_analytics_num_visits_cardinality_sum_53d952a6": null, "properties_hs_analytics_source": "OFFLINE", "properties_hs_analytics_source_data_1": "CONTACTS", "properties_hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "properties_hs_analytics_source_data_2": "CRM_UI", "properties_hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "properties_hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "properties_hs_annual_revenue_currency_code": "USD", "properties_hs_avatar_filemanager_key": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_date_entered_customer": "2023-04-04T15:00:58.081000+00:00", "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": null, "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": "2021-02-23T20:21:06.027000+00:00", "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": null, "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": "2023-04-04T15:00:58.081000+00:00", "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_ideal_customer_profile": null, "properties_hs_is_target_account": null, "properties_hs_last_booked_meeting_date": "2024-02-06T10:15:00+00:00", "properties_hs_last_logged_call_date": null, "properties_hs_last_open_task_date": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": "2024-02-06T10:15:05.376000+00:00", "properties_hs_latest_createdate_of_active_subscriptions": null, "properties_hs_latest_meeting_activity": "2024-02-06T10:15:00+00:00", "properties_hs_lead_status": null, "properties_hs_merged_object_ids": "5183403213", "properties_hs_num_blockers": 0, "properties_hs_num_child_companies": 0, "properties_hs_num_contacts_with_buying_roles": 0, "properties_hs_num_decision_makers": 0, "properties_hs_num_open_deals": 2, "properties_hs_object_id": 5000526215, "properties_hs_object_source": "CONTACTS", "properties_hs_object_source_id": "CRM_UI", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_parent_company_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "companies-lifecycle-pipeline", "properties_hs_predictivecontactscore_v2": 0.3, "properties_hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_target_account": null, "properties_hs_target_account_probability": 0.4857041537761688, "properties_hs_target_account_recommendation_snooze_time": null, "properties_hs_target_account_recommendation_state": null, "properties_hs_time_in_customer": 26611737514, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": null, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": 66508792054, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": null, "properties_hs_total_deal_value": 60010, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2020-12-11T01:27:40.002000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": "COMPUTER_SOFTWARE", "properties_is_public": false, "properties_lifecyclestage": "customer", "properties_linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "properties_linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_name": "Dataline", "properties_notes_last_contacted": "2024-02-06T10:15:00+00:00", "properties_notes_last_updated": "2024-02-06T10:15:00+00:00", "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 1, "properties_num_associated_deals": 3, "properties_num_contacted_notes": 2, "properties_num_conversion_events": null, "properties_num_conversion_events_cardinality_sum_d095f14b": null, "properties_num_notes": 2, "properties_numberofemployees": 50, "properties_phone": "", "properties_recent_conversion_date": null, "properties_recent_conversion_date_timestamp_latest_value_72856da1": null, "properties_recent_conversion_event_name": null, "properties_recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "properties_recent_deal_amount": 60000, "properties_recent_deal_close_date": "2023-04-04T14:59:45.103000+00:00", "properties_state": "CA", "properties_timezone": "", "properties_total_money_raised": null, "properties_total_revenue": 60000, "properties_twitterbio": null, "properties_twitterfollowers": null, "properties_twitterhandle": "AirbyteHQ", "properties_type": null, "properties_web_technologies": "slack;segment;google_tag_manager;cloud_flare;google_analytics;intercom;lever;google_apps", "properties_website": "dataline.io", "properties_zip": ""}, "emitted_at": 1707232195719} -{"stream": "companies", "data": {"id": "5000787595", "properties": {"about_us": null, "address": "2261 Market Street", "address2": null, "annualrevenue": 10000000, "city": "San Francisco", "closedate": null, "closedate_timestamp_earliest_value_a2a17e6e": null, "country": "United States", "createdate": "2020-12-11T01:28:27.673000+00:00", "custom_company_property": null, "days_to_close": null, "description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "domain": "Daxtarity.com", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "facebook_company_page": null, "facebookfans": null, "first_contact_createdate": null, "first_contact_createdate_timestamp_earliest_value_78b50eea": null, "first_conversion_date": null, "first_conversion_date_timestamp_earliest_value_61f58f2c": null, "first_conversion_event_name": null, "first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "first_deal_created_date": null, "founded_year": "2020", "googleplus_page": null, "hs_additional_domains": null, "hs_all_accessible_team_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_first_timestamp": null, "hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "hs_analytics_latest_source": "", "hs_analytics_latest_source_data_1": "", "hs_analytics_latest_source_data_2": "", "hs_analytics_latest_source_timestamp": null, "hs_analytics_num_page_views": null, "hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "hs_analytics_num_visits": null, "hs_analytics_num_visits_cardinality_sum_53d952a6": null, "hs_analytics_source": "", "hs_analytics_source_data_1": "", "hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "hs_analytics_source_data_2": "", "hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "hs_annual_revenue_currency_code": "USD", "hs_avatar_filemanager_key": null, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_date_entered_customer": null, "hs_date_entered_evangelist": null, "hs_date_entered_lead": null, "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": null, "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": null, "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": null, "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_ideal_customer_profile": null, "hs_is_target_account": null, "hs_last_booked_meeting_date": null, "hs_last_logged_call_date": null, "hs_last_open_task_date": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": "2024-01-31T23:50:34.138000+00:00", "hs_latest_createdate_of_active_subscriptions": null, "hs_latest_meeting_activity": null, "hs_lead_status": null, "hs_merged_object_ids": null, "hs_num_blockers": 0, "hs_num_child_companies": 0, "hs_num_contacts_with_buying_roles": 0, "hs_num_decision_makers": 0, "hs_num_open_deals": 0, "hs_object_id": 5000787595, "hs_object_source": "CONTACTS", "hs_object_source_id": "CRM_UI", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_parent_company_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": null, "hs_predictivecontactscore_v2": null, "hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_target_account": null, "hs_target_account_probability": 0.4076234698295593, "hs_target_account_recommendation_snooze_time": null, "hs_target_account_recommendation_state": null, "hs_time_in_customer": null, "hs_time_in_evangelist": null, "hs_time_in_lead": null, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": null, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": null, "hs_total_deal_value": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2020-12-11T01:28:27.673000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "hubspotscore": null, "industry": null, "is_public": false, "lifecyclestage": null, "linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "name": "Daxtarity", "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_contacts": 0, "num_associated_deals": null, "num_contacted_notes": null, "num_conversion_events": null, "num_conversion_events_cardinality_sum_d095f14b": null, "num_notes": null, "numberofemployees": 50, "phone": "+1 415-307-4864", "recent_conversion_date": null, "recent_conversion_date_timestamp_latest_value_72856da1": null, "recent_conversion_event_name": null, "recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "recent_deal_amount": null, "recent_deal_close_date": null, "state": "CA", "timezone": "", "total_money_raised": "31200000", "total_revenue": null, "twitterbio": null, "twitterfollowers": null, "twitterhandle": "AirbyteHQ", "type": null, "web_technologies": "slack;google_tag_manager;greenhouse;google_analytics;intercom;piwik;google_apps;hubspot;facebook_advertiser", "website": "Daxtarity.com", "zip": "94114"}, "createdAt": "2020-12-11T01:28:27.673Z", "updatedAt": "2024-01-31T23:50:34.138Z", "archived": false, "properties_about_us": null, "properties_address": "2261 Market Street", "properties_address2": null, "properties_annualrevenue": 10000000, "properties_city": "San Francisco", "properties_closedate": null, "properties_closedate_timestamp_earliest_value_a2a17e6e": null, "properties_country": "United States", "properties_createdate": "2020-12-11T01:28:27.673000+00:00", "properties_custom_company_property": null, "properties_days_to_close": null, "properties_description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_domain": "Daxtarity.com", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_facebook_company_page": null, "properties_facebookfans": null, "properties_first_contact_createdate": null, "properties_first_contact_createdate_timestamp_earliest_value_78b50eea": null, "properties_first_conversion_date": null, "properties_first_conversion_date_timestamp_earliest_value_61f58f2c": null, "properties_first_conversion_event_name": null, "properties_first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "properties_first_deal_created_date": null, "properties_founded_year": "2020", "properties_googleplus_page": null, "properties_hs_additional_domains": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_first_timestamp": null, "properties_hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "properties_hs_analytics_latest_source": "", "properties_hs_analytics_latest_source_data_1": "", "properties_hs_analytics_latest_source_data_2": "", "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_num_page_views": null, "properties_hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "properties_hs_analytics_num_visits": null, "properties_hs_analytics_num_visits_cardinality_sum_53d952a6": null, "properties_hs_analytics_source": "", "properties_hs_analytics_source_data_1": "", "properties_hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "properties_hs_analytics_source_data_2": "", "properties_hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "properties_hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "properties_hs_annual_revenue_currency_code": "USD", "properties_hs_avatar_filemanager_key": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_date_entered_customer": null, "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": null, "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": null, "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": null, "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": null, "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_ideal_customer_profile": null, "properties_hs_is_target_account": null, "properties_hs_last_booked_meeting_date": null, "properties_hs_last_logged_call_date": null, "properties_hs_last_open_task_date": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": "2024-01-31T23:50:34.138000+00:00", "properties_hs_latest_createdate_of_active_subscriptions": null, "properties_hs_latest_meeting_activity": null, "properties_hs_lead_status": null, "properties_hs_merged_object_ids": null, "properties_hs_num_blockers": 0, "properties_hs_num_child_companies": 0, "properties_hs_num_contacts_with_buying_roles": 0, "properties_hs_num_decision_makers": 0, "properties_hs_num_open_deals": 0, "properties_hs_object_id": 5000787595, "properties_hs_object_source": "CONTACTS", "properties_hs_object_source_id": "CRM_UI", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_parent_company_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": null, "properties_hs_predictivecontactscore_v2": null, "properties_hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_target_account": null, "properties_hs_target_account_probability": 0.4076234698295593, "properties_hs_target_account_recommendation_snooze_time": null, "properties_hs_target_account_recommendation_state": null, "properties_hs_time_in_customer": null, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": null, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": null, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": null, "properties_hs_total_deal_value": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2020-12-11T01:28:27.673000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": null, "properties_is_public": false, "properties_lifecyclestage": null, "properties_linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "properties_linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_name": "Daxtarity", "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_associated_deals": null, "properties_num_contacted_notes": null, "properties_num_conversion_events": null, "properties_num_conversion_events_cardinality_sum_d095f14b": null, "properties_num_notes": null, "properties_numberofemployees": 50, "properties_phone": "+1 415-307-4864", "properties_recent_conversion_date": null, "properties_recent_conversion_date_timestamp_latest_value_72856da1": null, "properties_recent_conversion_event_name": null, "properties_recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "properties_recent_deal_amount": null, "properties_recent_deal_close_date": null, "properties_state": "CA", "properties_timezone": "", "properties_total_money_raised": "31200000", "properties_total_revenue": null, "properties_twitterbio": null, "properties_twitterfollowers": null, "properties_twitterhandle": "AirbyteHQ", "properties_type": null, "properties_web_technologies": "slack;google_tag_manager;greenhouse;google_analytics;intercom;piwik;google_apps;hubspot;facebook_advertiser", "properties_website": "Daxtarity.com", "properties_zip": "94114"}, "emitted_at": 1707232195721} +{"stream": "companies", "data": {"id": "4992593519", "properties": {"about_us": null, "address": null, "address2": null, "annualrevenue": null, "city": "San Francisco", "closedate": null, "closedate_timestamp_earliest_value_a2a17e6e": null, "country": "United States", "createdate": "2020-12-10T07:58:09.554000+00:00", "custom_company_property": null, "days_to_close": null, "description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "domain": "airbyte.io", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "facebook_company_page": null, "facebookfans": null, "first_contact_createdate": null, "first_contact_createdate_timestamp_earliest_value_78b50eea": null, "first_conversion_date": null, "first_conversion_date_timestamp_earliest_value_61f58f2c": null, "first_conversion_event_name": null, "first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "first_deal_created_date": "2021-05-21T10:17:06.028000+00:00", "founded_year": "2020", "googleplus_page": null, "hs_additional_domains": null, "hs_all_accessible_team_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_first_timestamp": null, "hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "hs_analytics_latest_source": null, "hs_analytics_latest_source_data_1": null, "hs_analytics_latest_source_data_2": null, "hs_analytics_latest_source_timestamp": null, "hs_analytics_num_page_views": null, "hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "hs_analytics_num_visits": null, "hs_analytics_num_visits_cardinality_sum_53d952a6": null, "hs_analytics_source": null, "hs_analytics_source_data_1": null, "hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "hs_analytics_source_data_2": null, "hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "hs_annual_revenue_currency_code": "USD", "hs_avatar_filemanager_key": null, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_date_entered_customer": null, "hs_date_entered_evangelist": null, "hs_date_entered_lead": null, "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": "2021-05-21T10:17:28.964000+00:00", "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": null, "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": null, "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_ideal_customer_profile": null, "hs_is_target_account": null, "hs_last_booked_meeting_date": null, "hs_last_logged_call_date": null, "hs_last_open_task_date": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": "2023-01-26T11:45:49.817000+00:00", "hs_latest_createdate_of_active_subscriptions": null, "hs_latest_meeting_activity": null, "hs_lead_status": null, "hs_merged_object_ids": null, "hs_num_blockers": null, "hs_num_child_companies": 0, "hs_num_contacts_with_buying_roles": null, "hs_num_decision_makers": null, "hs_num_open_deals": 1, "hs_object_id": 4992593519, "hs_object_source": "CONTACTS", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "CRM_UI", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_parent_company_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": null, "hs_predictivecontactscore_v2": null, "hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_target_account": null, "hs_target_account_probability": 0.5476861596107483, "hs_target_account_recommendation_snooze_time": null, "hs_target_account_recommendation_state": null, "hs_time_in_customer": null, "hs_time_in_evangelist": null, "hs_time_in_lead": null, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": 86420513185, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": null, "hs_total_deal_value": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2020-12-10T07:58:09.554000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "hubspotscore": null, "industry": null, "is_public": false, "lifecyclestage": "opportunity", "linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "name": "Airbyte test1", "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_contacts": 0, "num_associated_deals": 1, "num_contacted_notes": null, "num_conversion_events": null, "num_conversion_events_cardinality_sum_d095f14b": null, "num_notes": null, "numberofemployees": 200, "phone": "+1 415-307-4864", "recent_conversion_date": null, "recent_conversion_date_timestamp_latest_value_72856da1": null, "recent_conversion_event_name": null, "recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "recent_deal_amount": null, "recent_deal_close_date": null, "state": "CA", "timezone": "America/Los_Angeles", "total_money_raised": null, "total_revenue": null, "twitterbio": null, "twitterfollowers": null, "twitterhandle": "AirbyteHQ", "type": null, "web_technologies": "slack;segment;google_tag_manager;greenhouse;google_analytics;intercom;piwik;google_apps;hubspot;facebook_advertiser", "website": "airbyte.io", "zip": "94114"}, "createdAt": "2020-12-10T07:58:09.554Z", "updatedAt": "2023-01-26T11:45:49.817Z", "archived": false, "properties_about_us": null, "properties_address": null, "properties_address2": null, "properties_annualrevenue": null, "properties_city": "San Francisco", "properties_closedate": null, "properties_closedate_timestamp_earliest_value_a2a17e6e": null, "properties_country": "United States", "properties_createdate": "2020-12-10T07:58:09.554000+00:00", "properties_custom_company_property": null, "properties_days_to_close": null, "properties_description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_domain": "airbyte.io", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_facebook_company_page": null, "properties_facebookfans": null, "properties_first_contact_createdate": null, "properties_first_contact_createdate_timestamp_earliest_value_78b50eea": null, "properties_first_conversion_date": null, "properties_first_conversion_date_timestamp_earliest_value_61f58f2c": null, "properties_first_conversion_event_name": null, "properties_first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "properties_first_deal_created_date": "2021-05-21T10:17:06.028000+00:00", "properties_founded_year": "2020", "properties_googleplus_page": null, "properties_hs_additional_domains": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_first_timestamp": null, "properties_hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "properties_hs_analytics_latest_source": null, "properties_hs_analytics_latest_source_data_1": null, "properties_hs_analytics_latest_source_data_2": null, "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_num_page_views": null, "properties_hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "properties_hs_analytics_num_visits": null, "properties_hs_analytics_num_visits_cardinality_sum_53d952a6": null, "properties_hs_analytics_source": null, "properties_hs_analytics_source_data_1": null, "properties_hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "properties_hs_analytics_source_data_2": null, "properties_hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "properties_hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "properties_hs_annual_revenue_currency_code": "USD", "properties_hs_avatar_filemanager_key": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_date_entered_customer": null, "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": null, "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": "2021-05-21T10:17:28.964000+00:00", "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": null, "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": null, "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_ideal_customer_profile": null, "properties_hs_is_target_account": null, "properties_hs_last_booked_meeting_date": null, "properties_hs_last_logged_call_date": null, "properties_hs_last_open_task_date": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": "2023-01-26T11:45:49.817000+00:00", "properties_hs_latest_createdate_of_active_subscriptions": null, "properties_hs_latest_meeting_activity": null, "properties_hs_lead_status": null, "properties_hs_merged_object_ids": null, "properties_hs_num_blockers": null, "properties_hs_num_child_companies": 0, "properties_hs_num_contacts_with_buying_roles": null, "properties_hs_num_decision_makers": null, "properties_hs_num_open_deals": 1, "properties_hs_object_id": 4992593519, "properties_hs_object_source": "CONTACTS", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "CRM_UI", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_parent_company_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": null, "properties_hs_predictivecontactscore_v2": null, "properties_hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_target_account": null, "properties_hs_target_account_probability": 0.5476861596107483, "properties_hs_target_account_recommendation_snooze_time": null, "properties_hs_target_account_recommendation_state": null, "properties_hs_time_in_customer": null, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": null, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": 86420513185, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": null, "properties_hs_total_deal_value": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2020-12-10T07:58:09.554000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": null, "properties_is_public": false, "properties_lifecyclestage": "opportunity", "properties_linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "properties_linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_name": "Airbyte test1", "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_associated_deals": 1, "properties_num_contacted_notes": null, "properties_num_conversion_events": null, "properties_num_conversion_events_cardinality_sum_d095f14b": null, "properties_num_notes": null, "properties_numberofemployees": 200, "properties_phone": "+1 415-307-4864", "properties_recent_conversion_date": null, "properties_recent_conversion_date_timestamp_latest_value_72856da1": null, "properties_recent_conversion_event_name": null, "properties_recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "properties_recent_deal_amount": null, "properties_recent_deal_close_date": null, "properties_state": "CA", "properties_timezone": "America/Los_Angeles", "properties_total_money_raised": null, "properties_total_revenue": null, "properties_twitterbio": null, "properties_twitterfollowers": null, "properties_twitterhandle": "AirbyteHQ", "properties_type": null, "properties_web_technologies": "slack;segment;google_tag_manager;greenhouse;google_analytics;intercom;piwik;google_apps;hubspot;facebook_advertiser", "properties_website": "airbyte.io", "properties_zip": "94114"}, "emitted_at": 1708012762427} +{"stream": "companies", "data": {"id": "5000526215", "properties": {"about_us": null, "address": null, "address2": null, "annualrevenue": 10000000, "city": "San Francisco", "closedate": "2023-04-04T15:00:58.081000+00:00", "closedate_timestamp_earliest_value_a2a17e6e": null, "country": "United States", "createdate": "2020-12-11T01:27:40.002000+00:00", "custom_company_property": null, "days_to_close": 844, "description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "domain": "dataline.io", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "facebook_company_page": null, "facebookfans": null, "first_contact_createdate": "2020-12-11T01:29:50.116000+00:00", "first_contact_createdate_timestamp_earliest_value_78b50eea": null, "first_conversion_date": null, "first_conversion_date_timestamp_earliest_value_61f58f2c": null, "first_conversion_event_name": null, "first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "first_deal_created_date": "2021-01-13T10:30:42.221000+00:00", "founded_year": "2020", "googleplus_page": null, "hs_additional_domains": null, "hs_all_accessible_team_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_first_timestamp": "2020-12-11T01:29:50.116000+00:00", "hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "hs_analytics_latest_source": "OFFLINE", "hs_analytics_latest_source_data_1": "CONTACTS", "hs_analytics_latest_source_data_2": "CRM_UI", "hs_analytics_latest_source_timestamp": "2020-12-11T01:29:50.153000+00:00", "hs_analytics_num_page_views": 0, "hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "hs_analytics_num_visits": 0, "hs_analytics_num_visits_cardinality_sum_53d952a6": null, "hs_analytics_source": "OFFLINE", "hs_analytics_source_data_1": "CONTACTS", "hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "hs_analytics_source_data_2": "CRM_UI", "hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "hs_annual_revenue_currency_code": "USD", "hs_avatar_filemanager_key": null, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_date_entered_customer": "2023-04-04T15:00:58.081000+00:00", "hs_date_entered_evangelist": null, "hs_date_entered_lead": null, "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": "2021-02-23T20:21:06.027000+00:00", "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": null, "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": "2023-04-04T15:00:58.081000+00:00", "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_ideal_customer_profile": null, "hs_is_target_account": null, "hs_last_booked_meeting_date": "2024-02-06T10:15:00+00:00", "hs_last_logged_call_date": null, "hs_last_open_task_date": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": "2024-02-06T10:15:05.376000+00:00", "hs_latest_createdate_of_active_subscriptions": null, "hs_latest_meeting_activity": "2024-02-06T10:15:00+00:00", "hs_lead_status": null, "hs_merged_object_ids": "5183403213", "hs_num_blockers": 0, "hs_num_child_companies": 0, "hs_num_contacts_with_buying_roles": 0, "hs_num_decision_makers": 0, "hs_num_open_deals": 2, "hs_object_id": 5000526215, "hs_object_source": "CONTACTS", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "CRM_UI", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_parent_company_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": "companies-lifecycle-pipeline", "hs_predictivecontactscore_v2": 0.3, "hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_target_account": null, "hs_target_account_probability": 0.4857041537761688, "hs_target_account_recommendation_snooze_time": null, "hs_target_account_recommendation_state": null, "hs_time_in_customer": 27392304072, "hs_time_in_evangelist": null, "hs_time_in_lead": null, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": 66508792054, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": null, "hs_total_deal_value": 60010, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2020-12-11T01:27:40.002000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "hubspotscore": null, "industry": "COMPUTER_SOFTWARE", "is_public": false, "lifecyclestage": "customer", "linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "name": "Dataline", "notes_last_contacted": "2024-02-06T10:15:00+00:00", "notes_last_updated": "2024-02-06T10:15:00+00:00", "notes_next_activity_date": null, "num_associated_contacts": 1, "num_associated_deals": 3, "num_contacted_notes": 2, "num_conversion_events": null, "num_conversion_events_cardinality_sum_d095f14b": null, "num_notes": 2, "numberofemployees": 50, "phone": "", "recent_conversion_date": null, "recent_conversion_date_timestamp_latest_value_72856da1": null, "recent_conversion_event_name": null, "recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "recent_deal_amount": 60000, "recent_deal_close_date": "2023-04-04T14:59:45.103000+00:00", "state": "CA", "timezone": "", "total_money_raised": null, "total_revenue": 60000, "twitterbio": null, "twitterfollowers": null, "twitterhandle": "AirbyteHQ", "type": null, "web_technologies": "slack;segment;google_tag_manager;cloud_flare;google_analytics;intercom;lever;google_apps", "website": "dataline.io", "zip": ""}, "createdAt": "2020-12-11T01:27:40.002Z", "updatedAt": "2024-02-06T10:15:05.376Z", "archived": false, "contacts": ["151", "151"], "properties_about_us": null, "properties_address": null, "properties_address2": null, "properties_annualrevenue": 10000000, "properties_city": "San Francisco", "properties_closedate": "2023-04-04T15:00:58.081000+00:00", "properties_closedate_timestamp_earliest_value_a2a17e6e": null, "properties_country": "United States", "properties_createdate": "2020-12-11T01:27:40.002000+00:00", "properties_custom_company_property": null, "properties_days_to_close": 844, "properties_description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_domain": "dataline.io", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_facebook_company_page": null, "properties_facebookfans": null, "properties_first_contact_createdate": "2020-12-11T01:29:50.116000+00:00", "properties_first_contact_createdate_timestamp_earliest_value_78b50eea": null, "properties_first_conversion_date": null, "properties_first_conversion_date_timestamp_earliest_value_61f58f2c": null, "properties_first_conversion_event_name": null, "properties_first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "properties_first_deal_created_date": "2021-01-13T10:30:42.221000+00:00", "properties_founded_year": "2020", "properties_googleplus_page": null, "properties_hs_additional_domains": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_first_timestamp": "2020-12-11T01:29:50.116000+00:00", "properties_hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "properties_hs_analytics_latest_source": "OFFLINE", "properties_hs_analytics_latest_source_data_1": "CONTACTS", "properties_hs_analytics_latest_source_data_2": "CRM_UI", "properties_hs_analytics_latest_source_timestamp": "2020-12-11T01:29:50.153000+00:00", "properties_hs_analytics_num_page_views": 0, "properties_hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "properties_hs_analytics_num_visits": 0, "properties_hs_analytics_num_visits_cardinality_sum_53d952a6": null, "properties_hs_analytics_source": "OFFLINE", "properties_hs_analytics_source_data_1": "CONTACTS", "properties_hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "properties_hs_analytics_source_data_2": "CRM_UI", "properties_hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "properties_hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "properties_hs_annual_revenue_currency_code": "USD", "properties_hs_avatar_filemanager_key": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_date_entered_customer": "2023-04-04T15:00:58.081000+00:00", "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": null, "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": "2021-02-23T20:21:06.027000+00:00", "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": null, "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": "2023-04-04T15:00:58.081000+00:00", "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_ideal_customer_profile": null, "properties_hs_is_target_account": null, "properties_hs_last_booked_meeting_date": "2024-02-06T10:15:00+00:00", "properties_hs_last_logged_call_date": null, "properties_hs_last_open_task_date": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": "2024-02-06T10:15:05.376000+00:00", "properties_hs_latest_createdate_of_active_subscriptions": null, "properties_hs_latest_meeting_activity": "2024-02-06T10:15:00+00:00", "properties_hs_lead_status": null, "properties_hs_merged_object_ids": "5183403213", "properties_hs_num_blockers": 0, "properties_hs_num_child_companies": 0, "properties_hs_num_contacts_with_buying_roles": 0, "properties_hs_num_decision_makers": 0, "properties_hs_num_open_deals": 2, "properties_hs_object_id": 5000526215, "properties_hs_object_source": "CONTACTS", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "CRM_UI", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_parent_company_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "companies-lifecycle-pipeline", "properties_hs_predictivecontactscore_v2": 0.3, "properties_hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_target_account": null, "properties_hs_target_account_probability": 0.4857041537761688, "properties_hs_target_account_recommendation_snooze_time": null, "properties_hs_target_account_recommendation_state": null, "properties_hs_time_in_customer": 27392304072, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": null, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": 66508792054, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": null, "properties_hs_total_deal_value": 60010, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2020-12-11T01:27:40.002000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": "COMPUTER_SOFTWARE", "properties_is_public": false, "properties_lifecyclestage": "customer", "properties_linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "properties_linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_name": "Dataline", "properties_notes_last_contacted": "2024-02-06T10:15:00+00:00", "properties_notes_last_updated": "2024-02-06T10:15:00+00:00", "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 1, "properties_num_associated_deals": 3, "properties_num_contacted_notes": 2, "properties_num_conversion_events": null, "properties_num_conversion_events_cardinality_sum_d095f14b": null, "properties_num_notes": 2, "properties_numberofemployees": 50, "properties_phone": "", "properties_recent_conversion_date": null, "properties_recent_conversion_date_timestamp_latest_value_72856da1": null, "properties_recent_conversion_event_name": null, "properties_recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "properties_recent_deal_amount": 60000, "properties_recent_deal_close_date": "2023-04-04T14:59:45.103000+00:00", "properties_state": "CA", "properties_timezone": "", "properties_total_money_raised": null, "properties_total_revenue": 60000, "properties_twitterbio": null, "properties_twitterfollowers": null, "properties_twitterhandle": "AirbyteHQ", "properties_type": null, "properties_web_technologies": "slack;segment;google_tag_manager;cloud_flare;google_analytics;intercom;lever;google_apps", "properties_website": "dataline.io", "properties_zip": ""}, "emitted_at": 1708012762428} +{"stream": "companies", "data": {"id": "5000787595", "properties": {"about_us": null, "address": "2261 Market Street", "address2": null, "annualrevenue": 10000000, "city": "San Francisco", "closedate": null, "closedate_timestamp_earliest_value_a2a17e6e": null, "country": "United States", "createdate": "2020-12-11T01:28:27.673000+00:00", "custom_company_property": null, "days_to_close": null, "description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "domain": "Daxtarity.com", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "facebook_company_page": null, "facebookfans": null, "first_contact_createdate": null, "first_contact_createdate_timestamp_earliest_value_78b50eea": null, "first_conversion_date": null, "first_conversion_date_timestamp_earliest_value_61f58f2c": null, "first_conversion_event_name": null, "first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "first_deal_created_date": null, "founded_year": "2020", "googleplus_page": null, "hs_additional_domains": null, "hs_all_accessible_team_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_first_timestamp": null, "hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "hs_analytics_latest_source": "", "hs_analytics_latest_source_data_1": "", "hs_analytics_latest_source_data_2": "", "hs_analytics_latest_source_timestamp": null, "hs_analytics_num_page_views": null, "hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "hs_analytics_num_visits": null, "hs_analytics_num_visits_cardinality_sum_53d952a6": null, "hs_analytics_source": "", "hs_analytics_source_data_1": "", "hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "hs_analytics_source_data_2": "", "hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "hs_annual_revenue_currency_code": "USD", "hs_avatar_filemanager_key": null, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_date_entered_customer": null, "hs_date_entered_evangelist": null, "hs_date_entered_lead": null, "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": null, "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": null, "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": null, "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_ideal_customer_profile": null, "hs_is_target_account": null, "hs_last_booked_meeting_date": null, "hs_last_logged_call_date": null, "hs_last_open_task_date": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": "2024-01-31T23:50:34.138000+00:00", "hs_latest_createdate_of_active_subscriptions": null, "hs_latest_meeting_activity": null, "hs_lead_status": null, "hs_merged_object_ids": null, "hs_num_blockers": 0, "hs_num_child_companies": 0, "hs_num_contacts_with_buying_roles": 0, "hs_num_decision_makers": 0, "hs_num_open_deals": 0, "hs_object_id": 5000787595, "hs_object_source": "CONTACTS", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "CRM_UI", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_parent_company_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": null, "hs_predictivecontactscore_v2": null, "hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_target_account": null, "hs_target_account_probability": 0.4076234698295593, "hs_target_account_recommendation_snooze_time": null, "hs_target_account_recommendation_state": null, "hs_time_in_customer": null, "hs_time_in_evangelist": null, "hs_time_in_lead": null, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": null, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": null, "hs_total_deal_value": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2020-12-11T01:28:27.673000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "hubspotscore": null, "industry": null, "is_public": false, "lifecyclestage": null, "linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "name": "Daxtarity", "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_contacts": 0, "num_associated_deals": null, "num_contacted_notes": null, "num_conversion_events": null, "num_conversion_events_cardinality_sum_d095f14b": null, "num_notes": null, "numberofemployees": 50, "phone": "+1 415-307-4864", "recent_conversion_date": null, "recent_conversion_date_timestamp_latest_value_72856da1": null, "recent_conversion_event_name": null, "recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "recent_deal_amount": null, "recent_deal_close_date": null, "state": "CA", "timezone": "", "total_money_raised": "31200000", "total_revenue": null, "twitterbio": null, "twitterfollowers": null, "twitterhandle": "AirbyteHQ", "type": null, "web_technologies": "slack;google_tag_manager;greenhouse;google_analytics;intercom;piwik;google_apps;hubspot;facebook_advertiser", "website": "Daxtarity.com", "zip": "94114"}, "createdAt": "2020-12-11T01:28:27.673Z", "updatedAt": "2024-01-31T23:50:34.138Z", "archived": false, "properties_about_us": null, "properties_address": "2261 Market Street", "properties_address2": null, "properties_annualrevenue": 10000000, "properties_city": "San Francisco", "properties_closedate": null, "properties_closedate_timestamp_earliest_value_a2a17e6e": null, "properties_country": "United States", "properties_createdate": "2020-12-11T01:28:27.673000+00:00", "properties_custom_company_property": null, "properties_days_to_close": null, "properties_description": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_domain": "Daxtarity.com", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_facebook_company_page": null, "properties_facebookfans": null, "properties_first_contact_createdate": null, "properties_first_contact_createdate_timestamp_earliest_value_78b50eea": null, "properties_first_conversion_date": null, "properties_first_conversion_date_timestamp_earliest_value_61f58f2c": null, "properties_first_conversion_event_name": null, "properties_first_conversion_event_name_timestamp_earliest_value_68ddae0a": null, "properties_first_deal_created_date": null, "properties_founded_year": "2020", "properties_googleplus_page": null, "properties_hs_additional_domains": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_first_timestamp": null, "properties_hs_analytics_first_timestamp_timestamp_earliest_value_11e3a63a": null, "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_touch_converting_campaign_timestamp_earliest_value_4757fe10": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_first_visit_timestamp_timestamp_earliest_value_accc17ae": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_timestamp_timestamp_latest_value_4e16365a": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_touch_converting_campaign_timestamp_latest_value_81a64e30": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_last_visit_timestamp_timestamp_latest_value_999a0fce": null, "properties_hs_analytics_latest_source": "", "properties_hs_analytics_latest_source_data_1": "", "properties_hs_analytics_latest_source_data_2": "", "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_num_page_views": null, "properties_hs_analytics_num_page_views_cardinality_sum_e46e85b0": null, "properties_hs_analytics_num_visits": null, "properties_hs_analytics_num_visits_cardinality_sum_53d952a6": null, "properties_hs_analytics_source": "", "properties_hs_analytics_source_data_1": "", "properties_hs_analytics_source_data_1_timestamp_earliest_value_9b2f1fa1": null, "properties_hs_analytics_source_data_2": "", "properties_hs_analytics_source_data_2_timestamp_earliest_value_9b2f9400": null, "properties_hs_analytics_source_timestamp_earliest_value_25a3a52c": null, "properties_hs_annual_revenue_currency_code": "USD", "properties_hs_avatar_filemanager_key": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_date_entered_customer": null, "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": null, "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": null, "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": null, "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": null, "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_ideal_customer_profile": null, "properties_hs_is_target_account": null, "properties_hs_last_booked_meeting_date": null, "properties_hs_last_logged_call_date": null, "properties_hs_last_open_task_date": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": "2024-01-31T23:50:34.138000+00:00", "properties_hs_latest_createdate_of_active_subscriptions": null, "properties_hs_latest_meeting_activity": null, "properties_hs_lead_status": null, "properties_hs_merged_object_ids": null, "properties_hs_num_blockers": 0, "properties_hs_num_child_companies": 0, "properties_hs_num_contacts_with_buying_roles": 0, "properties_hs_num_decision_makers": 0, "properties_hs_num_open_deals": 0, "properties_hs_object_id": 5000787595, "properties_hs_object_source": "CONTACTS", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "CRM_UI", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_parent_company_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": null, "properties_hs_predictivecontactscore_v2": null, "properties_hs_predictivecontactscore_v2_next_max_max_d4e58c1e": null, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_target_account": null, "properties_hs_target_account_probability": 0.4076234698295593, "properties_hs_target_account_recommendation_snooze_time": null, "properties_hs_target_account_recommendation_state": null, "properties_hs_time_in_customer": null, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": null, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": null, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": null, "properties_hs_total_deal_value": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2020-12-11T01:28:27.673000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": null, "properties_is_public": false, "properties_lifecyclestage": null, "properties_linkedin_company_page": "https://www.linkedin.com/company/airbytehq", "properties_linkedinbio": "Airbyte is an open-source data integration platform to build ELT pipelines. Consolidate your data in your data warehouses, lakes and databases.", "properties_name": "Daxtarity", "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_associated_deals": null, "properties_num_contacted_notes": null, "properties_num_conversion_events": null, "properties_num_conversion_events_cardinality_sum_d095f14b": null, "properties_num_notes": null, "properties_numberofemployees": 50, "properties_phone": "+1 415-307-4864", "properties_recent_conversion_date": null, "properties_recent_conversion_date_timestamp_latest_value_72856da1": null, "properties_recent_conversion_event_name": null, "properties_recent_conversion_event_name_timestamp_latest_value_66c820bf": null, "properties_recent_deal_amount": null, "properties_recent_deal_close_date": null, "properties_state": "CA", "properties_timezone": "", "properties_total_money_raised": "31200000", "properties_total_revenue": null, "properties_twitterbio": null, "properties_twitterfollowers": null, "properties_twitterhandle": "AirbyteHQ", "properties_type": null, "properties_web_technologies": "slack;google_tag_manager;greenhouse;google_analytics;intercom;piwik;google_apps;hubspot;facebook_advertiser", "properties_website": "Daxtarity.com", "properties_zip": "94114"}, "emitted_at": 1708012762430} {"stream": "contact_lists", "data": {"portalId": 8727216, "listId": 1, "createdAt": 1610634707370, "updatedAt": 1610634721116, "name": "tweeters", "listType": "DYNAMIC", "authorId": 0, "filters": [], "metaData": {"size": 0, "lastSizeChangeAt": 1625270400000, "processing": "DONE", "lastProcessingStateChangeAt": 1610634721950, "error": "", "listReferencesCount": null, "parentFolderId": null}, "archived": false, "teamIds": [], "ilsFilterBranch": "{\"filterBranchOperator\":\"OR\",\"filters\":[],\"filterBranches\":[{\"filterBranchOperator\":\"AND\",\"filters\":[{\"filterType\":\"PROPERTY\",\"property\":\"twitterhandle\",\"operation\":{\"propertyType\":\"string\",\"operator\":\"IS_EQUAL_TO\",\"value\":\"@hubspot\",\"defaultValue\":null,\"includeObjectsWithNoValueSet\":false,\"operationType\":\"string\",\"operatorName\":\"IS_EQUAL_TO\"},\"frameworkFilterId\":null}],\"filterBranches\":[],\"filterBranchType\":\"AND\"}],\"filterBranchType\":\"OR\"}", "readOnly": false, "dynamic": true, "internal": false, "limitExempt": false, "metaData_size": 0, "metaData_lastSizeChangeAt": 1625270400000, "metaData_processing": "DONE", "metaData_lastProcessingStateChangeAt": 1610634721950, "metaData_error": "", "metaData_listReferencesCount": null, "metaData_parentFolderId": null}, "emitted_at": 1697714189110} {"stream": "contact_lists", "data": {"portalId": 8727216, "listId": 2, "createdAt": 1610634770432, "updatedAt": 1610634780637, "name": "tweeters 1", "listType": "DYNAMIC", "authorId": 0, "filters": [], "metaData": {"size": 0, "lastSizeChangeAt": 1625270400000, "processing": "DONE", "lastProcessingStateChangeAt": 1610634781147, "error": "", "listReferencesCount": null, "parentFolderId": null}, "archived": false, "teamIds": [], "ilsFilterBranch": "{\"filterBranchOperator\":\"OR\",\"filters\":[],\"filterBranches\":[{\"filterBranchOperator\":\"AND\",\"filters\":[{\"filterType\":\"PROPERTY\",\"property\":\"twitterhandle\",\"operation\":{\"propertyType\":\"string\",\"operator\":\"IS_EQUAL_TO\",\"value\":\"@hubspot\",\"defaultValue\":null,\"includeObjectsWithNoValueSet\":false,\"operationType\":\"string\",\"operatorName\":\"IS_EQUAL_TO\"},\"frameworkFilterId\":null}],\"filterBranches\":[],\"filterBranchType\":\"AND\"}],\"filterBranchType\":\"OR\"}", "readOnly": false, "dynamic": true, "internal": false, "limitExempt": false, "metaData_size": 0, "metaData_lastSizeChangeAt": 1625270400000, "metaData_processing": "DONE", "metaData_lastProcessingStateChangeAt": 1610634781147, "metaData_error": "", "metaData_listReferencesCount": null, "metaData_parentFolderId": null}, "emitted_at": 1697714189112} {"stream": "contact_lists", "data": {"portalId": 8727216, "listId": 3, "createdAt": 1610634774356, "updatedAt": 1610634787734, "name": "tweeters 2", "listType": "DYNAMIC", "authorId": 0, "filters": [], "metaData": {"size": 0, "lastSizeChangeAt": 1625270400000, "processing": "DONE", "lastProcessingStateChangeAt": 1610634788528, "error": "", "listReferencesCount": null, "parentFolderId": null}, "archived": false, "teamIds": [], "ilsFilterBranch": "{\"filterBranchOperator\":\"OR\",\"filters\":[],\"filterBranches\":[{\"filterBranchOperator\":\"AND\",\"filters\":[{\"filterType\":\"PROPERTY\",\"property\":\"twitterhandle\",\"operation\":{\"propertyType\":\"string\",\"operator\":\"IS_EQUAL_TO\",\"value\":\"@hubspot\",\"defaultValue\":null,\"includeObjectsWithNoValueSet\":false,\"operationType\":\"string\",\"operatorName\":\"IS_EQUAL_TO\"},\"frameworkFilterId\":null}],\"filterBranches\":[],\"filterBranchType\":\"AND\"}],\"filterBranchType\":\"OR\"}", "readOnly": false, "dynamic": true, "internal": false, "limitExempt": false, "metaData_size": 0, "metaData_lastSizeChangeAt": 1625270400000, "metaData_processing": "DONE", "metaData_lastProcessingStateChangeAt": 1610634788528, "metaData_error": "", "metaData_listReferencesCount": null, "metaData_parentFolderId": null}, "emitted_at": 1697714189113} -{"stream": "contacts", "data": {"id": "151", "properties": {"address": null, "annualrevenue": null, "associatedcompanyid": 5000526215, "associatedcompanylastupdated": null, "city": null, "closedate": null, "company": null, "company_size": null, "country": null, "createdate": "2020-12-11T01:29:50.116000+00:00", "currentlyinworkflow": null, "date_of_birth": null, "days_to_close": null, "degree": null, "email": "shef@dne.io", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "fax": null, "field_of_study": null, "first_conversion_date": null, "first_conversion_event_name": null, "first_deal_created_date": null, "firstname": "she", "gender": null, "graduation_date": null, "hs_additional_emails": null, "hs_all_accessible_team_ids": null, "hs_all_contact_vids": "151", "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_average_page_views": 0, "hs_analytics_first_referrer": null, "hs_analytics_first_timestamp": "2020-12-11T01:29:50.116000+00:00", "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_url": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_last_referrer": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_url": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_num_event_completions": 0, "hs_analytics_num_page_views": 0, "hs_analytics_num_visits": 0, "hs_analytics_revenue": 0.0, "hs_analytics_source": "OFFLINE", "hs_analytics_source_data_1": "CONTACTS", "hs_analytics_source_data_2": "CRM_UI", "hs_avatar_filemanager_key": null, "hs_buying_role": null, "hs_calculated_form_submissions": null, "hs_calculated_merged_vids": null, "hs_calculated_mobile_number": null, "hs_calculated_phone_number": null, "hs_calculated_phone_number_area_code": null, "hs_calculated_phone_number_country_code": null, "hs_calculated_phone_number_region_code": null, "hs_clicked_linkedin_ad": null, "hs_content_membership_email": null, "hs_content_membership_email_confirmed": null, "hs_content_membership_follow_up_enqueued_at": null, "hs_content_membership_notes": null, "hs_content_membership_registered_at": null, "hs_content_membership_registration_domain_sent_to": null, "hs_content_membership_registration_email_sent_at": null, "hs_content_membership_status": null, "hs_conversations_visitor_email": null, "hs_count_is_unworked": 1, "hs_count_is_worked": 0, "hs_created_by_conversations": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_date_entered_customer": null, "hs_date_entered_evangelist": null, "hs_date_entered_lead": null, "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": null, "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": "2020-12-11T01:29:50.116000+00:00", "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": null, "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_document_last_revisited": null, "hs_email_bad_address": null, "hs_email_bounce": null, "hs_email_click": null, "hs_email_customer_quarantined_reason": null, "hs_email_delivered": null, "hs_email_domain": "dne.io", "hs_email_first_click_date": null, "hs_email_first_open_date": null, "hs_email_first_reply_date": null, "hs_email_first_send_date": null, "hs_email_hard_bounce_reason": null, "hs_email_hard_bounce_reason_enum": null, "hs_email_is_ineligible": null, "hs_email_last_click_date": null, "hs_email_last_email_name": null, "hs_email_last_open_date": null, "hs_email_last_reply_date": null, "hs_email_last_send_date": null, "hs_email_open": null, "hs_email_optout": null, "hs_email_optout_10798197": null, "hs_email_optout_11890603": null, "hs_email_optout_11890831": null, "hs_email_optout_23704464": null, "hs_email_optout_94692364": null, "hs_email_quarantined": null, "hs_email_quarantined_reason": null, "hs_email_recipient_fatigue_recovery_time": null, "hs_email_replied": null, "hs_email_sends_since_last_engagement": null, "hs_emailconfirmationstatus": null, "hs_facebook_ad_clicked": null, "hs_facebook_click_id": null, "hs_feedback_last_nps_follow_up": null, "hs_feedback_last_nps_rating": null, "hs_feedback_last_survey_date": null, "hs_feedback_show_nps_web_survey": null, "hs_first_engagement_object_id": null, "hs_first_outreach_date": null, "hs_first_subscription_create_date": null, "hs_google_click_id": null, "hs_has_active_subscription": null, "hs_ip_timezone": null, "hs_is_contact": true, "hs_is_unworked": true, "hs_language": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": null, "hs_latest_disqualified_lead_date": null, "hs_latest_meeting_activity": null, "hs_latest_open_lead_date": null, "hs_latest_qualified_lead_date": null, "hs_latest_sequence_ended_date": null, "hs_latest_sequence_enrolled": null, "hs_latest_sequence_enrolled_date": null, "hs_latest_sequence_finished_date": null, "hs_latest_sequence_unenrolled_date": null, "hs_latest_source": "OFFLINE", "hs_latest_source_data_1": "CONTACTS", "hs_latest_source_data_2": "CRM_UI", "hs_latest_source_timestamp": "2020-12-11T01:29:50.153000+00:00", "hs_latest_subscription_create_date": null, "hs_lead_status": null, "hs_legal_basis": null, "hs_lifecyclestage_customer_date": null, "hs_lifecyclestage_evangelist_date": null, "hs_lifecyclestage_lead_date": null, "hs_lifecyclestage_marketingqualifiedlead_date": null, "hs_lifecyclestage_opportunity_date": null, "hs_lifecyclestage_other_date": null, "hs_lifecyclestage_salesqualifiedlead_date": null, "hs_lifecyclestage_subscriber_date": "2020-12-11T01:29:50.116000+00:00", "hs_linkedin_ad_clicked": null, "hs_marketable_reason_id": null, "hs_marketable_reason_type": null, "hs_marketable_status": "false", "hs_marketable_until_renewal": "false", "hs_merged_object_ids": null, "hs_object_id": 151, "hs_object_source": "CONTACTS", "hs_object_source_id": "CRM_UI", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_persona": null, "hs_pinned_engagement_id": null, "hs_pipeline": "contacts-lifecycle-pipeline", "hs_predictivecontactscore": null, "hs_predictivecontactscore_v2": 0.3, "hs_predictivecontactscorebucket": null, "hs_predictivescoringtier": "tier_3", "hs_read_only": null, "hs_sa_first_engagement_date": null, "hs_sa_first_engagement_descr": null, "hs_sa_first_engagement_object_type": null, "hs_sales_email_last_clicked": null, "hs_sales_email_last_opened": null, "hs_sales_email_last_replied": null, "hs_searchable_calculated_international_mobile_number": null, "hs_searchable_calculated_international_phone_number": null, "hs_searchable_calculated_mobile_number": null, "hs_searchable_calculated_phone_number": null, "hs_sequences_actively_enrolled_count": null, "hs_sequences_enrolled_count": null, "hs_sequences_is_enrolled": null, "hs_testpurge": null, "hs_testrollback": null, "hs_time_between_contact_creation_and_deal_close": null, "hs_time_between_contact_creation_and_deal_creation": null, "hs_time_in_customer": null, "hs_time_in_evangelist": null, "hs_time_in_lead": null, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": null, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": 98536670035, "hs_time_to_first_engagement": null, "hs_time_to_move_from_lead_to_customer": null, "hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "hs_time_to_move_from_opportunity_to_customer": null, "hs_time_to_move_from_salesqualifiedlead_to_customer": null, "hs_time_to_move_from_subscriber_to_customer": null, "hs_timezone": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_v2_cumulative_time_in_customer": null, "hs_v2_cumulative_time_in_evangelist": null, "hs_v2_cumulative_time_in_lead": null, "hs_v2_cumulative_time_in_marketingqualifiedlead": null, "hs_v2_cumulative_time_in_opportunity": null, "hs_v2_cumulative_time_in_other": null, "hs_v2_cumulative_time_in_salesqualifiedlead": null, "hs_v2_cumulative_time_in_subscriber": null, "hs_v2_date_entered_customer": null, "hs_v2_date_entered_evangelist": null, "hs_v2_date_entered_lead": null, "hs_v2_date_entered_marketingqualifiedlead": null, "hs_v2_date_entered_opportunity": null, "hs_v2_date_entered_other": null, "hs_v2_date_entered_salesqualifiedlead": null, "hs_v2_date_entered_subscriber": "2020-12-11T01:29:50.116000+00:00", "hs_v2_date_exited_customer": null, "hs_v2_date_exited_evangelist": null, "hs_v2_date_exited_lead": null, "hs_v2_date_exited_marketingqualifiedlead": null, "hs_v2_date_exited_opportunity": null, "hs_v2_date_exited_other": null, "hs_v2_date_exited_salesqualifiedlead": null, "hs_v2_date_exited_subscriber": null, "hs_v2_latest_time_in_customer": null, "hs_v2_latest_time_in_evangelist": null, "hs_v2_latest_time_in_lead": null, "hs_v2_latest_time_in_marketingqualifiedlead": null, "hs_v2_latest_time_in_opportunity": null, "hs_v2_latest_time_in_other": null, "hs_v2_latest_time_in_salesqualifiedlead": null, "hs_v2_latest_time_in_subscriber": null, "hs_was_imported": null, "hs_whatsapp_phone_number": null, "hubspot_owner_assigneddate": "2020-12-11T01:29:50.093000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "hubspotscore": null, "industry": null, "ip_city": null, "ip_country": null, "ip_country_code": null, "ip_latlon": null, "ip_state": null, "ip_state_code": null, "ip_zipcode": null, "job_function": null, "jobtitle": null, "lastmodifieddate": "2023-11-22T21:10:04.346000+00:00", "lastname": "nad", "lifecyclestage": "subscriber", "marital_status": null, "message": null, "military_status": null, "mobilephone": null, "my_custom_test_property": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_deals": null, "num_contacted_notes": null, "num_conversion_events": 0, "num_notes": null, "num_unique_conversion_events": 0, "numemployees": null, "phone": null, "recent_conversion_date": null, "recent_conversion_event_name": null, "recent_deal_amount": null, "recent_deal_close_date": null, "relationship_status": null, "salutation": null, "school": null, "seniority": null, "start_date": null, "state": null, "surveymonkeyeventlastupdated": null, "test": null, "total_revenue": null, "twitterhandle": null, "webinareventlastupdated": null, "website": null, "work_email": null, "zip": null}, "createdAt": "2020-12-11T01:29:50.116Z", "updatedAt": "2023-11-22T21:10:04.346Z", "archived": false, "companies": ["5000526215", "5000526215"], "properties_address": null, "properties_annualrevenue": null, "properties_associatedcompanyid": 5000526215, "properties_associatedcompanylastupdated": null, "properties_city": null, "properties_closedate": null, "properties_company": null, "properties_company_size": null, "properties_country": null, "properties_createdate": "2020-12-11T01:29:50.116000+00:00", "properties_currentlyinworkflow": null, "properties_date_of_birth": null, "properties_days_to_close": null, "properties_degree": null, "properties_email": "shef@dne.io", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_fax": null, "properties_field_of_study": null, "properties_first_conversion_date": null, "properties_first_conversion_event_name": null, "properties_first_deal_created_date": null, "properties_firstname": "she", "properties_gender": null, "properties_graduation_date": null, "properties_hs_additional_emails": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_contact_vids": "151", "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_average_page_views": 0, "properties_hs_analytics_first_referrer": null, "properties_hs_analytics_first_timestamp": "2020-12-11T01:29:50.116000+00:00", "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_url": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_last_referrer": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_url": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_num_event_completions": 0, "properties_hs_analytics_num_page_views": 0, "properties_hs_analytics_num_visits": 0, "properties_hs_analytics_revenue": 0.0, "properties_hs_analytics_source": "OFFLINE", "properties_hs_analytics_source_data_1": "CONTACTS", "properties_hs_analytics_source_data_2": "CRM_UI", "properties_hs_avatar_filemanager_key": null, "properties_hs_buying_role": null, "properties_hs_calculated_form_submissions": null, "properties_hs_calculated_merged_vids": null, "properties_hs_calculated_mobile_number": null, "properties_hs_calculated_phone_number": null, "properties_hs_calculated_phone_number_area_code": null, "properties_hs_calculated_phone_number_country_code": null, "properties_hs_calculated_phone_number_region_code": null, "properties_hs_clicked_linkedin_ad": null, "properties_hs_content_membership_email": null, "properties_hs_content_membership_email_confirmed": null, "properties_hs_content_membership_follow_up_enqueued_at": null, "properties_hs_content_membership_notes": null, "properties_hs_content_membership_registered_at": null, "properties_hs_content_membership_registration_domain_sent_to": null, "properties_hs_content_membership_registration_email_sent_at": null, "properties_hs_content_membership_status": null, "properties_hs_conversations_visitor_email": null, "properties_hs_count_is_unworked": 1, "properties_hs_count_is_worked": 0, "properties_hs_created_by_conversations": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_date_entered_customer": null, "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": null, "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": null, "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": "2020-12-11T01:29:50.116000+00:00", "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": null, "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_document_last_revisited": null, "properties_hs_email_bad_address": null, "properties_hs_email_bounce": null, "properties_hs_email_click": null, "properties_hs_email_customer_quarantined_reason": null, "properties_hs_email_delivered": null, "properties_hs_email_domain": "dne.io", "properties_hs_email_first_click_date": null, "properties_hs_email_first_open_date": null, "properties_hs_email_first_reply_date": null, "properties_hs_email_first_send_date": null, "properties_hs_email_hard_bounce_reason": null, "properties_hs_email_hard_bounce_reason_enum": null, "properties_hs_email_is_ineligible": null, "properties_hs_email_last_click_date": null, "properties_hs_email_last_email_name": null, "properties_hs_email_last_open_date": null, "properties_hs_email_last_reply_date": null, "properties_hs_email_last_send_date": null, "properties_hs_email_open": null, "properties_hs_email_optout": null, "properties_hs_email_optout_10798197": null, "properties_hs_email_optout_11890603": null, "properties_hs_email_optout_11890831": null, "properties_hs_email_optout_23704464": null, "properties_hs_email_optout_94692364": null, "properties_hs_email_quarantined": null, "properties_hs_email_quarantined_reason": null, "properties_hs_email_recipient_fatigue_recovery_time": null, "properties_hs_email_replied": null, "properties_hs_email_sends_since_last_engagement": null, "properties_hs_emailconfirmationstatus": null, "properties_hs_facebook_ad_clicked": null, "properties_hs_facebook_click_id": null, "properties_hs_feedback_last_nps_follow_up": null, "properties_hs_feedback_last_nps_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_feedback_show_nps_web_survey": null, "properties_hs_first_engagement_object_id": null, "properties_hs_first_outreach_date": null, "properties_hs_first_subscription_create_date": null, "properties_hs_google_click_id": null, "properties_hs_has_active_subscription": null, "properties_hs_ip_timezone": null, "properties_hs_is_contact": true, "properties_hs_is_unworked": true, "properties_hs_language": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": null, "properties_hs_latest_disqualified_lead_date": null, "properties_hs_latest_meeting_activity": null, "properties_hs_latest_open_lead_date": null, "properties_hs_latest_qualified_lead_date": null, "properties_hs_latest_sequence_ended_date": null, "properties_hs_latest_sequence_enrolled": null, "properties_hs_latest_sequence_enrolled_date": null, "properties_hs_latest_sequence_finished_date": null, "properties_hs_latest_sequence_unenrolled_date": null, "properties_hs_latest_source": "OFFLINE", "properties_hs_latest_source_data_1": "CONTACTS", "properties_hs_latest_source_data_2": "CRM_UI", "properties_hs_latest_source_timestamp": "2020-12-11T01:29:50.153000+00:00", "properties_hs_latest_subscription_create_date": null, "properties_hs_lead_status": null, "properties_hs_legal_basis": null, "properties_hs_lifecyclestage_customer_date": null, "properties_hs_lifecyclestage_evangelist_date": null, "properties_hs_lifecyclestage_lead_date": null, "properties_hs_lifecyclestage_marketingqualifiedlead_date": null, "properties_hs_lifecyclestage_opportunity_date": null, "properties_hs_lifecyclestage_other_date": null, "properties_hs_lifecyclestage_salesqualifiedlead_date": null, "properties_hs_lifecyclestage_subscriber_date": "2020-12-11T01:29:50.116000+00:00", "properties_hs_linkedin_ad_clicked": null, "properties_hs_marketable_reason_id": null, "properties_hs_marketable_reason_type": null, "properties_hs_marketable_status": "false", "properties_hs_marketable_until_renewal": "false", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 151, "properties_hs_object_source": "CONTACTS", "properties_hs_object_source_id": "CRM_UI", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_persona": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "contacts-lifecycle-pipeline", "properties_hs_predictivecontactscore": null, "properties_hs_predictivecontactscore_v2": 0.3, "properties_hs_predictivecontactscorebucket": null, "properties_hs_predictivescoringtier": "tier_3", "properties_hs_read_only": null, "properties_hs_sa_first_engagement_date": null, "properties_hs_sa_first_engagement_descr": null, "properties_hs_sa_first_engagement_object_type": null, "properties_hs_sales_email_last_clicked": null, "properties_hs_sales_email_last_opened": null, "properties_hs_sales_email_last_replied": null, "properties_hs_searchable_calculated_international_mobile_number": null, "properties_hs_searchable_calculated_international_phone_number": null, "properties_hs_searchable_calculated_mobile_number": null, "properties_hs_searchable_calculated_phone_number": null, "properties_hs_sequences_actively_enrolled_count": null, "properties_hs_sequences_enrolled_count": null, "properties_hs_sequences_is_enrolled": null, "properties_hs_testpurge": null, "properties_hs_testrollback": null, "properties_hs_time_between_contact_creation_and_deal_close": null, "properties_hs_time_between_contact_creation_and_deal_creation": null, "properties_hs_time_in_customer": null, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": null, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": null, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": 98536670035, "properties_hs_time_to_first_engagement": null, "properties_hs_time_to_move_from_lead_to_customer": null, "properties_hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_opportunity_to_customer": null, "properties_hs_time_to_move_from_salesqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_subscriber_to_customer": null, "properties_hs_timezone": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_v2_cumulative_time_in_customer": null, "properties_hs_v2_cumulative_time_in_evangelist": null, "properties_hs_v2_cumulative_time_in_lead": null, "properties_hs_v2_cumulative_time_in_marketingqualifiedlead": null, "properties_hs_v2_cumulative_time_in_opportunity": null, "properties_hs_v2_cumulative_time_in_other": null, "properties_hs_v2_cumulative_time_in_salesqualifiedlead": null, "properties_hs_v2_cumulative_time_in_subscriber": null, "properties_hs_v2_date_entered_customer": null, "properties_hs_v2_date_entered_evangelist": null, "properties_hs_v2_date_entered_lead": null, "properties_hs_v2_date_entered_marketingqualifiedlead": null, "properties_hs_v2_date_entered_opportunity": null, "properties_hs_v2_date_entered_other": null, "properties_hs_v2_date_entered_salesqualifiedlead": null, "properties_hs_v2_date_entered_subscriber": "2020-12-11T01:29:50.116000+00:00", "properties_hs_v2_date_exited_customer": null, "properties_hs_v2_date_exited_evangelist": null, "properties_hs_v2_date_exited_lead": null, "properties_hs_v2_date_exited_marketingqualifiedlead": null, "properties_hs_v2_date_exited_opportunity": null, "properties_hs_v2_date_exited_other": null, "properties_hs_v2_date_exited_salesqualifiedlead": null, "properties_hs_v2_date_exited_subscriber": null, "properties_hs_v2_latest_time_in_customer": null, "properties_hs_v2_latest_time_in_evangelist": null, "properties_hs_v2_latest_time_in_lead": null, "properties_hs_v2_latest_time_in_marketingqualifiedlead": null, "properties_hs_v2_latest_time_in_opportunity": null, "properties_hs_v2_latest_time_in_other": null, "properties_hs_v2_latest_time_in_salesqualifiedlead": null, "properties_hs_v2_latest_time_in_subscriber": null, "properties_hs_was_imported": null, "properties_hs_whatsapp_phone_number": null, "properties_hubspot_owner_assigneddate": "2020-12-11T01:29:50.093000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": null, "properties_ip_city": null, "properties_ip_country": null, "properties_ip_country_code": null, "properties_ip_latlon": null, "properties_ip_state": null, "properties_ip_state_code": null, "properties_ip_zipcode": null, "properties_job_function": null, "properties_jobtitle": null, "properties_lastmodifieddate": "2023-11-22T21:10:04.346000+00:00", "properties_lastname": "nad", "properties_lifecyclestage": "subscriber", "properties_marital_status": null, "properties_message": null, "properties_military_status": null, "properties_mobilephone": null, "properties_my_custom_test_property": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_deals": null, "properties_num_contacted_notes": null, "properties_num_conversion_events": 0, "properties_num_notes": null, "properties_num_unique_conversion_events": 0, "properties_numemployees": null, "properties_phone": null, "properties_recent_conversion_date": null, "properties_recent_conversion_event_name": null, "properties_recent_deal_amount": null, "properties_recent_deal_close_date": null, "properties_relationship_status": null, "properties_salutation": null, "properties_school": null, "properties_seniority": null, "properties_start_date": null, "properties_state": null, "properties_surveymonkeyeventlastupdated": null, "properties_test": null, "properties_total_revenue": null, "properties_twitterhandle": null, "properties_webinareventlastupdated": null, "properties_website": null, "properties_work_email": null, "properties_zip": null}, "emitted_at": 1706186860294} -{"stream": "contacts", "data": {"id": "251", "properties": {"address": "25000000 First Street", "annualrevenue": null, "associatedcompanyid": 5170561229, "associatedcompanylastupdated": null, "city": "Cambridge", "closedate": null, "company": "HubSpot", "company_size": null, "country": "USA", "createdate": "2021-02-22T14:05:09.944000+00:00", "currentlyinworkflow": null, "date_of_birth": null, "days_to_close": null, "degree": null, "email": "testingdsapis@hubspot.com", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "fax": null, "field_of_study": null, "first_conversion_date": null, "first_conversion_event_name": null, "first_deal_created_date": null, "firstname": "Test User 5001", "gender": null, "graduation_date": null, "hs_additional_emails": null, "hs_all_accessible_team_ids": null, "hs_all_contact_vids": "251", "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_analytics_average_page_views": 0, "hs_analytics_first_referrer": null, "hs_analytics_first_timestamp": "2021-02-22T14:05:09.944000+00:00", "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_url": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_last_referrer": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_url": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_num_event_completions": 0, "hs_analytics_num_page_views": 0, "hs_analytics_num_visits": 0, "hs_analytics_revenue": 0.0, "hs_analytics_source": "OFFLINE", "hs_analytics_source_data_1": "API", "hs_analytics_source_data_2": null, "hs_avatar_filemanager_key": null, "hs_buying_role": null, "hs_calculated_form_submissions": null, "hs_calculated_merged_vids": null, "hs_calculated_mobile_number": null, "hs_calculated_phone_number": null, "hs_calculated_phone_number_area_code": null, "hs_calculated_phone_number_country_code": null, "hs_calculated_phone_number_region_code": null, "hs_clicked_linkedin_ad": null, "hs_content_membership_email": null, "hs_content_membership_email_confirmed": null, "hs_content_membership_follow_up_enqueued_at": null, "hs_content_membership_notes": null, "hs_content_membership_registered_at": null, "hs_content_membership_registration_domain_sent_to": null, "hs_content_membership_registration_email_sent_at": null, "hs_content_membership_status": null, "hs_conversations_visitor_email": null, "hs_count_is_unworked": null, "hs_count_is_worked": null, "hs_created_by_conversations": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_date_entered_customer": null, "hs_date_entered_evangelist": null, "hs_date_entered_lead": null, "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": null, "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": "2021-02-22T14:05:09.944000+00:00", "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": null, "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_document_last_revisited": null, "hs_email_bad_address": null, "hs_email_bounce": null, "hs_email_click": null, "hs_email_customer_quarantined_reason": null, "hs_email_delivered": null, "hs_email_domain": "hubspot.com", "hs_email_first_click_date": null, "hs_email_first_open_date": null, "hs_email_first_reply_date": null, "hs_email_first_send_date": null, "hs_email_hard_bounce_reason": null, "hs_email_hard_bounce_reason_enum": null, "hs_email_is_ineligible": null, "hs_email_last_click_date": null, "hs_email_last_email_name": null, "hs_email_last_open_date": null, "hs_email_last_reply_date": null, "hs_email_last_send_date": null, "hs_email_open": null, "hs_email_optout": null, "hs_email_optout_10798197": null, "hs_email_optout_11890603": null, "hs_email_optout_11890831": null, "hs_email_optout_23704464": null, "hs_email_optout_94692364": null, "hs_email_quarantined": null, "hs_email_quarantined_reason": null, "hs_email_recipient_fatigue_recovery_time": null, "hs_email_replied": null, "hs_email_sends_since_last_engagement": null, "hs_emailconfirmationstatus": null, "hs_facebook_ad_clicked": null, "hs_facebook_click_id": null, "hs_feedback_last_nps_follow_up": null, "hs_feedback_last_nps_rating": null, "hs_feedback_last_survey_date": null, "hs_feedback_show_nps_web_survey": null, "hs_first_engagement_object_id": null, "hs_first_outreach_date": null, "hs_first_subscription_create_date": null, "hs_google_click_id": null, "hs_has_active_subscription": null, "hs_ip_timezone": null, "hs_is_contact": true, "hs_is_unworked": true, "hs_language": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": null, "hs_latest_disqualified_lead_date": null, "hs_latest_meeting_activity": null, "hs_latest_open_lead_date": null, "hs_latest_qualified_lead_date": null, "hs_latest_sequence_ended_date": null, "hs_latest_sequence_enrolled": null, "hs_latest_sequence_enrolled_date": null, "hs_latest_sequence_finished_date": null, "hs_latest_sequence_unenrolled_date": null, "hs_latest_source": "OFFLINE", "hs_latest_source_data_1": "API", "hs_latest_source_data_2": null, "hs_latest_source_timestamp": "2021-02-22T14:05:10.036000+00:00", "hs_latest_subscription_create_date": null, "hs_lead_status": null, "hs_legal_basis": null, "hs_lifecyclestage_customer_date": null, "hs_lifecyclestage_evangelist_date": null, "hs_lifecyclestage_lead_date": null, "hs_lifecyclestage_marketingqualifiedlead_date": null, "hs_lifecyclestage_opportunity_date": null, "hs_lifecyclestage_other_date": null, "hs_lifecyclestage_salesqualifiedlead_date": null, "hs_lifecyclestage_subscriber_date": "2021-02-22T14:05:09.944000+00:00", "hs_linkedin_ad_clicked": null, "hs_marketable_reason_id": null, "hs_marketable_reason_type": null, "hs_marketable_status": "false", "hs_marketable_until_renewal": "false", "hs_merged_object_ids": null, "hs_object_id": 251, "hs_object_source": "API", "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_persona": null, "hs_pinned_engagement_id": null, "hs_pipeline": "contacts-lifecycle-pipeline", "hs_predictivecontactscore": null, "hs_predictivecontactscore_v2": 0.29, "hs_predictivecontactscorebucket": null, "hs_predictivescoringtier": "tier_4", "hs_read_only": null, "hs_sa_first_engagement_date": null, "hs_sa_first_engagement_descr": null, "hs_sa_first_engagement_object_type": null, "hs_sales_email_last_clicked": null, "hs_sales_email_last_opened": null, "hs_sales_email_last_replied": null, "hs_searchable_calculated_international_mobile_number": null, "hs_searchable_calculated_international_phone_number": null, "hs_searchable_calculated_mobile_number": null, "hs_searchable_calculated_phone_number": "5551222323", "hs_sequences_actively_enrolled_count": null, "hs_sequences_enrolled_count": null, "hs_sequences_is_enrolled": null, "hs_testpurge": null, "hs_testrollback": null, "hs_time_between_contact_creation_and_deal_close": null, "hs_time_between_contact_creation_and_deal_creation": null, "hs_time_in_customer": null, "hs_time_in_evangelist": null, "hs_time_in_lead": null, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": null, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": 92184150208, "hs_time_to_first_engagement": null, "hs_time_to_move_from_lead_to_customer": null, "hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "hs_time_to_move_from_opportunity_to_customer": null, "hs_time_to_move_from_salesqualifiedlead_to_customer": null, "hs_time_to_move_from_subscriber_to_customer": null, "hs_timezone": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_v2_cumulative_time_in_customer": null, "hs_v2_cumulative_time_in_evangelist": null, "hs_v2_cumulative_time_in_lead": null, "hs_v2_cumulative_time_in_marketingqualifiedlead": null, "hs_v2_cumulative_time_in_opportunity": null, "hs_v2_cumulative_time_in_other": null, "hs_v2_cumulative_time_in_salesqualifiedlead": null, "hs_v2_cumulative_time_in_subscriber": null, "hs_v2_date_entered_customer": null, "hs_v2_date_entered_evangelist": null, "hs_v2_date_entered_lead": null, "hs_v2_date_entered_marketingqualifiedlead": null, "hs_v2_date_entered_opportunity": null, "hs_v2_date_entered_other": null, "hs_v2_date_entered_salesqualifiedlead": null, "hs_v2_date_entered_subscriber": "2021-02-22T14:05:09.944000+00:00", "hs_v2_date_exited_customer": null, "hs_v2_date_exited_evangelist": null, "hs_v2_date_exited_lead": null, "hs_v2_date_exited_marketingqualifiedlead": null, "hs_v2_date_exited_opportunity": null, "hs_v2_date_exited_other": null, "hs_v2_date_exited_salesqualifiedlead": null, "hs_v2_date_exited_subscriber": null, "hs_v2_latest_time_in_customer": null, "hs_v2_latest_time_in_evangelist": null, "hs_v2_latest_time_in_lead": null, "hs_v2_latest_time_in_marketingqualifiedlead": null, "hs_v2_latest_time_in_opportunity": null, "hs_v2_latest_time_in_other": null, "hs_v2_latest_time_in_salesqualifiedlead": null, "hs_v2_latest_time_in_subscriber": null, "hs_was_imported": null, "hs_whatsapp_phone_number": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "hubspotscore": null, "industry": null, "ip_city": null, "ip_country": null, "ip_country_code": null, "ip_latlon": null, "ip_state": null, "ip_state_code": null, "ip_zipcode": null, "job_function": null, "jobtitle": null, "lastmodifieddate": "2023-03-21T19:29:13.036000+00:00", "lastname": "Test Lastname 5001", "lifecyclestage": "subscriber", "marital_status": null, "message": null, "military_status": null, "mobilephone": null, "my_custom_test_property": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_deals": null, "num_contacted_notes": null, "num_conversion_events": 0, "num_notes": null, "num_unique_conversion_events": 0, "numemployees": null, "phone": "555-122-2323", "recent_conversion_date": null, "recent_conversion_event_name": null, "recent_deal_amount": null, "recent_deal_close_date": null, "relationship_status": null, "salutation": null, "school": null, "seniority": null, "start_date": null, "state": "MA", "surveymonkeyeventlastupdated": null, "test": null, "total_revenue": null, "twitterhandle": null, "webinareventlastupdated": null, "website": "http://hubspot.com", "work_email": null, "zip": "02139"}, "createdAt": "2021-02-22T14:05:09.944Z", "updatedAt": "2023-03-21T19:29:13.036Z", "archived": false, "companies": ["5170561229", "5170561229"], "properties_address": "25000000 First Street", "properties_annualrevenue": null, "properties_associatedcompanyid": 5170561229, "properties_associatedcompanylastupdated": null, "properties_city": "Cambridge", "properties_closedate": null, "properties_company": "HubSpot", "properties_company_size": null, "properties_country": "USA", "properties_createdate": "2021-02-22T14:05:09.944000+00:00", "properties_currentlyinworkflow": null, "properties_date_of_birth": null, "properties_days_to_close": null, "properties_degree": null, "properties_email": "testingdsapis@hubspot.com", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_fax": null, "properties_field_of_study": null, "properties_first_conversion_date": null, "properties_first_conversion_event_name": null, "properties_first_deal_created_date": null, "properties_firstname": "Test User 5001", "properties_gender": null, "properties_graduation_date": null, "properties_hs_additional_emails": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_contact_vids": "251", "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_analytics_average_page_views": 0, "properties_hs_analytics_first_referrer": null, "properties_hs_analytics_first_timestamp": "2021-02-22T14:05:09.944000+00:00", "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_url": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_last_referrer": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_url": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_num_event_completions": 0, "properties_hs_analytics_num_page_views": 0, "properties_hs_analytics_num_visits": 0, "properties_hs_analytics_revenue": 0.0, "properties_hs_analytics_source": "OFFLINE", "properties_hs_analytics_source_data_1": "API", "properties_hs_analytics_source_data_2": null, "properties_hs_avatar_filemanager_key": null, "properties_hs_buying_role": null, "properties_hs_calculated_form_submissions": null, "properties_hs_calculated_merged_vids": null, "properties_hs_calculated_mobile_number": null, "properties_hs_calculated_phone_number": null, "properties_hs_calculated_phone_number_area_code": null, "properties_hs_calculated_phone_number_country_code": null, "properties_hs_calculated_phone_number_region_code": null, "properties_hs_clicked_linkedin_ad": null, "properties_hs_content_membership_email": null, "properties_hs_content_membership_email_confirmed": null, "properties_hs_content_membership_follow_up_enqueued_at": null, "properties_hs_content_membership_notes": null, "properties_hs_content_membership_registered_at": null, "properties_hs_content_membership_registration_domain_sent_to": null, "properties_hs_content_membership_registration_email_sent_at": null, "properties_hs_content_membership_status": null, "properties_hs_conversations_visitor_email": null, "properties_hs_count_is_unworked": null, "properties_hs_count_is_worked": null, "properties_hs_created_by_conversations": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_date_entered_customer": null, "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": null, "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": null, "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": "2021-02-22T14:05:09.944000+00:00", "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": null, "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_document_last_revisited": null, "properties_hs_email_bad_address": null, "properties_hs_email_bounce": null, "properties_hs_email_click": null, "properties_hs_email_customer_quarantined_reason": null, "properties_hs_email_delivered": null, "properties_hs_email_domain": "hubspot.com", "properties_hs_email_first_click_date": null, "properties_hs_email_first_open_date": null, "properties_hs_email_first_reply_date": null, "properties_hs_email_first_send_date": null, "properties_hs_email_hard_bounce_reason": null, "properties_hs_email_hard_bounce_reason_enum": null, "properties_hs_email_is_ineligible": null, "properties_hs_email_last_click_date": null, "properties_hs_email_last_email_name": null, "properties_hs_email_last_open_date": null, "properties_hs_email_last_reply_date": null, "properties_hs_email_last_send_date": null, "properties_hs_email_open": null, "properties_hs_email_optout": null, "properties_hs_email_optout_10798197": null, "properties_hs_email_optout_11890603": null, "properties_hs_email_optout_11890831": null, "properties_hs_email_optout_23704464": null, "properties_hs_email_optout_94692364": null, "properties_hs_email_quarantined": null, "properties_hs_email_quarantined_reason": null, "properties_hs_email_recipient_fatigue_recovery_time": null, "properties_hs_email_replied": null, "properties_hs_email_sends_since_last_engagement": null, "properties_hs_emailconfirmationstatus": null, "properties_hs_facebook_ad_clicked": null, "properties_hs_facebook_click_id": null, "properties_hs_feedback_last_nps_follow_up": null, "properties_hs_feedback_last_nps_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_feedback_show_nps_web_survey": null, "properties_hs_first_engagement_object_id": null, "properties_hs_first_outreach_date": null, "properties_hs_first_subscription_create_date": null, "properties_hs_google_click_id": null, "properties_hs_has_active_subscription": null, "properties_hs_ip_timezone": null, "properties_hs_is_contact": true, "properties_hs_is_unworked": true, "properties_hs_language": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": null, "properties_hs_latest_disqualified_lead_date": null, "properties_hs_latest_meeting_activity": null, "properties_hs_latest_open_lead_date": null, "properties_hs_latest_qualified_lead_date": null, "properties_hs_latest_sequence_ended_date": null, "properties_hs_latest_sequence_enrolled": null, "properties_hs_latest_sequence_enrolled_date": null, "properties_hs_latest_sequence_finished_date": null, "properties_hs_latest_sequence_unenrolled_date": null, "properties_hs_latest_source": "OFFLINE", "properties_hs_latest_source_data_1": "API", "properties_hs_latest_source_data_2": null, "properties_hs_latest_source_timestamp": "2021-02-22T14:05:10.036000+00:00", "properties_hs_latest_subscription_create_date": null, "properties_hs_lead_status": null, "properties_hs_legal_basis": null, "properties_hs_lifecyclestage_customer_date": null, "properties_hs_lifecyclestage_evangelist_date": null, "properties_hs_lifecyclestage_lead_date": null, "properties_hs_lifecyclestage_marketingqualifiedlead_date": null, "properties_hs_lifecyclestage_opportunity_date": null, "properties_hs_lifecyclestage_other_date": null, "properties_hs_lifecyclestage_salesqualifiedlead_date": null, "properties_hs_lifecyclestage_subscriber_date": "2021-02-22T14:05:09.944000+00:00", "properties_hs_linkedin_ad_clicked": null, "properties_hs_marketable_reason_id": null, "properties_hs_marketable_reason_type": null, "properties_hs_marketable_status": "false", "properties_hs_marketable_until_renewal": "false", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 251, "properties_hs_object_source": "API", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_persona": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "contacts-lifecycle-pipeline", "properties_hs_predictivecontactscore": null, "properties_hs_predictivecontactscore_v2": 0.29, "properties_hs_predictivecontactscorebucket": null, "properties_hs_predictivescoringtier": "tier_4", "properties_hs_read_only": null, "properties_hs_sa_first_engagement_date": null, "properties_hs_sa_first_engagement_descr": null, "properties_hs_sa_first_engagement_object_type": null, "properties_hs_sales_email_last_clicked": null, "properties_hs_sales_email_last_opened": null, "properties_hs_sales_email_last_replied": null, "properties_hs_searchable_calculated_international_mobile_number": null, "properties_hs_searchable_calculated_international_phone_number": null, "properties_hs_searchable_calculated_mobile_number": null, "properties_hs_searchable_calculated_phone_number": "5551222323", "properties_hs_sequences_actively_enrolled_count": null, "properties_hs_sequences_enrolled_count": null, "properties_hs_sequences_is_enrolled": null, "properties_hs_testpurge": null, "properties_hs_testrollback": null, "properties_hs_time_between_contact_creation_and_deal_close": null, "properties_hs_time_between_contact_creation_and_deal_creation": null, "properties_hs_time_in_customer": null, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": null, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": null, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": 92184150208, "properties_hs_time_to_first_engagement": null, "properties_hs_time_to_move_from_lead_to_customer": null, "properties_hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_opportunity_to_customer": null, "properties_hs_time_to_move_from_salesqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_subscriber_to_customer": null, "properties_hs_timezone": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_v2_cumulative_time_in_customer": null, "properties_hs_v2_cumulative_time_in_evangelist": null, "properties_hs_v2_cumulative_time_in_lead": null, "properties_hs_v2_cumulative_time_in_marketingqualifiedlead": null, "properties_hs_v2_cumulative_time_in_opportunity": null, "properties_hs_v2_cumulative_time_in_other": null, "properties_hs_v2_cumulative_time_in_salesqualifiedlead": null, "properties_hs_v2_cumulative_time_in_subscriber": null, "properties_hs_v2_date_entered_customer": null, "properties_hs_v2_date_entered_evangelist": null, "properties_hs_v2_date_entered_lead": null, "properties_hs_v2_date_entered_marketingqualifiedlead": null, "properties_hs_v2_date_entered_opportunity": null, "properties_hs_v2_date_entered_other": null, "properties_hs_v2_date_entered_salesqualifiedlead": null, "properties_hs_v2_date_entered_subscriber": "2021-02-22T14:05:09.944000+00:00", "properties_hs_v2_date_exited_customer": null, "properties_hs_v2_date_exited_evangelist": null, "properties_hs_v2_date_exited_lead": null, "properties_hs_v2_date_exited_marketingqualifiedlead": null, "properties_hs_v2_date_exited_opportunity": null, "properties_hs_v2_date_exited_other": null, "properties_hs_v2_date_exited_salesqualifiedlead": null, "properties_hs_v2_date_exited_subscriber": null, "properties_hs_v2_latest_time_in_customer": null, "properties_hs_v2_latest_time_in_evangelist": null, "properties_hs_v2_latest_time_in_lead": null, "properties_hs_v2_latest_time_in_marketingqualifiedlead": null, "properties_hs_v2_latest_time_in_opportunity": null, "properties_hs_v2_latest_time_in_other": null, "properties_hs_v2_latest_time_in_salesqualifiedlead": null, "properties_hs_v2_latest_time_in_subscriber": null, "properties_hs_was_imported": null, "properties_hs_whatsapp_phone_number": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": null, "properties_ip_city": null, "properties_ip_country": null, "properties_ip_country_code": null, "properties_ip_latlon": null, "properties_ip_state": null, "properties_ip_state_code": null, "properties_ip_zipcode": null, "properties_job_function": null, "properties_jobtitle": null, "properties_lastmodifieddate": "2023-03-21T19:29:13.036000+00:00", "properties_lastname": "Test Lastname 5001", "properties_lifecyclestage": "subscriber", "properties_marital_status": null, "properties_message": null, "properties_military_status": null, "properties_mobilephone": null, "properties_my_custom_test_property": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_deals": null, "properties_num_contacted_notes": null, "properties_num_conversion_events": 0, "properties_num_notes": null, "properties_num_unique_conversion_events": 0, "properties_numemployees": null, "properties_phone": "555-122-2323", "properties_recent_conversion_date": null, "properties_recent_conversion_event_name": null, "properties_recent_deal_amount": null, "properties_recent_deal_close_date": null, "properties_relationship_status": null, "properties_salutation": null, "properties_school": null, "properties_seniority": null, "properties_start_date": null, "properties_state": "MA", "properties_surveymonkeyeventlastupdated": null, "properties_test": null, "properties_total_revenue": null, "properties_twitterhandle": null, "properties_webinareventlastupdated": null, "properties_website": "http://hubspot.com", "properties_work_email": null, "properties_zip": "02139"}, "emitted_at": 1706186860299} -{"stream": "contacts", "data": {"id": "401", "properties": {"address": "25 First Street", "annualrevenue": null, "associatedcompanyid": null, "associatedcompanylastupdated": null, "city": "Cambridge", "closedate": null, "company": null, "company_size": null, "country": null, "createdate": "2021-02-23T20:10:36.191000+00:00", "currentlyinworkflow": null, "date_of_birth": null, "days_to_close": null, "degree": null, "email": "macmitch@hubspot.com", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "fax": null, "field_of_study": null, "first_conversion_date": null, "first_conversion_event_name": null, "first_deal_created_date": null, "firstname": "Mac", "gender": null, "graduation_date": null, "hs_additional_emails": null, "hs_all_accessible_team_ids": null, "hs_all_contact_vids": "401", "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_average_page_views": 0, "hs_analytics_first_referrer": null, "hs_analytics_first_timestamp": "2021-02-23T20:10:36.181000+00:00", "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_url": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_last_referrer": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_url": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_num_event_completions": 0, "hs_analytics_num_page_views": 0, "hs_analytics_num_visits": 0, "hs_analytics_revenue": 0.0, "hs_analytics_source": "OFFLINE", "hs_analytics_source_data_1": "IMPORT", "hs_analytics_source_data_2": "13256565", "hs_avatar_filemanager_key": null, "hs_buying_role": null, "hs_calculated_form_submissions": null, "hs_calculated_merged_vids": null, "hs_calculated_mobile_number": null, "hs_calculated_phone_number": "+18884827768", "hs_calculated_phone_number_area_code": null, "hs_calculated_phone_number_country_code": "US", "hs_calculated_phone_number_region_code": null, "hs_clicked_linkedin_ad": null, "hs_content_membership_email": null, "hs_content_membership_email_confirmed": null, "hs_content_membership_follow_up_enqueued_at": null, "hs_content_membership_notes": null, "hs_content_membership_registered_at": null, "hs_content_membership_registration_domain_sent_to": null, "hs_content_membership_registration_email_sent_at": null, "hs_content_membership_status": null, "hs_conversations_visitor_email": null, "hs_count_is_unworked": 1, "hs_count_is_worked": 0, "hs_created_by_conversations": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_date_entered_customer": null, "hs_date_entered_evangelist": null, "hs_date_entered_lead": "2021-02-23T20:10:36.181000+00:00", "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": null, "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": null, "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": null, "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_document_last_revisited": null, "hs_email_bad_address": null, "hs_email_bounce": null, "hs_email_click": null, "hs_email_customer_quarantined_reason": null, "hs_email_delivered": null, "hs_email_domain": "hubspot.com", "hs_email_first_click_date": null, "hs_email_first_open_date": null, "hs_email_first_reply_date": null, "hs_email_first_send_date": null, "hs_email_hard_bounce_reason": null, "hs_email_hard_bounce_reason_enum": "OTHER", "hs_email_is_ineligible": null, "hs_email_last_click_date": null, "hs_email_last_email_name": null, "hs_email_last_open_date": null, "hs_email_last_reply_date": null, "hs_email_last_send_date": null, "hs_email_open": null, "hs_email_optout": null, "hs_email_optout_10798197": null, "hs_email_optout_11890603": null, "hs_email_optout_11890831": null, "hs_email_optout_23704464": null, "hs_email_optout_94692364": null, "hs_email_quarantined": null, "hs_email_quarantined_reason": null, "hs_email_recipient_fatigue_recovery_time": null, "hs_email_replied": null, "hs_email_sends_since_last_engagement": null, "hs_emailconfirmationstatus": null, "hs_facebook_ad_clicked": null, "hs_facebook_click_id": null, "hs_feedback_last_nps_follow_up": null, "hs_feedback_last_nps_rating": null, "hs_feedback_last_survey_date": null, "hs_feedback_show_nps_web_survey": null, "hs_first_engagement_object_id": null, "hs_first_outreach_date": null, "hs_first_subscription_create_date": null, "hs_google_click_id": null, "hs_has_active_subscription": null, "hs_ip_timezone": null, "hs_is_contact": true, "hs_is_unworked": true, "hs_language": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": null, "hs_latest_disqualified_lead_date": null, "hs_latest_meeting_activity": null, "hs_latest_open_lead_date": null, "hs_latest_qualified_lead_date": null, "hs_latest_sequence_ended_date": null, "hs_latest_sequence_enrolled": null, "hs_latest_sequence_enrolled_date": null, "hs_latest_sequence_finished_date": null, "hs_latest_sequence_unenrolled_date": null, "hs_latest_source": "OFFLINE", "hs_latest_source_data_1": "IMPORT", "hs_latest_source_data_2": "13256565", "hs_latest_source_timestamp": "2021-02-23T20:10:36.210000+00:00", "hs_latest_subscription_create_date": null, "hs_lead_status": null, "hs_legal_basis": null, "hs_lifecyclestage_customer_date": null, "hs_lifecyclestage_evangelist_date": null, "hs_lifecyclestage_lead_date": "2021-02-23T20:10:36.181000+00:00", "hs_lifecyclestage_marketingqualifiedlead_date": null, "hs_lifecyclestage_opportunity_date": null, "hs_lifecyclestage_other_date": null, "hs_lifecyclestage_salesqualifiedlead_date": null, "hs_lifecyclestage_subscriber_date": null, "hs_linkedin_ad_clicked": null, "hs_marketable_reason_id": null, "hs_marketable_reason_type": null, "hs_marketable_status": "false", "hs_marketable_until_renewal": "false", "hs_merged_object_ids": null, "hs_object_id": 401, "hs_object_source": "IMPORT", "hs_object_source_id": "13256565", "hs_object_source_label": "IMPORT", "hs_object_source_user_id": null, "hs_persona": null, "hs_pinned_engagement_id": null, "hs_pipeline": "contacts-lifecycle-pipeline", "hs_predictivecontactscore": null, "hs_predictivecontactscore_v2": 0.29, "hs_predictivecontactscorebucket": null, "hs_predictivescoringtier": "tier_4", "hs_read_only": null, "hs_sa_first_engagement_date": null, "hs_sa_first_engagement_descr": null, "hs_sa_first_engagement_object_type": null, "hs_sales_email_last_clicked": null, "hs_sales_email_last_opened": null, "hs_sales_email_last_replied": null, "hs_searchable_calculated_international_mobile_number": null, "hs_searchable_calculated_international_phone_number": null, "hs_searchable_calculated_mobile_number": null, "hs_searchable_calculated_phone_number": "8884827768", "hs_sequences_actively_enrolled_count": null, "hs_sequences_enrolled_count": null, "hs_sequences_is_enrolled": null, "hs_testpurge": null, "hs_testrollback": null, "hs_time_between_contact_creation_and_deal_close": null, "hs_time_between_contact_creation_and_deal_creation": null, "hs_time_in_customer": null, "hs_time_in_evangelist": null, "hs_time_in_lead": 92075823971, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": null, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": null, "hs_time_to_first_engagement": null, "hs_time_to_move_from_lead_to_customer": null, "hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "hs_time_to_move_from_opportunity_to_customer": null, "hs_time_to_move_from_salesqualifiedlead_to_customer": null, "hs_time_to_move_from_subscriber_to_customer": null, "hs_timezone": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_v2_cumulative_time_in_customer": null, "hs_v2_cumulative_time_in_evangelist": null, "hs_v2_cumulative_time_in_lead": null, "hs_v2_cumulative_time_in_marketingqualifiedlead": null, "hs_v2_cumulative_time_in_opportunity": null, "hs_v2_cumulative_time_in_other": null, "hs_v2_cumulative_time_in_salesqualifiedlead": null, "hs_v2_cumulative_time_in_subscriber": null, "hs_v2_date_entered_customer": null, "hs_v2_date_entered_evangelist": null, "hs_v2_date_entered_lead": "2021-02-23T20:10:36.181000+00:00", "hs_v2_date_entered_marketingqualifiedlead": null, "hs_v2_date_entered_opportunity": null, "hs_v2_date_entered_other": null, "hs_v2_date_entered_salesqualifiedlead": null, "hs_v2_date_entered_subscriber": null, "hs_v2_date_exited_customer": null, "hs_v2_date_exited_evangelist": null, "hs_v2_date_exited_lead": null, "hs_v2_date_exited_marketingqualifiedlead": null, "hs_v2_date_exited_opportunity": null, "hs_v2_date_exited_other": null, "hs_v2_date_exited_salesqualifiedlead": null, "hs_v2_date_exited_subscriber": null, "hs_v2_latest_time_in_customer": null, "hs_v2_latest_time_in_evangelist": null, "hs_v2_latest_time_in_lead": null, "hs_v2_latest_time_in_marketingqualifiedlead": null, "hs_v2_latest_time_in_opportunity": null, "hs_v2_latest_time_in_other": null, "hs_v2_latest_time_in_salesqualifiedlead": null, "hs_v2_latest_time_in_subscriber": null, "hs_was_imported": true, "hs_whatsapp_phone_number": null, "hubspot_owner_assigneddate": "2021-05-21T10:20:30.963000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "hubspotscore": null, "industry": null, "ip_city": null, "ip_country": null, "ip_country_code": null, "ip_latlon": null, "ip_state": null, "ip_state_code": null, "ip_zipcode": null, "job_function": null, "jobtitle": null, "lastmodifieddate": "2023-03-21T19:31:00.563000+00:00", "lastname": "Mitchell", "lifecyclestage": "lead", "marital_status": null, "message": null, "military_status": null, "mobilephone": null, "my_custom_test_property": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_deals": null, "num_contacted_notes": null, "num_conversion_events": 0, "num_notes": null, "num_unique_conversion_events": 0, "numemployees": null, "phone": "1(888) 482-7768", "recent_conversion_date": null, "recent_conversion_event_name": null, "recent_deal_amount": null, "recent_deal_close_date": null, "relationship_status": null, "salutation": null, "school": null, "seniority": null, "start_date": null, "state": "MA", "surveymonkeyeventlastupdated": null, "test": null, "total_revenue": null, "twitterhandle": null, "webinareventlastupdated": null, "website": null, "work_email": null, "zip": "21430"}, "createdAt": "2021-02-23T20:10:36.191Z", "updatedAt": "2023-03-21T19:31:00.563Z", "archived": false, "properties_address": "25 First Street", "properties_annualrevenue": null, "properties_associatedcompanyid": null, "properties_associatedcompanylastupdated": null, "properties_city": "Cambridge", "properties_closedate": null, "properties_company": null, "properties_company_size": null, "properties_country": null, "properties_createdate": "2021-02-23T20:10:36.191000+00:00", "properties_currentlyinworkflow": null, "properties_date_of_birth": null, "properties_days_to_close": null, "properties_degree": null, "properties_email": "macmitch@hubspot.com", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_fax": null, "properties_field_of_study": null, "properties_first_conversion_date": null, "properties_first_conversion_event_name": null, "properties_first_deal_created_date": null, "properties_firstname": "Mac", "properties_gender": null, "properties_graduation_date": null, "properties_hs_additional_emails": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_contact_vids": "401", "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_average_page_views": 0, "properties_hs_analytics_first_referrer": null, "properties_hs_analytics_first_timestamp": "2021-02-23T20:10:36.181000+00:00", "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_url": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_last_referrer": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_url": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_num_event_completions": 0, "properties_hs_analytics_num_page_views": 0, "properties_hs_analytics_num_visits": 0, "properties_hs_analytics_revenue": 0.0, "properties_hs_analytics_source": "OFFLINE", "properties_hs_analytics_source_data_1": "IMPORT", "properties_hs_analytics_source_data_2": "13256565", "properties_hs_avatar_filemanager_key": null, "properties_hs_buying_role": null, "properties_hs_calculated_form_submissions": null, "properties_hs_calculated_merged_vids": null, "properties_hs_calculated_mobile_number": null, "properties_hs_calculated_phone_number": "+18884827768", "properties_hs_calculated_phone_number_area_code": null, "properties_hs_calculated_phone_number_country_code": "US", "properties_hs_calculated_phone_number_region_code": null, "properties_hs_clicked_linkedin_ad": null, "properties_hs_content_membership_email": null, "properties_hs_content_membership_email_confirmed": null, "properties_hs_content_membership_follow_up_enqueued_at": null, "properties_hs_content_membership_notes": null, "properties_hs_content_membership_registered_at": null, "properties_hs_content_membership_registration_domain_sent_to": null, "properties_hs_content_membership_registration_email_sent_at": null, "properties_hs_content_membership_status": null, "properties_hs_conversations_visitor_email": null, "properties_hs_count_is_unworked": 1, "properties_hs_count_is_worked": 0, "properties_hs_created_by_conversations": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_date_entered_customer": null, "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": "2021-02-23T20:10:36.181000+00:00", "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": null, "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": null, "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": null, "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_document_last_revisited": null, "properties_hs_email_bad_address": null, "properties_hs_email_bounce": null, "properties_hs_email_click": null, "properties_hs_email_customer_quarantined_reason": null, "properties_hs_email_delivered": null, "properties_hs_email_domain": "hubspot.com", "properties_hs_email_first_click_date": null, "properties_hs_email_first_open_date": null, "properties_hs_email_first_reply_date": null, "properties_hs_email_first_send_date": null, "properties_hs_email_hard_bounce_reason": null, "properties_hs_email_hard_bounce_reason_enum": "OTHER", "properties_hs_email_is_ineligible": null, "properties_hs_email_last_click_date": null, "properties_hs_email_last_email_name": null, "properties_hs_email_last_open_date": null, "properties_hs_email_last_reply_date": null, "properties_hs_email_last_send_date": null, "properties_hs_email_open": null, "properties_hs_email_optout": null, "properties_hs_email_optout_10798197": null, "properties_hs_email_optout_11890603": null, "properties_hs_email_optout_11890831": null, "properties_hs_email_optout_23704464": null, "properties_hs_email_optout_94692364": null, "properties_hs_email_quarantined": null, "properties_hs_email_quarantined_reason": null, "properties_hs_email_recipient_fatigue_recovery_time": null, "properties_hs_email_replied": null, "properties_hs_email_sends_since_last_engagement": null, "properties_hs_emailconfirmationstatus": null, "properties_hs_facebook_ad_clicked": null, "properties_hs_facebook_click_id": null, "properties_hs_feedback_last_nps_follow_up": null, "properties_hs_feedback_last_nps_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_feedback_show_nps_web_survey": null, "properties_hs_first_engagement_object_id": null, "properties_hs_first_outreach_date": null, "properties_hs_first_subscription_create_date": null, "properties_hs_google_click_id": null, "properties_hs_has_active_subscription": null, "properties_hs_ip_timezone": null, "properties_hs_is_contact": true, "properties_hs_is_unworked": true, "properties_hs_language": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": null, "properties_hs_latest_disqualified_lead_date": null, "properties_hs_latest_meeting_activity": null, "properties_hs_latest_open_lead_date": null, "properties_hs_latest_qualified_lead_date": null, "properties_hs_latest_sequence_ended_date": null, "properties_hs_latest_sequence_enrolled": null, "properties_hs_latest_sequence_enrolled_date": null, "properties_hs_latest_sequence_finished_date": null, "properties_hs_latest_sequence_unenrolled_date": null, "properties_hs_latest_source": "OFFLINE", "properties_hs_latest_source_data_1": "IMPORT", "properties_hs_latest_source_data_2": "13256565", "properties_hs_latest_source_timestamp": "2021-02-23T20:10:36.210000+00:00", "properties_hs_latest_subscription_create_date": null, "properties_hs_lead_status": null, "properties_hs_legal_basis": null, "properties_hs_lifecyclestage_customer_date": null, "properties_hs_lifecyclestage_evangelist_date": null, "properties_hs_lifecyclestage_lead_date": "2021-02-23T20:10:36.181000+00:00", "properties_hs_lifecyclestage_marketingqualifiedlead_date": null, "properties_hs_lifecyclestage_opportunity_date": null, "properties_hs_lifecyclestage_other_date": null, "properties_hs_lifecyclestage_salesqualifiedlead_date": null, "properties_hs_lifecyclestage_subscriber_date": null, "properties_hs_linkedin_ad_clicked": null, "properties_hs_marketable_reason_id": null, "properties_hs_marketable_reason_type": null, "properties_hs_marketable_status": "false", "properties_hs_marketable_until_renewal": "false", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 401, "properties_hs_object_source": "IMPORT", "properties_hs_object_source_id": "13256565", "properties_hs_object_source_label": "IMPORT", "properties_hs_object_source_user_id": null, "properties_hs_persona": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "contacts-lifecycle-pipeline", "properties_hs_predictivecontactscore": null, "properties_hs_predictivecontactscore_v2": 0.29, "properties_hs_predictivecontactscorebucket": null, "properties_hs_predictivescoringtier": "tier_4", "properties_hs_read_only": null, "properties_hs_sa_first_engagement_date": null, "properties_hs_sa_first_engagement_descr": null, "properties_hs_sa_first_engagement_object_type": null, "properties_hs_sales_email_last_clicked": null, "properties_hs_sales_email_last_opened": null, "properties_hs_sales_email_last_replied": null, "properties_hs_searchable_calculated_international_mobile_number": null, "properties_hs_searchable_calculated_international_phone_number": null, "properties_hs_searchable_calculated_mobile_number": null, "properties_hs_searchable_calculated_phone_number": "8884827768", "properties_hs_sequences_actively_enrolled_count": null, "properties_hs_sequences_enrolled_count": null, "properties_hs_sequences_is_enrolled": null, "properties_hs_testpurge": null, "properties_hs_testrollback": null, "properties_hs_time_between_contact_creation_and_deal_close": null, "properties_hs_time_between_contact_creation_and_deal_creation": null, "properties_hs_time_in_customer": null, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": 92075823971, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": null, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": null, "properties_hs_time_to_first_engagement": null, "properties_hs_time_to_move_from_lead_to_customer": null, "properties_hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_opportunity_to_customer": null, "properties_hs_time_to_move_from_salesqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_subscriber_to_customer": null, "properties_hs_timezone": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_v2_cumulative_time_in_customer": null, "properties_hs_v2_cumulative_time_in_evangelist": null, "properties_hs_v2_cumulative_time_in_lead": null, "properties_hs_v2_cumulative_time_in_marketingqualifiedlead": null, "properties_hs_v2_cumulative_time_in_opportunity": null, "properties_hs_v2_cumulative_time_in_other": null, "properties_hs_v2_cumulative_time_in_salesqualifiedlead": null, "properties_hs_v2_cumulative_time_in_subscriber": null, "properties_hs_v2_date_entered_customer": null, "properties_hs_v2_date_entered_evangelist": null, "properties_hs_v2_date_entered_lead": "2021-02-23T20:10:36.181000+00:00", "properties_hs_v2_date_entered_marketingqualifiedlead": null, "properties_hs_v2_date_entered_opportunity": null, "properties_hs_v2_date_entered_other": null, "properties_hs_v2_date_entered_salesqualifiedlead": null, "properties_hs_v2_date_entered_subscriber": null, "properties_hs_v2_date_exited_customer": null, "properties_hs_v2_date_exited_evangelist": null, "properties_hs_v2_date_exited_lead": null, "properties_hs_v2_date_exited_marketingqualifiedlead": null, "properties_hs_v2_date_exited_opportunity": null, "properties_hs_v2_date_exited_other": null, "properties_hs_v2_date_exited_salesqualifiedlead": null, "properties_hs_v2_date_exited_subscriber": null, "properties_hs_v2_latest_time_in_customer": null, "properties_hs_v2_latest_time_in_evangelist": null, "properties_hs_v2_latest_time_in_lead": null, "properties_hs_v2_latest_time_in_marketingqualifiedlead": null, "properties_hs_v2_latest_time_in_opportunity": null, "properties_hs_v2_latest_time_in_other": null, "properties_hs_v2_latest_time_in_salesqualifiedlead": null, "properties_hs_v2_latest_time_in_subscriber": null, "properties_hs_was_imported": true, "properties_hs_whatsapp_phone_number": null, "properties_hubspot_owner_assigneddate": "2021-05-21T10:20:30.963000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": null, "properties_ip_city": null, "properties_ip_country": null, "properties_ip_country_code": null, "properties_ip_latlon": null, "properties_ip_state": null, "properties_ip_state_code": null, "properties_ip_zipcode": null, "properties_job_function": null, "properties_jobtitle": null, "properties_lastmodifieddate": "2023-03-21T19:31:00.563000+00:00", "properties_lastname": "Mitchell", "properties_lifecyclestage": "lead", "properties_marital_status": null, "properties_message": null, "properties_military_status": null, "properties_mobilephone": null, "properties_my_custom_test_property": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_deals": null, "properties_num_contacted_notes": null, "properties_num_conversion_events": 0, "properties_num_notes": null, "properties_num_unique_conversion_events": 0, "properties_numemployees": null, "properties_phone": "1(888) 482-7768", "properties_recent_conversion_date": null, "properties_recent_conversion_event_name": null, "properties_recent_deal_amount": null, "properties_recent_deal_close_date": null, "properties_relationship_status": null, "properties_salutation": null, "properties_school": null, "properties_seniority": null, "properties_start_date": null, "properties_state": "MA", "properties_surveymonkeyeventlastupdated": null, "properties_test": null, "properties_total_revenue": null, "properties_twitterhandle": null, "properties_webinareventlastupdated": null, "properties_website": null, "properties_work_email": null, "properties_zip": "21430"}, "emitted_at": 1706186860302} +{"stream": "contacts", "data": {"id": "151", "properties": {"address": null, "annualrevenue": null, "associatedcompanyid": 5000526215, "associatedcompanylastupdated": null, "city": null, "closedate": null, "company": null, "company_size": null, "country": null, "createdate": "2020-12-11T01:29:50.116000+00:00", "currentlyinworkflow": null, "date_of_birth": null, "days_to_close": null, "degree": null, "email": "shef@dne.io", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "fax": null, "field_of_study": null, "first_conversion_date": null, "first_conversion_event_name": null, "first_deal_created_date": null, "firstname": "she", "gender": null, "graduation_date": null, "hs_additional_emails": null, "hs_all_accessible_team_ids": null, "hs_all_contact_vids": "151", "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_average_page_views": 0, "hs_analytics_first_referrer": null, "hs_analytics_first_timestamp": "2020-12-11T01:29:50.116000+00:00", "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_url": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_last_referrer": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_url": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_num_event_completions": 0, "hs_analytics_num_page_views": 0, "hs_analytics_num_visits": 0, "hs_analytics_revenue": 0.0, "hs_analytics_source": "OFFLINE", "hs_analytics_source_data_1": "CONTACTS", "hs_analytics_source_data_2": "CRM_UI", "hs_avatar_filemanager_key": null, "hs_buying_role": null, "hs_calculated_form_submissions": null, "hs_calculated_merged_vids": null, "hs_calculated_mobile_number": null, "hs_calculated_phone_number": null, "hs_calculated_phone_number_area_code": null, "hs_calculated_phone_number_country_code": null, "hs_calculated_phone_number_region_code": null, "hs_clicked_linkedin_ad": null, "hs_content_membership_email": null, "hs_content_membership_email_confirmed": null, "hs_content_membership_follow_up_enqueued_at": null, "hs_content_membership_notes": null, "hs_content_membership_registered_at": null, "hs_content_membership_registration_domain_sent_to": null, "hs_content_membership_registration_email_sent_at": null, "hs_content_membership_status": null, "hs_conversations_visitor_email": null, "hs_count_is_unworked": 1, "hs_count_is_worked": 0, "hs_created_by_conversations": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_date_entered_customer": null, "hs_date_entered_evangelist": null, "hs_date_entered_lead": null, "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": null, "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": "2020-12-11T01:29:50.116000+00:00", "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": null, "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_document_last_revisited": null, "hs_email_bad_address": null, "hs_email_bounce": null, "hs_email_click": null, "hs_email_customer_quarantined_reason": null, "hs_email_delivered": null, "hs_email_domain": "dne.io", "hs_email_first_click_date": null, "hs_email_first_open_date": null, "hs_email_first_reply_date": null, "hs_email_first_send_date": null, "hs_email_hard_bounce_reason": null, "hs_email_hard_bounce_reason_enum": null, "hs_email_is_ineligible": null, "hs_email_last_click_date": null, "hs_email_last_email_name": null, "hs_email_last_open_date": null, "hs_email_last_reply_date": null, "hs_email_last_send_date": null, "hs_email_open": null, "hs_email_optout": null, "hs_email_optout_10798197": null, "hs_email_optout_11890603": null, "hs_email_optout_11890831": null, "hs_email_optout_23704464": null, "hs_email_optout_94692364": null, "hs_email_quarantined": null, "hs_email_quarantined_reason": null, "hs_email_recipient_fatigue_recovery_time": null, "hs_email_replied": null, "hs_email_sends_since_last_engagement": null, "hs_emailconfirmationstatus": null, "hs_facebook_ad_clicked": null, "hs_facebook_click_id": null, "hs_feedback_last_nps_follow_up": null, "hs_feedback_last_nps_rating": null, "hs_feedback_last_survey_date": null, "hs_feedback_show_nps_web_survey": null, "hs_first_engagement_object_id": null, "hs_first_outreach_date": null, "hs_first_subscription_create_date": null, "hs_google_click_id": null, "hs_has_active_subscription": null, "hs_ip_timezone": null, "hs_is_contact": true, "hs_is_unworked": true, "hs_language": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": null, "hs_latest_disqualified_lead_date": null, "hs_latest_meeting_activity": null, "hs_latest_open_lead_date": null, "hs_latest_qualified_lead_date": null, "hs_latest_sequence_ended_date": null, "hs_latest_sequence_enrolled": null, "hs_latest_sequence_enrolled_date": null, "hs_latest_sequence_finished_date": null, "hs_latest_sequence_unenrolled_date": null, "hs_latest_source": "OFFLINE", "hs_latest_source_data_1": "CONTACTS", "hs_latest_source_data_2": "CRM_UI", "hs_latest_source_timestamp": "2020-12-11T01:29:50.153000+00:00", "hs_latest_subscription_create_date": null, "hs_lead_status": null, "hs_legal_basis": null, "hs_lifecyclestage_customer_date": null, "hs_lifecyclestage_evangelist_date": null, "hs_lifecyclestage_lead_date": null, "hs_lifecyclestage_marketingqualifiedlead_date": null, "hs_lifecyclestage_opportunity_date": null, "hs_lifecyclestage_other_date": null, "hs_lifecyclestage_salesqualifiedlead_date": null, "hs_lifecyclestage_subscriber_date": "2020-12-11T01:29:50.116000+00:00", "hs_linkedin_ad_clicked": null, "hs_marketable_reason_id": null, "hs_marketable_reason_type": null, "hs_marketable_status": "false", "hs_marketable_until_renewal": "false", "hs_merged_object_ids": null, "hs_object_id": 151, "hs_object_source": "CONTACTS", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "CRM_UI", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_persona": null, "hs_pinned_engagement_id": null, "hs_pipeline": "contacts-lifecycle-pipeline", "hs_predictivecontactscore": null, "hs_predictivecontactscore_v2": 0.3, "hs_predictivecontactscorebucket": null, "hs_predictivescoringtier": "tier_3", "hs_read_only": null, "hs_sa_first_engagement_date": null, "hs_sa_first_engagement_descr": null, "hs_sa_first_engagement_object_type": null, "hs_sales_email_last_clicked": null, "hs_sales_email_last_opened": null, "hs_sales_email_last_replied": null, "hs_searchable_calculated_international_mobile_number": null, "hs_searchable_calculated_international_phone_number": null, "hs_searchable_calculated_mobile_number": null, "hs_searchable_calculated_phone_number": null, "hs_sequences_actively_enrolled_count": null, "hs_sequences_enrolled_count": null, "hs_sequences_is_enrolled": null, "hs_testpurge": null, "hs_testrollback": null, "hs_time_between_contact_creation_and_deal_close": null, "hs_time_between_contact_creation_and_deal_creation": null, "hs_time_in_customer": null, "hs_time_in_evangelist": null, "hs_time_in_lead": null, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": null, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": 100362752053, "hs_time_to_first_engagement": null, "hs_time_to_move_from_lead_to_customer": null, "hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "hs_time_to_move_from_opportunity_to_customer": null, "hs_time_to_move_from_salesqualifiedlead_to_customer": null, "hs_time_to_move_from_subscriber_to_customer": null, "hs_timezone": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_v2_cumulative_time_in_customer": null, "hs_v2_cumulative_time_in_evangelist": null, "hs_v2_cumulative_time_in_lead": null, "hs_v2_cumulative_time_in_marketingqualifiedlead": null, "hs_v2_cumulative_time_in_opportunity": null, "hs_v2_cumulative_time_in_other": null, "hs_v2_cumulative_time_in_salesqualifiedlead": null, "hs_v2_cumulative_time_in_subscriber": null, "hs_v2_date_entered_customer": null, "hs_v2_date_entered_evangelist": null, "hs_v2_date_entered_lead": null, "hs_v2_date_entered_marketingqualifiedlead": null, "hs_v2_date_entered_opportunity": null, "hs_v2_date_entered_other": null, "hs_v2_date_entered_salesqualifiedlead": null, "hs_v2_date_entered_subscriber": "2020-12-11T01:29:50.116000+00:00", "hs_v2_date_exited_customer": null, "hs_v2_date_exited_evangelist": null, "hs_v2_date_exited_lead": null, "hs_v2_date_exited_marketingqualifiedlead": null, "hs_v2_date_exited_opportunity": null, "hs_v2_date_exited_other": null, "hs_v2_date_exited_salesqualifiedlead": null, "hs_v2_date_exited_subscriber": null, "hs_v2_latest_time_in_customer": null, "hs_v2_latest_time_in_evangelist": null, "hs_v2_latest_time_in_lead": null, "hs_v2_latest_time_in_marketingqualifiedlead": null, "hs_v2_latest_time_in_opportunity": null, "hs_v2_latest_time_in_other": null, "hs_v2_latest_time_in_salesqualifiedlead": null, "hs_v2_latest_time_in_subscriber": null, "hs_was_imported": null, "hs_whatsapp_phone_number": null, "hubspot_owner_assigneddate": "2020-12-11T01:29:50.093000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "hubspotscore": null, "industry": null, "ip_city": null, "ip_country": null, "ip_country_code": null, "ip_latlon": null, "ip_state": null, "ip_state_code": null, "ip_zipcode": null, "job_function": null, "jobtitle": null, "lastmodifieddate": "2023-11-22T21:10:04.346000+00:00", "lastname": "nad", "lifecyclestage": "subscriber", "marital_status": null, "message": null, "military_status": null, "mobilephone": null, "my_custom_test_property": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_deals": null, "num_contacted_notes": null, "num_conversion_events": 0, "num_notes": null, "num_unique_conversion_events": 0, "numemployees": null, "phone": null, "recent_conversion_date": null, "recent_conversion_event_name": null, "recent_deal_amount": null, "recent_deal_close_date": null, "relationship_status": null, "salutation": null, "school": null, "seniority": null, "start_date": null, "state": null, "surveymonkeyeventlastupdated": null, "test": null, "total_revenue": null, "twitterhandle": null, "webinareventlastupdated": null, "website": null, "work_email": null, "zip": null}, "createdAt": "2020-12-11T01:29:50.116Z", "updatedAt": "2023-11-22T21:10:04.346Z", "archived": false, "companies": ["5000526215", "5000526215"], "properties_address": null, "properties_annualrevenue": null, "properties_associatedcompanyid": 5000526215, "properties_associatedcompanylastupdated": null, "properties_city": null, "properties_closedate": null, "properties_company": null, "properties_company_size": null, "properties_country": null, "properties_createdate": "2020-12-11T01:29:50.116000+00:00", "properties_currentlyinworkflow": null, "properties_date_of_birth": null, "properties_days_to_close": null, "properties_degree": null, "properties_email": "shef@dne.io", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_fax": null, "properties_field_of_study": null, "properties_first_conversion_date": null, "properties_first_conversion_event_name": null, "properties_first_deal_created_date": null, "properties_firstname": "she", "properties_gender": null, "properties_graduation_date": null, "properties_hs_additional_emails": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_contact_vids": "151", "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_average_page_views": 0, "properties_hs_analytics_first_referrer": null, "properties_hs_analytics_first_timestamp": "2020-12-11T01:29:50.116000+00:00", "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_url": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_last_referrer": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_url": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_num_event_completions": 0, "properties_hs_analytics_num_page_views": 0, "properties_hs_analytics_num_visits": 0, "properties_hs_analytics_revenue": 0.0, "properties_hs_analytics_source": "OFFLINE", "properties_hs_analytics_source_data_1": "CONTACTS", "properties_hs_analytics_source_data_2": "CRM_UI", "properties_hs_avatar_filemanager_key": null, "properties_hs_buying_role": null, "properties_hs_calculated_form_submissions": null, "properties_hs_calculated_merged_vids": null, "properties_hs_calculated_mobile_number": null, "properties_hs_calculated_phone_number": null, "properties_hs_calculated_phone_number_area_code": null, "properties_hs_calculated_phone_number_country_code": null, "properties_hs_calculated_phone_number_region_code": null, "properties_hs_clicked_linkedin_ad": null, "properties_hs_content_membership_email": null, "properties_hs_content_membership_email_confirmed": null, "properties_hs_content_membership_follow_up_enqueued_at": null, "properties_hs_content_membership_notes": null, "properties_hs_content_membership_registered_at": null, "properties_hs_content_membership_registration_domain_sent_to": null, "properties_hs_content_membership_registration_email_sent_at": null, "properties_hs_content_membership_status": null, "properties_hs_conversations_visitor_email": null, "properties_hs_count_is_unworked": 1, "properties_hs_count_is_worked": 0, "properties_hs_created_by_conversations": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_date_entered_customer": null, "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": null, "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": null, "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": "2020-12-11T01:29:50.116000+00:00", "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": null, "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_document_last_revisited": null, "properties_hs_email_bad_address": null, "properties_hs_email_bounce": null, "properties_hs_email_click": null, "properties_hs_email_customer_quarantined_reason": null, "properties_hs_email_delivered": null, "properties_hs_email_domain": "dne.io", "properties_hs_email_first_click_date": null, "properties_hs_email_first_open_date": null, "properties_hs_email_first_reply_date": null, "properties_hs_email_first_send_date": null, "properties_hs_email_hard_bounce_reason": null, "properties_hs_email_hard_bounce_reason_enum": null, "properties_hs_email_is_ineligible": null, "properties_hs_email_last_click_date": null, "properties_hs_email_last_email_name": null, "properties_hs_email_last_open_date": null, "properties_hs_email_last_reply_date": null, "properties_hs_email_last_send_date": null, "properties_hs_email_open": null, "properties_hs_email_optout": null, "properties_hs_email_optout_10798197": null, "properties_hs_email_optout_11890603": null, "properties_hs_email_optout_11890831": null, "properties_hs_email_optout_23704464": null, "properties_hs_email_optout_94692364": null, "properties_hs_email_quarantined": null, "properties_hs_email_quarantined_reason": null, "properties_hs_email_recipient_fatigue_recovery_time": null, "properties_hs_email_replied": null, "properties_hs_email_sends_since_last_engagement": null, "properties_hs_emailconfirmationstatus": null, "properties_hs_facebook_ad_clicked": null, "properties_hs_facebook_click_id": null, "properties_hs_feedback_last_nps_follow_up": null, "properties_hs_feedback_last_nps_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_feedback_show_nps_web_survey": null, "properties_hs_first_engagement_object_id": null, "properties_hs_first_outreach_date": null, "properties_hs_first_subscription_create_date": null, "properties_hs_google_click_id": null, "properties_hs_has_active_subscription": null, "properties_hs_ip_timezone": null, "properties_hs_is_contact": true, "properties_hs_is_unworked": true, "properties_hs_language": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": null, "properties_hs_latest_disqualified_lead_date": null, "properties_hs_latest_meeting_activity": null, "properties_hs_latest_open_lead_date": null, "properties_hs_latest_qualified_lead_date": null, "properties_hs_latest_sequence_ended_date": null, "properties_hs_latest_sequence_enrolled": null, "properties_hs_latest_sequence_enrolled_date": null, "properties_hs_latest_sequence_finished_date": null, "properties_hs_latest_sequence_unenrolled_date": null, "properties_hs_latest_source": "OFFLINE", "properties_hs_latest_source_data_1": "CONTACTS", "properties_hs_latest_source_data_2": "CRM_UI", "properties_hs_latest_source_timestamp": "2020-12-11T01:29:50.153000+00:00", "properties_hs_latest_subscription_create_date": null, "properties_hs_lead_status": null, "properties_hs_legal_basis": null, "properties_hs_lifecyclestage_customer_date": null, "properties_hs_lifecyclestage_evangelist_date": null, "properties_hs_lifecyclestage_lead_date": null, "properties_hs_lifecyclestage_marketingqualifiedlead_date": null, "properties_hs_lifecyclestage_opportunity_date": null, "properties_hs_lifecyclestage_other_date": null, "properties_hs_lifecyclestage_salesqualifiedlead_date": null, "properties_hs_lifecyclestage_subscriber_date": "2020-12-11T01:29:50.116000+00:00", "properties_hs_linkedin_ad_clicked": null, "properties_hs_marketable_reason_id": null, "properties_hs_marketable_reason_type": null, "properties_hs_marketable_status": "false", "properties_hs_marketable_until_renewal": "false", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 151, "properties_hs_object_source": "CONTACTS", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "CRM_UI", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_persona": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "contacts-lifecycle-pipeline", "properties_hs_predictivecontactscore": null, "properties_hs_predictivecontactscore_v2": 0.3, "properties_hs_predictivecontactscorebucket": null, "properties_hs_predictivescoringtier": "tier_3", "properties_hs_read_only": null, "properties_hs_sa_first_engagement_date": null, "properties_hs_sa_first_engagement_descr": null, "properties_hs_sa_first_engagement_object_type": null, "properties_hs_sales_email_last_clicked": null, "properties_hs_sales_email_last_opened": null, "properties_hs_sales_email_last_replied": null, "properties_hs_searchable_calculated_international_mobile_number": null, "properties_hs_searchable_calculated_international_phone_number": null, "properties_hs_searchable_calculated_mobile_number": null, "properties_hs_searchable_calculated_phone_number": null, "properties_hs_sequences_actively_enrolled_count": null, "properties_hs_sequences_enrolled_count": null, "properties_hs_sequences_is_enrolled": null, "properties_hs_testpurge": null, "properties_hs_testrollback": null, "properties_hs_time_between_contact_creation_and_deal_close": null, "properties_hs_time_between_contact_creation_and_deal_creation": null, "properties_hs_time_in_customer": null, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": null, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": null, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": 100362752053, "properties_hs_time_to_first_engagement": null, "properties_hs_time_to_move_from_lead_to_customer": null, "properties_hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_opportunity_to_customer": null, "properties_hs_time_to_move_from_salesqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_subscriber_to_customer": null, "properties_hs_timezone": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_v2_cumulative_time_in_customer": null, "properties_hs_v2_cumulative_time_in_evangelist": null, "properties_hs_v2_cumulative_time_in_lead": null, "properties_hs_v2_cumulative_time_in_marketingqualifiedlead": null, "properties_hs_v2_cumulative_time_in_opportunity": null, "properties_hs_v2_cumulative_time_in_other": null, "properties_hs_v2_cumulative_time_in_salesqualifiedlead": null, "properties_hs_v2_cumulative_time_in_subscriber": null, "properties_hs_v2_date_entered_customer": null, "properties_hs_v2_date_entered_evangelist": null, "properties_hs_v2_date_entered_lead": null, "properties_hs_v2_date_entered_marketingqualifiedlead": null, "properties_hs_v2_date_entered_opportunity": null, "properties_hs_v2_date_entered_other": null, "properties_hs_v2_date_entered_salesqualifiedlead": null, "properties_hs_v2_date_entered_subscriber": "2020-12-11T01:29:50.116000+00:00", "properties_hs_v2_date_exited_customer": null, "properties_hs_v2_date_exited_evangelist": null, "properties_hs_v2_date_exited_lead": null, "properties_hs_v2_date_exited_marketingqualifiedlead": null, "properties_hs_v2_date_exited_opportunity": null, "properties_hs_v2_date_exited_other": null, "properties_hs_v2_date_exited_salesqualifiedlead": null, "properties_hs_v2_date_exited_subscriber": null, "properties_hs_v2_latest_time_in_customer": null, "properties_hs_v2_latest_time_in_evangelist": null, "properties_hs_v2_latest_time_in_lead": null, "properties_hs_v2_latest_time_in_marketingqualifiedlead": null, "properties_hs_v2_latest_time_in_opportunity": null, "properties_hs_v2_latest_time_in_other": null, "properties_hs_v2_latest_time_in_salesqualifiedlead": null, "properties_hs_v2_latest_time_in_subscriber": null, "properties_hs_was_imported": null, "properties_hs_whatsapp_phone_number": null, "properties_hubspot_owner_assigneddate": "2020-12-11T01:29:50.093000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": null, "properties_ip_city": null, "properties_ip_country": null, "properties_ip_country_code": null, "properties_ip_latlon": null, "properties_ip_state": null, "properties_ip_state_code": null, "properties_ip_zipcode": null, "properties_job_function": null, "properties_jobtitle": null, "properties_lastmodifieddate": "2023-11-22T21:10:04.346000+00:00", "properties_lastname": "nad", "properties_lifecyclestage": "subscriber", "properties_marital_status": null, "properties_message": null, "properties_military_status": null, "properties_mobilephone": null, "properties_my_custom_test_property": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_deals": null, "properties_num_contacted_notes": null, "properties_num_conversion_events": 0, "properties_num_notes": null, "properties_num_unique_conversion_events": 0, "properties_numemployees": null, "properties_phone": null, "properties_recent_conversion_date": null, "properties_recent_conversion_event_name": null, "properties_recent_deal_amount": null, "properties_recent_deal_close_date": null, "properties_relationship_status": null, "properties_salutation": null, "properties_school": null, "properties_seniority": null, "properties_start_date": null, "properties_state": null, "properties_surveymonkeyeventlastupdated": null, "properties_test": null, "properties_total_revenue": null, "properties_twitterhandle": null, "properties_webinareventlastupdated": null, "properties_website": null, "properties_work_email": null, "properties_zip": null}, "emitted_at": 1708012942318} +{"stream": "contacts", "data": {"id": "251", "properties": {"address": "25000000 First Street", "annualrevenue": null, "associatedcompanyid": 5170561229, "associatedcompanylastupdated": null, "city": "Cambridge", "closedate": null, "company": "HubSpot", "company_size": null, "country": "USA", "createdate": "2021-02-22T14:05:09.944000+00:00", "currentlyinworkflow": null, "date_of_birth": null, "days_to_close": null, "degree": null, "email": "testingdsapis@hubspot.com", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "fax": null, "field_of_study": null, "first_conversion_date": null, "first_conversion_event_name": null, "first_deal_created_date": null, "firstname": "Test User 5001", "gender": null, "graduation_date": null, "hs_additional_emails": null, "hs_all_accessible_team_ids": null, "hs_all_contact_vids": "251", "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_analytics_average_page_views": 0, "hs_analytics_first_referrer": null, "hs_analytics_first_timestamp": "2021-02-22T14:05:09.944000+00:00", "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_url": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_last_referrer": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_url": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_num_event_completions": 0, "hs_analytics_num_page_views": 0, "hs_analytics_num_visits": 0, "hs_analytics_revenue": 0.0, "hs_analytics_source": "OFFLINE", "hs_analytics_source_data_1": "API", "hs_analytics_source_data_2": null, "hs_avatar_filemanager_key": null, "hs_buying_role": null, "hs_calculated_form_submissions": null, "hs_calculated_merged_vids": null, "hs_calculated_mobile_number": null, "hs_calculated_phone_number": null, "hs_calculated_phone_number_area_code": null, "hs_calculated_phone_number_country_code": null, "hs_calculated_phone_number_region_code": null, "hs_clicked_linkedin_ad": null, "hs_content_membership_email": null, "hs_content_membership_email_confirmed": null, "hs_content_membership_follow_up_enqueued_at": null, "hs_content_membership_notes": null, "hs_content_membership_registered_at": null, "hs_content_membership_registration_domain_sent_to": null, "hs_content_membership_registration_email_sent_at": null, "hs_content_membership_status": null, "hs_conversations_visitor_email": null, "hs_count_is_unworked": null, "hs_count_is_worked": null, "hs_created_by_conversations": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_date_entered_customer": null, "hs_date_entered_evangelist": null, "hs_date_entered_lead": null, "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": null, "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": "2021-02-22T14:05:09.944000+00:00", "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": null, "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_document_last_revisited": null, "hs_email_bad_address": null, "hs_email_bounce": null, "hs_email_click": null, "hs_email_customer_quarantined_reason": null, "hs_email_delivered": null, "hs_email_domain": "hubspot.com", "hs_email_first_click_date": null, "hs_email_first_open_date": null, "hs_email_first_reply_date": null, "hs_email_first_send_date": null, "hs_email_hard_bounce_reason": null, "hs_email_hard_bounce_reason_enum": null, "hs_email_is_ineligible": null, "hs_email_last_click_date": null, "hs_email_last_email_name": null, "hs_email_last_open_date": null, "hs_email_last_reply_date": null, "hs_email_last_send_date": null, "hs_email_open": null, "hs_email_optout": null, "hs_email_optout_10798197": null, "hs_email_optout_11890603": null, "hs_email_optout_11890831": null, "hs_email_optout_23704464": null, "hs_email_optout_94692364": null, "hs_email_quarantined": null, "hs_email_quarantined_reason": null, "hs_email_recipient_fatigue_recovery_time": null, "hs_email_replied": null, "hs_email_sends_since_last_engagement": null, "hs_emailconfirmationstatus": null, "hs_facebook_ad_clicked": null, "hs_facebook_click_id": null, "hs_feedback_last_nps_follow_up": null, "hs_feedback_last_nps_rating": null, "hs_feedback_last_survey_date": null, "hs_feedback_show_nps_web_survey": null, "hs_first_engagement_object_id": null, "hs_first_outreach_date": null, "hs_first_subscription_create_date": null, "hs_google_click_id": null, "hs_has_active_subscription": null, "hs_ip_timezone": null, "hs_is_contact": true, "hs_is_unworked": true, "hs_language": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": null, "hs_latest_disqualified_lead_date": null, "hs_latest_meeting_activity": null, "hs_latest_open_lead_date": null, "hs_latest_qualified_lead_date": null, "hs_latest_sequence_ended_date": null, "hs_latest_sequence_enrolled": null, "hs_latest_sequence_enrolled_date": null, "hs_latest_sequence_finished_date": null, "hs_latest_sequence_unenrolled_date": null, "hs_latest_source": "OFFLINE", "hs_latest_source_data_1": "API", "hs_latest_source_data_2": null, "hs_latest_source_timestamp": "2021-02-22T14:05:10.036000+00:00", "hs_latest_subscription_create_date": null, "hs_lead_status": null, "hs_legal_basis": null, "hs_lifecyclestage_customer_date": null, "hs_lifecyclestage_evangelist_date": null, "hs_lifecyclestage_lead_date": null, "hs_lifecyclestage_marketingqualifiedlead_date": null, "hs_lifecyclestage_opportunity_date": null, "hs_lifecyclestage_other_date": null, "hs_lifecyclestage_salesqualifiedlead_date": null, "hs_lifecyclestage_subscriber_date": "2021-02-22T14:05:09.944000+00:00", "hs_linkedin_ad_clicked": null, "hs_marketable_reason_id": null, "hs_marketable_reason_type": null, "hs_marketable_status": "false", "hs_marketable_until_renewal": "false", "hs_merged_object_ids": null, "hs_object_id": 251, "hs_object_source": "API", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_persona": null, "hs_pinned_engagement_id": null, "hs_pipeline": "contacts-lifecycle-pipeline", "hs_predictivecontactscore": null, "hs_predictivecontactscore_v2": 0.29, "hs_predictivecontactscorebucket": null, "hs_predictivescoringtier": "tier_4", "hs_read_only": null, "hs_sa_first_engagement_date": null, "hs_sa_first_engagement_descr": null, "hs_sa_first_engagement_object_type": null, "hs_sales_email_last_clicked": null, "hs_sales_email_last_opened": null, "hs_sales_email_last_replied": null, "hs_searchable_calculated_international_mobile_number": null, "hs_searchable_calculated_international_phone_number": null, "hs_searchable_calculated_mobile_number": null, "hs_searchable_calculated_phone_number": "5551222323", "hs_sequences_actively_enrolled_count": null, "hs_sequences_enrolled_count": null, "hs_sequences_is_enrolled": null, "hs_testpurge": null, "hs_testrollback": null, "hs_time_between_contact_creation_and_deal_close": null, "hs_time_between_contact_creation_and_deal_creation": null, "hs_time_in_customer": null, "hs_time_in_evangelist": null, "hs_time_in_lead": null, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": null, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": 94010232227, "hs_time_to_first_engagement": null, "hs_time_to_move_from_lead_to_customer": null, "hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "hs_time_to_move_from_opportunity_to_customer": null, "hs_time_to_move_from_salesqualifiedlead_to_customer": null, "hs_time_to_move_from_subscriber_to_customer": null, "hs_timezone": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_v2_cumulative_time_in_customer": null, "hs_v2_cumulative_time_in_evangelist": null, "hs_v2_cumulative_time_in_lead": null, "hs_v2_cumulative_time_in_marketingqualifiedlead": null, "hs_v2_cumulative_time_in_opportunity": null, "hs_v2_cumulative_time_in_other": null, "hs_v2_cumulative_time_in_salesqualifiedlead": null, "hs_v2_cumulative_time_in_subscriber": null, "hs_v2_date_entered_customer": null, "hs_v2_date_entered_evangelist": null, "hs_v2_date_entered_lead": null, "hs_v2_date_entered_marketingqualifiedlead": null, "hs_v2_date_entered_opportunity": null, "hs_v2_date_entered_other": null, "hs_v2_date_entered_salesqualifiedlead": null, "hs_v2_date_entered_subscriber": "2021-02-22T14:05:09.944000+00:00", "hs_v2_date_exited_customer": null, "hs_v2_date_exited_evangelist": null, "hs_v2_date_exited_lead": null, "hs_v2_date_exited_marketingqualifiedlead": null, "hs_v2_date_exited_opportunity": null, "hs_v2_date_exited_other": null, "hs_v2_date_exited_salesqualifiedlead": null, "hs_v2_date_exited_subscriber": null, "hs_v2_latest_time_in_customer": null, "hs_v2_latest_time_in_evangelist": null, "hs_v2_latest_time_in_lead": null, "hs_v2_latest_time_in_marketingqualifiedlead": null, "hs_v2_latest_time_in_opportunity": null, "hs_v2_latest_time_in_other": null, "hs_v2_latest_time_in_salesqualifiedlead": null, "hs_v2_latest_time_in_subscriber": null, "hs_was_imported": null, "hs_whatsapp_phone_number": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "hubspotscore": null, "industry": null, "ip_city": null, "ip_country": null, "ip_country_code": null, "ip_latlon": null, "ip_state": null, "ip_state_code": null, "ip_zipcode": null, "job_function": null, "jobtitle": null, "lastmodifieddate": "2023-03-21T19:29:13.036000+00:00", "lastname": "Test Lastname 5001", "lifecyclestage": "subscriber", "marital_status": null, "message": null, "military_status": null, "mobilephone": null, "my_custom_test_property": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_deals": null, "num_contacted_notes": null, "num_conversion_events": 0, "num_notes": null, "num_unique_conversion_events": 0, "numemployees": null, "phone": "555-122-2323", "recent_conversion_date": null, "recent_conversion_event_name": null, "recent_deal_amount": null, "recent_deal_close_date": null, "relationship_status": null, "salutation": null, "school": null, "seniority": null, "start_date": null, "state": "MA", "surveymonkeyeventlastupdated": null, "test": null, "total_revenue": null, "twitterhandle": null, "webinareventlastupdated": null, "website": "http://hubspot.com", "work_email": null, "zip": "02139"}, "createdAt": "2021-02-22T14:05:09.944Z", "updatedAt": "2023-03-21T19:29:13.036Z", "archived": false, "companies": ["5170561229", "5170561229"], "properties_address": "25000000 First Street", "properties_annualrevenue": null, "properties_associatedcompanyid": 5170561229, "properties_associatedcompanylastupdated": null, "properties_city": "Cambridge", "properties_closedate": null, "properties_company": "HubSpot", "properties_company_size": null, "properties_country": "USA", "properties_createdate": "2021-02-22T14:05:09.944000+00:00", "properties_currentlyinworkflow": null, "properties_date_of_birth": null, "properties_days_to_close": null, "properties_degree": null, "properties_email": "testingdsapis@hubspot.com", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_fax": null, "properties_field_of_study": null, "properties_first_conversion_date": null, "properties_first_conversion_event_name": null, "properties_first_deal_created_date": null, "properties_firstname": "Test User 5001", "properties_gender": null, "properties_graduation_date": null, "properties_hs_additional_emails": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_contact_vids": "251", "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_analytics_average_page_views": 0, "properties_hs_analytics_first_referrer": null, "properties_hs_analytics_first_timestamp": "2021-02-22T14:05:09.944000+00:00", "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_url": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_last_referrer": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_url": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_num_event_completions": 0, "properties_hs_analytics_num_page_views": 0, "properties_hs_analytics_num_visits": 0, "properties_hs_analytics_revenue": 0.0, "properties_hs_analytics_source": "OFFLINE", "properties_hs_analytics_source_data_1": "API", "properties_hs_analytics_source_data_2": null, "properties_hs_avatar_filemanager_key": null, "properties_hs_buying_role": null, "properties_hs_calculated_form_submissions": null, "properties_hs_calculated_merged_vids": null, "properties_hs_calculated_mobile_number": null, "properties_hs_calculated_phone_number": null, "properties_hs_calculated_phone_number_area_code": null, "properties_hs_calculated_phone_number_country_code": null, "properties_hs_calculated_phone_number_region_code": null, "properties_hs_clicked_linkedin_ad": null, "properties_hs_content_membership_email": null, "properties_hs_content_membership_email_confirmed": null, "properties_hs_content_membership_follow_up_enqueued_at": null, "properties_hs_content_membership_notes": null, "properties_hs_content_membership_registered_at": null, "properties_hs_content_membership_registration_domain_sent_to": null, "properties_hs_content_membership_registration_email_sent_at": null, "properties_hs_content_membership_status": null, "properties_hs_conversations_visitor_email": null, "properties_hs_count_is_unworked": null, "properties_hs_count_is_worked": null, "properties_hs_created_by_conversations": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_date_entered_customer": null, "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": null, "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": null, "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": "2021-02-22T14:05:09.944000+00:00", "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": null, "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_document_last_revisited": null, "properties_hs_email_bad_address": null, "properties_hs_email_bounce": null, "properties_hs_email_click": null, "properties_hs_email_customer_quarantined_reason": null, "properties_hs_email_delivered": null, "properties_hs_email_domain": "hubspot.com", "properties_hs_email_first_click_date": null, "properties_hs_email_first_open_date": null, "properties_hs_email_first_reply_date": null, "properties_hs_email_first_send_date": null, "properties_hs_email_hard_bounce_reason": null, "properties_hs_email_hard_bounce_reason_enum": null, "properties_hs_email_is_ineligible": null, "properties_hs_email_last_click_date": null, "properties_hs_email_last_email_name": null, "properties_hs_email_last_open_date": null, "properties_hs_email_last_reply_date": null, "properties_hs_email_last_send_date": null, "properties_hs_email_open": null, "properties_hs_email_optout": null, "properties_hs_email_optout_10798197": null, "properties_hs_email_optout_11890603": null, "properties_hs_email_optout_11890831": null, "properties_hs_email_optout_23704464": null, "properties_hs_email_optout_94692364": null, "properties_hs_email_quarantined": null, "properties_hs_email_quarantined_reason": null, "properties_hs_email_recipient_fatigue_recovery_time": null, "properties_hs_email_replied": null, "properties_hs_email_sends_since_last_engagement": null, "properties_hs_emailconfirmationstatus": null, "properties_hs_facebook_ad_clicked": null, "properties_hs_facebook_click_id": null, "properties_hs_feedback_last_nps_follow_up": null, "properties_hs_feedback_last_nps_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_feedback_show_nps_web_survey": null, "properties_hs_first_engagement_object_id": null, "properties_hs_first_outreach_date": null, "properties_hs_first_subscription_create_date": null, "properties_hs_google_click_id": null, "properties_hs_has_active_subscription": null, "properties_hs_ip_timezone": null, "properties_hs_is_contact": true, "properties_hs_is_unworked": true, "properties_hs_language": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": null, "properties_hs_latest_disqualified_lead_date": null, "properties_hs_latest_meeting_activity": null, "properties_hs_latest_open_lead_date": null, "properties_hs_latest_qualified_lead_date": null, "properties_hs_latest_sequence_ended_date": null, "properties_hs_latest_sequence_enrolled": null, "properties_hs_latest_sequence_enrolled_date": null, "properties_hs_latest_sequence_finished_date": null, "properties_hs_latest_sequence_unenrolled_date": null, "properties_hs_latest_source": "OFFLINE", "properties_hs_latest_source_data_1": "API", "properties_hs_latest_source_data_2": null, "properties_hs_latest_source_timestamp": "2021-02-22T14:05:10.036000+00:00", "properties_hs_latest_subscription_create_date": null, "properties_hs_lead_status": null, "properties_hs_legal_basis": null, "properties_hs_lifecyclestage_customer_date": null, "properties_hs_lifecyclestage_evangelist_date": null, "properties_hs_lifecyclestage_lead_date": null, "properties_hs_lifecyclestage_marketingqualifiedlead_date": null, "properties_hs_lifecyclestage_opportunity_date": null, "properties_hs_lifecyclestage_other_date": null, "properties_hs_lifecyclestage_salesqualifiedlead_date": null, "properties_hs_lifecyclestage_subscriber_date": "2021-02-22T14:05:09.944000+00:00", "properties_hs_linkedin_ad_clicked": null, "properties_hs_marketable_reason_id": null, "properties_hs_marketable_reason_type": null, "properties_hs_marketable_status": "false", "properties_hs_marketable_until_renewal": "false", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 251, "properties_hs_object_source": "API", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_persona": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "contacts-lifecycle-pipeline", "properties_hs_predictivecontactscore": null, "properties_hs_predictivecontactscore_v2": 0.29, "properties_hs_predictivecontactscorebucket": null, "properties_hs_predictivescoringtier": "tier_4", "properties_hs_read_only": null, "properties_hs_sa_first_engagement_date": null, "properties_hs_sa_first_engagement_descr": null, "properties_hs_sa_first_engagement_object_type": null, "properties_hs_sales_email_last_clicked": null, "properties_hs_sales_email_last_opened": null, "properties_hs_sales_email_last_replied": null, "properties_hs_searchable_calculated_international_mobile_number": null, "properties_hs_searchable_calculated_international_phone_number": null, "properties_hs_searchable_calculated_mobile_number": null, "properties_hs_searchable_calculated_phone_number": "5551222323", "properties_hs_sequences_actively_enrolled_count": null, "properties_hs_sequences_enrolled_count": null, "properties_hs_sequences_is_enrolled": null, "properties_hs_testpurge": null, "properties_hs_testrollback": null, "properties_hs_time_between_contact_creation_and_deal_close": null, "properties_hs_time_between_contact_creation_and_deal_creation": null, "properties_hs_time_in_customer": null, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": null, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": null, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": 94010232227, "properties_hs_time_to_first_engagement": null, "properties_hs_time_to_move_from_lead_to_customer": null, "properties_hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_opportunity_to_customer": null, "properties_hs_time_to_move_from_salesqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_subscriber_to_customer": null, "properties_hs_timezone": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_v2_cumulative_time_in_customer": null, "properties_hs_v2_cumulative_time_in_evangelist": null, "properties_hs_v2_cumulative_time_in_lead": null, "properties_hs_v2_cumulative_time_in_marketingqualifiedlead": null, "properties_hs_v2_cumulative_time_in_opportunity": null, "properties_hs_v2_cumulative_time_in_other": null, "properties_hs_v2_cumulative_time_in_salesqualifiedlead": null, "properties_hs_v2_cumulative_time_in_subscriber": null, "properties_hs_v2_date_entered_customer": null, "properties_hs_v2_date_entered_evangelist": null, "properties_hs_v2_date_entered_lead": null, "properties_hs_v2_date_entered_marketingqualifiedlead": null, "properties_hs_v2_date_entered_opportunity": null, "properties_hs_v2_date_entered_other": null, "properties_hs_v2_date_entered_salesqualifiedlead": null, "properties_hs_v2_date_entered_subscriber": "2021-02-22T14:05:09.944000+00:00", "properties_hs_v2_date_exited_customer": null, "properties_hs_v2_date_exited_evangelist": null, "properties_hs_v2_date_exited_lead": null, "properties_hs_v2_date_exited_marketingqualifiedlead": null, "properties_hs_v2_date_exited_opportunity": null, "properties_hs_v2_date_exited_other": null, "properties_hs_v2_date_exited_salesqualifiedlead": null, "properties_hs_v2_date_exited_subscriber": null, "properties_hs_v2_latest_time_in_customer": null, "properties_hs_v2_latest_time_in_evangelist": null, "properties_hs_v2_latest_time_in_lead": null, "properties_hs_v2_latest_time_in_marketingqualifiedlead": null, "properties_hs_v2_latest_time_in_opportunity": null, "properties_hs_v2_latest_time_in_other": null, "properties_hs_v2_latest_time_in_salesqualifiedlead": null, "properties_hs_v2_latest_time_in_subscriber": null, "properties_hs_was_imported": null, "properties_hs_whatsapp_phone_number": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": null, "properties_ip_city": null, "properties_ip_country": null, "properties_ip_country_code": null, "properties_ip_latlon": null, "properties_ip_state": null, "properties_ip_state_code": null, "properties_ip_zipcode": null, "properties_job_function": null, "properties_jobtitle": null, "properties_lastmodifieddate": "2023-03-21T19:29:13.036000+00:00", "properties_lastname": "Test Lastname 5001", "properties_lifecyclestage": "subscriber", "properties_marital_status": null, "properties_message": null, "properties_military_status": null, "properties_mobilephone": null, "properties_my_custom_test_property": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_deals": null, "properties_num_contacted_notes": null, "properties_num_conversion_events": 0, "properties_num_notes": null, "properties_num_unique_conversion_events": 0, "properties_numemployees": null, "properties_phone": "555-122-2323", "properties_recent_conversion_date": null, "properties_recent_conversion_event_name": null, "properties_recent_deal_amount": null, "properties_recent_deal_close_date": null, "properties_relationship_status": null, "properties_salutation": null, "properties_school": null, "properties_seniority": null, "properties_start_date": null, "properties_state": "MA", "properties_surveymonkeyeventlastupdated": null, "properties_test": null, "properties_total_revenue": null, "properties_twitterhandle": null, "properties_webinareventlastupdated": null, "properties_website": "http://hubspot.com", "properties_work_email": null, "properties_zip": "02139"}, "emitted_at": 1708012942320} +{"stream": "contacts", "data": {"id": "401", "properties": {"address": "25 First Street", "annualrevenue": null, "associatedcompanyid": null, "associatedcompanylastupdated": null, "city": "Cambridge", "closedate": null, "company": null, "company_size": null, "country": null, "createdate": "2021-02-23T20:10:36.191000+00:00", "currentlyinworkflow": null, "date_of_birth": null, "days_to_close": null, "degree": null, "email": "macmitch@hubspot.com", "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "fax": null, "field_of_study": null, "first_conversion_date": null, "first_conversion_event_name": null, "first_deal_created_date": null, "firstname": "Mac", "gender": null, "graduation_date": null, "hs_additional_emails": null, "hs_all_accessible_team_ids": null, "hs_all_contact_vids": "401", "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_average_page_views": 0, "hs_analytics_first_referrer": null, "hs_analytics_first_timestamp": "2021-02-23T20:10:36.181000+00:00", "hs_analytics_first_touch_converting_campaign": null, "hs_analytics_first_url": null, "hs_analytics_first_visit_timestamp": null, "hs_analytics_last_referrer": null, "hs_analytics_last_timestamp": null, "hs_analytics_last_touch_converting_campaign": null, "hs_analytics_last_url": null, "hs_analytics_last_visit_timestamp": null, "hs_analytics_num_event_completions": 0, "hs_analytics_num_page_views": 0, "hs_analytics_num_visits": 0, "hs_analytics_revenue": 0.0, "hs_analytics_source": "OFFLINE", "hs_analytics_source_data_1": "IMPORT", "hs_analytics_source_data_2": "13256565", "hs_avatar_filemanager_key": null, "hs_buying_role": null, "hs_calculated_form_submissions": null, "hs_calculated_merged_vids": null, "hs_calculated_mobile_number": null, "hs_calculated_phone_number": "+18884827768", "hs_calculated_phone_number_area_code": null, "hs_calculated_phone_number_country_code": "US", "hs_calculated_phone_number_region_code": null, "hs_clicked_linkedin_ad": null, "hs_content_membership_email": null, "hs_content_membership_email_confirmed": null, "hs_content_membership_follow_up_enqueued_at": null, "hs_content_membership_notes": null, "hs_content_membership_registered_at": null, "hs_content_membership_registration_domain_sent_to": null, "hs_content_membership_registration_email_sent_at": null, "hs_content_membership_status": null, "hs_conversations_visitor_email": null, "hs_count_is_unworked": 1, "hs_count_is_worked": 0, "hs_created_by_conversations": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_date_entered_customer": null, "hs_date_entered_evangelist": null, "hs_date_entered_lead": "2021-02-23T20:10:36.181000+00:00", "hs_date_entered_marketingqualifiedlead": null, "hs_date_entered_opportunity": null, "hs_date_entered_other": null, "hs_date_entered_salesqualifiedlead": null, "hs_date_entered_subscriber": null, "hs_date_exited_customer": null, "hs_date_exited_evangelist": null, "hs_date_exited_lead": null, "hs_date_exited_marketingqualifiedlead": null, "hs_date_exited_opportunity": null, "hs_date_exited_other": null, "hs_date_exited_salesqualifiedlead": null, "hs_date_exited_subscriber": null, "hs_document_last_revisited": null, "hs_email_bad_address": null, "hs_email_bounce": null, "hs_email_click": null, "hs_email_customer_quarantined_reason": null, "hs_email_delivered": null, "hs_email_domain": "hubspot.com", "hs_email_first_click_date": null, "hs_email_first_open_date": null, "hs_email_first_reply_date": null, "hs_email_first_send_date": null, "hs_email_hard_bounce_reason": null, "hs_email_hard_bounce_reason_enum": "OTHER", "hs_email_is_ineligible": null, "hs_email_last_click_date": null, "hs_email_last_email_name": null, "hs_email_last_open_date": null, "hs_email_last_reply_date": null, "hs_email_last_send_date": null, "hs_email_open": null, "hs_email_optout": null, "hs_email_optout_10798197": null, "hs_email_optout_11890603": null, "hs_email_optout_11890831": null, "hs_email_optout_23704464": null, "hs_email_optout_94692364": null, "hs_email_quarantined": null, "hs_email_quarantined_reason": null, "hs_email_recipient_fatigue_recovery_time": null, "hs_email_replied": null, "hs_email_sends_since_last_engagement": null, "hs_emailconfirmationstatus": null, "hs_facebook_ad_clicked": null, "hs_facebook_click_id": null, "hs_feedback_last_nps_follow_up": null, "hs_feedback_last_nps_rating": null, "hs_feedback_last_survey_date": null, "hs_feedback_show_nps_web_survey": null, "hs_first_engagement_object_id": null, "hs_first_outreach_date": null, "hs_first_subscription_create_date": null, "hs_google_click_id": null, "hs_has_active_subscription": null, "hs_ip_timezone": null, "hs_is_contact": true, "hs_is_unworked": true, "hs_language": null, "hs_last_sales_activity_date": null, "hs_last_sales_activity_timestamp": null, "hs_last_sales_activity_type": null, "hs_lastmodifieddate": null, "hs_latest_disqualified_lead_date": null, "hs_latest_meeting_activity": null, "hs_latest_open_lead_date": null, "hs_latest_qualified_lead_date": null, "hs_latest_sequence_ended_date": null, "hs_latest_sequence_enrolled": null, "hs_latest_sequence_enrolled_date": null, "hs_latest_sequence_finished_date": null, "hs_latest_sequence_unenrolled_date": null, "hs_latest_source": "OFFLINE", "hs_latest_source_data_1": "IMPORT", "hs_latest_source_data_2": "13256565", "hs_latest_source_timestamp": "2021-02-23T20:10:36.210000+00:00", "hs_latest_subscription_create_date": null, "hs_lead_status": null, "hs_legal_basis": null, "hs_lifecyclestage_customer_date": null, "hs_lifecyclestage_evangelist_date": null, "hs_lifecyclestage_lead_date": "2021-02-23T20:10:36.181000+00:00", "hs_lifecyclestage_marketingqualifiedlead_date": null, "hs_lifecyclestage_opportunity_date": null, "hs_lifecyclestage_other_date": null, "hs_lifecyclestage_salesqualifiedlead_date": null, "hs_lifecyclestage_subscriber_date": null, "hs_linkedin_ad_clicked": null, "hs_marketable_reason_id": null, "hs_marketable_reason_type": null, "hs_marketable_status": "false", "hs_marketable_until_renewal": "false", "hs_merged_object_ids": null, "hs_object_id": 401, "hs_object_source": "IMPORT", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "13256565", "hs_object_source_label": "IMPORT", "hs_object_source_user_id": null, "hs_persona": null, "hs_pinned_engagement_id": null, "hs_pipeline": "contacts-lifecycle-pipeline", "hs_predictivecontactscore": null, "hs_predictivecontactscore_v2": 0.29, "hs_predictivecontactscorebucket": null, "hs_predictivescoringtier": "tier_4", "hs_read_only": null, "hs_sa_first_engagement_date": null, "hs_sa_first_engagement_descr": null, "hs_sa_first_engagement_object_type": null, "hs_sales_email_last_clicked": null, "hs_sales_email_last_opened": null, "hs_sales_email_last_replied": null, "hs_searchable_calculated_international_mobile_number": null, "hs_searchable_calculated_international_phone_number": null, "hs_searchable_calculated_mobile_number": null, "hs_searchable_calculated_phone_number": "8884827768", "hs_sequences_actively_enrolled_count": null, "hs_sequences_enrolled_count": null, "hs_sequences_is_enrolled": null, "hs_testpurge": null, "hs_testrollback": null, "hs_time_between_contact_creation_and_deal_close": null, "hs_time_between_contact_creation_and_deal_creation": null, "hs_time_in_customer": null, "hs_time_in_evangelist": null, "hs_time_in_lead": 93901905989, "hs_time_in_marketingqualifiedlead": null, "hs_time_in_opportunity": null, "hs_time_in_other": null, "hs_time_in_salesqualifiedlead": null, "hs_time_in_subscriber": null, "hs_time_to_first_engagement": null, "hs_time_to_move_from_lead_to_customer": null, "hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "hs_time_to_move_from_opportunity_to_customer": null, "hs_time_to_move_from_salesqualifiedlead_to_customer": null, "hs_time_to_move_from_subscriber_to_customer": null, "hs_timezone": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_v2_cumulative_time_in_customer": null, "hs_v2_cumulative_time_in_evangelist": null, "hs_v2_cumulative_time_in_lead": null, "hs_v2_cumulative_time_in_marketingqualifiedlead": null, "hs_v2_cumulative_time_in_opportunity": null, "hs_v2_cumulative_time_in_other": null, "hs_v2_cumulative_time_in_salesqualifiedlead": null, "hs_v2_cumulative_time_in_subscriber": null, "hs_v2_date_entered_customer": null, "hs_v2_date_entered_evangelist": null, "hs_v2_date_entered_lead": "2021-02-23T20:10:36.181000+00:00", "hs_v2_date_entered_marketingqualifiedlead": null, "hs_v2_date_entered_opportunity": null, "hs_v2_date_entered_other": null, "hs_v2_date_entered_salesqualifiedlead": null, "hs_v2_date_entered_subscriber": null, "hs_v2_date_exited_customer": null, "hs_v2_date_exited_evangelist": null, "hs_v2_date_exited_lead": null, "hs_v2_date_exited_marketingqualifiedlead": null, "hs_v2_date_exited_opportunity": null, "hs_v2_date_exited_other": null, "hs_v2_date_exited_salesqualifiedlead": null, "hs_v2_date_exited_subscriber": null, "hs_v2_latest_time_in_customer": null, "hs_v2_latest_time_in_evangelist": null, "hs_v2_latest_time_in_lead": null, "hs_v2_latest_time_in_marketingqualifiedlead": null, "hs_v2_latest_time_in_opportunity": null, "hs_v2_latest_time_in_other": null, "hs_v2_latest_time_in_salesqualifiedlead": null, "hs_v2_latest_time_in_subscriber": null, "hs_was_imported": true, "hs_whatsapp_phone_number": null, "hubspot_owner_assigneddate": "2021-05-21T10:20:30.963000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "hubspotscore": null, "industry": null, "ip_city": null, "ip_country": null, "ip_country_code": null, "ip_latlon": null, "ip_state": null, "ip_state_code": null, "ip_zipcode": null, "job_function": null, "jobtitle": null, "lastmodifieddate": "2023-03-21T19:31:00.563000+00:00", "lastname": "Mitchell", "lifecyclestage": "lead", "marital_status": null, "message": null, "military_status": null, "mobilephone": null, "my_custom_test_property": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_deals": null, "num_contacted_notes": null, "num_conversion_events": 0, "num_notes": null, "num_unique_conversion_events": 0, "numemployees": null, "phone": "1(888) 482-7768", "recent_conversion_date": null, "recent_conversion_event_name": null, "recent_deal_amount": null, "recent_deal_close_date": null, "relationship_status": null, "salutation": null, "school": null, "seniority": null, "start_date": null, "state": "MA", "surveymonkeyeventlastupdated": null, "test": null, "total_revenue": null, "twitterhandle": null, "webinareventlastupdated": null, "website": null, "work_email": null, "zip": "21430"}, "createdAt": "2021-02-23T20:10:36.191Z", "updatedAt": "2023-03-21T19:31:00.563Z", "archived": false, "properties_address": "25 First Street", "properties_annualrevenue": null, "properties_associatedcompanyid": null, "properties_associatedcompanylastupdated": null, "properties_city": "Cambridge", "properties_closedate": null, "properties_company": null, "properties_company_size": null, "properties_country": null, "properties_createdate": "2021-02-23T20:10:36.191000+00:00", "properties_currentlyinworkflow": null, "properties_date_of_birth": null, "properties_days_to_close": null, "properties_degree": null, "properties_email": "macmitch@hubspot.com", "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_fax": null, "properties_field_of_study": null, "properties_first_conversion_date": null, "properties_first_conversion_event_name": null, "properties_first_deal_created_date": null, "properties_firstname": "Mac", "properties_gender": null, "properties_graduation_date": null, "properties_hs_additional_emails": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_contact_vids": "401", "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_average_page_views": 0, "properties_hs_analytics_first_referrer": null, "properties_hs_analytics_first_timestamp": "2021-02-23T20:10:36.181000+00:00", "properties_hs_analytics_first_touch_converting_campaign": null, "properties_hs_analytics_first_url": null, "properties_hs_analytics_first_visit_timestamp": null, "properties_hs_analytics_last_referrer": null, "properties_hs_analytics_last_timestamp": null, "properties_hs_analytics_last_touch_converting_campaign": null, "properties_hs_analytics_last_url": null, "properties_hs_analytics_last_visit_timestamp": null, "properties_hs_analytics_num_event_completions": 0, "properties_hs_analytics_num_page_views": 0, "properties_hs_analytics_num_visits": 0, "properties_hs_analytics_revenue": 0.0, "properties_hs_analytics_source": "OFFLINE", "properties_hs_analytics_source_data_1": "IMPORT", "properties_hs_analytics_source_data_2": "13256565", "properties_hs_avatar_filemanager_key": null, "properties_hs_buying_role": null, "properties_hs_calculated_form_submissions": null, "properties_hs_calculated_merged_vids": null, "properties_hs_calculated_mobile_number": null, "properties_hs_calculated_phone_number": "+18884827768", "properties_hs_calculated_phone_number_area_code": null, "properties_hs_calculated_phone_number_country_code": "US", "properties_hs_calculated_phone_number_region_code": null, "properties_hs_clicked_linkedin_ad": null, "properties_hs_content_membership_email": null, "properties_hs_content_membership_email_confirmed": null, "properties_hs_content_membership_follow_up_enqueued_at": null, "properties_hs_content_membership_notes": null, "properties_hs_content_membership_registered_at": null, "properties_hs_content_membership_registration_domain_sent_to": null, "properties_hs_content_membership_registration_email_sent_at": null, "properties_hs_content_membership_status": null, "properties_hs_conversations_visitor_email": null, "properties_hs_count_is_unworked": 1, "properties_hs_count_is_worked": 0, "properties_hs_created_by_conversations": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_date_entered_customer": null, "properties_hs_date_entered_evangelist": null, "properties_hs_date_entered_lead": "2021-02-23T20:10:36.181000+00:00", "properties_hs_date_entered_marketingqualifiedlead": null, "properties_hs_date_entered_opportunity": null, "properties_hs_date_entered_other": null, "properties_hs_date_entered_salesqualifiedlead": null, "properties_hs_date_entered_subscriber": null, "properties_hs_date_exited_customer": null, "properties_hs_date_exited_evangelist": null, "properties_hs_date_exited_lead": null, "properties_hs_date_exited_marketingqualifiedlead": null, "properties_hs_date_exited_opportunity": null, "properties_hs_date_exited_other": null, "properties_hs_date_exited_salesqualifiedlead": null, "properties_hs_date_exited_subscriber": null, "properties_hs_document_last_revisited": null, "properties_hs_email_bad_address": null, "properties_hs_email_bounce": null, "properties_hs_email_click": null, "properties_hs_email_customer_quarantined_reason": null, "properties_hs_email_delivered": null, "properties_hs_email_domain": "hubspot.com", "properties_hs_email_first_click_date": null, "properties_hs_email_first_open_date": null, "properties_hs_email_first_reply_date": null, "properties_hs_email_first_send_date": null, "properties_hs_email_hard_bounce_reason": null, "properties_hs_email_hard_bounce_reason_enum": "OTHER", "properties_hs_email_is_ineligible": null, "properties_hs_email_last_click_date": null, "properties_hs_email_last_email_name": null, "properties_hs_email_last_open_date": null, "properties_hs_email_last_reply_date": null, "properties_hs_email_last_send_date": null, "properties_hs_email_open": null, "properties_hs_email_optout": null, "properties_hs_email_optout_10798197": null, "properties_hs_email_optout_11890603": null, "properties_hs_email_optout_11890831": null, "properties_hs_email_optout_23704464": null, "properties_hs_email_optout_94692364": null, "properties_hs_email_quarantined": null, "properties_hs_email_quarantined_reason": null, "properties_hs_email_recipient_fatigue_recovery_time": null, "properties_hs_email_replied": null, "properties_hs_email_sends_since_last_engagement": null, "properties_hs_emailconfirmationstatus": null, "properties_hs_facebook_ad_clicked": null, "properties_hs_facebook_click_id": null, "properties_hs_feedback_last_nps_follow_up": null, "properties_hs_feedback_last_nps_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_feedback_show_nps_web_survey": null, "properties_hs_first_engagement_object_id": null, "properties_hs_first_outreach_date": null, "properties_hs_first_subscription_create_date": null, "properties_hs_google_click_id": null, "properties_hs_has_active_subscription": null, "properties_hs_ip_timezone": null, "properties_hs_is_contact": true, "properties_hs_is_unworked": true, "properties_hs_language": null, "properties_hs_last_sales_activity_date": null, "properties_hs_last_sales_activity_timestamp": null, "properties_hs_last_sales_activity_type": null, "properties_hs_lastmodifieddate": null, "properties_hs_latest_disqualified_lead_date": null, "properties_hs_latest_meeting_activity": null, "properties_hs_latest_open_lead_date": null, "properties_hs_latest_qualified_lead_date": null, "properties_hs_latest_sequence_ended_date": null, "properties_hs_latest_sequence_enrolled": null, "properties_hs_latest_sequence_enrolled_date": null, "properties_hs_latest_sequence_finished_date": null, "properties_hs_latest_sequence_unenrolled_date": null, "properties_hs_latest_source": "OFFLINE", "properties_hs_latest_source_data_1": "IMPORT", "properties_hs_latest_source_data_2": "13256565", "properties_hs_latest_source_timestamp": "2021-02-23T20:10:36.210000+00:00", "properties_hs_latest_subscription_create_date": null, "properties_hs_lead_status": null, "properties_hs_legal_basis": null, "properties_hs_lifecyclestage_customer_date": null, "properties_hs_lifecyclestage_evangelist_date": null, "properties_hs_lifecyclestage_lead_date": "2021-02-23T20:10:36.181000+00:00", "properties_hs_lifecyclestage_marketingqualifiedlead_date": null, "properties_hs_lifecyclestage_opportunity_date": null, "properties_hs_lifecyclestage_other_date": null, "properties_hs_lifecyclestage_salesqualifiedlead_date": null, "properties_hs_lifecyclestage_subscriber_date": null, "properties_hs_linkedin_ad_clicked": null, "properties_hs_marketable_reason_id": null, "properties_hs_marketable_reason_type": null, "properties_hs_marketable_status": "false", "properties_hs_marketable_until_renewal": "false", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 401, "properties_hs_object_source": "IMPORT", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "13256565", "properties_hs_object_source_label": "IMPORT", "properties_hs_object_source_user_id": null, "properties_hs_persona": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "contacts-lifecycle-pipeline", "properties_hs_predictivecontactscore": null, "properties_hs_predictivecontactscore_v2": 0.29, "properties_hs_predictivecontactscorebucket": null, "properties_hs_predictivescoringtier": "tier_4", "properties_hs_read_only": null, "properties_hs_sa_first_engagement_date": null, "properties_hs_sa_first_engagement_descr": null, "properties_hs_sa_first_engagement_object_type": null, "properties_hs_sales_email_last_clicked": null, "properties_hs_sales_email_last_opened": null, "properties_hs_sales_email_last_replied": null, "properties_hs_searchable_calculated_international_mobile_number": null, "properties_hs_searchable_calculated_international_phone_number": null, "properties_hs_searchable_calculated_mobile_number": null, "properties_hs_searchable_calculated_phone_number": "8884827768", "properties_hs_sequences_actively_enrolled_count": null, "properties_hs_sequences_enrolled_count": null, "properties_hs_sequences_is_enrolled": null, "properties_hs_testpurge": null, "properties_hs_testrollback": null, "properties_hs_time_between_contact_creation_and_deal_close": null, "properties_hs_time_between_contact_creation_and_deal_creation": null, "properties_hs_time_in_customer": null, "properties_hs_time_in_evangelist": null, "properties_hs_time_in_lead": 93901905989, "properties_hs_time_in_marketingqualifiedlead": null, "properties_hs_time_in_opportunity": null, "properties_hs_time_in_other": null, "properties_hs_time_in_salesqualifiedlead": null, "properties_hs_time_in_subscriber": null, "properties_hs_time_to_first_engagement": null, "properties_hs_time_to_move_from_lead_to_customer": null, "properties_hs_time_to_move_from_marketingqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_opportunity_to_customer": null, "properties_hs_time_to_move_from_salesqualifiedlead_to_customer": null, "properties_hs_time_to_move_from_subscriber_to_customer": null, "properties_hs_timezone": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_v2_cumulative_time_in_customer": null, "properties_hs_v2_cumulative_time_in_evangelist": null, "properties_hs_v2_cumulative_time_in_lead": null, "properties_hs_v2_cumulative_time_in_marketingqualifiedlead": null, "properties_hs_v2_cumulative_time_in_opportunity": null, "properties_hs_v2_cumulative_time_in_other": null, "properties_hs_v2_cumulative_time_in_salesqualifiedlead": null, "properties_hs_v2_cumulative_time_in_subscriber": null, "properties_hs_v2_date_entered_customer": null, "properties_hs_v2_date_entered_evangelist": null, "properties_hs_v2_date_entered_lead": "2021-02-23T20:10:36.181000+00:00", "properties_hs_v2_date_entered_marketingqualifiedlead": null, "properties_hs_v2_date_entered_opportunity": null, "properties_hs_v2_date_entered_other": null, "properties_hs_v2_date_entered_salesqualifiedlead": null, "properties_hs_v2_date_entered_subscriber": null, "properties_hs_v2_date_exited_customer": null, "properties_hs_v2_date_exited_evangelist": null, "properties_hs_v2_date_exited_lead": null, "properties_hs_v2_date_exited_marketingqualifiedlead": null, "properties_hs_v2_date_exited_opportunity": null, "properties_hs_v2_date_exited_other": null, "properties_hs_v2_date_exited_salesqualifiedlead": null, "properties_hs_v2_date_exited_subscriber": null, "properties_hs_v2_latest_time_in_customer": null, "properties_hs_v2_latest_time_in_evangelist": null, "properties_hs_v2_latest_time_in_lead": null, "properties_hs_v2_latest_time_in_marketingqualifiedlead": null, "properties_hs_v2_latest_time_in_opportunity": null, "properties_hs_v2_latest_time_in_other": null, "properties_hs_v2_latest_time_in_salesqualifiedlead": null, "properties_hs_v2_latest_time_in_subscriber": null, "properties_hs_was_imported": true, "properties_hs_whatsapp_phone_number": null, "properties_hubspot_owner_assigneddate": "2021-05-21T10:20:30.963000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_hubspotscore": null, "properties_industry": null, "properties_ip_city": null, "properties_ip_country": null, "properties_ip_country_code": null, "properties_ip_latlon": null, "properties_ip_state": null, "properties_ip_state_code": null, "properties_ip_zipcode": null, "properties_job_function": null, "properties_jobtitle": null, "properties_lastmodifieddate": "2023-03-21T19:31:00.563000+00:00", "properties_lastname": "Mitchell", "properties_lifecyclestage": "lead", "properties_marital_status": null, "properties_message": null, "properties_military_status": null, "properties_mobilephone": null, "properties_my_custom_test_property": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_deals": null, "properties_num_contacted_notes": null, "properties_num_conversion_events": 0, "properties_num_notes": null, "properties_num_unique_conversion_events": 0, "properties_numemployees": null, "properties_phone": "1(888) 482-7768", "properties_recent_conversion_date": null, "properties_recent_conversion_event_name": null, "properties_recent_deal_amount": null, "properties_recent_deal_close_date": null, "properties_relationship_status": null, "properties_salutation": null, "properties_school": null, "properties_seniority": null, "properties_start_date": null, "properties_state": "MA", "properties_surveymonkeyeventlastupdated": null, "properties_test": null, "properties_total_revenue": null, "properties_twitterhandle": null, "properties_webinareventlastupdated": null, "properties_website": null, "properties_work_email": null, "properties_zip": "21430"}, "emitted_at": 1708012942321} {"stream": "contacts_list_memberships", "data": {"canonical-vid": 401, "static-list-id": 60, "internal-list-id": 2147483643, "timestamp": 1614111042672, "vid": 401, "is-member": true}, "emitted_at": 1697714191502} {"stream": "contacts_list_memberships", "data": {"canonical-vid": 401, "static-list-id": 61, "internal-list-id": 2147483643, "timestamp": 1615502112726, "vid": 401, "is-member": true}, "emitted_at": 1697714191513} {"stream": "contacts_list_memberships", "data": {"canonical-vid": 2501, "static-list-id": 60, "internal-list-id": 2147483643, "timestamp": 1675124235515, "vid": 2501, "is-member": true}, "emitted_at": 1697714191513} {"stream": "contacts_merged_audit", "data": {"canonical-vid": 651, "vid-to-merge": 201, "timestamp": 1688758327178, "entity-id": "auth:app-cookie | auth-level:app | login-id:integration-test@airbyte.io-1688758203663 | hub-id:8727216 | user-id:12282590 | origin-ip:2804:1b3:8402:b1f4:7d1b:f62e:b071:593d | correlation-id:3f139cd7-66fc-4300-8cbc-e6c1fe9ea7d1", "user-id": 12282590, "num-properties-moved": 45, "merged_from_email": {"value": "testingapis@hubspot.com", "source-type": "API", "source-id": null, "source-label": null, "updated-by-user-id": null, "timestamp": 1610634377014, "selected": false}, "merged_to_email": {"value": "testingapicontact_1@hubspot.com", "source-type": "API", "source-id": null, "source-label": null, "updated-by-user-id": null, "timestamp": 1634044981830, "selected": false}, "first-name": "test", "last-name": "testerson", "merged_from_email_value": "testingapis@hubspot.com", "merged_from_email_source-type": "API", "merged_from_email_source-id": null, "merged_from_email_source-label": null, "merged_from_email_updated-by-user-id": null, "merged_from_email_timestamp": 1610634377014, "merged_from_email_selected": false, "merged_to_email_value": "testingapicontact_1@hubspot.com", "merged_to_email_source-type": "API", "merged_to_email_source-id": null, "merged_to_email_source-label": null, "merged_to_email_updated-by-user-id": null, "merged_to_email_timestamp": 1634044981830, "merged_to_email_selected": false}, "emitted_at": 1697714194351} {"stream": "deal_pipelines", "data": {"label": "New Business Pipeline", "displayOrder": 3, "active": true, "stages": [{"label": "Initial Qualification", "displayOrder": 0, "metadata": {"isClosed": "false", "probability": "0.1"}, "stageId": "9567448", "createdAt": 1610635973956, "updatedAt": 1680620354263, "active": true}, {"label": "Success! Closed Won", "displayOrder": 2, "metadata": {"isClosed": "true", "probability": "1.0"}, "stageId": "customclosedwonstage", "createdAt": 1610635973956, "updatedAt": 1680620354263, "active": true}, {"label": "Negotiation", "displayOrder": 1, "metadata": {"isClosed": "false", "probability": "0.5"}, "stageId": "9567449", "createdAt": 1610635973956, "updatedAt": 1680620354263, "active": true}, {"label": "Closed Lost", "displayOrder": 3, "metadata": {"isClosed": "false", "probability": "0.1"}, "stageId": "66894120", "createdAt": 1680620354263, "updatedAt": 1680620354263, "active": true}], "objectType": "DEAL", "objectTypeId": "0-3", "pipelineId": "b9152945-a594-4835-9676-a6f405fecd71", "createdAt": 1610635973956, "updatedAt": 1680620354263, "default": false}, "emitted_at": 1697714195524} -{"stream": "deals", "data": {"id": "3980651569", "properties": {"amount": 60000, "amount_in_home_currency": 60000, "closed_lost_reason": null, "closed_won_reason": null, "closedate": "2014-08-31T00:00:00+00:00", "createdate": "2021-01-13T10:30:42.221000+00:00", "days_to_close": 0, "dealname": "Tim's Newer Deal", "dealstage": "appointmentscheduled", "dealtype": "newbusiness", "description": null, "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "hs_acv": null, "hs_all_accessible_team_ids": null, "hs_all_collaborator_owner_ids": null, "hs_all_deal_split_owner_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_latest_source": "OFFLINE", "hs_analytics_latest_source_company": "OFFLINE", "hs_analytics_latest_source_contact": null, "hs_analytics_latest_source_data_1": "CONTACTS", "hs_analytics_latest_source_data_1_company": "CONTACTS", "hs_analytics_latest_source_data_1_contact": null, "hs_analytics_latest_source_data_2": "CRM_UI", "hs_analytics_latest_source_data_2_company": "CRM_UI", "hs_analytics_latest_source_data_2_contact": null, "hs_analytics_latest_source_timestamp": null, "hs_analytics_latest_source_timestamp_company": null, "hs_analytics_latest_source_timestamp_contact": null, "hs_analytics_source": "OFFLINE", "hs_analytics_source_data_1": "CONTACTS", "hs_analytics_source_data_2": "CRM_UI", "hs_arr": null, "hs_campaign": null, "hs_closed_amount": 0, "hs_closed_amount_in_home_currency": 0, "hs_closed_won_count": null, "hs_closed_won_date": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-13T10:30:42.221000+00:00", "hs_date_entered_66894120": null, "hs_date_entered_9567448": null, "hs_date_entered_9567449": null, "hs_date_entered_appointmentscheduled": "2021-01-13T10:30:42.221000+00:00", "hs_date_entered_closedlost": null, "hs_date_entered_closedwon": null, "hs_date_entered_contractsent": null, "hs_date_entered_customclosedwonstage": null, "hs_date_entered_decisionmakerboughtin": null, "hs_date_entered_presentationscheduled": null, "hs_date_entered_qualifiedtobuy": null, "hs_date_exited_66894120": null, "hs_date_exited_9567448": null, "hs_date_exited_9567449": null, "hs_date_exited_appointmentscheduled": null, "hs_date_exited_closedlost": null, "hs_date_exited_closedwon": null, "hs_date_exited_contractsent": null, "hs_date_exited_customclosedwonstage": null, "hs_date_exited_decisionmakerboughtin": null, "hs_date_exited_presentationscheduled": null, "hs_date_exited_qualifiedtobuy": null, "hs_days_to_close_raw": 0, "hs_deal_amount_calculation_preference": null, "hs_deal_stage_probability": 0.2, "hs_deal_stage_probability_shadow": null, "hs_exchange_rate": null, "hs_forecast_amount": 60000, "hs_forecast_probability": null, "hs_is_closed": false, "hs_is_closed_won": false, "hs_is_deal_split": false, "hs_is_open_count": 1, "hs_lastmodifieddate": "2024-01-21T22:30:34.782000+00:00", "hs_latest_meeting_activity": null, "hs_likelihood_to_close": null, "hs_line_item_global_term_hs_discount_percentage": null, "hs_line_item_global_term_hs_discount_percentage_enabled": null, "hs_line_item_global_term_hs_recurring_billing_period": null, "hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "hs_line_item_global_term_hs_recurring_billing_start_date": null, "hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "hs_line_item_global_term_recurringbillingfrequency": null, "hs_line_item_global_term_recurringbillingfrequency_enabled": null, "hs_manual_forecast_category": null, "hs_merged_object_ids": null, "hs_mrr": null, "hs_next_step": null, "hs_num_associated_deal_splits": null, "hs_num_of_associated_line_items": 0, "hs_num_target_accounts": 0, "hs_object_id": 3980651569, "hs_object_source": "API", "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_pinned_engagement_id": null, "hs_predicted_amount": null, "hs_predicted_amount_in_home_currency": null, "hs_priority": null, "hs_projected_amount": 12000.0, "hs_projected_amount_in_home_currency": 12000.0, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_tcv": null, "hs_time_in_66894120": null, "hs_time_in_9567448": null, "hs_time_in_9567449": null, "hs_time_in_appointmentscheduled": 95654671212, "hs_time_in_closedlost": null, "hs_time_in_closedwon": null, "hs_time_in_contractsent": null, "hs_time_in_customclosedwonstage": null, "hs_time_in_decisionmakerboughtin": null, "hs_time_in_presentationscheduled": null, "hs_time_in_qualifiedtobuy": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2021-01-13T10:30:42.221000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_contacts": 0, "num_contacted_notes": null, "num_notes": null, "pipeline": "default"}, "createdAt": "2021-01-13T10:30:42.221Z", "updatedAt": "2024-01-21T22:30:34.782Z", "archived": false, "companies": ["5000526215", "5000526215"], "properties_amount": 60000, "properties_amount_in_home_currency": 60000, "properties_closed_lost_reason": null, "properties_closed_won_reason": null, "properties_closedate": "2014-08-31T00:00:00+00:00", "properties_createdate": "2021-01-13T10:30:42.221000+00:00", "properties_days_to_close": 0, "properties_dealname": "Tim's Newer Deal", "properties_dealstage": "appointmentscheduled", "properties_dealtype": "newbusiness", "properties_description": null, "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_hs_acv": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_collaborator_owner_ids": null, "properties_hs_all_deal_split_owner_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_latest_source": "OFFLINE", "properties_hs_analytics_latest_source_company": "OFFLINE", "properties_hs_analytics_latest_source_contact": null, "properties_hs_analytics_latest_source_data_1": "CONTACTS", "properties_hs_analytics_latest_source_data_1_company": "CONTACTS", "properties_hs_analytics_latest_source_data_1_contact": null, "properties_hs_analytics_latest_source_data_2": "CRM_UI", "properties_hs_analytics_latest_source_data_2_company": "CRM_UI", "properties_hs_analytics_latest_source_data_2_contact": null, "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_latest_source_timestamp_company": null, "properties_hs_analytics_latest_source_timestamp_contact": null, "properties_hs_analytics_source": "OFFLINE", "properties_hs_analytics_source_data_1": "CONTACTS", "properties_hs_analytics_source_data_2": "CRM_UI", "properties_hs_arr": null, "properties_hs_campaign": null, "properties_hs_closed_amount": 0, "properties_hs_closed_amount_in_home_currency": 0, "properties_hs_closed_won_count": null, "properties_hs_closed_won_date": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-13T10:30:42.221000+00:00", "properties_hs_date_entered_66894120": null, "properties_hs_date_entered_9567448": null, "properties_hs_date_entered_9567449": null, "properties_hs_date_entered_appointmentscheduled": "2021-01-13T10:30:42.221000+00:00", "properties_hs_date_entered_closedlost": null, "properties_hs_date_entered_closedwon": null, "properties_hs_date_entered_contractsent": null, "properties_hs_date_entered_customclosedwonstage": null, "properties_hs_date_entered_decisionmakerboughtin": null, "properties_hs_date_entered_presentationscheduled": null, "properties_hs_date_entered_qualifiedtobuy": null, "properties_hs_date_exited_66894120": null, "properties_hs_date_exited_9567448": null, "properties_hs_date_exited_9567449": null, "properties_hs_date_exited_appointmentscheduled": null, "properties_hs_date_exited_closedlost": null, "properties_hs_date_exited_closedwon": null, "properties_hs_date_exited_contractsent": null, "properties_hs_date_exited_customclosedwonstage": null, "properties_hs_date_exited_decisionmakerboughtin": null, "properties_hs_date_exited_presentationscheduled": null, "properties_hs_date_exited_qualifiedtobuy": null, "properties_hs_days_to_close_raw": 0, "properties_hs_deal_amount_calculation_preference": null, "properties_hs_deal_stage_probability": 0.2, "properties_hs_deal_stage_probability_shadow": null, "properties_hs_exchange_rate": null, "properties_hs_forecast_amount": 60000, "properties_hs_forecast_probability": null, "properties_hs_is_closed": false, "properties_hs_is_closed_won": false, "properties_hs_is_deal_split": false, "properties_hs_is_open_count": 1, "properties_hs_lastmodifieddate": "2024-01-21T22:30:34.782000+00:00", "properties_hs_latest_meeting_activity": null, "properties_hs_likelihood_to_close": null, "properties_hs_line_item_global_term_hs_discount_percentage": null, "properties_hs_line_item_global_term_hs_discount_percentage_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_period": null, "properties_hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "properties_hs_line_item_global_term_recurringbillingfrequency": null, "properties_hs_line_item_global_term_recurringbillingfrequency_enabled": null, "properties_hs_manual_forecast_category": null, "properties_hs_merged_object_ids": null, "properties_hs_mrr": null, "properties_hs_next_step": null, "properties_hs_num_associated_deal_splits": null, "properties_hs_num_of_associated_line_items": 0, "properties_hs_num_target_accounts": 0, "properties_hs_object_id": 3980651569, "properties_hs_object_source": "API", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_predicted_amount": null, "properties_hs_predicted_amount_in_home_currency": null, "properties_hs_priority": null, "properties_hs_projected_amount": 12000.0, "properties_hs_projected_amount_in_home_currency": 12000.0, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_tcv": null, "properties_hs_time_in_66894120": null, "properties_hs_time_in_9567448": null, "properties_hs_time_in_9567449": null, "properties_hs_time_in_appointmentscheduled": 95654671212, "properties_hs_time_in_closedlost": null, "properties_hs_time_in_closedwon": null, "properties_hs_time_in_contractsent": null, "properties_hs_time_in_customclosedwonstage": null, "properties_hs_time_in_decisionmakerboughtin": null, "properties_hs_time_in_presentationscheduled": null, "properties_hs_time_in_qualifiedtobuy": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2021-01-13T10:30:42.221000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_pipeline": "default"}, "emitted_at": 1706188513541} -{"stream": "deals", "data": {"id": "3980673856", "properties": {"amount": 60000, "amount_in_home_currency": 60000, "closed_lost_reason": null, "closed_won_reason": null, "closedate": "2014-08-31T00:00:00+00:00", "createdate": "2021-01-13T10:31:51.154000+00:00", "days_to_close": 0, "dealname": "Tim's Newer Deal", "dealstage": "appointmentscheduled", "dealtype": "newbusiness", "description": null, "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "hs_acv": null, "hs_all_accessible_team_ids": null, "hs_all_collaborator_owner_ids": null, "hs_all_deal_split_owner_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_latest_source": null, "hs_analytics_latest_source_company": null, "hs_analytics_latest_source_contact": null, "hs_analytics_latest_source_data_1": null, "hs_analytics_latest_source_data_1_company": null, "hs_analytics_latest_source_data_1_contact": null, "hs_analytics_latest_source_data_2": null, "hs_analytics_latest_source_data_2_company": null, "hs_analytics_latest_source_data_2_contact": null, "hs_analytics_latest_source_timestamp": null, "hs_analytics_latest_source_timestamp_company": null, "hs_analytics_latest_source_timestamp_contact": null, "hs_analytics_source": null, "hs_analytics_source_data_1": null, "hs_analytics_source_data_2": null, "hs_arr": null, "hs_campaign": null, "hs_closed_amount": 0, "hs_closed_amount_in_home_currency": 0, "hs_closed_won_count": null, "hs_closed_won_date": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-13T10:31:51.154000+00:00", "hs_date_entered_66894120": null, "hs_date_entered_9567448": null, "hs_date_entered_9567449": null, "hs_date_entered_appointmentscheduled": "2021-01-13T10:31:51.154000+00:00", "hs_date_entered_closedlost": null, "hs_date_entered_closedwon": null, "hs_date_entered_contractsent": null, "hs_date_entered_customclosedwonstage": null, "hs_date_entered_decisionmakerboughtin": null, "hs_date_entered_presentationscheduled": null, "hs_date_entered_qualifiedtobuy": null, "hs_date_exited_66894120": null, "hs_date_exited_9567448": null, "hs_date_exited_9567449": null, "hs_date_exited_appointmentscheduled": null, "hs_date_exited_closedlost": null, "hs_date_exited_closedwon": null, "hs_date_exited_contractsent": null, "hs_date_exited_customclosedwonstage": null, "hs_date_exited_decisionmakerboughtin": null, "hs_date_exited_presentationscheduled": null, "hs_date_exited_qualifiedtobuy": null, "hs_days_to_close_raw": 0, "hs_deal_amount_calculation_preference": null, "hs_deal_stage_probability": 0.2, "hs_deal_stage_probability_shadow": null, "hs_exchange_rate": null, "hs_forecast_amount": 60000, "hs_forecast_probability": null, "hs_is_closed": false, "hs_is_closed_won": false, "hs_is_deal_split": false, "hs_is_open_count": 1, "hs_lastmodifieddate": "2024-01-21T02:48:34.022000+00:00", "hs_latest_meeting_activity": null, "hs_likelihood_to_close": null, "hs_line_item_global_term_hs_discount_percentage": null, "hs_line_item_global_term_hs_discount_percentage_enabled": null, "hs_line_item_global_term_hs_recurring_billing_period": null, "hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "hs_line_item_global_term_hs_recurring_billing_start_date": null, "hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "hs_line_item_global_term_recurringbillingfrequency": null, "hs_line_item_global_term_recurringbillingfrequency_enabled": null, "hs_manual_forecast_category": null, "hs_merged_object_ids": null, "hs_mrr": null, "hs_next_step": null, "hs_num_associated_deal_splits": null, "hs_num_of_associated_line_items": 0, "hs_num_target_accounts": null, "hs_object_id": 3980673856, "hs_object_source": "API", "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_pinned_engagement_id": null, "hs_predicted_amount": null, "hs_predicted_amount_in_home_currency": null, "hs_priority": null, "hs_projected_amount": 12000.0, "hs_projected_amount_in_home_currency": 12000.0, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_tcv": null, "hs_time_in_66894120": null, "hs_time_in_9567448": null, "hs_time_in_9567449": null, "hs_time_in_appointmentscheduled": 95654602279, "hs_time_in_closedlost": null, "hs_time_in_closedwon": null, "hs_time_in_contractsent": null, "hs_time_in_customclosedwonstage": null, "hs_time_in_decisionmakerboughtin": null, "hs_time_in_presentationscheduled": null, "hs_time_in_qualifiedtobuy": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2021-01-13T10:31:51.154000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_contacts": 0, "num_contacted_notes": null, "num_notes": null, "pipeline": "default"}, "createdAt": "2021-01-13T10:31:51.154Z", "updatedAt": "2024-01-21T02:48:34.022Z", "archived": false, "properties_amount": 60000, "properties_amount_in_home_currency": 60000, "properties_closed_lost_reason": null, "properties_closed_won_reason": null, "properties_closedate": "2014-08-31T00:00:00+00:00", "properties_createdate": "2021-01-13T10:31:51.154000+00:00", "properties_days_to_close": 0, "properties_dealname": "Tim's Newer Deal", "properties_dealstage": "appointmentscheduled", "properties_dealtype": "newbusiness", "properties_description": null, "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_hs_acv": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_collaborator_owner_ids": null, "properties_hs_all_deal_split_owner_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_latest_source": null, "properties_hs_analytics_latest_source_company": null, "properties_hs_analytics_latest_source_contact": null, "properties_hs_analytics_latest_source_data_1": null, "properties_hs_analytics_latest_source_data_1_company": null, "properties_hs_analytics_latest_source_data_1_contact": null, "properties_hs_analytics_latest_source_data_2": null, "properties_hs_analytics_latest_source_data_2_company": null, "properties_hs_analytics_latest_source_data_2_contact": null, "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_latest_source_timestamp_company": null, "properties_hs_analytics_latest_source_timestamp_contact": null, "properties_hs_analytics_source": null, "properties_hs_analytics_source_data_1": null, "properties_hs_analytics_source_data_2": null, "properties_hs_arr": null, "properties_hs_campaign": null, "properties_hs_closed_amount": 0, "properties_hs_closed_amount_in_home_currency": 0, "properties_hs_closed_won_count": null, "properties_hs_closed_won_date": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-13T10:31:51.154000+00:00", "properties_hs_date_entered_66894120": null, "properties_hs_date_entered_9567448": null, "properties_hs_date_entered_9567449": null, "properties_hs_date_entered_appointmentscheduled": "2021-01-13T10:31:51.154000+00:00", "properties_hs_date_entered_closedlost": null, "properties_hs_date_entered_closedwon": null, "properties_hs_date_entered_contractsent": null, "properties_hs_date_entered_customclosedwonstage": null, "properties_hs_date_entered_decisionmakerboughtin": null, "properties_hs_date_entered_presentationscheduled": null, "properties_hs_date_entered_qualifiedtobuy": null, "properties_hs_date_exited_66894120": null, "properties_hs_date_exited_9567448": null, "properties_hs_date_exited_9567449": null, "properties_hs_date_exited_appointmentscheduled": null, "properties_hs_date_exited_closedlost": null, "properties_hs_date_exited_closedwon": null, "properties_hs_date_exited_contractsent": null, "properties_hs_date_exited_customclosedwonstage": null, "properties_hs_date_exited_decisionmakerboughtin": null, "properties_hs_date_exited_presentationscheduled": null, "properties_hs_date_exited_qualifiedtobuy": null, "properties_hs_days_to_close_raw": 0, "properties_hs_deal_amount_calculation_preference": null, "properties_hs_deal_stage_probability": 0.2, "properties_hs_deal_stage_probability_shadow": null, "properties_hs_exchange_rate": null, "properties_hs_forecast_amount": 60000, "properties_hs_forecast_probability": null, "properties_hs_is_closed": false, "properties_hs_is_closed_won": false, "properties_hs_is_deal_split": false, "properties_hs_is_open_count": 1, "properties_hs_lastmodifieddate": "2024-01-21T02:48:34.022000+00:00", "properties_hs_latest_meeting_activity": null, "properties_hs_likelihood_to_close": null, "properties_hs_line_item_global_term_hs_discount_percentage": null, "properties_hs_line_item_global_term_hs_discount_percentage_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_period": null, "properties_hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "properties_hs_line_item_global_term_recurringbillingfrequency": null, "properties_hs_line_item_global_term_recurringbillingfrequency_enabled": null, "properties_hs_manual_forecast_category": null, "properties_hs_merged_object_ids": null, "properties_hs_mrr": null, "properties_hs_next_step": null, "properties_hs_num_associated_deal_splits": null, "properties_hs_num_of_associated_line_items": 0, "properties_hs_num_target_accounts": null, "properties_hs_object_id": 3980673856, "properties_hs_object_source": "API", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_predicted_amount": null, "properties_hs_predicted_amount_in_home_currency": null, "properties_hs_priority": null, "properties_hs_projected_amount": 12000.0, "properties_hs_projected_amount_in_home_currency": 12000.0, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_tcv": null, "properties_hs_time_in_66894120": null, "properties_hs_time_in_9567448": null, "properties_hs_time_in_9567449": null, "properties_hs_time_in_appointmentscheduled": 95654602279, "properties_hs_time_in_closedlost": null, "properties_hs_time_in_closedwon": null, "properties_hs_time_in_contractsent": null, "properties_hs_time_in_customclosedwonstage": null, "properties_hs_time_in_decisionmakerboughtin": null, "properties_hs_time_in_presentationscheduled": null, "properties_hs_time_in_qualifiedtobuy": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2021-01-13T10:31:51.154000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_pipeline": "default"}, "emitted_at": 1706188513543} -{"stream": "deals", "data": {"id": "3986867076", "properties": {"amount": 6, "amount_in_home_currency": 6, "closed_lost_reason": null, "closed_won_reason": null, "closedate": "2014-08-31T00:00:00+00:00", "createdate": "2021-01-14T14:38:00.797000+00:00", "days_to_close": 0, "dealname": "Test Deal 2", "dealstage": "appointmentscheduled", "dealtype": "newbusiness", "description": null, "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "hs_acv": null, "hs_all_accessible_team_ids": null, "hs_all_collaborator_owner_ids": null, "hs_all_deal_split_owner_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_latest_source": null, "hs_analytics_latest_source_company": null, "hs_analytics_latest_source_contact": null, "hs_analytics_latest_source_data_1": null, "hs_analytics_latest_source_data_1_company": null, "hs_analytics_latest_source_data_1_contact": null, "hs_analytics_latest_source_data_2": null, "hs_analytics_latest_source_data_2_company": null, "hs_analytics_latest_source_data_2_contact": null, "hs_analytics_latest_source_timestamp": null, "hs_analytics_latest_source_timestamp_company": null, "hs_analytics_latest_source_timestamp_contact": null, "hs_analytics_source": null, "hs_analytics_source_data_1": null, "hs_analytics_source_data_2": null, "hs_arr": null, "hs_campaign": null, "hs_closed_amount": 0, "hs_closed_amount_in_home_currency": 0, "hs_closed_won_count": null, "hs_closed_won_date": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-14T14:38:00.797000+00:00", "hs_date_entered_66894120": null, "hs_date_entered_9567448": null, "hs_date_entered_9567449": null, "hs_date_entered_appointmentscheduled": "2021-01-14T14:38:00.797000+00:00", "hs_date_entered_closedlost": null, "hs_date_entered_closedwon": null, "hs_date_entered_contractsent": null, "hs_date_entered_customclosedwonstage": null, "hs_date_entered_decisionmakerboughtin": null, "hs_date_entered_presentationscheduled": null, "hs_date_entered_qualifiedtobuy": null, "hs_date_exited_66894120": null, "hs_date_exited_9567448": null, "hs_date_exited_9567449": null, "hs_date_exited_appointmentscheduled": null, "hs_date_exited_closedlost": null, "hs_date_exited_closedwon": null, "hs_date_exited_contractsent": null, "hs_date_exited_customclosedwonstage": null, "hs_date_exited_decisionmakerboughtin": null, "hs_date_exited_presentationscheduled": null, "hs_date_exited_qualifiedtobuy": null, "hs_days_to_close_raw": 0, "hs_deal_amount_calculation_preference": null, "hs_deal_stage_probability": 0.2, "hs_deal_stage_probability_shadow": null, "hs_exchange_rate": null, "hs_forecast_amount": 6, "hs_forecast_probability": null, "hs_is_closed": false, "hs_is_closed_won": false, "hs_is_deal_split": false, "hs_is_open_count": 1, "hs_lastmodifieddate": "2024-01-20T00:59:40.882000+00:00", "hs_latest_meeting_activity": null, "hs_likelihood_to_close": null, "hs_line_item_global_term_hs_discount_percentage": null, "hs_line_item_global_term_hs_discount_percentage_enabled": null, "hs_line_item_global_term_hs_recurring_billing_period": null, "hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "hs_line_item_global_term_hs_recurring_billing_start_date": null, "hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "hs_line_item_global_term_recurringbillingfrequency": null, "hs_line_item_global_term_recurringbillingfrequency_enabled": null, "hs_manual_forecast_category": null, "hs_merged_object_ids": null, "hs_mrr": null, "hs_next_step": null, "hs_num_associated_deal_splits": null, "hs_num_of_associated_line_items": 0, "hs_num_target_accounts": 0, "hs_object_id": 3986867076, "hs_object_source": "API", "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_pinned_engagement_id": null, "hs_predicted_amount": null, "hs_predicted_amount_in_home_currency": null, "hs_priority": null, "hs_projected_amount": 1.2000000000000002, "hs_projected_amount_in_home_currency": 1.2000000000000002, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_tcv": null, "hs_time_in_66894120": null, "hs_time_in_9567448": null, "hs_time_in_9567449": null, "hs_time_in_appointmentscheduled": 95553432636, "hs_time_in_closedlost": null, "hs_time_in_closedwon": null, "hs_time_in_contractsent": null, "hs_time_in_customclosedwonstage": null, "hs_time_in_decisionmakerboughtin": null, "hs_time_in_presentationscheduled": null, "hs_time_in_qualifiedtobuy": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2021-01-14T14:38:00.797000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_contacts": 0, "num_contacted_notes": null, "num_notes": null, "pipeline": "default"}, "createdAt": "2021-01-14T14:38:00.797Z", "updatedAt": "2024-01-20T00:59:40.882Z", "archived": false, "companies": ["5183409178", "5183409178"], "properties_amount": 6, "properties_amount_in_home_currency": 6, "properties_closed_lost_reason": null, "properties_closed_won_reason": null, "properties_closedate": "2014-08-31T00:00:00+00:00", "properties_createdate": "2021-01-14T14:38:00.797000+00:00", "properties_days_to_close": 0, "properties_dealname": "Test Deal 2", "properties_dealstage": "appointmentscheduled", "properties_dealtype": "newbusiness", "properties_description": null, "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_hs_acv": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_collaborator_owner_ids": null, "properties_hs_all_deal_split_owner_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_latest_source": null, "properties_hs_analytics_latest_source_company": null, "properties_hs_analytics_latest_source_contact": null, "properties_hs_analytics_latest_source_data_1": null, "properties_hs_analytics_latest_source_data_1_company": null, "properties_hs_analytics_latest_source_data_1_contact": null, "properties_hs_analytics_latest_source_data_2": null, "properties_hs_analytics_latest_source_data_2_company": null, "properties_hs_analytics_latest_source_data_2_contact": null, "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_latest_source_timestamp_company": null, "properties_hs_analytics_latest_source_timestamp_contact": null, "properties_hs_analytics_source": null, "properties_hs_analytics_source_data_1": null, "properties_hs_analytics_source_data_2": null, "properties_hs_arr": null, "properties_hs_campaign": null, "properties_hs_closed_amount": 0, "properties_hs_closed_amount_in_home_currency": 0, "properties_hs_closed_won_count": null, "properties_hs_closed_won_date": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-14T14:38:00.797000+00:00", "properties_hs_date_entered_66894120": null, "properties_hs_date_entered_9567448": null, "properties_hs_date_entered_9567449": null, "properties_hs_date_entered_appointmentscheduled": "2021-01-14T14:38:00.797000+00:00", "properties_hs_date_entered_closedlost": null, "properties_hs_date_entered_closedwon": null, "properties_hs_date_entered_contractsent": null, "properties_hs_date_entered_customclosedwonstage": null, "properties_hs_date_entered_decisionmakerboughtin": null, "properties_hs_date_entered_presentationscheduled": null, "properties_hs_date_entered_qualifiedtobuy": null, "properties_hs_date_exited_66894120": null, "properties_hs_date_exited_9567448": null, "properties_hs_date_exited_9567449": null, "properties_hs_date_exited_appointmentscheduled": null, "properties_hs_date_exited_closedlost": null, "properties_hs_date_exited_closedwon": null, "properties_hs_date_exited_contractsent": null, "properties_hs_date_exited_customclosedwonstage": null, "properties_hs_date_exited_decisionmakerboughtin": null, "properties_hs_date_exited_presentationscheduled": null, "properties_hs_date_exited_qualifiedtobuy": null, "properties_hs_days_to_close_raw": 0, "properties_hs_deal_amount_calculation_preference": null, "properties_hs_deal_stage_probability": 0.2, "properties_hs_deal_stage_probability_shadow": null, "properties_hs_exchange_rate": null, "properties_hs_forecast_amount": 6, "properties_hs_forecast_probability": null, "properties_hs_is_closed": false, "properties_hs_is_closed_won": false, "properties_hs_is_deal_split": false, "properties_hs_is_open_count": 1, "properties_hs_lastmodifieddate": "2024-01-20T00:59:40.882000+00:00", "properties_hs_latest_meeting_activity": null, "properties_hs_likelihood_to_close": null, "properties_hs_line_item_global_term_hs_discount_percentage": null, "properties_hs_line_item_global_term_hs_discount_percentage_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_period": null, "properties_hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "properties_hs_line_item_global_term_recurringbillingfrequency": null, "properties_hs_line_item_global_term_recurringbillingfrequency_enabled": null, "properties_hs_manual_forecast_category": null, "properties_hs_merged_object_ids": null, "properties_hs_mrr": null, "properties_hs_next_step": null, "properties_hs_num_associated_deal_splits": null, "properties_hs_num_of_associated_line_items": 0, "properties_hs_num_target_accounts": 0, "properties_hs_object_id": 3986867076, "properties_hs_object_source": "API", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_predicted_amount": null, "properties_hs_predicted_amount_in_home_currency": null, "properties_hs_priority": null, "properties_hs_projected_amount": 1.2000000000000002, "properties_hs_projected_amount_in_home_currency": 1.2000000000000002, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_tcv": null, "properties_hs_time_in_66894120": null, "properties_hs_time_in_9567448": null, "properties_hs_time_in_9567449": null, "properties_hs_time_in_appointmentscheduled": 95553432636, "properties_hs_time_in_closedlost": null, "properties_hs_time_in_closedwon": null, "properties_hs_time_in_contractsent": null, "properties_hs_time_in_customclosedwonstage": null, "properties_hs_time_in_decisionmakerboughtin": null, "properties_hs_time_in_presentationscheduled": null, "properties_hs_time_in_qualifiedtobuy": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2021-01-14T14:38:00.797000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_pipeline": "default"}, "emitted_at": 1706188513544} +{"stream": "deals", "data": {"id": "3980651569", "properties": {"amount": 60000, "amount_in_home_currency": 60000, "closed_lost_reason": null, "closed_won_reason": null, "closedate": "2014-08-31T00:00:00+00:00", "createdate": "2021-01-13T10:30:42.221000+00:00", "days_to_close": 0, "dealname": "Tim's Newer Deal", "dealstage": "appointmentscheduled", "dealtype": "newbusiness", "description": null, "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "hs_acv": null, "hs_all_accessible_team_ids": null, "hs_all_collaborator_owner_ids": null, "hs_all_deal_split_owner_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_latest_source": "OFFLINE", "hs_analytics_latest_source_company": "OFFLINE", "hs_analytics_latest_source_contact": null, "hs_analytics_latest_source_data_1": "CONTACTS", "hs_analytics_latest_source_data_1_company": "CONTACTS", "hs_analytics_latest_source_data_1_contact": null, "hs_analytics_latest_source_data_2": "CRM_UI", "hs_analytics_latest_source_data_2_company": "CRM_UI", "hs_analytics_latest_source_data_2_contact": null, "hs_analytics_latest_source_timestamp": null, "hs_analytics_latest_source_timestamp_company": null, "hs_analytics_latest_source_timestamp_contact": null, "hs_analytics_source": "OFFLINE", "hs_analytics_source_data_1": "CONTACTS", "hs_analytics_source_data_2": "CRM_UI", "hs_arr": null, "hs_campaign": null, "hs_closed_amount": 0, "hs_closed_amount_in_home_currency": 0, "hs_closed_won_count": null, "hs_closed_won_date": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-13T10:30:42.221000+00:00", "hs_date_entered_66894120": null, "hs_date_entered_9567448": null, "hs_date_entered_9567449": null, "hs_date_entered_appointmentscheduled": "2021-01-13T10:30:42.221000+00:00", "hs_date_entered_closedlost": null, "hs_date_entered_closedwon": null, "hs_date_entered_contractsent": null, "hs_date_entered_customclosedwonstage": null, "hs_date_entered_decisionmakerboughtin": null, "hs_date_entered_presentationscheduled": null, "hs_date_entered_qualifiedtobuy": null, "hs_date_exited_66894120": null, "hs_date_exited_9567448": null, "hs_date_exited_9567449": null, "hs_date_exited_appointmentscheduled": null, "hs_date_exited_closedlost": null, "hs_date_exited_closedwon": null, "hs_date_exited_contractsent": null, "hs_date_exited_customclosedwonstage": null, "hs_date_exited_decisionmakerboughtin": null, "hs_date_exited_presentationscheduled": null, "hs_date_exited_qualifiedtobuy": null, "hs_days_to_close_raw": 0, "hs_deal_amount_calculation_preference": null, "hs_deal_stage_probability": 0.2, "hs_deal_stage_probability_shadow": null, "hs_exchange_rate": null, "hs_forecast_amount": 60000, "hs_forecast_probability": null, "hs_is_closed": false, "hs_is_closed_won": false, "hs_is_deal_split": false, "hs_is_open_count": 1, "hs_lastmodifieddate": "2024-01-21T22:30:34.782000+00:00", "hs_latest_meeting_activity": null, "hs_likelihood_to_close": null, "hs_line_item_global_term_hs_discount_percentage": null, "hs_line_item_global_term_hs_discount_percentage_enabled": null, "hs_line_item_global_term_hs_recurring_billing_period": null, "hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "hs_line_item_global_term_hs_recurring_billing_start_date": null, "hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "hs_line_item_global_term_recurringbillingfrequency": null, "hs_line_item_global_term_recurringbillingfrequency_enabled": null, "hs_manual_forecast_category": null, "hs_merged_object_ids": null, "hs_mrr": null, "hs_next_step": null, "hs_num_associated_deal_splits": null, "hs_num_of_associated_line_items": 0, "hs_num_target_accounts": 0, "hs_object_id": 3980651569, "hs_object_source": "API", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_pinned_engagement_id": null, "hs_predicted_amount": null, "hs_predicted_amount_in_home_currency": null, "hs_priority": null, "hs_projected_amount": 12000.0, "hs_projected_amount_in_home_currency": 12000.0, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_tcv": null, "hs_time_in_66894120": null, "hs_time_in_9567448": null, "hs_time_in_9567449": null, "hs_time_in_appointmentscheduled": 97479374284, "hs_time_in_closedlost": null, "hs_time_in_closedwon": null, "hs_time_in_contractsent": null, "hs_time_in_customclosedwonstage": null, "hs_time_in_decisionmakerboughtin": null, "hs_time_in_presentationscheduled": null, "hs_time_in_qualifiedtobuy": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2021-01-13T10:30:42.221000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_contacts": 0, "num_contacted_notes": null, "num_notes": null, "pipeline": "default"}, "createdAt": "2021-01-13T10:30:42.221Z", "updatedAt": "2024-01-21T22:30:34.782Z", "archived": false, "companies": ["5000526215", "5000526215"], "properties_amount": 60000, "properties_amount_in_home_currency": 60000, "properties_closed_lost_reason": null, "properties_closed_won_reason": null, "properties_closedate": "2014-08-31T00:00:00+00:00", "properties_createdate": "2021-01-13T10:30:42.221000+00:00", "properties_days_to_close": 0, "properties_dealname": "Tim's Newer Deal", "properties_dealstage": "appointmentscheduled", "properties_dealtype": "newbusiness", "properties_description": null, "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_hs_acv": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_collaborator_owner_ids": null, "properties_hs_all_deal_split_owner_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_latest_source": "OFFLINE", "properties_hs_analytics_latest_source_company": "OFFLINE", "properties_hs_analytics_latest_source_contact": null, "properties_hs_analytics_latest_source_data_1": "CONTACTS", "properties_hs_analytics_latest_source_data_1_company": "CONTACTS", "properties_hs_analytics_latest_source_data_1_contact": null, "properties_hs_analytics_latest_source_data_2": "CRM_UI", "properties_hs_analytics_latest_source_data_2_company": "CRM_UI", "properties_hs_analytics_latest_source_data_2_contact": null, "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_latest_source_timestamp_company": null, "properties_hs_analytics_latest_source_timestamp_contact": null, "properties_hs_analytics_source": "OFFLINE", "properties_hs_analytics_source_data_1": "CONTACTS", "properties_hs_analytics_source_data_2": "CRM_UI", "properties_hs_arr": null, "properties_hs_campaign": null, "properties_hs_closed_amount": 0, "properties_hs_closed_amount_in_home_currency": 0, "properties_hs_closed_won_count": null, "properties_hs_closed_won_date": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-13T10:30:42.221000+00:00", "properties_hs_date_entered_66894120": null, "properties_hs_date_entered_9567448": null, "properties_hs_date_entered_9567449": null, "properties_hs_date_entered_appointmentscheduled": "2021-01-13T10:30:42.221000+00:00", "properties_hs_date_entered_closedlost": null, "properties_hs_date_entered_closedwon": null, "properties_hs_date_entered_contractsent": null, "properties_hs_date_entered_customclosedwonstage": null, "properties_hs_date_entered_decisionmakerboughtin": null, "properties_hs_date_entered_presentationscheduled": null, "properties_hs_date_entered_qualifiedtobuy": null, "properties_hs_date_exited_66894120": null, "properties_hs_date_exited_9567448": null, "properties_hs_date_exited_9567449": null, "properties_hs_date_exited_appointmentscheduled": null, "properties_hs_date_exited_closedlost": null, "properties_hs_date_exited_closedwon": null, "properties_hs_date_exited_contractsent": null, "properties_hs_date_exited_customclosedwonstage": null, "properties_hs_date_exited_decisionmakerboughtin": null, "properties_hs_date_exited_presentationscheduled": null, "properties_hs_date_exited_qualifiedtobuy": null, "properties_hs_days_to_close_raw": 0, "properties_hs_deal_amount_calculation_preference": null, "properties_hs_deal_stage_probability": 0.2, "properties_hs_deal_stage_probability_shadow": null, "properties_hs_exchange_rate": null, "properties_hs_forecast_amount": 60000, "properties_hs_forecast_probability": null, "properties_hs_is_closed": false, "properties_hs_is_closed_won": false, "properties_hs_is_deal_split": false, "properties_hs_is_open_count": 1, "properties_hs_lastmodifieddate": "2024-01-21T22:30:34.782000+00:00", "properties_hs_latest_meeting_activity": null, "properties_hs_likelihood_to_close": null, "properties_hs_line_item_global_term_hs_discount_percentage": null, "properties_hs_line_item_global_term_hs_discount_percentage_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_period": null, "properties_hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "properties_hs_line_item_global_term_recurringbillingfrequency": null, "properties_hs_line_item_global_term_recurringbillingfrequency_enabled": null, "properties_hs_manual_forecast_category": null, "properties_hs_merged_object_ids": null, "properties_hs_mrr": null, "properties_hs_next_step": null, "properties_hs_num_associated_deal_splits": null, "properties_hs_num_of_associated_line_items": 0, "properties_hs_num_target_accounts": 0, "properties_hs_object_id": 3980651569, "properties_hs_object_source": "API", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_predicted_amount": null, "properties_hs_predicted_amount_in_home_currency": null, "properties_hs_priority": null, "properties_hs_projected_amount": 12000.0, "properties_hs_projected_amount_in_home_currency": 12000.0, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_tcv": null, "properties_hs_time_in_66894120": null, "properties_hs_time_in_9567448": null, "properties_hs_time_in_9567449": null, "properties_hs_time_in_appointmentscheduled": 97479374284, "properties_hs_time_in_closedlost": null, "properties_hs_time_in_closedwon": null, "properties_hs_time_in_contractsent": null, "properties_hs_time_in_customclosedwonstage": null, "properties_hs_time_in_decisionmakerboughtin": null, "properties_hs_time_in_presentationscheduled": null, "properties_hs_time_in_qualifiedtobuy": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2021-01-13T10:30:42.221000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_pipeline": "default"}, "emitted_at": 1708013216666} +{"stream": "deals", "data": {"id": "3980673856", "properties": {"amount": 60000, "amount_in_home_currency": 60000, "closed_lost_reason": null, "closed_won_reason": null, "closedate": "2014-08-31T00:00:00+00:00", "createdate": "2021-01-13T10:31:51.154000+00:00", "days_to_close": 0, "dealname": "Tim's Newer Deal", "dealstage": "appointmentscheduled", "dealtype": "newbusiness", "description": null, "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "hs_acv": null, "hs_all_accessible_team_ids": null, "hs_all_collaborator_owner_ids": null, "hs_all_deal_split_owner_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_latest_source": null, "hs_analytics_latest_source_company": null, "hs_analytics_latest_source_contact": null, "hs_analytics_latest_source_data_1": null, "hs_analytics_latest_source_data_1_company": null, "hs_analytics_latest_source_data_1_contact": null, "hs_analytics_latest_source_data_2": null, "hs_analytics_latest_source_data_2_company": null, "hs_analytics_latest_source_data_2_contact": null, "hs_analytics_latest_source_timestamp": null, "hs_analytics_latest_source_timestamp_company": null, "hs_analytics_latest_source_timestamp_contact": null, "hs_analytics_source": null, "hs_analytics_source_data_1": null, "hs_analytics_source_data_2": null, "hs_arr": null, "hs_campaign": null, "hs_closed_amount": 0, "hs_closed_amount_in_home_currency": 0, "hs_closed_won_count": null, "hs_closed_won_date": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-13T10:31:51.154000+00:00", "hs_date_entered_66894120": null, "hs_date_entered_9567448": null, "hs_date_entered_9567449": null, "hs_date_entered_appointmentscheduled": "2021-01-13T10:31:51.154000+00:00", "hs_date_entered_closedlost": null, "hs_date_entered_closedwon": null, "hs_date_entered_contractsent": null, "hs_date_entered_customclosedwonstage": null, "hs_date_entered_decisionmakerboughtin": null, "hs_date_entered_presentationscheduled": null, "hs_date_entered_qualifiedtobuy": null, "hs_date_exited_66894120": null, "hs_date_exited_9567448": null, "hs_date_exited_9567449": null, "hs_date_exited_appointmentscheduled": null, "hs_date_exited_closedlost": null, "hs_date_exited_closedwon": null, "hs_date_exited_contractsent": null, "hs_date_exited_customclosedwonstage": null, "hs_date_exited_decisionmakerboughtin": null, "hs_date_exited_presentationscheduled": null, "hs_date_exited_qualifiedtobuy": null, "hs_days_to_close_raw": 0, "hs_deal_amount_calculation_preference": null, "hs_deal_stage_probability": 0.2, "hs_deal_stage_probability_shadow": null, "hs_exchange_rate": null, "hs_forecast_amount": 60000, "hs_forecast_probability": null, "hs_is_closed": false, "hs_is_closed_won": false, "hs_is_deal_split": false, "hs_is_open_count": 1, "hs_lastmodifieddate": "2024-01-21T02:48:34.022000+00:00", "hs_latest_meeting_activity": null, "hs_likelihood_to_close": null, "hs_line_item_global_term_hs_discount_percentage": null, "hs_line_item_global_term_hs_discount_percentage_enabled": null, "hs_line_item_global_term_hs_recurring_billing_period": null, "hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "hs_line_item_global_term_hs_recurring_billing_start_date": null, "hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "hs_line_item_global_term_recurringbillingfrequency": null, "hs_line_item_global_term_recurringbillingfrequency_enabled": null, "hs_manual_forecast_category": null, "hs_merged_object_ids": null, "hs_mrr": null, "hs_next_step": null, "hs_num_associated_deal_splits": null, "hs_num_of_associated_line_items": 0, "hs_num_target_accounts": null, "hs_object_id": 3980673856, "hs_object_source": "API", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_pinned_engagement_id": null, "hs_predicted_amount": null, "hs_predicted_amount_in_home_currency": null, "hs_priority": null, "hs_projected_amount": 12000.0, "hs_projected_amount_in_home_currency": 12000.0, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_tcv": null, "hs_time_in_66894120": null, "hs_time_in_9567448": null, "hs_time_in_9567449": null, "hs_time_in_appointmentscheduled": 97479305351, "hs_time_in_closedlost": null, "hs_time_in_closedwon": null, "hs_time_in_contractsent": null, "hs_time_in_customclosedwonstage": null, "hs_time_in_decisionmakerboughtin": null, "hs_time_in_presentationscheduled": null, "hs_time_in_qualifiedtobuy": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2021-01-13T10:31:51.154000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_contacts": 0, "num_contacted_notes": null, "num_notes": null, "pipeline": "default"}, "createdAt": "2021-01-13T10:31:51.154Z", "updatedAt": "2024-01-21T02:48:34.022Z", "archived": false, "properties_amount": 60000, "properties_amount_in_home_currency": 60000, "properties_closed_lost_reason": null, "properties_closed_won_reason": null, "properties_closedate": "2014-08-31T00:00:00+00:00", "properties_createdate": "2021-01-13T10:31:51.154000+00:00", "properties_days_to_close": 0, "properties_dealname": "Tim's Newer Deal", "properties_dealstage": "appointmentscheduled", "properties_dealtype": "newbusiness", "properties_description": null, "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_hs_acv": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_collaborator_owner_ids": null, "properties_hs_all_deal_split_owner_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_latest_source": null, "properties_hs_analytics_latest_source_company": null, "properties_hs_analytics_latest_source_contact": null, "properties_hs_analytics_latest_source_data_1": null, "properties_hs_analytics_latest_source_data_1_company": null, "properties_hs_analytics_latest_source_data_1_contact": null, "properties_hs_analytics_latest_source_data_2": null, "properties_hs_analytics_latest_source_data_2_company": null, "properties_hs_analytics_latest_source_data_2_contact": null, "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_latest_source_timestamp_company": null, "properties_hs_analytics_latest_source_timestamp_contact": null, "properties_hs_analytics_source": null, "properties_hs_analytics_source_data_1": null, "properties_hs_analytics_source_data_2": null, "properties_hs_arr": null, "properties_hs_campaign": null, "properties_hs_closed_amount": 0, "properties_hs_closed_amount_in_home_currency": 0, "properties_hs_closed_won_count": null, "properties_hs_closed_won_date": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-13T10:31:51.154000+00:00", "properties_hs_date_entered_66894120": null, "properties_hs_date_entered_9567448": null, "properties_hs_date_entered_9567449": null, "properties_hs_date_entered_appointmentscheduled": "2021-01-13T10:31:51.154000+00:00", "properties_hs_date_entered_closedlost": null, "properties_hs_date_entered_closedwon": null, "properties_hs_date_entered_contractsent": null, "properties_hs_date_entered_customclosedwonstage": null, "properties_hs_date_entered_decisionmakerboughtin": null, "properties_hs_date_entered_presentationscheduled": null, "properties_hs_date_entered_qualifiedtobuy": null, "properties_hs_date_exited_66894120": null, "properties_hs_date_exited_9567448": null, "properties_hs_date_exited_9567449": null, "properties_hs_date_exited_appointmentscheduled": null, "properties_hs_date_exited_closedlost": null, "properties_hs_date_exited_closedwon": null, "properties_hs_date_exited_contractsent": null, "properties_hs_date_exited_customclosedwonstage": null, "properties_hs_date_exited_decisionmakerboughtin": null, "properties_hs_date_exited_presentationscheduled": null, "properties_hs_date_exited_qualifiedtobuy": null, "properties_hs_days_to_close_raw": 0, "properties_hs_deal_amount_calculation_preference": null, "properties_hs_deal_stage_probability": 0.2, "properties_hs_deal_stage_probability_shadow": null, "properties_hs_exchange_rate": null, "properties_hs_forecast_amount": 60000, "properties_hs_forecast_probability": null, "properties_hs_is_closed": false, "properties_hs_is_closed_won": false, "properties_hs_is_deal_split": false, "properties_hs_is_open_count": 1, "properties_hs_lastmodifieddate": "2024-01-21T02:48:34.022000+00:00", "properties_hs_latest_meeting_activity": null, "properties_hs_likelihood_to_close": null, "properties_hs_line_item_global_term_hs_discount_percentage": null, "properties_hs_line_item_global_term_hs_discount_percentage_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_period": null, "properties_hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "properties_hs_line_item_global_term_recurringbillingfrequency": null, "properties_hs_line_item_global_term_recurringbillingfrequency_enabled": null, "properties_hs_manual_forecast_category": null, "properties_hs_merged_object_ids": null, "properties_hs_mrr": null, "properties_hs_next_step": null, "properties_hs_num_associated_deal_splits": null, "properties_hs_num_of_associated_line_items": 0, "properties_hs_num_target_accounts": null, "properties_hs_object_id": 3980673856, "properties_hs_object_source": "API", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_predicted_amount": null, "properties_hs_predicted_amount_in_home_currency": null, "properties_hs_priority": null, "properties_hs_projected_amount": 12000.0, "properties_hs_projected_amount_in_home_currency": 12000.0, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_tcv": null, "properties_hs_time_in_66894120": null, "properties_hs_time_in_9567448": null, "properties_hs_time_in_9567449": null, "properties_hs_time_in_appointmentscheduled": 97479305351, "properties_hs_time_in_closedlost": null, "properties_hs_time_in_closedwon": null, "properties_hs_time_in_contractsent": null, "properties_hs_time_in_customclosedwonstage": null, "properties_hs_time_in_decisionmakerboughtin": null, "properties_hs_time_in_presentationscheduled": null, "properties_hs_time_in_qualifiedtobuy": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2021-01-13T10:31:51.154000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_pipeline": "default"}, "emitted_at": 1708013216668} +{"stream": "deals", "data": {"id": "3986867076", "properties": {"amount": 6, "amount_in_home_currency": 6, "closed_lost_reason": null, "closed_won_reason": null, "closedate": "2014-08-31T00:00:00+00:00", "createdate": "2021-01-14T14:38:00.797000+00:00", "days_to_close": 0, "dealname": "Test Deal 2", "dealstage": "appointmentscheduled", "dealtype": "newbusiness", "description": null, "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "hs_acv": null, "hs_all_accessible_team_ids": null, "hs_all_collaborator_owner_ids": null, "hs_all_deal_split_owner_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_latest_source": null, "hs_analytics_latest_source_company": null, "hs_analytics_latest_source_contact": null, "hs_analytics_latest_source_data_1": null, "hs_analytics_latest_source_data_1_company": null, "hs_analytics_latest_source_data_1_contact": null, "hs_analytics_latest_source_data_2": null, "hs_analytics_latest_source_data_2_company": null, "hs_analytics_latest_source_data_2_contact": null, "hs_analytics_latest_source_timestamp": null, "hs_analytics_latest_source_timestamp_company": null, "hs_analytics_latest_source_timestamp_contact": null, "hs_analytics_source": null, "hs_analytics_source_data_1": null, "hs_analytics_source_data_2": null, "hs_arr": null, "hs_campaign": null, "hs_closed_amount": 0, "hs_closed_amount_in_home_currency": 0, "hs_closed_won_count": null, "hs_closed_won_date": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-14T14:38:00.797000+00:00", "hs_date_entered_66894120": null, "hs_date_entered_9567448": null, "hs_date_entered_9567449": null, "hs_date_entered_appointmentscheduled": "2021-01-14T14:38:00.797000+00:00", "hs_date_entered_closedlost": null, "hs_date_entered_closedwon": null, "hs_date_entered_contractsent": null, "hs_date_entered_customclosedwonstage": null, "hs_date_entered_decisionmakerboughtin": null, "hs_date_entered_presentationscheduled": null, "hs_date_entered_qualifiedtobuy": null, "hs_date_exited_66894120": null, "hs_date_exited_9567448": null, "hs_date_exited_9567449": null, "hs_date_exited_appointmentscheduled": null, "hs_date_exited_closedlost": null, "hs_date_exited_closedwon": null, "hs_date_exited_contractsent": null, "hs_date_exited_customclosedwonstage": null, "hs_date_exited_decisionmakerboughtin": null, "hs_date_exited_presentationscheduled": null, "hs_date_exited_qualifiedtobuy": null, "hs_days_to_close_raw": 0, "hs_deal_amount_calculation_preference": null, "hs_deal_stage_probability": 0.2, "hs_deal_stage_probability_shadow": null, "hs_exchange_rate": null, "hs_forecast_amount": 6, "hs_forecast_probability": null, "hs_is_closed": false, "hs_is_closed_won": false, "hs_is_deal_split": false, "hs_is_open_count": 1, "hs_lastmodifieddate": "2024-01-20T00:59:40.882000+00:00", "hs_latest_meeting_activity": null, "hs_likelihood_to_close": null, "hs_line_item_global_term_hs_discount_percentage": null, "hs_line_item_global_term_hs_discount_percentage_enabled": null, "hs_line_item_global_term_hs_recurring_billing_period": null, "hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "hs_line_item_global_term_hs_recurring_billing_start_date": null, "hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "hs_line_item_global_term_recurringbillingfrequency": null, "hs_line_item_global_term_recurringbillingfrequency_enabled": null, "hs_manual_forecast_category": null, "hs_merged_object_ids": null, "hs_mrr": null, "hs_next_step": null, "hs_num_associated_deal_splits": null, "hs_num_of_associated_line_items": 0, "hs_num_target_accounts": 0, "hs_object_id": 3986867076, "hs_object_source": "API", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_pinned_engagement_id": null, "hs_predicted_amount": null, "hs_predicted_amount_in_home_currency": null, "hs_priority": null, "hs_projected_amount": 1.2000000000000002, "hs_projected_amount_in_home_currency": 1.2000000000000002, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_tcv": null, "hs_time_in_66894120": null, "hs_time_in_9567448": null, "hs_time_in_9567449": null, "hs_time_in_appointmentscheduled": 97378135709, "hs_time_in_closedlost": null, "hs_time_in_closedwon": null, "hs_time_in_contractsent": null, "hs_time_in_customclosedwonstage": null, "hs_time_in_decisionmakerboughtin": null, "hs_time_in_presentationscheduled": null, "hs_time_in_qualifiedtobuy": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2021-01-14T14:38:00.797000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "num_associated_contacts": 0, "num_contacted_notes": null, "num_notes": null, "pipeline": "default"}, "createdAt": "2021-01-14T14:38:00.797Z", "updatedAt": "2024-01-20T00:59:40.882Z", "archived": false, "companies": ["5183409178", "5183409178"], "properties_amount": 6, "properties_amount_in_home_currency": 6, "properties_closed_lost_reason": null, "properties_closed_won_reason": null, "properties_closedate": "2014-08-31T00:00:00+00:00", "properties_createdate": "2021-01-14T14:38:00.797000+00:00", "properties_days_to_close": 0, "properties_dealname": "Test Deal 2", "properties_dealstage": "appointmentscheduled", "properties_dealtype": "newbusiness", "properties_description": null, "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_hs_acv": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_collaborator_owner_ids": null, "properties_hs_all_deal_split_owner_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_latest_source": null, "properties_hs_analytics_latest_source_company": null, "properties_hs_analytics_latest_source_contact": null, "properties_hs_analytics_latest_source_data_1": null, "properties_hs_analytics_latest_source_data_1_company": null, "properties_hs_analytics_latest_source_data_1_contact": null, "properties_hs_analytics_latest_source_data_2": null, "properties_hs_analytics_latest_source_data_2_company": null, "properties_hs_analytics_latest_source_data_2_contact": null, "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_latest_source_timestamp_company": null, "properties_hs_analytics_latest_source_timestamp_contact": null, "properties_hs_analytics_source": null, "properties_hs_analytics_source_data_1": null, "properties_hs_analytics_source_data_2": null, "properties_hs_arr": null, "properties_hs_campaign": null, "properties_hs_closed_amount": 0, "properties_hs_closed_amount_in_home_currency": 0, "properties_hs_closed_won_count": null, "properties_hs_closed_won_date": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-14T14:38:00.797000+00:00", "properties_hs_date_entered_66894120": null, "properties_hs_date_entered_9567448": null, "properties_hs_date_entered_9567449": null, "properties_hs_date_entered_appointmentscheduled": "2021-01-14T14:38:00.797000+00:00", "properties_hs_date_entered_closedlost": null, "properties_hs_date_entered_closedwon": null, "properties_hs_date_entered_contractsent": null, "properties_hs_date_entered_customclosedwonstage": null, "properties_hs_date_entered_decisionmakerboughtin": null, "properties_hs_date_entered_presentationscheduled": null, "properties_hs_date_entered_qualifiedtobuy": null, "properties_hs_date_exited_66894120": null, "properties_hs_date_exited_9567448": null, "properties_hs_date_exited_9567449": null, "properties_hs_date_exited_appointmentscheduled": null, "properties_hs_date_exited_closedlost": null, "properties_hs_date_exited_closedwon": null, "properties_hs_date_exited_contractsent": null, "properties_hs_date_exited_customclosedwonstage": null, "properties_hs_date_exited_decisionmakerboughtin": null, "properties_hs_date_exited_presentationscheduled": null, "properties_hs_date_exited_qualifiedtobuy": null, "properties_hs_days_to_close_raw": 0, "properties_hs_deal_amount_calculation_preference": null, "properties_hs_deal_stage_probability": 0.2, "properties_hs_deal_stage_probability_shadow": null, "properties_hs_exchange_rate": null, "properties_hs_forecast_amount": 6, "properties_hs_forecast_probability": null, "properties_hs_is_closed": false, "properties_hs_is_closed_won": false, "properties_hs_is_deal_split": false, "properties_hs_is_open_count": 1, "properties_hs_lastmodifieddate": "2024-01-20T00:59:40.882000+00:00", "properties_hs_latest_meeting_activity": null, "properties_hs_likelihood_to_close": null, "properties_hs_line_item_global_term_hs_discount_percentage": null, "properties_hs_line_item_global_term_hs_discount_percentage_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_period": null, "properties_hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "properties_hs_line_item_global_term_recurringbillingfrequency": null, "properties_hs_line_item_global_term_recurringbillingfrequency_enabled": null, "properties_hs_manual_forecast_category": null, "properties_hs_merged_object_ids": null, "properties_hs_mrr": null, "properties_hs_next_step": null, "properties_hs_num_associated_deal_splits": null, "properties_hs_num_of_associated_line_items": 0, "properties_hs_num_target_accounts": 0, "properties_hs_object_id": 3986867076, "properties_hs_object_source": "API", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_predicted_amount": null, "properties_hs_predicted_amount_in_home_currency": null, "properties_hs_priority": null, "properties_hs_projected_amount": 1.2000000000000002, "properties_hs_projected_amount_in_home_currency": 1.2000000000000002, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_tcv": null, "properties_hs_time_in_66894120": null, "properties_hs_time_in_9567448": null, "properties_hs_time_in_9567449": null, "properties_hs_time_in_appointmentscheduled": 97378135709, "properties_hs_time_in_closedlost": null, "properties_hs_time_in_closedwon": null, "properties_hs_time_in_contractsent": null, "properties_hs_time_in_customclosedwonstage": null, "properties_hs_time_in_decisionmakerboughtin": null, "properties_hs_time_in_presentationscheduled": null, "properties_hs_time_in_qualifiedtobuy": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2021-01-14T14:38:00.797000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_pipeline": "default"}, "emitted_at": 1708013216669} {"stream": "email_events", "data": {"appName": "BatchTest", "location": {"country": "Unknown", "state": "Unknown", "city": "Unknown", "zipcode": "Unknown"}, "id": "17d3fcc4-bc34-38b4-9103-69b5896bbdde", "duration": 0, "browser": {"name": "Google Image Cache", "family": "Google Image Cache", "producer": "", "producerUrl": "", "type": "Proxy", "url": "", "version": []}, "created": 1614191191202, "userAgent": "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via ggpht.com GoogleImageProxy)", "deviceType": "COMPUTER", "type": "OPEN", "recipient": "integration-test@airbyte.io", "portalId": 8727216, "sentBy": {"id": "dd239309-7866-4705-a3e9-c571dd349477", "created": 1614119023182}, "smtpId": null, "filteredEvent": false, "appId": 20053, "emailCampaignId": 2}, "emitted_at": 1697714199237} {"stream": "email_events", "data": {"appName": "BatchTest", "location": {"country": "Unknown", "state": "Unknown", "city": "Unknown", "zipcode": "Unknown"}, "id": "e5cbe134-db76-32cb-9e82-9dafcbaf8b64", "duration": 0, "browser": {"name": "Google Image Cache", "family": "Google Image Cache", "producer": "", "producerUrl": "", "type": "Proxy", "url": "", "version": []}, "created": 1614122124339, "userAgent": "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via ggpht.com GoogleImageProxy)", "deviceType": "COMPUTER", "type": "OPEN", "recipient": "integration-test@airbyte.io", "portalId": 8727216, "sentBy": {"id": "dd239309-7866-4705-a3e9-c571dd349477", "created": 1614119023182}, "smtpId": null, "filteredEvent": false, "appId": 20053, "emailCampaignId": 2}, "emitted_at": 1697714199238} {"stream": "email_events", "data": {"appName": "BatchTest", "location": {"country": "UNITED STATES", "state": "california", "city": "mountain view", "latitude": 37.40599, "longitude": -122.078514, "zipcode": "94043"}, "id": "35b79cd1-3527-3ae7-b316-be0bbf872839", "duration": 1229, "browser": {"name": "Microsoft Edge 12.246", "family": "Microsoft Edge", "producer": "Microsoft Corporation.", "producerUrl": "https://www.microsoft.com/about/", "type": "Browser", "url": "https://en.wikipedia.org/wiki/Microsoft_Edge", "version": ["12.246"]}, "created": 1614119026757, "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246 Mozilla/5.0", "deviceType": "COMPUTER", "type": "OPEN", "recipient": "integration-test@airbyte.io", "portalId": 8727216, "sentBy": {"id": "dd239309-7866-4705-a3e9-c571dd349477", "created": 1614119023182}, "smtpId": null, "filteredEvent": true, "appId": 20053, "emailCampaignId": 2}, "emitted_at": 1697714199239} @@ -26,30 +26,30 @@ {"stream": "engagements", "data": {"id": 10584327028, "portalId": 8727216, "active": true, "createdAt": 1610636372009, "lastUpdated": 1610636372009, "type": "NOTE", "timestamp": 1409172644778, "allAccessibleTeamIds": [], "bodyPreview": "note body 5", "queueMembershipIds": [], "bodyPreviewIsTruncated": false, "bodyPreviewHtml": "\n \n \n note body 5\n \n", "gdprDeleted": false, "associations": {"contactIds": [], "companyIds": [], "dealIds": [], "ownerIds": [], "workflowIds": [], "ticketIds": [], "contentIds": [], "quoteIds": [], "marketingEventIds": []}, "attachments": [{"id": 4241968539}], "metadata": {"body": "note body 5"}, "associations_contactIds": [], "associations_companyIds": [], "associations_dealIds": [], "associations_ownerIds": [], "associations_workflowIds": [], "associations_ticketIds": [], "associations_contentIds": [], "associations_quoteIds": [], "associations_marketingEventIds": [], "metadata_body": "note body 5"}, "emitted_at": 1707257892750} {"stream": "engagements", "data": {"id": 10584327043, "portalId": 8727216, "active": true, "createdAt": 1610636372714, "lastUpdated": 1610636372714, "type": "NOTE", "timestamp": 1409172644778, "allAccessibleTeamIds": [], "bodyPreview": "note body 7", "queueMembershipIds": [], "bodyPreviewIsTruncated": false, "bodyPreviewHtml": "\n \n \n note body 7\n \n", "gdprDeleted": false, "associations": {"contactIds": [], "companyIds": [], "dealIds": [], "ownerIds": [], "workflowIds": [], "ticketIds": [], "contentIds": [], "quoteIds": [], "marketingEventIds": []}, "attachments": [{"id": 4241968539}], "metadata": {"body": "note body 7"}, "associations_contactIds": [], "associations_companyIds": [], "associations_dealIds": [], "associations_ownerIds": [], "associations_workflowIds": [], "associations_ticketIds": [], "associations_contentIds": [], "associations_quoteIds": [], "associations_marketingEventIds": [], "metadata_body": "note body 7"}, "emitted_at": 1707257892753} {"stream": "engagements", "data": {"id": 10584344127, "portalId": 8727216, "active": true, "createdAt": 1610636320990, "lastUpdated": 1610636320990, "type": "NOTE", "timestamp": 1409172644778, "allAccessibleTeamIds": [], "bodyPreview": "note body", "queueMembershipIds": [], "bodyPreviewIsTruncated": false, "bodyPreviewHtml": "\n \n \n note body\n \n", "gdprDeleted": false, "associations": {"contactIds": [], "companyIds": [], "dealIds": [], "ownerIds": [], "workflowIds": [], "ticketIds": [], "contentIds": [], "quoteIds": [], "marketingEventIds": []}, "attachments": [{"id": 4241968539}], "metadata": {"body": "note body"}, "associations_contactIds": [], "associations_companyIds": [], "associations_dealIds": [], "associations_ownerIds": [], "associations_workflowIds": [], "associations_ticketIds": [], "associations_contentIds": [], "associations_quoteIds": [], "associations_marketingEventIds": [], "metadata_body": "note body"}, "emitted_at": 1707257892756} -{"stream": "engagements_notes", "data": {"id": "10584327028", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": "4241968539", "hs_body_preview": "note body 5", "hs_body_preview_html": "\n \n \n note body 5\n \n", "hs_body_preview_is_truncated": false, "hs_created_by": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-14T14:59:32.009000+00:00", "hs_engagement_source": null, "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": false, "hs_lastmodifieddate": "2021-01-14T14:59:32.009000+00:00", "hs_merged_object_ids": null, "hs_modified_by": null, "hs_note_body": "note body 5", "hs_object_id": 10584327028, "hs_object_source": "API", "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": "", "hubspot_team_id": null}, "createdAt": "2021-01-14T14:59:32.009Z", "updatedAt": "2021-01-14T14:59:32.009Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": "4241968539", "properties_hs_body_preview": "note body 5", "properties_hs_body_preview_html": "\n \n \n note body 5\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_created_by": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-14T14:59:32.009000+00:00", "properties_hs_engagement_source": null, "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": false, "properties_hs_lastmodifieddate": "2021-01-14T14:59:32.009000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": null, "properties_hs_note_body": "note body 5", "properties_hs_object_id": 10584327028, "properties_hs_object_source": "API", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": "", "properties_hubspot_team_id": null}, "emitted_at": 1706189898297} -{"stream": "engagements_notes", "data": {"id": "10584327043", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": "4241968539", "hs_body_preview": "note body 7", "hs_body_preview_html": "\n \n \n note body 7\n \n", "hs_body_preview_is_truncated": false, "hs_created_by": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-14T14:59:32.714000+00:00", "hs_engagement_source": null, "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": false, "hs_lastmodifieddate": "2021-01-14T14:59:32.714000+00:00", "hs_merged_object_ids": null, "hs_modified_by": null, "hs_note_body": "note body 7", "hs_object_id": 10584327043, "hs_object_source": "API", "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": "", "hubspot_team_id": null}, "createdAt": "2021-01-14T14:59:32.714Z", "updatedAt": "2021-01-14T14:59:32.714Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": "4241968539", "properties_hs_body_preview": "note body 7", "properties_hs_body_preview_html": "\n \n \n note body 7\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_created_by": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-14T14:59:32.714000+00:00", "properties_hs_engagement_source": null, "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": false, "properties_hs_lastmodifieddate": "2021-01-14T14:59:32.714000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": null, "properties_hs_note_body": "note body 7", "properties_hs_object_id": 10584327043, "properties_hs_object_source": "API", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": "", "properties_hubspot_team_id": null}, "emitted_at": 1706189898299} -{"stream": "engagements_notes", "data": {"id": "10584344127", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": "4241968539", "hs_body_preview": "note body", "hs_body_preview_html": "\n \n \n note body\n \n", "hs_body_preview_is_truncated": false, "hs_created_by": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-14T14:58:40.990000+00:00", "hs_engagement_source": null, "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": false, "hs_lastmodifieddate": "2021-01-14T14:58:40.990000+00:00", "hs_merged_object_ids": null, "hs_modified_by": null, "hs_note_body": "note body", "hs_object_id": 10584344127, "hs_object_source": "API", "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": "", "hubspot_team_id": null}, "createdAt": "2021-01-14T14:58:40.990Z", "updatedAt": "2021-01-14T14:58:40.990Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": "4241968539", "properties_hs_body_preview": "note body", "properties_hs_body_preview_html": "\n \n \n note body\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_created_by": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-14T14:58:40.990000+00:00", "properties_hs_engagement_source": null, "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": false, "properties_hs_lastmodifieddate": "2021-01-14T14:58:40.990000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": null, "properties_hs_note_body": "note body", "properties_hs_object_id": 10584344127, "properties_hs_object_source": "API", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": "", "properties_hubspot_team_id": null}, "emitted_at": 1706189898299} -{"stream": "engagements_tasks", "data": {"id": "11257289597", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_body_preview": "Regarding note logged on Tuesday, February 23, 2021 10:25 PM", "hs_body_preview_html": "\n \n \n Regarding note logged on Tuesday, February 23, 2021 10:25 PM\n \n", "hs_body_preview_is_truncated": false, "hs_calendar_event_id": null, "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2021-02-23T20:25:07.503000+00:00", "hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_engagement_source": null, "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": false, "hs_lastmodifieddate": "2023-04-19T14:52:43.485000+00:00", "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_msteams_message_id": null, "hs_object_id": 11257289597, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_repeat_status": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":11257289597,\"portalId\":8727216,\"engagementType\":\"TASK\",\"taskType\":\"REMINDER\",\"timestamp\":1614319200000,\"uuid\":\"TASK:e41fd851-f7c7-4381-85fa-796d076163aa\"}]}", "hs_task_body": "Regarding note logged on Tuesday, February 23, 2021 10:25 PM", "hs_task_completion_count": null, "hs_task_completion_date": null, "hs_task_contact_timezone": null, "hs_task_family": "SALES", "hs_task_for_object_type": "OWNER", "hs_task_is_all_day": false, "hs_task_is_completed": 0, "hs_task_is_completed_call": 0, "hs_task_is_completed_email": 0, "hs_task_is_completed_linked_in": 0, "hs_task_is_completed_sequence": 0, "hs_task_is_overdue": true, "hs_task_is_past_due_date": true, "hs_task_last_contact_outreach": null, "hs_task_last_sales_activity_timestamp": null, "hs_task_missed_due_date": true, "hs_task_missed_due_date_count": 1, "hs_task_priority": "NONE", "hs_task_probability_to_complete": null, "hs_task_relative_reminders": null, "hs_task_reminders": "1614319200000", "hs_task_repeat_interval": null, "hs_task_send_default_reminder": null, "hs_task_sequence_enrollment_active": null, "hs_task_sequence_step_enrollment_id": null, "hs_task_sequence_step_order": null, "hs_task_status": "NOT_STARTED", "hs_task_subject": "Follow up on Test deal 2", "hs_task_template_id": null, "hs_task_type": "TODO", "hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_timestamp": "2021-02-26T06:00:00+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2021-02-23T20:25:07.503000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2021-02-23T20:25:07.503Z", "updatedAt": "2023-04-19T14:52:43.485Z", "archived": false, "deals": ["4315375411"], "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_body_preview": "Regarding note logged on Tuesday, February 23, 2021 10:25 PM", "properties_hs_body_preview_html": "\n \n \n Regarding note logged on Tuesday, February 23, 2021 10:25 PM\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_calendar_event_id": null, "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2021-02-23T20:25:07.503000+00:00", "properties_hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_engagement_source": null, "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": false, "properties_hs_lastmodifieddate": "2023-04-19T14:52:43.485000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_msteams_message_id": null, "properties_hs_object_id": 11257289597, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_repeat_status": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":11257289597,\"portalId\":8727216,\"engagementType\":\"TASK\",\"taskType\":\"REMINDER\",\"timestamp\":1614319200000,\"uuid\":\"TASK:e41fd851-f7c7-4381-85fa-796d076163aa\"}]}", "properties_hs_task_body": "Regarding note logged on Tuesday, February 23, 2021 10:25 PM", "properties_hs_task_completion_count": null, "properties_hs_task_completion_date": null, "properties_hs_task_contact_timezone": null, "properties_hs_task_family": "SALES", "properties_hs_task_for_object_type": "OWNER", "properties_hs_task_is_all_day": false, "properties_hs_task_is_completed": 0, "properties_hs_task_is_completed_call": 0, "properties_hs_task_is_completed_email": 0, "properties_hs_task_is_completed_linked_in": 0, "properties_hs_task_is_completed_sequence": 0, "properties_hs_task_is_overdue": true, "properties_hs_task_is_past_due_date": true, "properties_hs_task_last_contact_outreach": null, "properties_hs_task_last_sales_activity_timestamp": null, "properties_hs_task_missed_due_date": true, "properties_hs_task_missed_due_date_count": 1, "properties_hs_task_priority": "NONE", "properties_hs_task_probability_to_complete": null, "properties_hs_task_relative_reminders": null, "properties_hs_task_reminders": "1614319200000", "properties_hs_task_repeat_interval": null, "properties_hs_task_send_default_reminder": null, "properties_hs_task_sequence_enrollment_active": null, "properties_hs_task_sequence_step_enrollment_id": null, "properties_hs_task_sequence_step_order": null, "properties_hs_task_status": "NOT_STARTED", "properties_hs_task_subject": "Follow up on Test deal 2", "properties_hs_task_template_id": null, "properties_hs_task_type": "TODO", "properties_hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_timestamp": "2021-02-26T06:00:00+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2021-02-23T20:25:07.503000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1707303846634} -{"stream": "engagements_tasks", "data": {"id": "30652597343", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_body_preview": null, "hs_body_preview_html": null, "hs_body_preview_is_truncated": false, "hs_calendar_event_id": null, "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-01-30T23:41:48.834000+00:00", "hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_engagement_source": "CRM_UI", "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_lastmodifieddate": "2023-04-04T15:11:47.231000+00:00", "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_msteams_message_id": null, "hs_object_id": 30652597343, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_repeat_status": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[]}", "hs_task_body": null, "hs_task_completion_count": null, "hs_task_completion_date": null, "hs_task_contact_timezone": null, "hs_task_family": "SALES", "hs_task_for_object_type": "OWNER", "hs_task_is_all_day": false, "hs_task_is_completed": 0, "hs_task_is_completed_call": 0, "hs_task_is_completed_email": 0, "hs_task_is_completed_linked_in": 0, "hs_task_is_completed_sequence": 0, "hs_task_is_overdue": true, "hs_task_is_past_due_date": true, "hs_task_last_contact_outreach": null, "hs_task_last_sales_activity_timestamp": null, "hs_task_missed_due_date": true, "hs_task_missed_due_date_count": 1, "hs_task_priority": "NONE", "hs_task_probability_to_complete": null, "hs_task_relative_reminders": "[]", "hs_task_reminders": null, "hs_task_repeat_interval": null, "hs_task_send_default_reminder": false, "hs_task_sequence_enrollment_active": null, "hs_task_sequence_step_enrollment_id": null, "hs_task_sequence_step_order": null, "hs_task_status": "NOT_STARTED", "hs_task_subject": "test", "hs_task_template_id": null, "hs_task_type": "TODO", "hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_timestamp": "2023-02-03T07:00:00+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2023-01-30T23:41:48.834000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2023-01-30T23:41:48.834Z", "updatedAt": "2023-04-04T15:11:47.231Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_body_preview": null, "properties_hs_body_preview_html": null, "properties_hs_body_preview_is_truncated": false, "properties_hs_calendar_event_id": null, "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-01-30T23:41:48.834000+00:00", "properties_hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_engagement_source": "CRM_UI", "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_lastmodifieddate": "2023-04-04T15:11:47.231000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_msteams_message_id": null, "properties_hs_object_id": 30652597343, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_repeat_status": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[]}", "properties_hs_task_body": null, "properties_hs_task_completion_count": null, "properties_hs_task_completion_date": null, "properties_hs_task_contact_timezone": null, "properties_hs_task_family": "SALES", "properties_hs_task_for_object_type": "OWNER", "properties_hs_task_is_all_day": false, "properties_hs_task_is_completed": 0, "properties_hs_task_is_completed_call": 0, "properties_hs_task_is_completed_email": 0, "properties_hs_task_is_completed_linked_in": 0, "properties_hs_task_is_completed_sequence": 0, "properties_hs_task_is_overdue": true, "properties_hs_task_is_past_due_date": true, "properties_hs_task_last_contact_outreach": null, "properties_hs_task_last_sales_activity_timestamp": null, "properties_hs_task_missed_due_date": true, "properties_hs_task_missed_due_date_count": 1, "properties_hs_task_priority": "NONE", "properties_hs_task_probability_to_complete": null, "properties_hs_task_relative_reminders": "[]", "properties_hs_task_reminders": null, "properties_hs_task_repeat_interval": null, "properties_hs_task_send_default_reminder": false, "properties_hs_task_sequence_enrollment_active": null, "properties_hs_task_sequence_step_enrollment_id": null, "properties_hs_task_sequence_step_order": null, "properties_hs_task_status": "NOT_STARTED", "properties_hs_task_subject": "test", "properties_hs_task_template_id": null, "properties_hs_task_type": "TODO", "properties_hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_timestamp": "2023-02-03T07:00:00+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2023-01-30T23:41:48.834000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1707303846636} -{"stream": "engagements_tasks", "data": {"id": "30652613208", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_body_preview": null, "hs_body_preview_html": null, "hs_body_preview_is_truncated": false, "hs_calendar_event_id": null, "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-01-30T23:51:52.099000+00:00", "hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_engagement_source": "CRM_UI", "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_lastmodifieddate": "2023-01-30T23:51:54.343000+00:00", "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_msteams_message_id": null, "hs_object_id": 30652613208, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_repeat_status": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[]}", "hs_task_body": null, "hs_task_completion_count": null, "hs_task_completion_date": null, "hs_task_contact_timezone": null, "hs_task_family": "SALES", "hs_task_for_object_type": "OWNER", "hs_task_is_all_day": false, "hs_task_is_completed": 0, "hs_task_is_completed_call": 0, "hs_task_is_completed_email": 0, "hs_task_is_completed_linked_in": 0, "hs_task_is_completed_sequence": 0, "hs_task_is_overdue": true, "hs_task_is_past_due_date": true, "hs_task_last_contact_outreach": null, "hs_task_last_sales_activity_timestamp": null, "hs_task_missed_due_date": true, "hs_task_missed_due_date_count": 1, "hs_task_priority": "NONE", "hs_task_probability_to_complete": null, "hs_task_relative_reminders": "[]", "hs_task_reminders": null, "hs_task_repeat_interval": null, "hs_task_send_default_reminder": false, "hs_task_sequence_enrollment_active": null, "hs_task_sequence_step_enrollment_id": null, "hs_task_sequence_step_order": null, "hs_task_status": "NOT_STARTED", "hs_task_subject": "test", "hs_task_template_id": null, "hs_task_type": "TODO", "hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_timestamp": "2023-02-03T07:00:00+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2023-01-30T23:51:52.099000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2023-01-30T23:51:52.099Z", "updatedAt": "2023-01-30T23:51:54.343Z", "archived": false, "companies": ["11481383026"], "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_body_preview": null, "properties_hs_body_preview_html": null, "properties_hs_body_preview_is_truncated": false, "properties_hs_calendar_event_id": null, "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-01-30T23:51:52.099000+00:00", "properties_hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_engagement_source": "CRM_UI", "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_lastmodifieddate": "2023-01-30T23:51:54.343000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_msteams_message_id": null, "properties_hs_object_id": 30652613208, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_repeat_status": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[]}", "properties_hs_task_body": null, "properties_hs_task_completion_count": null, "properties_hs_task_completion_date": null, "properties_hs_task_contact_timezone": null, "properties_hs_task_family": "SALES", "properties_hs_task_for_object_type": "OWNER", "properties_hs_task_is_all_day": false, "properties_hs_task_is_completed": 0, "properties_hs_task_is_completed_call": 0, "properties_hs_task_is_completed_email": 0, "properties_hs_task_is_completed_linked_in": 0, "properties_hs_task_is_completed_sequence": 0, "properties_hs_task_is_overdue": true, "properties_hs_task_is_past_due_date": true, "properties_hs_task_last_contact_outreach": null, "properties_hs_task_last_sales_activity_timestamp": null, "properties_hs_task_missed_due_date": true, "properties_hs_task_missed_due_date_count": 1, "properties_hs_task_priority": "NONE", "properties_hs_task_probability_to_complete": null, "properties_hs_task_relative_reminders": "[]", "properties_hs_task_reminders": null, "properties_hs_task_repeat_interval": null, "properties_hs_task_send_default_reminder": false, "properties_hs_task_sequence_enrollment_active": null, "properties_hs_task_sequence_step_enrollment_id": null, "properties_hs_task_sequence_step_order": null, "properties_hs_task_status": "NOT_STARTED", "properties_hs_task_subject": "test", "properties_hs_task_template_id": null, "properties_hs_task_type": "TODO", "properties_hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_timestamp": "2023-02-03T07:00:00+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2023-01-30T23:51:52.099000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1707303846637} +{"stream": "engagements_notes", "data": {"id": "10584327028", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": "4241968539", "hs_body_preview": "note body 5", "hs_body_preview_html": "\n \n \n note body 5\n \n", "hs_body_preview_is_truncated": false, "hs_created_by": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-14T14:59:32.009000+00:00", "hs_engagement_source": null, "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": false, "hs_lastmodifieddate": "2021-01-14T14:59:32.009000+00:00", "hs_merged_object_ids": null, "hs_modified_by": null, "hs_note_body": "note body 5", "hs_note_ms_teams_payload": null, "hs_object_id": 10584327028, "hs_object_source": "API", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": "", "hubspot_team_id": null}, "createdAt": "2021-01-14T14:59:32.009Z", "updatedAt": "2021-01-14T14:59:32.009Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": "4241968539", "properties_hs_body_preview": "note body 5", "properties_hs_body_preview_html": "\n \n \n note body 5\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_created_by": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-14T14:59:32.009000+00:00", "properties_hs_engagement_source": null, "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": false, "properties_hs_lastmodifieddate": "2021-01-14T14:59:32.009000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": null, "properties_hs_note_body": "note body 5", "properties_hs_note_ms_teams_payload": null, "properties_hs_object_id": 10584327028, "properties_hs_object_source": "API", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": "", "properties_hubspot_team_id": null}, "emitted_at": 1708013474865} +{"stream": "engagements_notes", "data": {"id": "10584327043", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": "4241968539", "hs_body_preview": "note body 7", "hs_body_preview_html": "\n \n \n note body 7\n \n", "hs_body_preview_is_truncated": false, "hs_created_by": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-14T14:59:32.714000+00:00", "hs_engagement_source": null, "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": false, "hs_lastmodifieddate": "2021-01-14T14:59:32.714000+00:00", "hs_merged_object_ids": null, "hs_modified_by": null, "hs_note_body": "note body 7", "hs_note_ms_teams_payload": null, "hs_object_id": 10584327043, "hs_object_source": "API", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": "", "hubspot_team_id": null}, "createdAt": "2021-01-14T14:59:32.714Z", "updatedAt": "2021-01-14T14:59:32.714Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": "4241968539", "properties_hs_body_preview": "note body 7", "properties_hs_body_preview_html": "\n \n \n note body 7\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_created_by": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-14T14:59:32.714000+00:00", "properties_hs_engagement_source": null, "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": false, "properties_hs_lastmodifieddate": "2021-01-14T14:59:32.714000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": null, "properties_hs_note_body": "note body 7", "properties_hs_note_ms_teams_payload": null, "properties_hs_object_id": 10584327043, "properties_hs_object_source": "API", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": "", "properties_hubspot_team_id": null}, "emitted_at": 1708013474865} +{"stream": "engagements_notes", "data": {"id": "10584344127", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": "4241968539", "hs_body_preview": "note body", "hs_body_preview_html": "\n \n \n note body\n \n", "hs_body_preview_is_truncated": false, "hs_created_by": null, "hs_created_by_user_id": null, "hs_createdate": "2021-01-14T14:58:40.990000+00:00", "hs_engagement_source": null, "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": false, "hs_lastmodifieddate": "2021-01-14T14:58:40.990000+00:00", "hs_merged_object_ids": null, "hs_modified_by": null, "hs_note_body": "note body", "hs_note_ms_teams_payload": null, "hs_object_id": 10584344127, "hs_object_source": "API", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": null, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": "", "hubspot_team_id": null}, "createdAt": "2021-01-14T14:58:40.990Z", "updatedAt": "2021-01-14T14:58:40.990Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": "4241968539", "properties_hs_body_preview": "note body", "properties_hs_body_preview_html": "\n \n \n note body\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_created_by": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": "2021-01-14T14:58:40.990000+00:00", "properties_hs_engagement_source": null, "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": false, "properties_hs_lastmodifieddate": "2021-01-14T14:58:40.990000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": null, "properties_hs_note_body": "note body", "properties_hs_note_ms_teams_payload": null, "properties_hs_object_id": 10584344127, "properties_hs_object_source": "API", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": null, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_timestamp": "2014-08-27T20:50:44.778000+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": "", "properties_hubspot_team_id": null}, "emitted_at": 1708013474865} +{"stream": "engagements_tasks", "data": {"id": "11257289597", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_body_preview": "Regarding note logged on Tuesday, February 23, 2021 10:25 PM", "hs_body_preview_html": "\n \n \n Regarding note logged on Tuesday, February 23, 2021 10:25 PM\n \n", "hs_body_preview_is_truncated": false, "hs_calendar_event_id": null, "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2021-02-23T20:25:07.503000+00:00", "hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_engagement_source": null, "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": false, "hs_lastmodifieddate": "2023-04-19T14:52:43.485000+00:00", "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_msteams_message_id": null, "hs_object_id": 11257289597, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_repeat_status": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":11257289597,\"portalId\":8727216,\"engagementType\":\"TASK\",\"taskType\":\"REMINDER\",\"timestamp\":1614319200000,\"uuid\":\"TASK:e41fd851-f7c7-4381-85fa-796d076163aa\"}]}", "hs_task_body": "Regarding note logged on Tuesday, February 23, 2021 10:25 PM", "hs_task_completion_count": null, "hs_task_completion_date": null, "hs_task_contact_timezone": null, "hs_task_family": "SALES", "hs_task_for_object_type": "OWNER", "hs_task_is_all_day": false, "hs_task_is_completed": 0, "hs_task_is_completed_call": 0, "hs_task_is_completed_email": 0, "hs_task_is_completed_linked_in": 0, "hs_task_is_completed_sequence": 0, "hs_task_is_overdue": true, "hs_task_is_past_due_date": true, "hs_task_last_contact_outreach": null, "hs_task_last_sales_activity_timestamp": null, "hs_task_missed_due_date": true, "hs_task_missed_due_date_count": 1, "hs_task_ms_teams_payload": null, "hs_task_priority": "NONE", "hs_task_probability_to_complete": null, "hs_task_relative_reminders": null, "hs_task_reminders": "1614319200000", "hs_task_repeat_interval": null, "hs_task_send_default_reminder": null, "hs_task_sequence_enrollment_active": null, "hs_task_sequence_step_enrollment_id": null, "hs_task_sequence_step_order": null, "hs_task_status": "NOT_STARTED", "hs_task_subject": "Follow up on Test deal 2", "hs_task_template_id": null, "hs_task_type": "TODO", "hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_timestamp": "2021-02-26T06:00:00+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2021-02-23T20:25:07.503000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2021-02-23T20:25:07.503Z", "updatedAt": "2023-04-19T14:52:43.485Z", "archived": false, "deals": ["4315375411"], "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_body_preview": "Regarding note logged on Tuesday, February 23, 2021 10:25 PM", "properties_hs_body_preview_html": "\n \n \n Regarding note logged on Tuesday, February 23, 2021 10:25 PM\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_calendar_event_id": null, "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2021-02-23T20:25:07.503000+00:00", "properties_hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_engagement_source": null, "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": false, "properties_hs_lastmodifieddate": "2023-04-19T14:52:43.485000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_msteams_message_id": null, "properties_hs_object_id": 11257289597, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_repeat_status": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":11257289597,\"portalId\":8727216,\"engagementType\":\"TASK\",\"taskType\":\"REMINDER\",\"timestamp\":1614319200000,\"uuid\":\"TASK:e41fd851-f7c7-4381-85fa-796d076163aa\"}]}", "properties_hs_task_body": "Regarding note logged on Tuesday, February 23, 2021 10:25 PM", "properties_hs_task_completion_count": null, "properties_hs_task_completion_date": null, "properties_hs_task_contact_timezone": null, "properties_hs_task_family": "SALES", "properties_hs_task_for_object_type": "OWNER", "properties_hs_task_is_all_day": false, "properties_hs_task_is_completed": 0, "properties_hs_task_is_completed_call": 0, "properties_hs_task_is_completed_email": 0, "properties_hs_task_is_completed_linked_in": 0, "properties_hs_task_is_completed_sequence": 0, "properties_hs_task_is_overdue": true, "properties_hs_task_is_past_due_date": true, "properties_hs_task_last_contact_outreach": null, "properties_hs_task_last_sales_activity_timestamp": null, "properties_hs_task_missed_due_date": true, "properties_hs_task_missed_due_date_count": 1, "properties_hs_task_ms_teams_payload": null, "properties_hs_task_priority": "NONE", "properties_hs_task_probability_to_complete": null, "properties_hs_task_relative_reminders": null, "properties_hs_task_reminders": "1614319200000", "properties_hs_task_repeat_interval": null, "properties_hs_task_send_default_reminder": null, "properties_hs_task_sequence_enrollment_active": null, "properties_hs_task_sequence_step_enrollment_id": null, "properties_hs_task_sequence_step_order": null, "properties_hs_task_status": "NOT_STARTED", "properties_hs_task_subject": "Follow up on Test deal 2", "properties_hs_task_template_id": null, "properties_hs_task_type": "TODO", "properties_hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_timestamp": "2021-02-26T06:00:00+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2021-02-23T20:25:07.503000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1708013653895} +{"stream": "engagements_tasks", "data": {"id": "30652597343", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_body_preview": null, "hs_body_preview_html": null, "hs_body_preview_is_truncated": false, "hs_calendar_event_id": null, "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-01-30T23:41:48.834000+00:00", "hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_engagement_source": "CRM_UI", "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_lastmodifieddate": "2023-04-04T15:11:47.231000+00:00", "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_msteams_message_id": null, "hs_object_id": 30652597343, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_repeat_status": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[]}", "hs_task_body": null, "hs_task_completion_count": null, "hs_task_completion_date": null, "hs_task_contact_timezone": null, "hs_task_family": "SALES", "hs_task_for_object_type": "OWNER", "hs_task_is_all_day": false, "hs_task_is_completed": 0, "hs_task_is_completed_call": 0, "hs_task_is_completed_email": 0, "hs_task_is_completed_linked_in": 0, "hs_task_is_completed_sequence": 0, "hs_task_is_overdue": true, "hs_task_is_past_due_date": true, "hs_task_last_contact_outreach": null, "hs_task_last_sales_activity_timestamp": null, "hs_task_missed_due_date": true, "hs_task_missed_due_date_count": 1, "hs_task_ms_teams_payload": null, "hs_task_priority": "NONE", "hs_task_probability_to_complete": null, "hs_task_relative_reminders": "[]", "hs_task_reminders": null, "hs_task_repeat_interval": null, "hs_task_send_default_reminder": false, "hs_task_sequence_enrollment_active": null, "hs_task_sequence_step_enrollment_id": null, "hs_task_sequence_step_order": null, "hs_task_status": "NOT_STARTED", "hs_task_subject": "test", "hs_task_template_id": null, "hs_task_type": "TODO", "hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_timestamp": "2023-02-03T07:00:00+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2023-01-30T23:41:48.834000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2023-01-30T23:41:48.834Z", "updatedAt": "2023-04-04T15:11:47.231Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_body_preview": null, "properties_hs_body_preview_html": null, "properties_hs_body_preview_is_truncated": false, "properties_hs_calendar_event_id": null, "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-01-30T23:41:48.834000+00:00", "properties_hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_engagement_source": "CRM_UI", "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_lastmodifieddate": "2023-04-04T15:11:47.231000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_msteams_message_id": null, "properties_hs_object_id": 30652597343, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_repeat_status": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[]}", "properties_hs_task_body": null, "properties_hs_task_completion_count": null, "properties_hs_task_completion_date": null, "properties_hs_task_contact_timezone": null, "properties_hs_task_family": "SALES", "properties_hs_task_for_object_type": "OWNER", "properties_hs_task_is_all_day": false, "properties_hs_task_is_completed": 0, "properties_hs_task_is_completed_call": 0, "properties_hs_task_is_completed_email": 0, "properties_hs_task_is_completed_linked_in": 0, "properties_hs_task_is_completed_sequence": 0, "properties_hs_task_is_overdue": true, "properties_hs_task_is_past_due_date": true, "properties_hs_task_last_contact_outreach": null, "properties_hs_task_last_sales_activity_timestamp": null, "properties_hs_task_missed_due_date": true, "properties_hs_task_missed_due_date_count": 1, "properties_hs_task_ms_teams_payload": null, "properties_hs_task_priority": "NONE", "properties_hs_task_probability_to_complete": null, "properties_hs_task_relative_reminders": "[]", "properties_hs_task_reminders": null, "properties_hs_task_repeat_interval": null, "properties_hs_task_send_default_reminder": false, "properties_hs_task_sequence_enrollment_active": null, "properties_hs_task_sequence_step_enrollment_id": null, "properties_hs_task_sequence_step_order": null, "properties_hs_task_status": "NOT_STARTED", "properties_hs_task_subject": "test", "properties_hs_task_template_id": null, "properties_hs_task_type": "TODO", "properties_hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_timestamp": "2023-02-03T07:00:00+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2023-01-30T23:41:48.834000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1708013653896} +{"stream": "engagements_tasks", "data": {"id": "30652613208", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_body_preview": null, "hs_body_preview_html": null, "hs_body_preview_is_truncated": false, "hs_calendar_event_id": null, "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-01-30T23:51:52.099000+00:00", "hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_engagement_source": "CRM_UI", "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_lastmodifieddate": "2023-01-30T23:51:54.343000+00:00", "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_msteams_message_id": null, "hs_object_id": 30652613208, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_repeat_status": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[]}", "hs_task_body": null, "hs_task_completion_count": null, "hs_task_completion_date": null, "hs_task_contact_timezone": null, "hs_task_family": "SALES", "hs_task_for_object_type": "OWNER", "hs_task_is_all_day": false, "hs_task_is_completed": 0, "hs_task_is_completed_call": 0, "hs_task_is_completed_email": 0, "hs_task_is_completed_linked_in": 0, "hs_task_is_completed_sequence": 0, "hs_task_is_overdue": true, "hs_task_is_past_due_date": true, "hs_task_last_contact_outreach": null, "hs_task_last_sales_activity_timestamp": null, "hs_task_missed_due_date": true, "hs_task_missed_due_date_count": 1, "hs_task_ms_teams_payload": null, "hs_task_priority": "NONE", "hs_task_probability_to_complete": null, "hs_task_relative_reminders": "[]", "hs_task_reminders": null, "hs_task_repeat_interval": null, "hs_task_send_default_reminder": false, "hs_task_sequence_enrollment_active": null, "hs_task_sequence_step_enrollment_id": null, "hs_task_sequence_step_order": null, "hs_task_status": "NOT_STARTED", "hs_task_subject": "test", "hs_task_template_id": null, "hs_task_type": "TODO", "hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "hs_timestamp": "2023-02-03T07:00:00+00:00", "hs_unique_creation_key": null, "hs_unique_id": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2023-01-30T23:51:52.099000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2023-01-30T23:51:52.099Z", "updatedAt": "2023-01-30T23:51:54.343Z", "archived": false, "companies": ["11481383026"], "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_body_preview": null, "properties_hs_body_preview_html": null, "properties_hs_body_preview_is_truncated": false, "properties_hs_calendar_event_id": null, "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-01-30T23:51:52.099000+00:00", "properties_hs_date_entered_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_entered_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_entered_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_entered_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_entered_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_date_exited_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_date_exited_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_date_exited_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_date_exited_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_date_exited_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_engagement_source": "CRM_UI", "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_lastmodifieddate": "2023-01-30T23:51:54.343000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_msteams_message_id": null, "properties_hs_object_id": 30652613208, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_repeat_status": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[]}", "properties_hs_task_body": null, "properties_hs_task_completion_count": null, "properties_hs_task_completion_date": null, "properties_hs_task_contact_timezone": null, "properties_hs_task_family": "SALES", "properties_hs_task_for_object_type": "OWNER", "properties_hs_task_is_all_day": false, "properties_hs_task_is_completed": 0, "properties_hs_task_is_completed_call": 0, "properties_hs_task_is_completed_email": 0, "properties_hs_task_is_completed_linked_in": 0, "properties_hs_task_is_completed_sequence": 0, "properties_hs_task_is_overdue": true, "properties_hs_task_is_past_due_date": true, "properties_hs_task_last_contact_outreach": null, "properties_hs_task_last_sales_activity_timestamp": null, "properties_hs_task_missed_due_date": true, "properties_hs_task_missed_due_date_count": 1, "properties_hs_task_ms_teams_payload": null, "properties_hs_task_priority": "NONE", "properties_hs_task_probability_to_complete": null, "properties_hs_task_relative_reminders": "[]", "properties_hs_task_reminders": null, "properties_hs_task_repeat_interval": null, "properties_hs_task_send_default_reminder": false, "properties_hs_task_sequence_enrollment_active": null, "properties_hs_task_sequence_step_enrollment_id": null, "properties_hs_task_sequence_step_order": null, "properties_hs_task_status": "NOT_STARTED", "properties_hs_task_subject": "test", "properties_hs_task_template_id": null, "properties_hs_task_type": "TODO", "properties_hs_time_in_60b5c368_04c4_4d32_9b4a_457e159f49b7_13292096": null, "properties_hs_time_in_61bafb31_e7fa_46ed_aaa9_1322438d6e67_1866552342": null, "properties_hs_time_in_af0e6a5c_2ea3_4c72_b69f_7c6cb3fdb591_1652950531": null, "properties_hs_time_in_dd5826e4_c976_4654_a527_b59ada542e52_2144133616": null, "properties_hs_time_in_fc8148fb_3a2d_4b59_834e_69b7859347cb_1813133675": null, "properties_hs_timestamp": "2023-02-03T07:00:00+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2023-01-30T23:51:52.099000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1708013653897} {"stream": "forms", "data": {"id": "01ba116c-f3a8-4957-8884-ff0c4420af76", "name": "DemoForm", "createdAt": "2021-01-14T14:44:48.278Z", "updatedAt": "2021-01-14T14:44:48.278Z", "archived": false, "fieldGroups": [{"groupType": "default_group", "richTextType": "text", "fields": [{"objectTypeId": "0-1", "name": "firstname", "label": "First Name", "required": false, "hidden": false, "fieldType": "single_line_text"}]}, {"groupType": "default_group", "richTextType": "text", "fields": [{"objectTypeId": "0-1", "name": "lastname", "label": "Last Name", "required": false, "hidden": false, "fieldType": "single_line_text"}]}, {"groupType": "default_group", "richTextType": "text", "fields": [{"objectTypeId": "0-1", "name": "adress_1", "label": "Adress 1", "required": false, "hidden": false, "fieldType": "single_line_text"}]}], "configuration": {"language": "en", "cloneable": true, "postSubmitAction": {"type": "thank_you", "value": ""}, "editable": true, "archivable": true, "recaptchaEnabled": false, "notifyContactOwner": false, "notifyRecipients": [], "createNewContactForNewEmail": false, "prePopulateKnownValues": true, "allowLinkToResetKnownValues": false, "lifecycleStages": []}, "displayOptions": {"renderRawHtml": false, "theme": "default_style", "submitButtonText": "Submit", "style": {"fontFamily": "arial, helvetica, sans-serif", "backgroundWidth": "100%", "labelTextColor": "#33475b", "labelTextSize": "11px", "helpTextColor": "#7C98B6", "helpTextSize": "11px", "legalConsentTextColor": "#33475b", "legalConsentTextSize": "14px", "submitColor": "#ff7a59", "submitAlignment": "left", "submitFontColor": "#ffffff", "submitSize": "12px"}, "cssClass": null}, "legalConsentOptions": {"type": "none"}, "formType": "hubspot"}, "emitted_at": 1697714221520} {"stream": "forms", "data": {"id": "03e69987-1dcb-4d55-9cb6-d3812ac00ee6", "name": "New form 93", "createdAt": "2023-02-13T16:56:33.108Z", "updatedAt": "2023-02-13T16:56:33.108Z", "archived": false, "fieldGroups": [{"groupType": "default_group", "richTextType": "text", "fields": [{"objectTypeId": "0-1", "name": "email", "label": "Email", "required": true, "hidden": false, "fieldType": "email", "validation": {"blockedEmailDomains": [], "useDefaultBlockList": false}}]}], "configuration": {"language": "en", "cloneable": true, "postSubmitAction": {"type": "thank_you", "value": "Thanks for submitting the form."}, "editable": true, "archivable": true, "recaptchaEnabled": false, "notifyContactOwner": false, "notifyRecipients": ["12282590"], "createNewContactForNewEmail": false, "prePopulateKnownValues": true, "allowLinkToResetKnownValues": false, "lifecycleStages": []}, "displayOptions": {"renderRawHtml": false, "theme": "default_style", "submitButtonText": "Submit", "style": {"fontFamily": "arial, helvetica, sans-serif", "backgroundWidth": "100%", "labelTextColor": "#33475b", "labelTextSize": "14px", "helpTextColor": "#7C98B6", "helpTextSize": "11px", "legalConsentTextColor": "#33475b", "legalConsentTextSize": "14px", "submitColor": "#ff7a59", "submitAlignment": "left", "submitFontColor": "#ffffff", "submitSize": "12px"}, "cssClass": "hs-form stacked"}, "legalConsentOptions": {"type": "implicit_consent_to_process", "communicationConsentText": "integrationtest is committed to protecting and respecting your privacy, and we\u2019ll only use your personal information to administer your account and to provide the products and services you requested from us. From time to time, we would like to contact you about our products and services, as well as other content that may be of interest to you. If you consent to us contacting you for this purpose, please tick below to say how you would like us to contact you:", "communicationsCheckboxes": [{"required": false, "subscriptionTypeId": 23704464, "label": "I agree to receive other communications from [MAIN] integration test account."}], "privacyText": "You may unsubscribe from these communications at any time. For more information on how to unsubscribe, our privacy practices, and how we are committed to protecting and respecting your privacy, please review our Privacy Policy.", "consentToProcessText": "By clicking submit below, you consent to allow integrationtest to store and process the personal information submitted above to provide you the content requested."}, "formType": "hubspot"}, "emitted_at": 1697714221521} {"stream": "forms", "data": {"id": "0a7fd84f-471e-444a-a4e0-ca36d39f8af7", "name": "New form 27", "createdAt": "2023-02-13T16:45:22.640Z", "updatedAt": "2023-02-13T16:45:22.640Z", "archived": false, "fieldGroups": [{"groupType": "default_group", "richTextType": "text", "fields": [{"objectTypeId": "0-1", "name": "email", "label": "Email", "required": true, "hidden": false, "fieldType": "email", "validation": {"blockedEmailDomains": [], "useDefaultBlockList": false}}]}], "configuration": {"language": "en", "cloneable": true, "postSubmitAction": {"type": "thank_you", "value": "Thanks for submitting the form."}, "editable": true, "archivable": true, "recaptchaEnabled": false, "notifyContactOwner": false, "notifyRecipients": ["12282590"], "createNewContactForNewEmail": false, "prePopulateKnownValues": true, "allowLinkToResetKnownValues": false, "lifecycleStages": []}, "displayOptions": {"renderRawHtml": false, "theme": "default_style", "submitButtonText": "Submit", "style": {"fontFamily": "arial, helvetica, sans-serif", "backgroundWidth": "100%", "labelTextColor": "#33475b", "labelTextSize": "14px", "helpTextColor": "#7C98B6", "helpTextSize": "11px", "legalConsentTextColor": "#33475b", "legalConsentTextSize": "14px", "submitColor": "#ff7a59", "submitAlignment": "left", "submitFontColor": "#ffffff", "submitSize": "12px"}, "cssClass": "hs-form stacked"}, "legalConsentOptions": {"type": "implicit_consent_to_process", "communicationConsentText": "integrationtest is committed to protecting and respecting your privacy, and we\u2019ll only use your personal information to administer your account and to provide the products and services you requested from us. From time to time, we would like to contact you about our products and services, as well as other content that may be of interest to you. If you consent to us contacting you for this purpose, please tick below to say how you would like us to contact you:", "communicationsCheckboxes": [{"required": false, "subscriptionTypeId": 23704464, "label": "I agree to receive other communications from [MAIN] integration test account."}], "privacyText": "You may unsubscribe from these communications at any time. For more information on how to unsubscribe, our privacy practices, and how we are committed to protecting and respecting your privacy, please review our Privacy Policy.", "consentToProcessText": "By clicking submit below, you consent to allow integrationtest to store and process the personal information submitted above to provide you the content requested."}, "formType": "hubspot"}, "emitted_at": 1697714221522} -{"stream": "goals", "data": {"id": "221880757009", "properties": {"hs__migration_soft_delete": null, "hs_ad_account_asset_ids": null, "hs_ad_campaign_asset_ids": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignee_team_id": null, "hs_assignee_user_id": 26748728, "hs_contact_lifecycle_stage": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-10T13:57:36.691000+00:00", "hs_currency": null, "hs_deal_pipeline_ids": null, "hs_edit_updates_notification_frequency": "weekly", "hs_end_date": null, "hs_end_datetime": "2023-07-31T23:59:59.999000+00:00", "hs_fiscal_year_offset": 0, "hs_goal_definition_key": null, "hs_goal_definition_key_with_team": null, "hs_goal_definition_key_with_user": null, "hs_goal_name": "Integration Test Goal Hubspot", "hs_goal_target_group_id": 221880750627, "hs_goal_type": "average_ticket_response_time", "hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "hs_is_forecastable": "true", "hs_is_legacy": null, "hs_kpi_display_unit": "hour", "hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "hs_kpi_filter_groups_for_key_grouping": null, "hs_kpi_filter_groups_for_key_team_grouping": null, "hs_kpi_is_team_rollup": false, "hs_kpi_metric_type": "AVG", "hs_kpi_object_type": "TICKET", "hs_kpi_object_type_id": "0-5", "hs_kpi_progress_percent": null, "hs_kpi_property_name": "time_to_first_agent_reply", "hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "hs_kpi_time_period_property": "createdate", "hs_kpi_tracking_method": "LOWER_IS_BETTER", "hs_kpi_unit_type": "duration", "hs_kpi_value": 0.0, "hs_kpi_value_calculated_at": null, "hs_kpi_value_last_calculated_at": "2023-08-01T00:45:14.830000+00:00", "hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "hs_legacy_active": null, "hs_legacy_created_at": null, "hs_legacy_created_by": null, "hs_legacy_quarterly_target_composite_id": null, "hs_legacy_sql_id": null, "hs_legacy_unique_sql_id": null, "hs_legacy_updated_at": null, "hs_legacy_updated_by": null, "hs_merged_object_ids": null, "hs_migration_soft_delete": null, "hs_milestone": "monthly", "hs_object_id": 221880757009, "hs_object_source": null, "hs_object_source_id": null, "hs_object_source_label": null, "hs_object_source_user_id": null, "hs_outcome": "completed", "hs_owner_ids_of_all_owners": "111730024", "hs_pipelines": "0", "hs_progress_updates_notification_frequency": "weekly", "hs_read_only": null, "hs_should_notify_on_achieved": "false", "hs_should_notify_on_edit_updates": "false", "hs_should_notify_on_exceeded": "false", "hs_should_notify_on_kickoff": "false", "hs_should_notify_on_missed": "false", "hs_should_notify_on_progress_updates": "false", "hs_should_recalculate": "false", "hs_start_date": null, "hs_start_datetime": "2023-07-01T00:00:00+00:00", "hs_static_kpi_filter_groups": "[]", "hs_status": "achieved", "hs_status_display_order": 4, "hs_target_amount": 0.0, "hs_target_amount_in_home_currency": 0.0, "hs_team_id": null, "hs_template_id": 4, "hs_ticket_pipeline_ids": "0", "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "26748728", "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null}, "createdAt": "2023-04-10T13:57:36.691Z", "updatedAt": "2023-12-11T20:46:14.473Z", "archived": false, "properties_hs__migration_soft_delete": null, "properties_hs_ad_account_asset_ids": null, "properties_hs_ad_campaign_asset_ids": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignee_team_id": null, "properties_hs_assignee_user_id": 26748728, "properties_hs_contact_lifecycle_stage": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-10T13:57:36.691000+00:00", "properties_hs_currency": null, "properties_hs_deal_pipeline_ids": null, "properties_hs_edit_updates_notification_frequency": "weekly", "properties_hs_end_date": null, "properties_hs_end_datetime": "2023-07-31T23:59:59.999000+00:00", "properties_hs_fiscal_year_offset": 0, "properties_hs_goal_definition_key": null, "properties_hs_goal_definition_key_with_team": null, "properties_hs_goal_definition_key_with_user": null, "properties_hs_goal_name": "Integration Test Goal Hubspot", "properties_hs_goal_target_group_id": 221880750627, "properties_hs_goal_type": "average_ticket_response_time", "properties_hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "properties_hs_is_forecastable": "true", "properties_hs_is_legacy": null, "properties_hs_kpi_display_unit": "hour", "properties_hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "properties_hs_kpi_filter_groups_for_key_grouping": null, "properties_hs_kpi_filter_groups_for_key_team_grouping": null, "properties_hs_kpi_is_team_rollup": false, "properties_hs_kpi_metric_type": "AVG", "properties_hs_kpi_object_type": "TICKET", "properties_hs_kpi_object_type_id": "0-5", "properties_hs_kpi_progress_percent": null, "properties_hs_kpi_property_name": "time_to_first_agent_reply", "properties_hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "properties_hs_kpi_time_period_property": "createdate", "properties_hs_kpi_tracking_method": "LOWER_IS_BETTER", "properties_hs_kpi_unit_type": "duration", "properties_hs_kpi_value": 0.0, "properties_hs_kpi_value_calculated_at": null, "properties_hs_kpi_value_last_calculated_at": "2023-08-01T00:45:14.830000+00:00", "properties_hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "properties_hs_legacy_active": null, "properties_hs_legacy_created_at": null, "properties_hs_legacy_created_by": null, "properties_hs_legacy_quarterly_target_composite_id": null, "properties_hs_legacy_sql_id": null, "properties_hs_legacy_unique_sql_id": null, "properties_hs_legacy_updated_at": null, "properties_hs_legacy_updated_by": null, "properties_hs_merged_object_ids": null, "properties_hs_migration_soft_delete": null, "properties_hs_milestone": "monthly", "properties_hs_object_id": 221880757009, "properties_hs_object_source": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": null, "properties_hs_object_source_user_id": null, "properties_hs_outcome": "completed", "properties_hs_owner_ids_of_all_owners": "111730024", "properties_hs_pipelines": "0", "properties_hs_progress_updates_notification_frequency": "weekly", "properties_hs_read_only": null, "properties_hs_should_notify_on_achieved": "false", "properties_hs_should_notify_on_edit_updates": "false", "properties_hs_should_notify_on_exceeded": "false", "properties_hs_should_notify_on_kickoff": "false", "properties_hs_should_notify_on_missed": "false", "properties_hs_should_notify_on_progress_updates": "false", "properties_hs_should_recalculate": "false", "properties_hs_start_date": null, "properties_hs_start_datetime": "2023-07-01T00:00:00+00:00", "properties_hs_static_kpi_filter_groups": "[]", "properties_hs_status": "achieved", "properties_hs_status_display_order": 4, "properties_hs_target_amount": 0.0, "properties_hs_target_amount_in_home_currency": 0.0, "properties_hs_team_id": null, "properties_hs_template_id": 4, "properties_hs_ticket_pipeline_ids": "0", "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "26748728", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null}, "emitted_at": 1707314192086} -{"stream": "goals", "data": {"id": "221880757010", "properties": {"hs__migration_soft_delete": null, "hs_ad_account_asset_ids": null, "hs_ad_campaign_asset_ids": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignee_team_id": null, "hs_assignee_user_id": 26748728, "hs_contact_lifecycle_stage": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-10T13:57:36.691000+00:00", "hs_currency": null, "hs_deal_pipeline_ids": null, "hs_edit_updates_notification_frequency": "weekly", "hs_end_date": null, "hs_end_datetime": "2023-09-30T23:59:59.999000+00:00", "hs_fiscal_year_offset": 0, "hs_goal_definition_key": null, "hs_goal_definition_key_with_team": null, "hs_goal_definition_key_with_user": null, "hs_goal_name": "Integration Test Goal Hubspot", "hs_goal_target_group_id": 221880750627, "hs_goal_type": "average_ticket_response_time", "hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "hs_is_forecastable": "true", "hs_is_legacy": null, "hs_kpi_display_unit": "hour", "hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "hs_kpi_filter_groups_for_key_grouping": null, "hs_kpi_filter_groups_for_key_team_grouping": null, "hs_kpi_is_team_rollup": false, "hs_kpi_metric_type": "AVG", "hs_kpi_object_type": "TICKET", "hs_kpi_object_type_id": "0-5", "hs_kpi_progress_percent": null, "hs_kpi_property_name": "time_to_first_agent_reply", "hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "hs_kpi_time_period_property": "createdate", "hs_kpi_tracking_method": "LOWER_IS_BETTER", "hs_kpi_unit_type": "duration", "hs_kpi_value": 0.0, "hs_kpi_value_calculated_at": null, "hs_kpi_value_last_calculated_at": "2023-10-01T22:31:08.621000+00:00", "hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "hs_legacy_active": null, "hs_legacy_created_at": null, "hs_legacy_created_by": null, "hs_legacy_quarterly_target_composite_id": null, "hs_legacy_sql_id": null, "hs_legacy_unique_sql_id": null, "hs_legacy_updated_at": null, "hs_legacy_updated_by": null, "hs_merged_object_ids": null, "hs_migration_soft_delete": null, "hs_milestone": "monthly", "hs_object_id": 221880757010, "hs_object_source": null, "hs_object_source_id": null, "hs_object_source_label": null, "hs_object_source_user_id": null, "hs_outcome": "completed", "hs_owner_ids_of_all_owners": "111730024", "hs_pipelines": "0", "hs_progress_updates_notification_frequency": "weekly", "hs_read_only": null, "hs_should_notify_on_achieved": "false", "hs_should_notify_on_edit_updates": "false", "hs_should_notify_on_exceeded": "false", "hs_should_notify_on_kickoff": "false", "hs_should_notify_on_missed": "false", "hs_should_notify_on_progress_updates": "false", "hs_should_recalculate": "false", "hs_start_date": null, "hs_start_datetime": "2023-09-01T00:00:00+00:00", "hs_static_kpi_filter_groups": "[]", "hs_status": "achieved", "hs_status_display_order": 4, "hs_target_amount": 0.0, "hs_target_amount_in_home_currency": 0.0, "hs_team_id": null, "hs_template_id": 4, "hs_ticket_pipeline_ids": "0", "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "26748728", "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null}, "createdAt": "2023-04-10T13:57:36.691Z", "updatedAt": "2023-12-11T20:46:14.473Z", "archived": false, "properties_hs__migration_soft_delete": null, "properties_hs_ad_account_asset_ids": null, "properties_hs_ad_campaign_asset_ids": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignee_team_id": null, "properties_hs_assignee_user_id": 26748728, "properties_hs_contact_lifecycle_stage": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-10T13:57:36.691000+00:00", "properties_hs_currency": null, "properties_hs_deal_pipeline_ids": null, "properties_hs_edit_updates_notification_frequency": "weekly", "properties_hs_end_date": null, "properties_hs_end_datetime": "2023-09-30T23:59:59.999000+00:00", "properties_hs_fiscal_year_offset": 0, "properties_hs_goal_definition_key": null, "properties_hs_goal_definition_key_with_team": null, "properties_hs_goal_definition_key_with_user": null, "properties_hs_goal_name": "Integration Test Goal Hubspot", "properties_hs_goal_target_group_id": 221880750627, "properties_hs_goal_type": "average_ticket_response_time", "properties_hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "properties_hs_is_forecastable": "true", "properties_hs_is_legacy": null, "properties_hs_kpi_display_unit": "hour", "properties_hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "properties_hs_kpi_filter_groups_for_key_grouping": null, "properties_hs_kpi_filter_groups_for_key_team_grouping": null, "properties_hs_kpi_is_team_rollup": false, "properties_hs_kpi_metric_type": "AVG", "properties_hs_kpi_object_type": "TICKET", "properties_hs_kpi_object_type_id": "0-5", "properties_hs_kpi_progress_percent": null, "properties_hs_kpi_property_name": "time_to_first_agent_reply", "properties_hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "properties_hs_kpi_time_period_property": "createdate", "properties_hs_kpi_tracking_method": "LOWER_IS_BETTER", "properties_hs_kpi_unit_type": "duration", "properties_hs_kpi_value": 0.0, "properties_hs_kpi_value_calculated_at": null, "properties_hs_kpi_value_last_calculated_at": "2023-10-01T22:31:08.621000+00:00", "properties_hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "properties_hs_legacy_active": null, "properties_hs_legacy_created_at": null, "properties_hs_legacy_created_by": null, "properties_hs_legacy_quarterly_target_composite_id": null, "properties_hs_legacy_sql_id": null, "properties_hs_legacy_unique_sql_id": null, "properties_hs_legacy_updated_at": null, "properties_hs_legacy_updated_by": null, "properties_hs_merged_object_ids": null, "properties_hs_migration_soft_delete": null, "properties_hs_milestone": "monthly", "properties_hs_object_id": 221880757010, "properties_hs_object_source": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": null, "properties_hs_object_source_user_id": null, "properties_hs_outcome": "completed", "properties_hs_owner_ids_of_all_owners": "111730024", "properties_hs_pipelines": "0", "properties_hs_progress_updates_notification_frequency": "weekly", "properties_hs_read_only": null, "properties_hs_should_notify_on_achieved": "false", "properties_hs_should_notify_on_edit_updates": "false", "properties_hs_should_notify_on_exceeded": "false", "properties_hs_should_notify_on_kickoff": "false", "properties_hs_should_notify_on_missed": "false", "properties_hs_should_notify_on_progress_updates": "false", "properties_hs_should_recalculate": "false", "properties_hs_start_date": null, "properties_hs_start_datetime": "2023-09-01T00:00:00+00:00", "properties_hs_static_kpi_filter_groups": "[]", "properties_hs_status": "achieved", "properties_hs_status_display_order": 4, "properties_hs_target_amount": 0.0, "properties_hs_target_amount_in_home_currency": 0.0, "properties_hs_team_id": null, "properties_hs_template_id": 4, "properties_hs_ticket_pipeline_ids": "0", "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "26748728", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null}, "emitted_at": 1707314192088} -{"stream": "goals", "data": {"id": "221880757011", "properties": {"hs__migration_soft_delete": null, "hs_ad_account_asset_ids": null, "hs_ad_campaign_asset_ids": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignee_team_id": null, "hs_assignee_user_id": 26748728, "hs_contact_lifecycle_stage": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-10T13:57:36.691000+00:00", "hs_currency": null, "hs_deal_pipeline_ids": null, "hs_edit_updates_notification_frequency": "weekly", "hs_end_date": null, "hs_end_datetime": "2023-08-31T23:59:59.999000+00:00", "hs_fiscal_year_offset": 0, "hs_goal_definition_key": null, "hs_goal_definition_key_with_team": null, "hs_goal_definition_key_with_user": null, "hs_goal_name": "Integration Test Goal Hubspot", "hs_goal_target_group_id": 221880750627, "hs_goal_type": "average_ticket_response_time", "hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "hs_is_forecastable": "true", "hs_is_legacy": null, "hs_kpi_display_unit": "hour", "hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "hs_kpi_filter_groups_for_key_grouping": null, "hs_kpi_filter_groups_for_key_team_grouping": null, "hs_kpi_is_team_rollup": false, "hs_kpi_metric_type": "AVG", "hs_kpi_object_type": "TICKET", "hs_kpi_object_type_id": "0-5", "hs_kpi_progress_percent": null, "hs_kpi_property_name": "time_to_first_agent_reply", "hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "hs_kpi_time_period_property": "createdate", "hs_kpi_tracking_method": "LOWER_IS_BETTER", "hs_kpi_unit_type": "duration", "hs_kpi_value": 0.0, "hs_kpi_value_calculated_at": null, "hs_kpi_value_last_calculated_at": "2023-09-01T15:26:00.500000+00:00", "hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "hs_legacy_active": null, "hs_legacy_created_at": null, "hs_legacy_created_by": null, "hs_legacy_quarterly_target_composite_id": null, "hs_legacy_sql_id": null, "hs_legacy_unique_sql_id": null, "hs_legacy_updated_at": null, "hs_legacy_updated_by": null, "hs_merged_object_ids": null, "hs_migration_soft_delete": null, "hs_milestone": "monthly", "hs_object_id": 221880757011, "hs_object_source": null, "hs_object_source_id": null, "hs_object_source_label": null, "hs_object_source_user_id": null, "hs_outcome": "completed", "hs_owner_ids_of_all_owners": "111730024", "hs_pipelines": "0", "hs_progress_updates_notification_frequency": "weekly", "hs_read_only": null, "hs_should_notify_on_achieved": "false", "hs_should_notify_on_edit_updates": "false", "hs_should_notify_on_exceeded": "false", "hs_should_notify_on_kickoff": "false", "hs_should_notify_on_missed": "false", "hs_should_notify_on_progress_updates": "false", "hs_should_recalculate": "false", "hs_start_date": null, "hs_start_datetime": "2023-08-01T00:00:00+00:00", "hs_static_kpi_filter_groups": "[]", "hs_status": "achieved", "hs_status_display_order": 4, "hs_target_amount": 0.0, "hs_target_amount_in_home_currency": 0.0, "hs_team_id": null, "hs_template_id": 4, "hs_ticket_pipeline_ids": "0", "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "26748728", "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null}, "createdAt": "2023-04-10T13:57:36.691Z", "updatedAt": "2023-12-11T20:46:14.473Z", "archived": false, "properties_hs__migration_soft_delete": null, "properties_hs_ad_account_asset_ids": null, "properties_hs_ad_campaign_asset_ids": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignee_team_id": null, "properties_hs_assignee_user_id": 26748728, "properties_hs_contact_lifecycle_stage": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-10T13:57:36.691000+00:00", "properties_hs_currency": null, "properties_hs_deal_pipeline_ids": null, "properties_hs_edit_updates_notification_frequency": "weekly", "properties_hs_end_date": null, "properties_hs_end_datetime": "2023-08-31T23:59:59.999000+00:00", "properties_hs_fiscal_year_offset": 0, "properties_hs_goal_definition_key": null, "properties_hs_goal_definition_key_with_team": null, "properties_hs_goal_definition_key_with_user": null, "properties_hs_goal_name": "Integration Test Goal Hubspot", "properties_hs_goal_target_group_id": 221880750627, "properties_hs_goal_type": "average_ticket_response_time", "properties_hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "properties_hs_is_forecastable": "true", "properties_hs_is_legacy": null, "properties_hs_kpi_display_unit": "hour", "properties_hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "properties_hs_kpi_filter_groups_for_key_grouping": null, "properties_hs_kpi_filter_groups_for_key_team_grouping": null, "properties_hs_kpi_is_team_rollup": false, "properties_hs_kpi_metric_type": "AVG", "properties_hs_kpi_object_type": "TICKET", "properties_hs_kpi_object_type_id": "0-5", "properties_hs_kpi_progress_percent": null, "properties_hs_kpi_property_name": "time_to_first_agent_reply", "properties_hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "properties_hs_kpi_time_period_property": "createdate", "properties_hs_kpi_tracking_method": "LOWER_IS_BETTER", "properties_hs_kpi_unit_type": "duration", "properties_hs_kpi_value": 0.0, "properties_hs_kpi_value_calculated_at": null, "properties_hs_kpi_value_last_calculated_at": "2023-09-01T15:26:00.500000+00:00", "properties_hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "properties_hs_legacy_active": null, "properties_hs_legacy_created_at": null, "properties_hs_legacy_created_by": null, "properties_hs_legacy_quarterly_target_composite_id": null, "properties_hs_legacy_sql_id": null, "properties_hs_legacy_unique_sql_id": null, "properties_hs_legacy_updated_at": null, "properties_hs_legacy_updated_by": null, "properties_hs_merged_object_ids": null, "properties_hs_migration_soft_delete": null, "properties_hs_milestone": "monthly", "properties_hs_object_id": 221880757011, "properties_hs_object_source": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": null, "properties_hs_object_source_user_id": null, "properties_hs_outcome": "completed", "properties_hs_owner_ids_of_all_owners": "111730024", "properties_hs_pipelines": "0", "properties_hs_progress_updates_notification_frequency": "weekly", "properties_hs_read_only": null, "properties_hs_should_notify_on_achieved": "false", "properties_hs_should_notify_on_edit_updates": "false", "properties_hs_should_notify_on_exceeded": "false", "properties_hs_should_notify_on_kickoff": "false", "properties_hs_should_notify_on_missed": "false", "properties_hs_should_notify_on_progress_updates": "false", "properties_hs_should_recalculate": "false", "properties_hs_start_date": null, "properties_hs_start_datetime": "2023-08-01T00:00:00+00:00", "properties_hs_static_kpi_filter_groups": "[]", "properties_hs_status": "achieved", "properties_hs_status_display_order": 4, "properties_hs_target_amount": 0.0, "properties_hs_target_amount_in_home_currency": 0.0, "properties_hs_team_id": null, "properties_hs_template_id": 4, "properties_hs_ticket_pipeline_ids": "0", "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "26748728", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null}, "emitted_at": 1707314192091} -{"stream": "line_items", "data": {"id": "1188257165", "properties": {"amount": 10.0, "createdate": "2021-02-23T20:11:54.030000+00:00", "description": "Baseball hat, medium", "discount": null, "hs_acv": 10.0, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_allow_buyer_selected_quantity": null, "hs_arr": 0.0, "hs_billing_period_end_date": null, "hs_billing_period_start_date": null, "hs_billing_start_delay_days": null, "hs_billing_start_delay_months": null, "hs_billing_start_delay_type": null, "hs_cost_of_goods_sold": 5, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_discount_percentage": null, "hs_external_id": null, "hs_images": null, "hs_lastmodifieddate": "2021-07-17T23:50:32.502000+00:00", "hs_line_item_currency_code": null, "hs_margin": 5.0, "hs_margin_acv": 5.0, "hs_margin_arr": 0.0, "hs_margin_mrr": 0.0, "hs_margin_tcv": 5.0, "hs_merged_object_ids": null, "hs_mrr": 0.0, "hs_object_id": 1188257165, "hs_object_source": "CRM_UI", "hs_object_source_id": "integration-test@airbyte.io", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_position_on_quote": 0, "hs_pre_discount_amount": 10, "hs_product_id": 646778218, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_end_date": null, "hs_recurring_billing_number_of_payments": 1, "hs_recurring_billing_period": null, "hs_recurring_billing_start_date": null, "hs_recurring_billing_terms": null, "hs_sku": null, "hs_sync_amount": null, "hs_tcv": 10.0, "hs_term_in_months": null, "hs_total_discount": 0, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_variant_id": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Blue Hat", "price": 10, "quantity": 1, "recurringbillingfrequency": null, "tax": null, "test": null, "test_product_price": null}, "createdAt": "2021-02-23T20:11:54.030Z", "updatedAt": "2021-07-17T23:50:32.502Z", "archived": false, "properties_amount": 10.0, "properties_createdate": "2021-02-23T20:11:54.030000+00:00", "properties_description": "Baseball hat, medium", "properties_discount": null, "properties_hs_acv": 10.0, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_allow_buyer_selected_quantity": null, "properties_hs_arr": 0.0, "properties_hs_billing_period_end_date": null, "properties_hs_billing_period_start_date": null, "properties_hs_billing_start_delay_days": null, "properties_hs_billing_start_delay_months": null, "properties_hs_billing_start_delay_type": null, "properties_hs_cost_of_goods_sold": 5, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_external_id": null, "properties_hs_images": null, "properties_hs_lastmodifieddate": "2021-07-17T23:50:32.502000+00:00", "properties_hs_line_item_currency_code": null, "properties_hs_margin": 5.0, "properties_hs_margin_acv": 5.0, "properties_hs_margin_arr": 0.0, "properties_hs_margin_mrr": 0.0, "properties_hs_margin_tcv": 5.0, "properties_hs_merged_object_ids": null, "properties_hs_mrr": 0.0, "properties_hs_object_id": 1188257165, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "integration-test@airbyte.io", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_position_on_quote": 0, "properties_hs_pre_discount_amount": 10, "properties_hs_product_id": 646778218, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_end_date": null, "properties_hs_recurring_billing_number_of_payments": 1, "properties_hs_recurring_billing_period": null, "properties_hs_recurring_billing_start_date": null, "properties_hs_recurring_billing_terms": null, "properties_hs_sku": null, "properties_hs_sync_amount": null, "properties_hs_tcv": 10.0, "properties_hs_term_in_months": null, "properties_hs_total_discount": 0, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_variant_id": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Blue Hat", "properties_price": 10, "properties_quantity": 1, "properties_recurringbillingfrequency": null, "properties_tax": null, "properties_test": null, "properties_test_product_price": null}, "emitted_at": 1706192514669} -{"stream": "line_items", "data": {"id": "1188257309", "properties": {"amount": 10.0, "createdate": "2021-02-23T20:11:54.030000+00:00", "description": "Baseball hat, medium", "discount": null, "hs_acv": 10.0, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_allow_buyer_selected_quantity": null, "hs_arr": 0.0, "hs_billing_period_end_date": null, "hs_billing_period_start_date": null, "hs_billing_start_delay_days": null, "hs_billing_start_delay_months": null, "hs_billing_start_delay_type": null, "hs_cost_of_goods_sold": 5, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_discount_percentage": null, "hs_external_id": null, "hs_images": null, "hs_lastmodifieddate": "2021-07-19T03:57:09.834000+00:00", "hs_line_item_currency_code": null, "hs_margin": 5.0, "hs_margin_acv": 5.0, "hs_margin_arr": 0.0, "hs_margin_mrr": 0.0, "hs_margin_tcv": 5.0, "hs_merged_object_ids": null, "hs_mrr": 0.0, "hs_object_id": 1188257309, "hs_object_source": "CRM_UI", "hs_object_source_id": "integration-test@airbyte.io", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_position_on_quote": 0, "hs_pre_discount_amount": 10, "hs_product_id": 646778218, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_end_date": null, "hs_recurring_billing_number_of_payments": 1, "hs_recurring_billing_period": null, "hs_recurring_billing_start_date": null, "hs_recurring_billing_terms": null, "hs_sku": null, "hs_sync_amount": null, "hs_tcv": 10.0, "hs_term_in_months": null, "hs_total_discount": 0, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_variant_id": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Blue Hat", "price": 10, "quantity": 1, "recurringbillingfrequency": null, "tax": null, "test": null, "test_product_price": null}, "createdAt": "2021-02-23T20:11:54.030Z", "updatedAt": "2021-07-19T03:57:09.834Z", "archived": false, "properties_amount": 10.0, "properties_createdate": "2021-02-23T20:11:54.030000+00:00", "properties_description": "Baseball hat, medium", "properties_discount": null, "properties_hs_acv": 10.0, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_allow_buyer_selected_quantity": null, "properties_hs_arr": 0.0, "properties_hs_billing_period_end_date": null, "properties_hs_billing_period_start_date": null, "properties_hs_billing_start_delay_days": null, "properties_hs_billing_start_delay_months": null, "properties_hs_billing_start_delay_type": null, "properties_hs_cost_of_goods_sold": 5, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_external_id": null, "properties_hs_images": null, "properties_hs_lastmodifieddate": "2021-07-19T03:57:09.834000+00:00", "properties_hs_line_item_currency_code": null, "properties_hs_margin": 5.0, "properties_hs_margin_acv": 5.0, "properties_hs_margin_arr": 0.0, "properties_hs_margin_mrr": 0.0, "properties_hs_margin_tcv": 5.0, "properties_hs_merged_object_ids": null, "properties_hs_mrr": 0.0, "properties_hs_object_id": 1188257309, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "integration-test@airbyte.io", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_position_on_quote": 0, "properties_hs_pre_discount_amount": 10, "properties_hs_product_id": 646778218, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_end_date": null, "properties_hs_recurring_billing_number_of_payments": 1, "properties_hs_recurring_billing_period": null, "properties_hs_recurring_billing_start_date": null, "properties_hs_recurring_billing_terms": null, "properties_hs_sku": null, "properties_hs_sync_amount": null, "properties_hs_tcv": 10.0, "properties_hs_term_in_months": null, "properties_hs_total_discount": 0, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_variant_id": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Blue Hat", "properties_price": 10, "properties_quantity": 1, "properties_recurringbillingfrequency": null, "properties_tax": null, "properties_test": null, "properties_test_product_price": null}, "emitted_at": 1706192514672} -{"stream": "line_items", "data": {"id": "1510167477", "properties": {"amount": 20.0, "createdate": "2021-05-21T10:22:40.683000+00:00", "description": "Top hat, large", "discount": null, "hs_acv": 60.0, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_allow_buyer_selected_quantity": null, "hs_arr": 60.0, "hs_billing_period_end_date": null, "hs_billing_period_start_date": null, "hs_billing_start_delay_days": null, "hs_billing_start_delay_months": null, "hs_billing_start_delay_type": null, "hs_cost_of_goods_sold": 10, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_discount_percentage": null, "hs_external_id": null, "hs_images": null, "hs_lastmodifieddate": "2022-02-23T08:09:16.555000+00:00", "hs_line_item_currency_code": null, "hs_margin": 10.0, "hs_margin_acv": 30.0, "hs_margin_arr": 30.0, "hs_margin_mrr": 10.0, "hs_margin_tcv": 30.0, "hs_merged_object_ids": null, "hs_mrr": 20.0, "hs_object_id": 1510167477, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_position_on_quote": null, "hs_pre_discount_amount": 20, "hs_product_id": 646777910, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_end_date": "2022-05-28", "hs_recurring_billing_number_of_payments": 3, "hs_recurring_billing_period": "P3M", "hs_recurring_billing_start_date": "2022-02-28", "hs_recurring_billing_terms": null, "hs_sku": null, "hs_sync_amount": null, "hs_tcv": 60.0, "hs_term_in_months": 3, "hs_total_discount": 0, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_variant_id": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Red Hat", "price": 20, "quantity": 1, "recurringbillingfrequency": "monthly", "tax": null, "test": "2022-02-24", "test_product_price": "2022-02-23"}, "createdAt": "2021-05-21T10:22:40.683Z", "updatedAt": "2022-02-23T08:09:16.555Z", "archived": false, "properties_amount": 20.0, "properties_createdate": "2021-05-21T10:22:40.683000+00:00", "properties_description": "Top hat, large", "properties_discount": null, "properties_hs_acv": 60.0, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_allow_buyer_selected_quantity": null, "properties_hs_arr": 60.0, "properties_hs_billing_period_end_date": null, "properties_hs_billing_period_start_date": null, "properties_hs_billing_start_delay_days": null, "properties_hs_billing_start_delay_months": null, "properties_hs_billing_start_delay_type": null, "properties_hs_cost_of_goods_sold": 10, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_external_id": null, "properties_hs_images": null, "properties_hs_lastmodifieddate": "2022-02-23T08:09:16.555000+00:00", "properties_hs_line_item_currency_code": null, "properties_hs_margin": 10.0, "properties_hs_margin_acv": 30.0, "properties_hs_margin_arr": 30.0, "properties_hs_margin_mrr": 10.0, "properties_hs_margin_tcv": 30.0, "properties_hs_merged_object_ids": null, "properties_hs_mrr": 20.0, "properties_hs_object_id": 1510167477, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_position_on_quote": null, "properties_hs_pre_discount_amount": 20, "properties_hs_product_id": 646777910, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_end_date": "2022-05-28", "properties_hs_recurring_billing_number_of_payments": 3, "properties_hs_recurring_billing_period": "P3M", "properties_hs_recurring_billing_start_date": "2022-02-28", "properties_hs_recurring_billing_terms": null, "properties_hs_sku": null, "properties_hs_sync_amount": null, "properties_hs_tcv": 60.0, "properties_hs_term_in_months": 3, "properties_hs_total_discount": 0, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_variant_id": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Red Hat", "properties_price": 20, "properties_quantity": 1, "properties_recurringbillingfrequency": "monthly", "properties_tax": null, "properties_test": "2022-02-24", "properties_test_product_price": "2022-02-23"}, "emitted_at": 1706192514674} -{"stream": "marketing_emails", "data": {"ab": false, "abHoursToWait": 4, "abSampleSizeDefault": null, "abSamplingDefault": null, "abSuccessMetric": null, "abTestPercentage": 50, "abVariation": false, "absoluteUrl": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-86812db1-e3c8-43cd-ae80-69a0934cd1de", "aifeatures": null, "allEmailCampaignIds": [243851494], "analyticsPageId": "100523515217", "analyticsPageType": "email", "archivedAt": 0, "archivedInDashboard": false, "audienceAccess": "PUBLIC", "author": "integration-test@airbyte.io", "authorName": "Team-1 Airbyte", "blogRssSettings": null, "canSpamSettingsId": 36765207029, "categoryId": 2, "contentAccessRuleIds": [], "contentAccessRuleTypes": [], "contentTypeCategory": 2, "createPage": false, "created": 1675121582718, "createdById": 12282590, "currentState": "PUBLISHED", "currentlyPublished": true, "customReplyTo": "", "customReplyToEnabled": false, "domain": "", "emailBody": "{% content_attribute \"email_body\" %}{{ default_email_body }}{% end_content_attribute %}", "emailNote": "", "emailTemplateMode": "DRAG_AND_DROP", "emailType": "BATCH_EMAIL", "emailbodyPlaintext": "", "feedbackSurveyId": null, "flexAreas": {"main": {"boxed": false, "isSingleColumnFullWidth": false, "sections": [{"columns": [{"id": "column-0-0", "widgets": ["module-0-0-0"], "width": 12}], "id": "section-0", "style": {"backgroundColor": "#eaf0f6", "backgroundType": "CONTENT", "paddingBottom": "10px", "paddingTop": "10px"}}, {"columns": [{"id": "column-1-0", "widgets": ["module-1-0-0"], "width": 12}], "id": "section-1", "style": {"backgroundType": "CONTENT", "paddingBottom": "30px", "paddingTop": "30px"}}, {"columns": [{"id": "column-2-0", "widgets": ["module-2-0-0"], "width": 12}], "id": "section-2", "style": {"backgroundColor": "", "backgroundType": "CONTENT", "paddingBottom": "20px", "paddingTop": "20px"}}]}}, "freezeDate": 1675121645993, "fromName": "Team Airbyte", "hasContentAccessRules": false, "htmlTitle": "", "id": 100523515217, "isCreatedFomSandboxSync": false, "isGraymailSuppressionEnabled": true, "isInstanceLayoutPage": false, "isPublished": true, "isRecipientFatigueSuppressionEnabled": null, "language": "en", "layoutSections": {}, "liveDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "mailingListsExcluded": [], "mailingListsIncluded": [], "maxRssEntries": 5, "metaDescription": "", "name": "test", "pageExpiryEnabled": false, "pageRedirected": false, "pastMabExperimentIds": [], "portalId": 8727216, "previewKey": "nlkwziGL", "primaryEmailCampaignId": 243851494, "processingStatus": "PUBLISHED", "publishDate": 1675121645000, "publishImmediately": true, "publishedAt": 1675121646297, "publishedByEmail": "integration-test@airbyte.io", "publishedById": 12282590, "publishedByName": "Team-1 Airbyte", "publishedUrl": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-86812db1-e3c8-43cd-ae80-69a0934cd1de", "replyTo": "integration-test@airbyte.io", "resolvedDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "rootMicId": null, "rssEmailByText": "By", "rssEmailClickThroughText": "Read more »", "rssEmailCommentText": "Comment »", "rssEmailEntryTemplateEnabled": false, "rssEmailImageMaxWidth": 0, "rssEmailUrl": "", "sections": {}, "securityState": "NONE", "selected": 0, "slug": "-temporary-slug-86812db1-e3c8-43cd-ae80-69a0934cd1de", "smartEmailFields": {}, "state": "PUBLISHED", "stats": {"counters": {"sent": 0, "open": 0, "delivered": 0, "bounce": 0, "unsubscribed": 0, "click": 0, "reply": 0, "dropped": 1, "selected": 1, "spamreport": 0, "suppressed": 0, "hardbounced": 0, "softbounced": 0, "pending": 0, "contactslost": 0, "notsent": 1}, "deviceBreakdown": {"open_device_type": {"computer": 0, "mobile": 0, "unknown": 0}, "click_device_type": {"computer": 0, "mobile": 0, "unknown": 0}}, "failedToLoad": false, "qualifierStats": {}, "ratios": {"clickratio": 0, "clickthroughratio": 0, "deliveredratio": 0, "openratio": 0, "replyratio": 0, "unsubscribedratio": 0, "spamreportratio": 0, "bounceratio": 0, "hardbounceratio": 0, "softbounceratio": 0, "contactslostratio": 0, "pendingratio": 0, "notsentratio": 100.0}}, "styleSettings": {"background_color": "#EAF0F6", "background_image": null, "background_image_type": null, "body_border_color": "#EAF0F6", "body_border_color_choice": "BORDER_MANUAL", "body_border_width": "1", "body_color": "#ffffff", "color_picker_favorite1": null, "color_picker_favorite2": null, "color_picker_favorite3": null, "color_picker_favorite4": null, "color_picker_favorite5": null, "color_picker_favorite6": null, "email_body_padding": null, "email_body_width": null, "heading_one_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "28", "underline": null}, "heading_two_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "22", "underline": null}, "links_font": {"bold": false, "color": "#00a4bd", "font": null, "font_style": {}, "italic": false, "size": null, "underline": true}, "primary_accent_color": null, "primary_font": "Arial, sans-serif", "primary_font_color": "#23496d", "primary_font_line_height": null, "primary_font_size": "15", "secondary_accent_color": null, "secondary_font": "Arial, sans-serif", "secondary_font_color": "#23496d", "secondary_font_line_height": null, "secondary_font_size": "12", "use_email_client_default_settings": false, "user_module_defaults": {"button_email": {"background_color": "#00a4bd", "corner_radius": 8, "font": "Arial, sans-serif", "font_color": "#ffffff", "font_size": 16, "font_style": {"color": "#ffffff", "font": "Arial, sans-serif", "size": {"units": "px", "value": 16}, "styles": {"bold": false, "italic": false, "underline": false}}}, "email_divider": {"color": {"color": "#23496d", "opacity": 100}, "height": 1, "line_type": "solid"}}}, "subcategory": "batch", "subject": "test", "subscription": 23704464, "subscriptionName": "Test sub", "teamPerms": [], "templatePath": "@hubspot/email/dnd/welcome.html", "transactional": false, "translations": {}, "unpublishedAt": 0, "updated": 1675121702583, "updatedById": 12282590, "url": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-86812db1-e3c8-43cd-ae80-69a0934cd1de", "useRssHeadlineAsSubject": false, "userPerms": [], "vidsExcluded": [], "vidsIncluded": [2501], "visibleToAll": true}, "emitted_at": 1706192639128} -{"stream": "marketing_emails", "data": {"ab": false, "abHoursToWait": 4, "abSampleSizeDefault": null, "abSamplingDefault": null, "abSuccessMetric": null, "abTestPercentage": 50, "abVariation": false, "absoluteUrl": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-f142cfbc-0d58-4eb5-b442-0d221f27b420", "aifeatures": null, "allEmailCampaignIds": [169919555], "analyticsPageId": "57347028995", "analyticsPageType": "email", "archivedAt": 0, "archivedInDashboard": false, "audienceAccess": "PUBLIC", "author": "integration-test@airbyte.io", "authorName": "Team-1 Airbyte", "blogRssSettings": null, "canSpamSettingsId": 36765207029, "categoryId": 2, "contentAccessRuleIds": [], "contentAccessRuleTypes": [], "contentTypeCategory": 2, "createPage": false, "created": 1634050240841, "createdById": 12282590, "currentState": "PUBLISHED", "currentlyPublished": true, "customReplyTo": "", "customReplyToEnabled": false, "domain": "", "emailBody": "{% content_attribute \"email_body\" %}{{ default_email_body }}{% end_content_attribute %}", "emailNote": "", "emailTemplateMode": "DRAG_AND_DROP", "emailType": "BATCH_EMAIL", "emailbodyPlaintext": "", "feedbackSurveyId": null, "flexAreas": {"main": {"boxed": false, "isSingleColumnFullWidth": false, "sections": [{"columns": [{"id": "column-0-0", "widgets": ["module-0-0-0"], "width": 12}], "id": "section-0", "style": {"backgroundType": "CONTENT", "paddingBottom": "40px", "paddingTop": "40px"}}, {"columns": [{"id": "column-1-0", "widgets": ["module-1-0-0"], "width": 12}], "id": "section-1", "style": {"backgroundColor": "", "backgroundType": "CONTENT", "paddingBottom": "0px", "paddingTop": "0px"}}]}}, "freezeDate": 1634050421336, "fromName": "Team Airbyte", "hasContentAccessRules": false, "htmlTitle": "", "id": 57347028995, "isCreatedFomSandboxSync": false, "isGraymailSuppressionEnabled": true, "isInstanceLayoutPage": false, "isPublished": true, "isRecipientFatigueSuppressionEnabled": null, "language": "en", "layoutSections": {}, "liveDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "mailingListsExcluded": [], "mailingListsIncluded": [130, 129, 131, 128, 126, 127, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116], "maxRssEntries": 5, "metaDescription": "", "name": "First test email - 1", "pageExpiryEnabled": false, "pageRedirected": false, "pastMabExperimentIds": [], "portalId": 8727216, "previewKey": "bgNuSvDn", "primaryEmailCampaignId": 169919555, "processingStatus": "PUBLISHED", "publishDate": 1634050421000, "publishImmediately": true, "publishedAt": 1634050421580, "publishedByEmail": "integration-test@airbyte.io", "publishedById": 12282590, "publishedByName": "Team-1 Airbyte", "publishedUrl": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-f142cfbc-0d58-4eb5-b442-0d221f27b420", "replyTo": "integration-test@airbyte.io", "resolvedDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "rootMicId": null, "rssEmailByText": "By", "rssEmailClickThroughText": "Read more »", "rssEmailCommentText": "Comment »", "rssEmailEntryTemplateEnabled": false, "rssEmailImageMaxWidth": 0, "rssEmailUrl": "", "sections": {}, "securityState": "NONE", "selected": 0, "slug": "-temporary-slug-f142cfbc-0d58-4eb5-b442-0d221f27b420", "smartEmailFields": {}, "state": "PUBLISHED", "stats": {"counters": {"sent": 0}, "deviceBreakdown": {}, "failedToLoad": false, "qualifierStats": {}, "ratios": {"clickratio": 0, "clickthroughratio": 0, "deliveredratio": 0, "openratio": 0, "replyratio": 0, "unsubscribedratio": 0, "spamreportratio": 0, "bounceratio": 0, "hardbounceratio": 0, "softbounceratio": 0, "contactslostratio": 0, "pendingratio": 0, "notsentratio": 0}}, "styleSettings": {"background_color": "#ffffff", "background_image": null, "background_image_type": null, "body_border_color": null, "body_border_color_choice": null, "body_border_width": "1", "body_color": "#ffffff", "color_picker_favorite1": null, "color_picker_favorite2": null, "color_picker_favorite3": null, "color_picker_favorite4": null, "color_picker_favorite5": null, "color_picker_favorite6": null, "email_body_padding": null, "email_body_width": null, "heading_one_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "28", "underline": null}, "heading_two_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "22", "underline": null}, "links_font": {"bold": false, "color": "#00a4bd", "font": null, "font_style": {}, "italic": false, "size": null, "underline": true}, "primary_accent_color": null, "primary_font": "Arial, sans-serif", "primary_font_color": "#23496d", "primary_font_line_height": null, "primary_font_size": "15", "secondary_accent_color": null, "secondary_font": "Arial, sans-serif", "secondary_font_color": "#23496d", "secondary_font_line_height": null, "secondary_font_size": "12", "use_email_client_default_settings": false, "user_module_defaults": {"button_email": {"background_color": null, "corner_radius": 8, "font": "Arial, sans-serif", "font_color": "#ffffff", "font_size": 16, "font_style": {"color": "#ffffff", "font": "Arial, sans-serif", "size": {"units": "px", "value": 16}, "styles": {"bold": false, "italic": false, "underline": false}}}, "email_divider": {"color": {"color": "#000000", "opacity": 100}, "height": 1, "line_type": null}}}, "subcategory": "batch", "subject": "Subject l", "subscription": 23704464, "subscriptionName": "Test sub", "teamPerms": [], "templatePath": "@hubspot/email/dnd/plain_text.html", "transactional": false, "translations": {}, "unpublishedAt": 0, "updated": 1634050455543, "updatedById": 12282590, "url": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-f142cfbc-0d58-4eb5-b442-0d221f27b420", "useRssHeadlineAsSubject": false, "userPerms": [], "vidsExcluded": [], "vidsIncluded": [], "visibleToAll": true}, "emitted_at": 1706192639130} -{"stream": "marketing_emails", "data": {"ab": false, "abHoursToWait": 4, "abSampleSizeDefault": null, "abSamplingDefault": null, "abSuccessMetric": null, "abTestPercentage": 50, "abVariation": false, "absoluteUrl": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-fb53d6bf-1eb6-4ee6-90fe-610fc2569ea7", "aifeatures": null, "allEmailCampaignIds": [], "analyticsPageId": "42930862366", "analyticsPageType": "email", "archivedAt": 0, "archivedInDashboard": false, "audienceAccess": "PUBLIC", "author": "integration-test@airbyte.io", "authorName": "Team-1 Airbyte", "blogRssSettings": null, "canSpamSettingsId": 36765207029, "categoryId": 2, "clonedFrom": 41886608509, "contentAccessRuleIds": [], "contentAccessRuleTypes": [], "contentTypeCategory": 2, "createPage": false, "created": 1615502115346, "createdById": 100, "currentState": "AUTOMATED_DRAFT", "currentlyPublished": false, "customReplyTo": "", "customReplyToEnabled": false, "domain": "", "emailBody": "{% content_attribute \"email_body\" %}{{ default_email_body }}{% end_content_attribute %}", "emailNote": "", "emailTemplateMode": "DRAG_AND_DROP", "emailType": "AUTOMATED_EMAIL", "emailbodyPlaintext": "", "feedbackSurveyId": null, "flexAreas": {"main": {"boxed": false, "isSingleColumnFullWidth": false, "sections": [{"columns": [{"id": "column-0-1", "widgets": ["module-0-1-1"], "width": 12}], "id": "section-0", "style": {"backgroundColor": "#eaf0f6", "backgroundType": "CONTENT", "paddingBottom": "10px", "paddingTop": "10px"}}, {"columns": [{"id": "column-1-1", "widgets": ["module-1-1-1"], "width": 12}], "id": "section-1", "style": {"backgroundType": "CONTENT", "paddingBottom": "30px", "paddingTop": "30px"}}, {"columns": [{"id": "column-2-1", "widgets": ["module-2-1-1"], "width": 12}], "id": "section-2", "style": {"backgroundColor": "", "backgroundType": "CONTENT", "paddingBottom": "20px", "paddingTop": "20px"}}]}}, "freezeDate": 1634042970319, "fromName": "Team Airbyte", "hasContentAccessRules": false, "htmlTitle": "", "id": 42930862366, "isCreatedFomSandboxSync": false, "isGraymailSuppressionEnabled": false, "isInstanceLayoutPage": false, "isPublished": false, "isRecipientFatigueSuppressionEnabled": null, "language": "en", "lastEditSessionId": 1634042969643, "lastEditUpdateId": 0, "layoutSections": {}, "liveDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "mailingListsExcluded": [], "mailingListsIncluded": [], "maxRssEntries": 5, "metaDescription": "", "name": "Test subject (Test campaing - Clone)", "pageExpiryEnabled": false, "pageRedirected": false, "pastMabExperimentIds": [], "portalId": 8727216, "previewKey": "UmZGYZsU", "processingStatus": "UNDEFINED", "publishDate": 1634042970000, "publishImmediately": true, "publishedUrl": "", "replyTo": "integration-test@airbyte.io", "resolvedDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "rootMicId": null, "rssEmailByText": "By", "rssEmailClickThroughText": "Read more »", "rssEmailCommentText": "Comment »", "rssEmailEntryTemplateEnabled": false, "rssEmailImageMaxWidth": 0, "rssEmailUrl": "", "sections": {}, "securityState": "NONE", "slug": "-temporary-slug-fb53d6bf-1eb6-4ee6-90fe-610fc2569ea7", "smartEmailFields": {}, "state": "AUTOMATED_DRAFT", "styleSettings": {"background_color": "#EAF0F6", "background_image": null, "background_image_type": null, "body_border_color": "#EAF0F6", "body_border_color_choice": "BORDER_MANUAL", "body_border_width": "1", "body_color": "#ffffff", "color_picker_favorite1": null, "color_picker_favorite2": null, "color_picker_favorite3": null, "color_picker_favorite4": null, "color_picker_favorite5": null, "color_picker_favorite6": null, "email_body_padding": null, "email_body_width": null, "heading_one_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "28", "underline": null}, "heading_two_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "22", "underline": null}, "links_font": {"bold": false, "color": "#00a4bd", "font": null, "font_style": {}, "italic": false, "size": null, "underline": true}, "primary_accent_color": null, "primary_font": "Arial, sans-serif", "primary_font_color": "#23496d", "primary_font_line_height": null, "primary_font_size": "15", "secondary_accent_color": null, "secondary_font": "Arial, sans-serif", "secondary_font_color": "#23496d", "secondary_font_line_height": null, "secondary_font_size": "12", "use_email_client_default_settings": false, "user_module_defaults": {"button_email": {"background_color": "#00a4bd", "corner_radius": 8, "font": "Arial, sans-serif", "font_color": "#ffffff", "font_size": 16, "font_style": {"color": "#ffffff", "font": "Arial, sans-serif", "size": {"units": "px", "value": 16}, "styles": {"bold": false, "italic": false, "underline": false}}}, "email_divider": {"color": {"color": "#23496d", "opacity": 100}, "height": 1, "line_type": "solid"}}}, "subcategory": "automated", "subject": "Test subject", "subscription": 11890831, "subscriptionName": "Test subscription", "teamPerms": [], "templatePath": "@hubspot/email/dnd/welcome.html", "transactional": false, "translations": {}, "unpublishedAt": 0, "updated": 1634042970321, "updatedById": 12282590, "url": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-fb53d6bf-1eb6-4ee6-90fe-610fc2569ea7", "useRssHeadlineAsSubject": false, "userPerms": [], "vidsExcluded": [], "vidsIncluded": [], "visibleToAll": true}, "emitted_at": 1706192639131} +{"stream": "goals", "data": {"id": "221880757009", "properties": {"hs__migration_soft_delete": null, "hs_ad_account_asset_ids": null, "hs_ad_campaign_asset_ids": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignee_team_id": null, "hs_assignee_user_id": 26748728, "hs_contact_lifecycle_stage": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-10T13:57:36.691000+00:00", "hs_currency": null, "hs_deal_pipeline_ids": null, "hs_edit_updates_notification_frequency": "weekly", "hs_end_date": null, "hs_end_datetime": "2023-07-31T23:59:59.999000+00:00", "hs_fiscal_year_offset": 0, "hs_goal_definition_key": null, "hs_goal_definition_key_with_team": null, "hs_goal_definition_key_with_user": null, "hs_goal_name": "Integration Test Goal Hubspot", "hs_goal_target_group_id": 221880750627, "hs_goal_type": "average_ticket_response_time", "hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "hs_is_forecastable": "true", "hs_is_legacy": null, "hs_kpi_display_unit": "hour", "hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "hs_kpi_filter_groups_for_key_grouping": null, "hs_kpi_filter_groups_for_key_team_grouping": null, "hs_kpi_is_team_rollup": false, "hs_kpi_metric_type": "AVG", "hs_kpi_object_type": "TICKET", "hs_kpi_object_type_id": "0-5", "hs_kpi_progress_percent": null, "hs_kpi_property_name": "time_to_first_agent_reply", "hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "hs_kpi_time_period_property": "createdate", "hs_kpi_tracking_method": "LOWER_IS_BETTER", "hs_kpi_unit_type": "duration", "hs_kpi_value": 0.0, "hs_kpi_value_calculated_at": null, "hs_kpi_value_last_calculated_at": "2023-08-01T00:45:14.830000+00:00", "hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "hs_legacy_active": null, "hs_legacy_created_at": null, "hs_legacy_created_by": null, "hs_legacy_quarterly_target_composite_id": null, "hs_legacy_sql_id": null, "hs_legacy_unique_sql_id": null, "hs_legacy_updated_at": null, "hs_legacy_updated_by": null, "hs_merged_object_ids": null, "hs_migration_soft_delete": null, "hs_milestone": "monthly", "hs_object_id": 221880757009, "hs_object_source": null, "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": null, "hs_object_source_user_id": null, "hs_outcome": "completed", "hs_owner_ids_of_all_owners": "111730024", "hs_pipelines": "0", "hs_progress_updates_notification_frequency": "weekly", "hs_read_only": null, "hs_should_notify_on_achieved": "false", "hs_should_notify_on_edit_updates": "false", "hs_should_notify_on_exceeded": "false", "hs_should_notify_on_kickoff": "false", "hs_should_notify_on_missed": "false", "hs_should_notify_on_progress_updates": "false", "hs_should_recalculate": "false", "hs_start_date": null, "hs_start_datetime": "2023-07-01T00:00:00+00:00", "hs_static_kpi_filter_groups": "[]", "hs_status": "achieved", "hs_status_display_order": 4, "hs_target_amount": 0.0, "hs_target_amount_in_home_currency": 0.0, "hs_team_id": null, "hs_template_id": 4, "hs_ticket_pipeline_ids": "0", "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "26748728", "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null}, "createdAt": "2023-04-10T13:57:36.691Z", "updatedAt": "2023-12-11T20:46:14.473Z", "archived": false, "properties_hs__migration_soft_delete": null, "properties_hs_ad_account_asset_ids": null, "properties_hs_ad_campaign_asset_ids": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignee_team_id": null, "properties_hs_assignee_user_id": 26748728, "properties_hs_contact_lifecycle_stage": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-10T13:57:36.691000+00:00", "properties_hs_currency": null, "properties_hs_deal_pipeline_ids": null, "properties_hs_edit_updates_notification_frequency": "weekly", "properties_hs_end_date": null, "properties_hs_end_datetime": "2023-07-31T23:59:59.999000+00:00", "properties_hs_fiscal_year_offset": 0, "properties_hs_goal_definition_key": null, "properties_hs_goal_definition_key_with_team": null, "properties_hs_goal_definition_key_with_user": null, "properties_hs_goal_name": "Integration Test Goal Hubspot", "properties_hs_goal_target_group_id": 221880750627, "properties_hs_goal_type": "average_ticket_response_time", "properties_hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "properties_hs_is_forecastable": "true", "properties_hs_is_legacy": null, "properties_hs_kpi_display_unit": "hour", "properties_hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "properties_hs_kpi_filter_groups_for_key_grouping": null, "properties_hs_kpi_filter_groups_for_key_team_grouping": null, "properties_hs_kpi_is_team_rollup": false, "properties_hs_kpi_metric_type": "AVG", "properties_hs_kpi_object_type": "TICKET", "properties_hs_kpi_object_type_id": "0-5", "properties_hs_kpi_progress_percent": null, "properties_hs_kpi_property_name": "time_to_first_agent_reply", "properties_hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "properties_hs_kpi_time_period_property": "createdate", "properties_hs_kpi_tracking_method": "LOWER_IS_BETTER", "properties_hs_kpi_unit_type": "duration", "properties_hs_kpi_value": 0.0, "properties_hs_kpi_value_calculated_at": null, "properties_hs_kpi_value_last_calculated_at": "2023-08-01T00:45:14.830000+00:00", "properties_hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "properties_hs_legacy_active": null, "properties_hs_legacy_created_at": null, "properties_hs_legacy_created_by": null, "properties_hs_legacy_quarterly_target_composite_id": null, "properties_hs_legacy_sql_id": null, "properties_hs_legacy_unique_sql_id": null, "properties_hs_legacy_updated_at": null, "properties_hs_legacy_updated_by": null, "properties_hs_merged_object_ids": null, "properties_hs_migration_soft_delete": null, "properties_hs_milestone": "monthly", "properties_hs_object_id": 221880757009, "properties_hs_object_source": null, "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": null, "properties_hs_object_source_user_id": null, "properties_hs_outcome": "completed", "properties_hs_owner_ids_of_all_owners": "111730024", "properties_hs_pipelines": "0", "properties_hs_progress_updates_notification_frequency": "weekly", "properties_hs_read_only": null, "properties_hs_should_notify_on_achieved": "false", "properties_hs_should_notify_on_edit_updates": "false", "properties_hs_should_notify_on_exceeded": "false", "properties_hs_should_notify_on_kickoff": "false", "properties_hs_should_notify_on_missed": "false", "properties_hs_should_notify_on_progress_updates": "false", "properties_hs_should_recalculate": "false", "properties_hs_start_date": null, "properties_hs_start_datetime": "2023-07-01T00:00:00+00:00", "properties_hs_static_kpi_filter_groups": "[]", "properties_hs_status": "achieved", "properties_hs_status_display_order": 4, "properties_hs_target_amount": 0.0, "properties_hs_target_amount_in_home_currency": 0.0, "properties_hs_team_id": null, "properties_hs_template_id": 4, "properties_hs_ticket_pipeline_ids": "0", "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "26748728", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null}, "emitted_at": 1708013857256} +{"stream": "goals", "data": {"id": "221880757010", "properties": {"hs__migration_soft_delete": null, "hs_ad_account_asset_ids": null, "hs_ad_campaign_asset_ids": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignee_team_id": null, "hs_assignee_user_id": 26748728, "hs_contact_lifecycle_stage": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-10T13:57:36.691000+00:00", "hs_currency": null, "hs_deal_pipeline_ids": null, "hs_edit_updates_notification_frequency": "weekly", "hs_end_date": null, "hs_end_datetime": "2023-09-30T23:59:59.999000+00:00", "hs_fiscal_year_offset": 0, "hs_goal_definition_key": null, "hs_goal_definition_key_with_team": null, "hs_goal_definition_key_with_user": null, "hs_goal_name": "Integration Test Goal Hubspot", "hs_goal_target_group_id": 221880750627, "hs_goal_type": "average_ticket_response_time", "hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "hs_is_forecastable": "true", "hs_is_legacy": null, "hs_kpi_display_unit": "hour", "hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "hs_kpi_filter_groups_for_key_grouping": null, "hs_kpi_filter_groups_for_key_team_grouping": null, "hs_kpi_is_team_rollup": false, "hs_kpi_metric_type": "AVG", "hs_kpi_object_type": "TICKET", "hs_kpi_object_type_id": "0-5", "hs_kpi_progress_percent": null, "hs_kpi_property_name": "time_to_first_agent_reply", "hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "hs_kpi_time_period_property": "createdate", "hs_kpi_tracking_method": "LOWER_IS_BETTER", "hs_kpi_unit_type": "duration", "hs_kpi_value": 0.0, "hs_kpi_value_calculated_at": null, "hs_kpi_value_last_calculated_at": "2023-10-01T22:31:08.621000+00:00", "hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "hs_legacy_active": null, "hs_legacy_created_at": null, "hs_legacy_created_by": null, "hs_legacy_quarterly_target_composite_id": null, "hs_legacy_sql_id": null, "hs_legacy_unique_sql_id": null, "hs_legacy_updated_at": null, "hs_legacy_updated_by": null, "hs_merged_object_ids": null, "hs_migration_soft_delete": null, "hs_milestone": "monthly", "hs_object_id": 221880757010, "hs_object_source": null, "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": null, "hs_object_source_user_id": null, "hs_outcome": "completed", "hs_owner_ids_of_all_owners": "111730024", "hs_pipelines": "0", "hs_progress_updates_notification_frequency": "weekly", "hs_read_only": null, "hs_should_notify_on_achieved": "false", "hs_should_notify_on_edit_updates": "false", "hs_should_notify_on_exceeded": "false", "hs_should_notify_on_kickoff": "false", "hs_should_notify_on_missed": "false", "hs_should_notify_on_progress_updates": "false", "hs_should_recalculate": "false", "hs_start_date": null, "hs_start_datetime": "2023-09-01T00:00:00+00:00", "hs_static_kpi_filter_groups": "[]", "hs_status": "achieved", "hs_status_display_order": 4, "hs_target_amount": 0.0, "hs_target_amount_in_home_currency": 0.0, "hs_team_id": null, "hs_template_id": 4, "hs_ticket_pipeline_ids": "0", "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "26748728", "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null}, "createdAt": "2023-04-10T13:57:36.691Z", "updatedAt": "2023-12-11T20:46:14.473Z", "archived": false, "properties_hs__migration_soft_delete": null, "properties_hs_ad_account_asset_ids": null, "properties_hs_ad_campaign_asset_ids": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignee_team_id": null, "properties_hs_assignee_user_id": 26748728, "properties_hs_contact_lifecycle_stage": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-10T13:57:36.691000+00:00", "properties_hs_currency": null, "properties_hs_deal_pipeline_ids": null, "properties_hs_edit_updates_notification_frequency": "weekly", "properties_hs_end_date": null, "properties_hs_end_datetime": "2023-09-30T23:59:59.999000+00:00", "properties_hs_fiscal_year_offset": 0, "properties_hs_goal_definition_key": null, "properties_hs_goal_definition_key_with_team": null, "properties_hs_goal_definition_key_with_user": null, "properties_hs_goal_name": "Integration Test Goal Hubspot", "properties_hs_goal_target_group_id": 221880750627, "properties_hs_goal_type": "average_ticket_response_time", "properties_hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "properties_hs_is_forecastable": "true", "properties_hs_is_legacy": null, "properties_hs_kpi_display_unit": "hour", "properties_hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "properties_hs_kpi_filter_groups_for_key_grouping": null, "properties_hs_kpi_filter_groups_for_key_team_grouping": null, "properties_hs_kpi_is_team_rollup": false, "properties_hs_kpi_metric_type": "AVG", "properties_hs_kpi_object_type": "TICKET", "properties_hs_kpi_object_type_id": "0-5", "properties_hs_kpi_progress_percent": null, "properties_hs_kpi_property_name": "time_to_first_agent_reply", "properties_hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "properties_hs_kpi_time_period_property": "createdate", "properties_hs_kpi_tracking_method": "LOWER_IS_BETTER", "properties_hs_kpi_unit_type": "duration", "properties_hs_kpi_value": 0.0, "properties_hs_kpi_value_calculated_at": null, "properties_hs_kpi_value_last_calculated_at": "2023-10-01T22:31:08.621000+00:00", "properties_hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "properties_hs_legacy_active": null, "properties_hs_legacy_created_at": null, "properties_hs_legacy_created_by": null, "properties_hs_legacy_quarterly_target_composite_id": null, "properties_hs_legacy_sql_id": null, "properties_hs_legacy_unique_sql_id": null, "properties_hs_legacy_updated_at": null, "properties_hs_legacy_updated_by": null, "properties_hs_merged_object_ids": null, "properties_hs_migration_soft_delete": null, "properties_hs_milestone": "monthly", "properties_hs_object_id": 221880757010, "properties_hs_object_source": null, "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": null, "properties_hs_object_source_user_id": null, "properties_hs_outcome": "completed", "properties_hs_owner_ids_of_all_owners": "111730024", "properties_hs_pipelines": "0", "properties_hs_progress_updates_notification_frequency": "weekly", "properties_hs_read_only": null, "properties_hs_should_notify_on_achieved": "false", "properties_hs_should_notify_on_edit_updates": "false", "properties_hs_should_notify_on_exceeded": "false", "properties_hs_should_notify_on_kickoff": "false", "properties_hs_should_notify_on_missed": "false", "properties_hs_should_notify_on_progress_updates": "false", "properties_hs_should_recalculate": "false", "properties_hs_start_date": null, "properties_hs_start_datetime": "2023-09-01T00:00:00+00:00", "properties_hs_static_kpi_filter_groups": "[]", "properties_hs_status": "achieved", "properties_hs_status_display_order": 4, "properties_hs_target_amount": 0.0, "properties_hs_target_amount_in_home_currency": 0.0, "properties_hs_team_id": null, "properties_hs_template_id": 4, "properties_hs_ticket_pipeline_ids": "0", "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "26748728", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null}, "emitted_at": 1708013857258} +{"stream": "goals", "data": {"id": "221880757011", "properties": {"hs__migration_soft_delete": null, "hs_ad_account_asset_ids": null, "hs_ad_campaign_asset_ids": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignee_team_id": null, "hs_assignee_user_id": 26748728, "hs_contact_lifecycle_stage": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-10T13:57:36.691000+00:00", "hs_currency": null, "hs_deal_pipeline_ids": null, "hs_edit_updates_notification_frequency": "weekly", "hs_end_date": null, "hs_end_datetime": "2023-08-31T23:59:59.999000+00:00", "hs_fiscal_year_offset": 0, "hs_goal_definition_key": null, "hs_goal_definition_key_with_team": null, "hs_goal_definition_key_with_user": null, "hs_goal_name": "Integration Test Goal Hubspot", "hs_goal_target_group_id": 221880750627, "hs_goal_type": "average_ticket_response_time", "hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "hs_is_forecastable": "true", "hs_is_legacy": null, "hs_kpi_display_unit": "hour", "hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "hs_kpi_filter_groups_for_key_grouping": null, "hs_kpi_filter_groups_for_key_team_grouping": null, "hs_kpi_is_team_rollup": false, "hs_kpi_metric_type": "AVG", "hs_kpi_object_type": "TICKET", "hs_kpi_object_type_id": "0-5", "hs_kpi_progress_percent": null, "hs_kpi_property_name": "time_to_first_agent_reply", "hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "hs_kpi_time_period_property": "createdate", "hs_kpi_tracking_method": "LOWER_IS_BETTER", "hs_kpi_unit_type": "duration", "hs_kpi_value": 0.0, "hs_kpi_value_calculated_at": null, "hs_kpi_value_last_calculated_at": "2023-09-01T15:26:00.500000+00:00", "hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "hs_legacy_active": null, "hs_legacy_created_at": null, "hs_legacy_created_by": null, "hs_legacy_quarterly_target_composite_id": null, "hs_legacy_sql_id": null, "hs_legacy_unique_sql_id": null, "hs_legacy_updated_at": null, "hs_legacy_updated_by": null, "hs_merged_object_ids": null, "hs_migration_soft_delete": null, "hs_milestone": "monthly", "hs_object_id": 221880757011, "hs_object_source": null, "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": null, "hs_object_source_user_id": null, "hs_outcome": "completed", "hs_owner_ids_of_all_owners": "111730024", "hs_pipelines": "0", "hs_progress_updates_notification_frequency": "weekly", "hs_read_only": null, "hs_should_notify_on_achieved": "false", "hs_should_notify_on_edit_updates": "false", "hs_should_notify_on_exceeded": "false", "hs_should_notify_on_kickoff": "false", "hs_should_notify_on_missed": "false", "hs_should_notify_on_progress_updates": "false", "hs_should_recalculate": "false", "hs_start_date": null, "hs_start_datetime": "2023-08-01T00:00:00+00:00", "hs_static_kpi_filter_groups": "[]", "hs_status": "achieved", "hs_status_display_order": 4, "hs_target_amount": 0.0, "hs_target_amount_in_home_currency": 0.0, "hs_team_id": null, "hs_template_id": 4, "hs_ticket_pipeline_ids": "0", "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "26748728", "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null}, "createdAt": "2023-04-10T13:57:36.691Z", "updatedAt": "2023-12-11T20:46:14.473Z", "archived": false, "properties_hs__migration_soft_delete": null, "properties_hs_ad_account_asset_ids": null, "properties_hs_ad_campaign_asset_ids": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignee_team_id": null, "properties_hs_assignee_user_id": 26748728, "properties_hs_contact_lifecycle_stage": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-10T13:57:36.691000+00:00", "properties_hs_currency": null, "properties_hs_deal_pipeline_ids": null, "properties_hs_edit_updates_notification_frequency": "weekly", "properties_hs_end_date": null, "properties_hs_end_datetime": "2023-08-31T23:59:59.999000+00:00", "properties_hs_fiscal_year_offset": 0, "properties_hs_goal_definition_key": null, "properties_hs_goal_definition_key_with_team": null, "properties_hs_goal_definition_key_with_user": null, "properties_hs_goal_name": "Integration Test Goal Hubspot", "properties_hs_goal_target_group_id": 221880750627, "properties_hs_goal_type": "average_ticket_response_time", "properties_hs_group_correlation_uuid": "5c49f251-be20-43c6-87c7-dd273732b3a4", "properties_hs_is_forecastable": "true", "properties_hs_is_legacy": null, "properties_hs_kpi_display_unit": "hour", "properties_hs_kpi_filter_groups": "[{\"filters\":[{\"property\":\"hs_pipeline\",\"operator\":\"IN\",\"values\":[\"0\"]}]}]", "properties_hs_kpi_filter_groups_for_key_grouping": null, "properties_hs_kpi_filter_groups_for_key_team_grouping": null, "properties_hs_kpi_is_team_rollup": false, "properties_hs_kpi_metric_type": "AVG", "properties_hs_kpi_object_type": "TICKET", "properties_hs_kpi_object_type_id": "0-5", "properties_hs_kpi_progress_percent": null, "properties_hs_kpi_property_name": "time_to_first_agent_reply", "properties_hs_kpi_single_object_custom_goal_type_name": "avg_time_to_first_agent_reply_0-5", "properties_hs_kpi_time_period_property": "createdate", "properties_hs_kpi_tracking_method": "LOWER_IS_BETTER", "properties_hs_kpi_unit_type": "duration", "properties_hs_kpi_value": 0.0, "properties_hs_kpi_value_calculated_at": null, "properties_hs_kpi_value_last_calculated_at": "2023-09-01T15:26:00.500000+00:00", "properties_hs_lastmodifieddate": "2023-12-11T20:46:14.473000+00:00", "properties_hs_legacy_active": null, "properties_hs_legacy_created_at": null, "properties_hs_legacy_created_by": null, "properties_hs_legacy_quarterly_target_composite_id": null, "properties_hs_legacy_sql_id": null, "properties_hs_legacy_unique_sql_id": null, "properties_hs_legacy_updated_at": null, "properties_hs_legacy_updated_by": null, "properties_hs_merged_object_ids": null, "properties_hs_migration_soft_delete": null, "properties_hs_milestone": "monthly", "properties_hs_object_id": 221880757011, "properties_hs_object_source": null, "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": null, "properties_hs_object_source_user_id": null, "properties_hs_outcome": "completed", "properties_hs_owner_ids_of_all_owners": "111730024", "properties_hs_pipelines": "0", "properties_hs_progress_updates_notification_frequency": "weekly", "properties_hs_read_only": null, "properties_hs_should_notify_on_achieved": "false", "properties_hs_should_notify_on_edit_updates": "false", "properties_hs_should_notify_on_exceeded": "false", "properties_hs_should_notify_on_kickoff": "false", "properties_hs_should_notify_on_missed": "false", "properties_hs_should_notify_on_progress_updates": "false", "properties_hs_should_recalculate": "false", "properties_hs_start_date": null, "properties_hs_start_datetime": "2023-08-01T00:00:00+00:00", "properties_hs_static_kpi_filter_groups": "[]", "properties_hs_status": "achieved", "properties_hs_status_display_order": 4, "properties_hs_target_amount": 0.0, "properties_hs_target_amount_in_home_currency": 0.0, "properties_hs_team_id": null, "properties_hs_template_id": 4, "properties_hs_ticket_pipeline_ids": "0", "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "26748728", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null}, "emitted_at": 1708013857259} +{"stream": "line_items", "data": {"id": "1510167477", "properties": {"amount": 20.0, "createdate": "2021-05-21T10:22:40.683000+00:00", "description": "Top hat, large", "discount": null, "hs_acv": 60.0, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_allow_buyer_selected_quantity": null, "hs_arr": 60.0, "hs_billing_period_end_date": null, "hs_billing_period_start_date": null, "hs_billing_start_delay_days": null, "hs_billing_start_delay_months": null, "hs_billing_start_delay_type": null, "hs_cost_of_goods_sold": 10, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_discount_percentage": null, "hs_external_id": null, "hs_images": null, "hs_lastmodifieddate": "2022-02-23T08:09:16.555000+00:00", "hs_line_item_currency_code": null, "hs_margin": 10.0, "hs_margin_acv": 30.0, "hs_margin_arr": 30.0, "hs_margin_mrr": 10.0, "hs_margin_tcv": 30.0, "hs_merged_object_ids": null, "hs_mrr": 20.0, "hs_object_id": 1510167477, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_position_on_quote": null, "hs_pre_discount_amount": 20, "hs_product_id": 646777910, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_end_date": "2022-05-28", "hs_recurring_billing_number_of_payments": 3, "hs_recurring_billing_period": "P3M", "hs_recurring_billing_start_date": "2022-02-28", "hs_recurring_billing_terms": null, "hs_sku": null, "hs_sync_amount": null, "hs_tcv": 60.0, "hs_term_in_months": 3, "hs_total_discount": 0, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_variant_id": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Red Hat", "price": 20, "quantity": 1, "recurringbillingfrequency": "monthly", "tax": null, "test": "2022-02-24", "test_product_price": "2022-02-23"}, "createdAt": "2021-05-21T10:22:40.683Z", "updatedAt": "2022-02-23T08:09:16.555Z", "archived": false, "properties_amount": 20.0, "properties_createdate": "2021-05-21T10:22:40.683000+00:00", "properties_description": "Top hat, large", "properties_discount": null, "properties_hs_acv": 60.0, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_allow_buyer_selected_quantity": null, "properties_hs_arr": 60.0, "properties_hs_billing_period_end_date": null, "properties_hs_billing_period_start_date": null, "properties_hs_billing_start_delay_days": null, "properties_hs_billing_start_delay_months": null, "properties_hs_billing_start_delay_type": null, "properties_hs_cost_of_goods_sold": 10, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_external_id": null, "properties_hs_images": null, "properties_hs_lastmodifieddate": "2022-02-23T08:09:16.555000+00:00", "properties_hs_line_item_currency_code": null, "properties_hs_margin": 10.0, "properties_hs_margin_acv": 30.0, "properties_hs_margin_arr": 30.0, "properties_hs_margin_mrr": 10.0, "properties_hs_margin_tcv": 30.0, "properties_hs_merged_object_ids": null, "properties_hs_mrr": 20.0, "properties_hs_object_id": 1510167477, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_position_on_quote": null, "properties_hs_pre_discount_amount": 20, "properties_hs_product_id": 646777910, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_end_date": "2022-05-28", "properties_hs_recurring_billing_number_of_payments": 3, "properties_hs_recurring_billing_period": "P3M", "properties_hs_recurring_billing_start_date": "2022-02-28", "properties_hs_recurring_billing_terms": null, "properties_hs_sku": null, "properties_hs_sync_amount": null, "properties_hs_tcv": 60.0, "properties_hs_term_in_months": 3, "properties_hs_total_discount": 0, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_variant_id": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Red Hat", "properties_price": 20, "properties_quantity": 1, "properties_recurringbillingfrequency": "monthly", "properties_tax": null, "properties_test": "2022-02-24", "properties_test_product_price": "2022-02-23"}, "emitted_at": 1708014135793} +{"stream": "line_items", "data": {"id": "2089468681", "properties": {"amount": 10.0, "createdate": "2021-10-12T13:50:13.117000+00:00", "description": "baseball hat, large", "discount": null, "hs_acv": 10.0, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_allow_buyer_selected_quantity": null, "hs_arr": 0.0, "hs_billing_period_end_date": null, "hs_billing_period_start_date": null, "hs_billing_start_delay_days": null, "hs_billing_start_delay_months": null, "hs_billing_start_delay_type": null, "hs_cost_of_goods_sold": 5, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_discount_percentage": null, "hs_external_id": null, "hs_images": null, "hs_lastmodifieddate": "2021-10-12T13:50:13.117000+00:00", "hs_line_item_currency_code": null, "hs_margin": 5.0, "hs_margin_acv": 5.0, "hs_margin_arr": 0.0, "hs_margin_mrr": 0.0, "hs_margin_tcv": 5.0, "hs_merged_object_ids": null, "hs_mrr": 0.0, "hs_object_id": 2089468681, "hs_object_source": "API", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "INTERNAL_PROCESSING", "hs_object_source_user_id": 12282590, "hs_position_on_quote": 0, "hs_pre_discount_amount": 10, "hs_product_id": 646316535, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_end_date": null, "hs_recurring_billing_number_of_payments": 1, "hs_recurring_billing_period": null, "hs_recurring_billing_start_date": null, "hs_recurring_billing_terms": null, "hs_sku": null, "hs_sync_amount": null, "hs_tcv": 10.0, "hs_term_in_months": null, "hs_total_discount": 0, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_variant_id": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Green Hat", "price": 10, "quantity": 1, "recurringbillingfrequency": null, "tax": null, "test": null, "test_product_price": null}, "createdAt": "2021-10-12T13:50:13.117Z", "updatedAt": "2021-10-12T13:50:13.117Z", "archived": false, "properties_amount": 10.0, "properties_createdate": "2021-10-12T13:50:13.117000+00:00", "properties_description": "baseball hat, large", "properties_discount": null, "properties_hs_acv": 10.0, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_allow_buyer_selected_quantity": null, "properties_hs_arr": 0.0, "properties_hs_billing_period_end_date": null, "properties_hs_billing_period_start_date": null, "properties_hs_billing_start_delay_days": null, "properties_hs_billing_start_delay_months": null, "properties_hs_billing_start_delay_type": null, "properties_hs_cost_of_goods_sold": 5, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_external_id": null, "properties_hs_images": null, "properties_hs_lastmodifieddate": "2021-10-12T13:50:13.117000+00:00", "properties_hs_line_item_currency_code": null, "properties_hs_margin": 5.0, "properties_hs_margin_acv": 5.0, "properties_hs_margin_arr": 0.0, "properties_hs_margin_mrr": 0.0, "properties_hs_margin_tcv": 5.0, "properties_hs_merged_object_ids": null, "properties_hs_mrr": 0.0, "properties_hs_object_id": 2089468681, "properties_hs_object_source": "API", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "INTERNAL_PROCESSING", "properties_hs_object_source_user_id": 12282590, "properties_hs_position_on_quote": 0, "properties_hs_pre_discount_amount": 10, "properties_hs_product_id": 646316535, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_end_date": null, "properties_hs_recurring_billing_number_of_payments": 1, "properties_hs_recurring_billing_period": null, "properties_hs_recurring_billing_start_date": null, "properties_hs_recurring_billing_terms": null, "properties_hs_sku": null, "properties_hs_sync_amount": null, "properties_hs_tcv": 10.0, "properties_hs_term_in_months": null, "properties_hs_total_discount": 0, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_variant_id": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Green Hat", "properties_price": 10, "properties_quantity": 1, "properties_recurringbillingfrequency": null, "properties_tax": null, "properties_test": null, "properties_test_product_price": null}, "emitted_at": 1708014135796} +{"stream": "line_items", "data": {"id": "2089616136", "properties": {"amount": 10.0, "createdate": "2021-10-12T13:50:13.028000+00:00", "description": "baseball hat, large", "discount": null, "hs_acv": 10.0, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_allow_buyer_selected_quantity": null, "hs_arr": 0.0, "hs_billing_period_end_date": null, "hs_billing_period_start_date": null, "hs_billing_start_delay_days": null, "hs_billing_start_delay_months": null, "hs_billing_start_delay_type": null, "hs_cost_of_goods_sold": 5, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_discount_percentage": null, "hs_external_id": null, "hs_images": null, "hs_lastmodifieddate": "2021-10-12T13:50:13.028000+00:00", "hs_line_item_currency_code": null, "hs_margin": 5.0, "hs_margin_acv": 5.0, "hs_margin_arr": 0.0, "hs_margin_mrr": 0.0, "hs_margin_tcv": 5.0, "hs_merged_object_ids": null, "hs_mrr": 0.0, "hs_object_id": 2089616136, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_position_on_quote": 0, "hs_pre_discount_amount": 10, "hs_product_id": 646316535, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_end_date": null, "hs_recurring_billing_number_of_payments": 1, "hs_recurring_billing_period": null, "hs_recurring_billing_start_date": null, "hs_recurring_billing_terms": null, "hs_sku": null, "hs_sync_amount": null, "hs_tcv": 10.0, "hs_term_in_months": null, "hs_total_discount": 0, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_variant_id": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Green Hat", "price": 10, "quantity": 1, "recurringbillingfrequency": null, "tax": null, "test": null, "test_product_price": null}, "createdAt": "2021-10-12T13:50:13.028Z", "updatedAt": "2021-10-12T13:50:13.028Z", "archived": false, "properties_amount": 10.0, "properties_createdate": "2021-10-12T13:50:13.028000+00:00", "properties_description": "baseball hat, large", "properties_discount": null, "properties_hs_acv": 10.0, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_allow_buyer_selected_quantity": null, "properties_hs_arr": 0.0, "properties_hs_billing_period_end_date": null, "properties_hs_billing_period_start_date": null, "properties_hs_billing_start_delay_days": null, "properties_hs_billing_start_delay_months": null, "properties_hs_billing_start_delay_type": null, "properties_hs_cost_of_goods_sold": 5, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_external_id": null, "properties_hs_images": null, "properties_hs_lastmodifieddate": "2021-10-12T13:50:13.028000+00:00", "properties_hs_line_item_currency_code": null, "properties_hs_margin": 5.0, "properties_hs_margin_acv": 5.0, "properties_hs_margin_arr": 0.0, "properties_hs_margin_mrr": 0.0, "properties_hs_margin_tcv": 5.0, "properties_hs_merged_object_ids": null, "properties_hs_mrr": 0.0, "properties_hs_object_id": 2089616136, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_position_on_quote": 0, "properties_hs_pre_discount_amount": 10, "properties_hs_product_id": 646316535, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_end_date": null, "properties_hs_recurring_billing_number_of_payments": 1, "properties_hs_recurring_billing_period": null, "properties_hs_recurring_billing_start_date": null, "properties_hs_recurring_billing_terms": null, "properties_hs_sku": null, "properties_hs_sync_amount": null, "properties_hs_tcv": 10.0, "properties_hs_term_in_months": null, "properties_hs_total_discount": 0, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_variant_id": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Green Hat", "properties_price": 10, "properties_quantity": 1, "properties_recurringbillingfrequency": null, "properties_tax": null, "properties_test": null, "properties_test_product_price": null}, "emitted_at": 1708014135799} +{"stream": "marketing_emails", "data": {"ab": false, "abHoursToWait": 4, "abSampleSizeDefault": null, "abSamplingDefault": null, "abSuccessMetric": null, "abTestPercentage": 50, "abVariation": false, "absoluteUrl": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-86812db1-e3c8-43cd-ae80-69a0934cd1de", "aifeatures": null, "allEmailCampaignIds": [243851494], "analyticsPageId": "100523515217", "analyticsPageType": "email", "archivedAt": 0, "archivedInDashboard": false, "audienceAccess": "PUBLIC", "author": "integration-test@airbyte.io", "authorName": "Team-1 Airbyte", "blogRssSettings": null, "canSpamSettingsId": 36765207029, "categoryId": 2, "contentAccessRuleIds": [], "contentAccessRuleTypes": [], "contentTypeCategory": 2, "createPage": false, "created": 1675121582718, "createdById": 12282590, "currentState": "PUBLISHED", "currentlyPublished": true, "customReplyTo": "", "customReplyToEnabled": false, "domain": "", "emailBody": "{% content_attribute \"email_body\" %}{{ default_email_body }}{% end_content_attribute %}", "emailNote": "", "emailTemplateMode": "DRAG_AND_DROP", "emailType": "BATCH_EMAIL", "emailbodyPlaintext": "", "feedbackSurveyId": null, "flexAreas": {"main": {"boxed": false, "isSingleColumnFullWidth": false, "sections": [{"columns": [{"id": "column-0-0", "widgets": ["module-0-0-0"], "width": 12}], "id": "section-0", "style": {"backgroundColor": "#eaf0f6", "backgroundType": "CONTENT", "paddingBottom": "10px", "paddingTop": "10px"}}, {"columns": [{"id": "column-1-0", "widgets": ["module-1-0-0"], "width": 12}], "id": "section-1", "style": {"backgroundType": "CONTENT", "paddingBottom": "30px", "paddingTop": "30px"}}, {"columns": [{"id": "column-2-0", "widgets": ["module-2-0-0"], "width": 12}], "id": "section-2", "style": {"backgroundColor": "", "backgroundType": "CONTENT", "paddingBottom": "20px", "paddingTop": "20px"}}]}}, "freezeDate": 1675121645993, "fromName": "Team Airbyte", "hasContentAccessRules": false, "htmlTitle": "", "id": 100523515217, "isCreatedFomSandboxSync": false, "isGraymailSuppressionEnabled": true, "isInstanceLayoutPage": false, "isPublished": true, "isRecipientFatigueSuppressionEnabled": null, "language": "en", "layoutSections": {}, "liveDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "mailingIlsListsExcluded": [], "mailingIlsListsIncluded": [], "mailingListsExcluded": [], "mailingListsIncluded": [], "maxRssEntries": 5, "metaDescription": "", "name": "test", "pageExpiryEnabled": false, "pageRedirected": false, "pastMabExperimentIds": [], "portalId": 8727216, "previewKey": "nlkwziGL", "primaryEmailCampaignId": 243851494, "processingStatus": "PUBLISHED", "publishDate": 1675121645000, "publishImmediately": true, "publishedAt": 1675121646297, "publishedByEmail": "integration-test@airbyte.io", "publishedById": 12282590, "publishedByName": "Team-1 Airbyte", "publishedUrl": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-86812db1-e3c8-43cd-ae80-69a0934cd1de", "replyTo": "integration-test@airbyte.io", "resolvedDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "rootMicId": null, "rssEmailByText": "By", "rssEmailClickThroughText": "Read more »", "rssEmailCommentText": "Comment »", "rssEmailEntryTemplateEnabled": false, "rssEmailImageMaxWidth": 0, "rssEmailUrl": "", "sections": {}, "securityState": "NONE", "selected": 0, "slug": "-temporary-slug-86812db1-e3c8-43cd-ae80-69a0934cd1de", "smartEmailFields": {}, "state": "PUBLISHED", "stats": {"counters": {"sent": 0, "open": 0, "delivered": 0, "bounce": 0, "unsubscribed": 0, "click": 0, "reply": 0, "dropped": 1, "selected": 1, "spamreport": 0, "suppressed": 0, "hardbounced": 0, "softbounced": 0, "pending": 0, "contactslost": 0, "notsent": 1}, "deviceBreakdown": {"open_device_type": {"computer": 0, "mobile": 0, "unknown": 0}, "click_device_type": {"computer": 0, "mobile": 0, "unknown": 0}}, "failedToLoad": false, "qualifierStats": {}, "ratios": {"clickratio": 0, "clickthroughratio": 0, "deliveredratio": 0, "openratio": 0, "replyratio": 0, "unsubscribedratio": 0, "spamreportratio": 0, "bounceratio": 0, "hardbounceratio": 0, "softbounceratio": 0, "contactslostratio": 0, "pendingratio": 0, "notsentratio": 100.0}}, "styleSettings": {"background_color": "#EAF0F6", "background_image": null, "background_image_type": null, "body_border_color": "#EAF0F6", "body_border_color_choice": "BORDER_MANUAL", "body_border_width": "1", "body_color": "#ffffff", "color_picker_favorite1": null, "color_picker_favorite2": null, "color_picker_favorite3": null, "color_picker_favorite4": null, "color_picker_favorite5": null, "color_picker_favorite6": null, "email_body_padding": null, "email_body_width": null, "heading_one_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "28", "underline": null}, "heading_two_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "22", "underline": null}, "links_font": {"bold": false, "color": "#00a4bd", "font": null, "font_style": {}, "italic": false, "size": null, "underline": true}, "primary_accent_color": null, "primary_font": "Arial, sans-serif", "primary_font_color": "#23496d", "primary_font_line_height": null, "primary_font_size": "15", "secondary_accent_color": null, "secondary_font": "Arial, sans-serif", "secondary_font_color": "#23496d", "secondary_font_line_height": null, "secondary_font_size": "12", "use_email_client_default_settings": false, "user_module_defaults": {"button_email": {"background_color": "#00a4bd", "corner_radius": 8, "font": "Arial, sans-serif", "font_color": "#ffffff", "font_size": 16, "font_style": {"color": "#ffffff", "font": "Arial, sans-serif", "size": {"units": "px", "value": 16}, "styles": {"bold": false, "italic": false, "underline": false}}}, "email_divider": {"color": {"color": "#23496d", "opacity": 100}, "height": 1, "line_type": "solid"}}}, "subcategory": "batch", "subject": "test", "subscription": 23704464, "subscriptionName": "Test sub", "teamPerms": [], "templatePath": "@hubspot/email/dnd/welcome.html", "transactional": false, "translations": {}, "unpublishedAt": 0, "updated": 1675121702583, "updatedById": 12282590, "url": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-86812db1-e3c8-43cd-ae80-69a0934cd1de", "useRssHeadlineAsSubject": false, "userPerms": [], "vidsExcluded": [], "vidsIncluded": [2501], "visibleToAll": true}, "emitted_at": 1708014401022} +{"stream": "marketing_emails", "data": {"ab": false, "abHoursToWait": 4, "abSampleSizeDefault": null, "abSamplingDefault": null, "abSuccessMetric": null, "abTestPercentage": 50, "abVariation": false, "absoluteUrl": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-f142cfbc-0d58-4eb5-b442-0d221f27b420", "aifeatures": null, "allEmailCampaignIds": [169919555], "analyticsPageId": "57347028995", "analyticsPageType": "email", "archivedAt": 0, "archivedInDashboard": false, "audienceAccess": "PUBLIC", "author": "integration-test@airbyte.io", "authorName": "Team-1 Airbyte", "blogRssSettings": null, "canSpamSettingsId": 36765207029, "categoryId": 2, "contentAccessRuleIds": [], "contentAccessRuleTypes": [], "contentTypeCategory": 2, "createPage": false, "created": 1634050240841, "createdById": 12282590, "currentState": "PUBLISHED", "currentlyPublished": true, "customReplyTo": "", "customReplyToEnabled": false, "domain": "", "emailBody": "{% content_attribute \"email_body\" %}{{ default_email_body }}{% end_content_attribute %}", "emailNote": "", "emailTemplateMode": "DRAG_AND_DROP", "emailType": "BATCH_EMAIL", "emailbodyPlaintext": "", "feedbackSurveyId": null, "flexAreas": {"main": {"boxed": false, "isSingleColumnFullWidth": false, "sections": [{"columns": [{"id": "column-0-0", "widgets": ["module-0-0-0"], "width": 12}], "id": "section-0", "style": {"backgroundType": "CONTENT", "paddingBottom": "40px", "paddingTop": "40px"}}, {"columns": [{"id": "column-1-0", "widgets": ["module-1-0-0"], "width": 12}], "id": "section-1", "style": {"backgroundColor": "", "backgroundType": "CONTENT", "paddingBottom": "0px", "paddingTop": "0px"}}]}}, "freezeDate": 1634050421336, "fromName": "Team Airbyte", "hasContentAccessRules": false, "htmlTitle": "", "id": 57347028995, "isCreatedFomSandboxSync": false, "isGraymailSuppressionEnabled": true, "isInstanceLayoutPage": false, "isPublished": true, "isRecipientFatigueSuppressionEnabled": null, "language": "en", "layoutSections": {}, "liveDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "mailingIlsListsExcluded": [], "mailingIlsListsIncluded": [], "mailingListsExcluded": [], "mailingListsIncluded": [130, 129, 131, 128, 126, 127, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116], "maxRssEntries": 5, "metaDescription": "", "name": "First test email - 1", "pageExpiryEnabled": false, "pageRedirected": false, "pastMabExperimentIds": [], "portalId": 8727216, "previewKey": "bgNuSvDn", "primaryEmailCampaignId": 169919555, "processingStatus": "PUBLISHED", "publishDate": 1634050421000, "publishImmediately": true, "publishedAt": 1634050421580, "publishedByEmail": "integration-test@airbyte.io", "publishedById": 12282590, "publishedByName": "Team-1 Airbyte", "publishedUrl": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-f142cfbc-0d58-4eb5-b442-0d221f27b420", "replyTo": "integration-test@airbyte.io", "resolvedDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "rootMicId": null, "rssEmailByText": "By", "rssEmailClickThroughText": "Read more »", "rssEmailCommentText": "Comment »", "rssEmailEntryTemplateEnabled": false, "rssEmailImageMaxWidth": 0, "rssEmailUrl": "", "sections": {}, "securityState": "NONE", "selected": 0, "slug": "-temporary-slug-f142cfbc-0d58-4eb5-b442-0d221f27b420", "smartEmailFields": {}, "state": "PUBLISHED", "stats": {"counters": {"sent": 0}, "deviceBreakdown": {}, "failedToLoad": false, "qualifierStats": {}, "ratios": {"clickratio": 0, "clickthroughratio": 0, "deliveredratio": 0, "openratio": 0, "replyratio": 0, "unsubscribedratio": 0, "spamreportratio": 0, "bounceratio": 0, "hardbounceratio": 0, "softbounceratio": 0, "contactslostratio": 0, "pendingratio": 0, "notsentratio": 0}}, "styleSettings": {"background_color": "#ffffff", "background_image": null, "background_image_type": null, "body_border_color": null, "body_border_color_choice": null, "body_border_width": "1", "body_color": "#ffffff", "color_picker_favorite1": null, "color_picker_favorite2": null, "color_picker_favorite3": null, "color_picker_favorite4": null, "color_picker_favorite5": null, "color_picker_favorite6": null, "email_body_padding": null, "email_body_width": null, "heading_one_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "28", "underline": null}, "heading_two_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "22", "underline": null}, "links_font": {"bold": false, "color": "#00a4bd", "font": null, "font_style": {}, "italic": false, "size": null, "underline": true}, "primary_accent_color": null, "primary_font": "Arial, sans-serif", "primary_font_color": "#23496d", "primary_font_line_height": null, "primary_font_size": "15", "secondary_accent_color": null, "secondary_font": "Arial, sans-serif", "secondary_font_color": "#23496d", "secondary_font_line_height": null, "secondary_font_size": "12", "use_email_client_default_settings": false, "user_module_defaults": {"button_email": {"background_color": null, "corner_radius": 8, "font": "Arial, sans-serif", "font_color": "#ffffff", "font_size": 16, "font_style": {"color": "#ffffff", "font": "Arial, sans-serif", "size": {"units": "px", "value": 16}, "styles": {"bold": false, "italic": false, "underline": false}}}, "email_divider": {"color": {"color": "#000000", "opacity": 100}, "height": 1, "line_type": null}}}, "subcategory": "batch", "subject": "Subject l", "subscription": 23704464, "subscriptionName": "Test sub", "teamPerms": [], "templatePath": "@hubspot/email/dnd/plain_text.html", "transactional": false, "translations": {}, "unpublishedAt": 0, "updated": 1634050455543, "updatedById": 12282590, "url": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-f142cfbc-0d58-4eb5-b442-0d221f27b420", "useRssHeadlineAsSubject": false, "userPerms": [], "vidsExcluded": [], "vidsIncluded": [], "visibleToAll": true}, "emitted_at": 1708014401026} +{"stream": "marketing_emails", "data": {"ab": false, "abHoursToWait": 4, "abSampleSizeDefault": null, "abSamplingDefault": null, "abSuccessMetric": null, "abTestPercentage": 50, "abVariation": false, "absoluteUrl": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-fb53d6bf-1eb6-4ee6-90fe-610fc2569ea7", "aifeatures": null, "allEmailCampaignIds": [], "analyticsPageId": "42930862366", "analyticsPageType": "email", "archivedAt": 0, "archivedInDashboard": false, "audienceAccess": "PUBLIC", "author": "integration-test@airbyte.io", "authorName": "Team-1 Airbyte", "blogRssSettings": null, "canSpamSettingsId": 36765207029, "categoryId": 2, "clonedFrom": 41886608509, "contentAccessRuleIds": [], "contentAccessRuleTypes": [], "contentTypeCategory": 2, "createPage": false, "created": 1615502115346, "createdById": 100, "currentState": "AUTOMATED_DRAFT", "currentlyPublished": false, "customReplyTo": "", "customReplyToEnabled": false, "domain": "", "emailBody": "{% content_attribute \"email_body\" %}{{ default_email_body }}{% end_content_attribute %}", "emailNote": "", "emailTemplateMode": "DRAG_AND_DROP", "emailType": "AUTOMATED_EMAIL", "emailbodyPlaintext": "", "feedbackSurveyId": null, "flexAreas": {"main": {"boxed": false, "isSingleColumnFullWidth": false, "sections": [{"columns": [{"id": "column-0-1", "widgets": ["module-0-1-1"], "width": 12}], "id": "section-0", "style": {"backgroundColor": "#eaf0f6", "backgroundType": "CONTENT", "paddingBottom": "10px", "paddingTop": "10px"}}, {"columns": [{"id": "column-1-1", "widgets": ["module-1-1-1"], "width": 12}], "id": "section-1", "style": {"backgroundType": "CONTENT", "paddingBottom": "30px", "paddingTop": "30px"}}, {"columns": [{"id": "column-2-1", "widgets": ["module-2-1-1"], "width": 12}], "id": "section-2", "style": {"backgroundColor": "", "backgroundType": "CONTENT", "paddingBottom": "20px", "paddingTop": "20px"}}]}}, "freezeDate": 1634042970319, "fromName": "Team Airbyte", "hasContentAccessRules": false, "htmlTitle": "", "id": 42930862366, "isCreatedFomSandboxSync": false, "isGraymailSuppressionEnabled": false, "isInstanceLayoutPage": false, "isPublished": false, "isRecipientFatigueSuppressionEnabled": null, "language": "en", "lastEditSessionId": 1634042969643, "lastEditUpdateId": 0, "layoutSections": {}, "liveDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "mailingIlsListsExcluded": [], "mailingIlsListsIncluded": [], "mailingListsExcluded": [], "mailingListsIncluded": [], "maxRssEntries": 5, "metaDescription": "", "name": "Test subject (Test campaing - Clone)", "pageExpiryEnabled": false, "pageRedirected": false, "pastMabExperimentIds": [], "portalId": 8727216, "previewKey": "UmZGYZsU", "processingStatus": "UNDEFINED", "publishDate": 1634042970000, "publishImmediately": true, "publishedUrl": "", "replyTo": "integration-test@airbyte.io", "resolvedDomain": "integrationtest-dev-8727216-8727216.hs-sites.com", "rootMicId": null, "rssEmailByText": "By", "rssEmailClickThroughText": "Read more »", "rssEmailCommentText": "Comment »", "rssEmailEntryTemplateEnabled": false, "rssEmailImageMaxWidth": 0, "rssEmailUrl": "", "sections": {}, "securityState": "NONE", "slug": "-temporary-slug-fb53d6bf-1eb6-4ee6-90fe-610fc2569ea7", "smartEmailFields": {}, "state": "AUTOMATED_DRAFT", "styleSettings": {"background_color": "#EAF0F6", "background_image": null, "background_image_type": null, "body_border_color": "#EAF0F6", "body_border_color_choice": "BORDER_MANUAL", "body_border_width": "1", "body_color": "#ffffff", "color_picker_favorite1": null, "color_picker_favorite2": null, "color_picker_favorite3": null, "color_picker_favorite4": null, "color_picker_favorite5": null, "color_picker_favorite6": null, "email_body_padding": null, "email_body_width": null, "heading_one_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "28", "underline": null}, "heading_two_font": {"bold": null, "color": null, "font": null, "font_style": {}, "italic": null, "size": "22", "underline": null}, "links_font": {"bold": false, "color": "#00a4bd", "font": null, "font_style": {}, "italic": false, "size": null, "underline": true}, "primary_accent_color": null, "primary_font": "Arial, sans-serif", "primary_font_color": "#23496d", "primary_font_line_height": null, "primary_font_size": "15", "secondary_accent_color": null, "secondary_font": "Arial, sans-serif", "secondary_font_color": "#23496d", "secondary_font_line_height": null, "secondary_font_size": "12", "use_email_client_default_settings": false, "user_module_defaults": {"button_email": {"background_color": "#00a4bd", "corner_radius": 8, "font": "Arial, sans-serif", "font_color": "#ffffff", "font_size": 16, "font_style": {"color": "#ffffff", "font": "Arial, sans-serif", "size": {"units": "px", "value": 16}, "styles": {"bold": false, "italic": false, "underline": false}}}, "email_divider": {"color": {"color": "#23496d", "opacity": 100}, "height": 1, "line_type": "solid"}}}, "subcategory": "automated", "subject": "Test subject", "subscription": 11890831, "subscriptionName": "Test subscription", "teamPerms": [], "templatePath": "@hubspot/email/dnd/welcome.html", "transactional": false, "translations": {}, "unpublishedAt": 0, "updated": 1634042970321, "updatedById": 12282590, "url": "http://integrationtest-dev-8727216-8727216.hs-sites.com/-temporary-slug-fb53d6bf-1eb6-4ee6-90fe-610fc2569ea7", "useRssHeadlineAsSubject": false, "userPerms": [], "vidsExcluded": [], "vidsIncluded": [], "visibleToAll": true}, "emitted_at": 1708014401029} {"stream": "owners", "data": {"id": "52550153", "email": "integration-test@airbyte.io", "firstName": "Team-1", "lastName": "Airbyte", "userId": 12282590, "createdAt": "2020-10-28T21:17:56.082Z", "updatedAt": "2023-01-31T00:25:34.448Z", "archived": false}, "emitted_at": 1697714250730} {"stream": "owners", "data": {"id": "65568071", "email": "test-integration-test-user1@airbyte.io", "firstName": "", "lastName": "", "userId": 23660227, "createdAt": "2021-03-15T11:00:50.053Z", "updatedAt": "2021-03-15T11:00:50.053Z", "archived": false}, "emitted_at": 1697714250731} {"stream": "owners", "data": {"id": "65568800", "email": "test-integration-test-user2@airbyte.io", "firstName": "", "lastName": "", "userId": 23660229, "createdAt": "2021-03-15T11:01:02.183Z", "updatedAt": "2021-03-15T11:01:02.183Z", "archived": false}, "emitted_at": 1697714250732} -{"stream": "products", "data": {"id": "646176421", "properties": {"amount": null, "createdate": "2021-02-23T20:03:18.336000+00:00", "description": null, "discount": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_avatar_filemanager_key": null, "hs_cost_of_goods_sold": null, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_discount_percentage": null, "hs_folder_id": null, "hs_folder_name": null, "hs_images": null, "hs_lastmodifieddate": "2021-02-23T20:03:18.336000+00:00", "hs_merged_object_ids": null, "hs_object_id": 646176421, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_period": null, "hs_recurring_billing_start_date": null, "hs_sku": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Test product", "price": 100, "quantity": null, "recurringbillingfrequency": null, "tax": null, "test": null, "test_product_price": null}, "createdAt": "2021-02-23T20:03:18.336Z", "updatedAt": "2021-02-23T20:03:18.336Z", "archived": false, "properties_amount": null, "properties_createdate": "2021-02-23T20:03:18.336000+00:00", "properties_description": null, "properties_discount": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_avatar_filemanager_key": null, "properties_hs_cost_of_goods_sold": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_folder_id": null, "properties_hs_folder_name": null, "properties_hs_images": null, "properties_hs_lastmodifieddate": "2021-02-23T20:03:18.336000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 646176421, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_period": null, "properties_hs_recurring_billing_start_date": null, "properties_hs_sku": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Test product", "properties_price": 100, "properties_quantity": null, "properties_recurringbillingfrequency": null, "properties_tax": null, "properties_test": null, "properties_test_product_price": null}, "emitted_at": 1706192761055} -{"stream": "products", "data": {"id": "646176423", "properties": {"amount": null, "createdate": "2021-02-23T20:03:48.577000+00:00", "description": null, "discount": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_avatar_filemanager_key": null, "hs_cost_of_goods_sold": null, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_discount_percentage": null, "hs_folder_id": 2430008, "hs_folder_name": "test folder", "hs_images": null, "hs_lastmodifieddate": "2021-02-23T20:03:48.577000+00:00", "hs_merged_object_ids": null, "hs_object_id": 646176423, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_period": null, "hs_recurring_billing_start_date": null, "hs_sku": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Test product 1", "price": 123, "quantity": null, "recurringbillingfrequency": null, "tax": null, "test": null, "test_product_price": null}, "createdAt": "2021-02-23T20:03:48.577Z", "updatedAt": "2021-02-23T20:03:48.577Z", "archived": false, "properties_amount": null, "properties_createdate": "2021-02-23T20:03:48.577000+00:00", "properties_description": null, "properties_discount": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_avatar_filemanager_key": null, "properties_hs_cost_of_goods_sold": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_folder_id": 2430008, "properties_hs_folder_name": "test folder", "properties_hs_images": null, "properties_hs_lastmodifieddate": "2021-02-23T20:03:48.577000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 646176423, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_period": null, "properties_hs_recurring_billing_start_date": null, "properties_hs_sku": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Test product 1", "properties_price": 123, "properties_quantity": null, "properties_recurringbillingfrequency": null, "properties_tax": null, "properties_test": null, "properties_test_product_price": null}, "emitted_at": 1706192761056} -{"stream": "products", "data": {"id": "646316535", "properties": {"amount": null, "createdate": "2021-02-23T20:11:54.030000+00:00", "description": "baseball hat, large", "discount": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_avatar_filemanager_key": null, "hs_cost_of_goods_sold": 5, "hs_created_by_user_id": null, "hs_createdate": null, "hs_discount_percentage": null, "hs_folder_id": null, "hs_folder_name": null, "hs_images": null, "hs_lastmodifieddate": "2021-02-23T20:11:54.030000+00:00", "hs_merged_object_ids": null, "hs_object_id": 646316535, "hs_object_source": "IMPORT", "hs_object_source_id": null, "hs_object_source_label": "IMPORT", "hs_object_source_user_id": null, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_period": null, "hs_recurring_billing_start_date": null, "hs_sku": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": true, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Green Hat", "price": 10, "quantity": null, "recurringbillingfrequency": null, "tax": null, "test": null, "test_product_price": null}, "createdAt": "2021-02-23T20:11:54.030Z", "updatedAt": "2021-02-23T20:11:54.030Z", "archived": false, "properties_amount": null, "properties_createdate": "2021-02-23T20:11:54.030000+00:00", "properties_description": "baseball hat, large", "properties_discount": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_avatar_filemanager_key": null, "properties_hs_cost_of_goods_sold": 5, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_folder_id": null, "properties_hs_folder_name": null, "properties_hs_images": null, "properties_hs_lastmodifieddate": "2021-02-23T20:11:54.030000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 646316535, "properties_hs_object_source": "IMPORT", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "IMPORT", "properties_hs_object_source_user_id": null, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_period": null, "properties_hs_recurring_billing_start_date": null, "properties_hs_sku": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": true, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Green Hat", "properties_price": 10, "properties_quantity": null, "properties_recurringbillingfrequency": null, "properties_tax": null, "properties_test": null, "properties_test_product_price": null}, "emitted_at": 1706192761057} +{"stream": "products", "data": {"id": "646176421", "properties": {"amount": null, "createdate": "2021-02-23T20:03:18.336000+00:00", "description": null, "discount": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_avatar_filemanager_key": null, "hs_cost_of_goods_sold": null, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_discount_percentage": null, "hs_folder_id": null, "hs_folder_name": null, "hs_images": null, "hs_lastmodifieddate": "2021-02-23T20:03:18.336000+00:00", "hs_merged_object_ids": null, "hs_object_id": 646176421, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_period": null, "hs_recurring_billing_start_date": null, "hs_sku": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Test product", "price": 100, "quantity": null, "recurringbillingfrequency": null, "tax": null, "test": null, "test_product_price": null}, "createdAt": "2021-02-23T20:03:18.336Z", "updatedAt": "2021-02-23T20:03:18.336Z", "archived": false, "properties_amount": null, "properties_createdate": "2021-02-23T20:03:18.336000+00:00", "properties_description": null, "properties_discount": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_avatar_filemanager_key": null, "properties_hs_cost_of_goods_sold": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_folder_id": null, "properties_hs_folder_name": null, "properties_hs_images": null, "properties_hs_lastmodifieddate": "2021-02-23T20:03:18.336000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 646176421, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_period": null, "properties_hs_recurring_billing_start_date": null, "properties_hs_sku": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Test product", "properties_price": 100, "properties_quantity": null, "properties_recurringbillingfrequency": null, "properties_tax": null, "properties_test": null, "properties_test_product_price": null}, "emitted_at": 1708014628640} +{"stream": "products", "data": {"id": "646176423", "properties": {"amount": null, "createdate": "2021-02-23T20:03:48.577000+00:00", "description": null, "discount": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_avatar_filemanager_key": null, "hs_cost_of_goods_sold": null, "hs_created_by_user_id": 12282590, "hs_createdate": null, "hs_discount_percentage": null, "hs_folder_id": 2430008, "hs_folder_name": "test folder", "hs_images": null, "hs_lastmodifieddate": "2021-02-23T20:03:48.577000+00:00", "hs_merged_object_ids": null, "hs_object_id": 646176423, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_period": null, "hs_recurring_billing_start_date": null, "hs_sku": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Test product 1", "price": 123, "quantity": null, "recurringbillingfrequency": null, "tax": null, "test": null, "test_product_price": null}, "createdAt": "2021-02-23T20:03:48.577Z", "updatedAt": "2021-02-23T20:03:48.577Z", "archived": false, "properties_amount": null, "properties_createdate": "2021-02-23T20:03:48.577000+00:00", "properties_description": null, "properties_discount": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_avatar_filemanager_key": null, "properties_hs_cost_of_goods_sold": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_folder_id": 2430008, "properties_hs_folder_name": "test folder", "properties_hs_images": null, "properties_hs_lastmodifieddate": "2021-02-23T20:03:48.577000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 646176423, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_period": null, "properties_hs_recurring_billing_start_date": null, "properties_hs_sku": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Test product 1", "properties_price": 123, "properties_quantity": null, "properties_recurringbillingfrequency": null, "properties_tax": null, "properties_test": null, "properties_test_product_price": null}, "emitted_at": 1708014628643} +{"stream": "products", "data": {"id": "646316535", "properties": {"amount": null, "createdate": "2021-02-23T20:11:54.030000+00:00", "description": "baseball hat, large", "discount": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_avatar_filemanager_key": null, "hs_cost_of_goods_sold": 5, "hs_created_by_user_id": null, "hs_createdate": null, "hs_discount_percentage": null, "hs_folder_id": null, "hs_folder_name": null, "hs_images": null, "hs_lastmodifieddate": "2021-02-23T20:11:54.030000+00:00", "hs_merged_object_ids": null, "hs_object_id": 646316535, "hs_object_source": "IMPORT", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "IMPORT", "hs_object_source_user_id": null, "hs_product_type": null, "hs_read_only": null, "hs_recurring_billing_period": null, "hs_recurring_billing_start_date": null, "hs_sku": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_url": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": true, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "name": "Green Hat", "price": 10, "quantity": null, "recurringbillingfrequency": null, "tax": null, "test": null, "test_product_price": null}, "createdAt": "2021-02-23T20:11:54.030Z", "updatedAt": "2021-02-23T20:11:54.030Z", "archived": false, "properties_amount": null, "properties_createdate": "2021-02-23T20:11:54.030000+00:00", "properties_description": "baseball hat, large", "properties_discount": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_avatar_filemanager_key": null, "properties_hs_cost_of_goods_sold": 5, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_discount_percentage": null, "properties_hs_folder_id": null, "properties_hs_folder_name": null, "properties_hs_images": null, "properties_hs_lastmodifieddate": "2021-02-23T20:11:54.030000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 646316535, "properties_hs_object_source": "IMPORT", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "IMPORT", "properties_hs_object_source_user_id": null, "properties_hs_product_type": null, "properties_hs_read_only": null, "properties_hs_recurring_billing_period": null, "properties_hs_recurring_billing_start_date": null, "properties_hs_sku": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_url": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": true, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_name": "Green Hat", "properties_price": 10, "properties_quantity": null, "properties_recurringbillingfrequency": null, "properties_tax": null, "properties_test": null, "properties_test_product_price": null}, "emitted_at": 1708014628645} {"stream": "contacts_property_history", "data": {"value": "testo", "source-type": "CRM_UI", "source-id": "userId:12282590", "source-label": null, "updated-by-user-id": 12282590, "timestamp": 1700681340515, "selected": false, "property": "firstname", "vid": 2501, "portal-id": 8727216, "is-contact": true, "canonical-vid": 2501}, "emitted_at": 1701905506064} {"stream": "contacts_property_history", "data": {"value": "test", "source-type": "CRM_UI", "source-id": "userId:12282590", "source-label": null, "updated-by-user-id": 12282590, "timestamp": 1675120629904, "selected": false, "property": "firstname", "vid": 2501, "portal-id": 8727216, "is-contact": true, "canonical-vid": 2501}, "emitted_at": 1701905506064} {"stream": "companies_property_history", "data": {"name": "hs_analytics_latest_source_data_2", "value": "CRM_UI", "timestamp": 1657222285656, "sourceId": "RollupProperties", "source": "MIGRATION", "sourceVid": [], "property": "hs_analytics_latest_source_data_2", "companyId": 5000526215, "portalId": 8727216, "isDeleted": false}, "emitted_at": 1701905731242} @@ -58,25 +58,25 @@ {"stream": "subscription_changes", "data": {"timestamp": 1616173134301, "portalId": 8727216, "recipient": "0c90ecf5-629e-4fe4-8516-05f75636c3e3@gdpr-forgotten.hubspot.com", "normalizedEmailId": "0c90ecf5-629e-4fe4-8516-05f75636c3e3", "changes": [{"source": "SOURCE_HUBSPOT_CUSTOMER", "timestamp": 1616173134301, "portalId": 8727216, "causedByEvent": {"id": "d70b78b9-a411-4d3e-808b-fe931be35b43", "created": 1616173134301}, "changeType": "PORTAL_STATUS", "change": "SUBSCRIBED"}]}, "emitted_at": 1697714255435} {"stream": "subscription_changes", "data": {"timestamp": 1616173134301, "portalId": 8727216, "recipient": "0c90ecf5-629e-4fe4-8516-05f75636c3e3@gdpr-forgotten.hubspot.com", "normalizedEmailId": "0c90ecf5-629e-4fe4-8516-05f75636c3e3", "changes": [{"source": "SOURCE_HUBSPOT_CUSTOMER", "timestamp": 1616173134301, "subscriptionId": 10798197, "portalId": 8727216, "causedByEvent": {"id": "ff118718-786d-4a35-94f9-6bbd413654de", "created": 1616173134301}, "changeType": "SUBSCRIPTION_STATUS", "change": "SUBSCRIBED"}]}, "emitted_at": 1697714255436} {"stream": "subscription_changes", "data": {"timestamp": 1616173106737, "portalId": 8727216, "recipient": "0c90ecf5-629e-4fe4-8516-05f75636c3e3@gdpr-forgotten.hubspot.com", "normalizedEmailId": "0c90ecf5-629e-4fe4-8516-05f75636c3e3", "changes": [{"source": "SOURCE_HUBSPOT_CUSTOMER", "timestamp": 1616173106737, "portalId": 8727216, "causedByEvent": {"id": "24539f1f-0b20-4296-a5bf-6ba3bb9dc1b8", "created": 1616173106737}, "changeType": "PORTAL_STATUS", "change": "SUBSCRIBED"}]}, "emitted_at": 1697714255437} -{"stream": "tickets", "data": {"id": "312929579", "properties": {"closed_date": "2021-02-23T20:08:49.603000+00:00", "content": null, "created_by": null, "createdate": "2021-02-23T20:08:49.603000+00:00", "first_agent_reply_date": null, "hs_all_accessible_team_ids": null, "hs_all_associated_contact_companies": null, "hs_all_associated_contact_emails": null, "hs_all_associated_contact_firstnames": null, "hs_all_associated_contact_lastnames": null, "hs_all_associated_contact_mobilephones": null, "hs_all_associated_contact_phones": null, "hs_all_conversation_mentions": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignment_method": null, "hs_auto_generated_from_thread_id": null, "hs_conversations_originating_message_id": null, "hs_conversations_originating_thread_id": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_custom_inbox": null, "hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_151692305": null, "hs_date_entered_151692306": null, "hs_date_entered_151692307": null, "hs_date_entered_151692308": null, "hs_date_entered_2": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_3": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_4": "2021-02-23T20:08:49.603000+00:00", "hs_date_exited_1": "2021-02-23T20:08:49.603000+00:00", "hs_date_exited_151692305": null, "hs_date_exited_151692306": null, "hs_date_exited_151692307": null, "hs_date_exited_151692308": null, "hs_date_exited_2": "2021-02-23T20:08:49.603000+00:00", "hs_date_exited_3": "2021-02-23T20:08:49.603000+00:00", "hs_date_exited_4": null, "hs_external_object_ids": null, "hs_feedback_last_ces_follow_up": null, "hs_feedback_last_ces_rating": null, "hs_feedback_last_survey_date": null, "hs_file_upload": null, "hs_first_agent_message_sent_at": null, "hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "hs_in_helpdesk": null, "hs_inbox_id": null, "hs_is_visible_in_help_desk": null, "hs_last_email_activity": null, "hs_last_email_date": null, "hs_last_message_from_visitor": false, "hs_last_message_received_at": null, "hs_last_message_sent_at": null, "hs_lastactivitydate": null, "hs_lastcontacted": null, "hs_lastmodifieddate": "2021-02-23T20:08:53.371000+00:00", "hs_latest_message_seen_by_agent_ids": null, "hs_merged_object_ids": null, "hs_most_relevant_sla_status": null, "hs_most_relevant_sla_type": null, "hs_msteams_message_id": null, "hs_nextactivitydate": null, "hs_num_associated_companies": 0, "hs_num_associated_conversations": null, "hs_num_times_contacted": null, "hs_object_id": 312929579, "hs_object_source": "IMPORT", "hs_object_source_id": null, "hs_object_source_label": "IMPORT", "hs_object_source_user_id": null, "hs_originating_channel_instance_id": null, "hs_originating_email_engagement_id": null, "hs_originating_generic_channel_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": "0", "hs_pipeline_stage": "4", "hs_primary_company": null, "hs_primary_company_id": null, "hs_primary_company_name": null, "hs_read_only": null, "hs_resolution": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_thread_ids_to_restore": null, "hs_ticket_category": null, "hs_ticket_id": 312929579, "hs_ticket_priority": "LOW", "hs_time_in_1": 0, "hs_time_in_151692305": null, "hs_time_in_151692306": null, "hs_time_in_151692307": null, "hs_time_in_151692308": null, "hs_time_in_2": 0, "hs_time_in_3": 0, "hs_time_in_4": 93215284227, "hs_time_to_close_sla_at": null, "hs_time_to_close_sla_status": null, "hs_time_to_first_response_sla_at": null, "hs_time_to_first_response_sla_status": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": true, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "last_engagement_date": null, "last_reply_date": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "nps_follow_up_answer": null, "nps_follow_up_question_version": null, "nps_score": null, "num_contacted_notes": null, "num_notes": null, "source_ref": null, "source_thread_id": null, "source_type": "CHAT", "subject": "Marketing Starter", "tags": null, "time_to_close": 0, "time_to_first_agent_reply": null}, "createdAt": "2021-02-23T20:08:49.603Z", "updatedAt": "2021-02-23T20:08:53.371Z", "archived": false, "properties_closed_date": "2021-02-23T20:08:49.603000+00:00", "properties_content": null, "properties_created_by": null, "properties_createdate": "2021-02-23T20:08:49.603000+00:00", "properties_first_agent_reply_date": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_associated_contact_companies": null, "properties_hs_all_associated_contact_emails": null, "properties_hs_all_associated_contact_firstnames": null, "properties_hs_all_associated_contact_lastnames": null, "properties_hs_all_associated_contact_mobilephones": null, "properties_hs_all_associated_contact_phones": null, "properties_hs_all_conversation_mentions": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignment_method": null, "properties_hs_auto_generated_from_thread_id": null, "properties_hs_conversations_originating_message_id": null, "properties_hs_conversations_originating_thread_id": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_custom_inbox": null, "properties_hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_151692305": null, "properties_hs_date_entered_151692306": null, "properties_hs_date_entered_151692307": null, "properties_hs_date_entered_151692308": null, "properties_hs_date_entered_2": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_3": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_4": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_exited_1": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_exited_151692305": null, "properties_hs_date_exited_151692306": null, "properties_hs_date_exited_151692307": null, "properties_hs_date_exited_151692308": null, "properties_hs_date_exited_2": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_exited_3": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_exited_4": null, "properties_hs_external_object_ids": null, "properties_hs_feedback_last_ces_follow_up": null, "properties_hs_feedback_last_ces_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_file_upload": null, "properties_hs_first_agent_message_sent_at": null, "properties_hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "properties_hs_in_helpdesk": null, "properties_hs_inbox_id": null, "properties_hs_is_visible_in_help_desk": null, "properties_hs_last_email_activity": null, "properties_hs_last_email_date": null, "properties_hs_last_message_from_visitor": false, "properties_hs_last_message_received_at": null, "properties_hs_last_message_sent_at": null, "properties_hs_lastactivitydate": null, "properties_hs_lastcontacted": null, "properties_hs_lastmodifieddate": "2021-02-23T20:08:53.371000+00:00", "properties_hs_latest_message_seen_by_agent_ids": null, "properties_hs_merged_object_ids": null, "properties_hs_most_relevant_sla_status": null, "properties_hs_most_relevant_sla_type": null, "properties_hs_msteams_message_id": null, "properties_hs_nextactivitydate": null, "properties_hs_num_associated_companies": 0, "properties_hs_num_associated_conversations": null, "properties_hs_num_times_contacted": null, "properties_hs_object_id": 312929579, "properties_hs_object_source": "IMPORT", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "IMPORT", "properties_hs_object_source_user_id": null, "properties_hs_originating_channel_instance_id": null, "properties_hs_originating_email_engagement_id": null, "properties_hs_originating_generic_channel_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "0", "properties_hs_pipeline_stage": "4", "properties_hs_primary_company": null, "properties_hs_primary_company_id": null, "properties_hs_primary_company_name": null, "properties_hs_read_only": null, "properties_hs_resolution": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_thread_ids_to_restore": null, "properties_hs_ticket_category": null, "properties_hs_ticket_id": 312929579, "properties_hs_ticket_priority": "LOW", "properties_hs_time_in_1": 0, "properties_hs_time_in_151692305": null, "properties_hs_time_in_151692306": null, "properties_hs_time_in_151692307": null, "properties_hs_time_in_151692308": null, "properties_hs_time_in_2": 0, "properties_hs_time_in_3": 0, "properties_hs_time_in_4": 93215284227, "properties_hs_time_to_close_sla_at": null, "properties_hs_time_to_close_sla_status": null, "properties_hs_time_to_first_response_sla_at": null, "properties_hs_time_to_first_response_sla_status": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": true, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_last_engagement_date": null, "properties_last_reply_date": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_nps_follow_up_answer": null, "properties_nps_follow_up_question_version": null, "properties_nps_score": null, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_source_ref": null, "properties_source_thread_id": null, "properties_source_type": "CHAT", "properties_subject": "Marketing Starter", "properties_tags": null, "properties_time_to_close": 0, "properties_time_to_first_agent_reply": null}, "emitted_at": 1707326213728} -{"stream": "tickets", "data": {"id": "312972611", "properties": {"closed_date": null, "content": null, "created_by": null, "createdate": "2021-02-23T20:08:49.603000+00:00", "first_agent_reply_date": null, "hs_all_accessible_team_ids": null, "hs_all_associated_contact_companies": null, "hs_all_associated_contact_emails": null, "hs_all_associated_contact_firstnames": null, "hs_all_associated_contact_lastnames": null, "hs_all_associated_contact_mobilephones": null, "hs_all_associated_contact_phones": null, "hs_all_conversation_mentions": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignment_method": null, "hs_auto_generated_from_thread_id": null, "hs_conversations_originating_message_id": null, "hs_conversations_originating_thread_id": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_custom_inbox": null, "hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_151692305": null, "hs_date_entered_151692306": null, "hs_date_entered_151692307": null, "hs_date_entered_151692308": null, "hs_date_entered_2": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_3": null, "hs_date_entered_4": null, "hs_date_exited_1": "2021-02-23T20:08:49.603000+00:00", "hs_date_exited_151692305": null, "hs_date_exited_151692306": null, "hs_date_exited_151692307": null, "hs_date_exited_151692308": null, "hs_date_exited_2": null, "hs_date_exited_3": null, "hs_date_exited_4": null, "hs_external_object_ids": null, "hs_feedback_last_ces_follow_up": null, "hs_feedback_last_ces_rating": null, "hs_feedback_last_survey_date": null, "hs_file_upload": null, "hs_first_agent_message_sent_at": null, "hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "hs_in_helpdesk": null, "hs_inbox_id": null, "hs_is_visible_in_help_desk": null, "hs_last_email_activity": null, "hs_last_email_date": null, "hs_last_message_from_visitor": false, "hs_last_message_received_at": null, "hs_last_message_sent_at": null, "hs_lastactivitydate": null, "hs_lastcontacted": null, "hs_lastmodifieddate": "2021-02-23T20:08:52.663000+00:00", "hs_latest_message_seen_by_agent_ids": null, "hs_merged_object_ids": null, "hs_most_relevant_sla_status": null, "hs_most_relevant_sla_type": null, "hs_msteams_message_id": null, "hs_nextactivitydate": null, "hs_num_associated_companies": 0, "hs_num_associated_conversations": null, "hs_num_times_contacted": null, "hs_object_id": 312972611, "hs_object_source": "IMPORT", "hs_object_source_id": null, "hs_object_source_label": "IMPORT", "hs_object_source_user_id": null, "hs_originating_channel_instance_id": null, "hs_originating_email_engagement_id": null, "hs_originating_generic_channel_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": "0", "hs_pipeline_stage": "2", "hs_primary_company": null, "hs_primary_company_id": null, "hs_primary_company_name": null, "hs_read_only": null, "hs_resolution": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_thread_ids_to_restore": null, "hs_ticket_category": null, "hs_ticket_id": 312972611, "hs_ticket_priority": "LOW", "hs_time_in_1": 0, "hs_time_in_151692305": null, "hs_time_in_151692306": null, "hs_time_in_151692307": null, "hs_time_in_151692308": null, "hs_time_in_2": 93215284226, "hs_time_in_3": null, "hs_time_in_4": null, "hs_time_to_close_sla_at": null, "hs_time_to_close_sla_status": null, "hs_time_to_first_response_sla_at": null, "hs_time_to_first_response_sla_status": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": true, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "last_engagement_date": null, "last_reply_date": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "nps_follow_up_answer": null, "nps_follow_up_question_version": null, "nps_score": null, "num_contacted_notes": null, "num_notes": null, "source_ref": null, "source_thread_id": null, "source_type": "FORM", "subject": "Sales Starter", "tags": null, "time_to_close": null, "time_to_first_agent_reply": null}, "createdAt": "2021-02-23T20:08:49.603Z", "updatedAt": "2021-02-23T20:08:52.663Z", "archived": false, "properties_closed_date": null, "properties_content": null, "properties_created_by": null, "properties_createdate": "2021-02-23T20:08:49.603000+00:00", "properties_first_agent_reply_date": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_associated_contact_companies": null, "properties_hs_all_associated_contact_emails": null, "properties_hs_all_associated_contact_firstnames": null, "properties_hs_all_associated_contact_lastnames": null, "properties_hs_all_associated_contact_mobilephones": null, "properties_hs_all_associated_contact_phones": null, "properties_hs_all_conversation_mentions": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignment_method": null, "properties_hs_auto_generated_from_thread_id": null, "properties_hs_conversations_originating_message_id": null, "properties_hs_conversations_originating_thread_id": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_custom_inbox": null, "properties_hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_151692305": null, "properties_hs_date_entered_151692306": null, "properties_hs_date_entered_151692307": null, "properties_hs_date_entered_151692308": null, "properties_hs_date_entered_2": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_3": null, "properties_hs_date_entered_4": null, "properties_hs_date_exited_1": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_exited_151692305": null, "properties_hs_date_exited_151692306": null, "properties_hs_date_exited_151692307": null, "properties_hs_date_exited_151692308": null, "properties_hs_date_exited_2": null, "properties_hs_date_exited_3": null, "properties_hs_date_exited_4": null, "properties_hs_external_object_ids": null, "properties_hs_feedback_last_ces_follow_up": null, "properties_hs_feedback_last_ces_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_file_upload": null, "properties_hs_first_agent_message_sent_at": null, "properties_hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "properties_hs_in_helpdesk": null, "properties_hs_inbox_id": null, "properties_hs_is_visible_in_help_desk": null, "properties_hs_last_email_activity": null, "properties_hs_last_email_date": null, "properties_hs_last_message_from_visitor": false, "properties_hs_last_message_received_at": null, "properties_hs_last_message_sent_at": null, "properties_hs_lastactivitydate": null, "properties_hs_lastcontacted": null, "properties_hs_lastmodifieddate": "2021-02-23T20:08:52.663000+00:00", "properties_hs_latest_message_seen_by_agent_ids": null, "properties_hs_merged_object_ids": null, "properties_hs_most_relevant_sla_status": null, "properties_hs_most_relevant_sla_type": null, "properties_hs_msteams_message_id": null, "properties_hs_nextactivitydate": null, "properties_hs_num_associated_companies": 0, "properties_hs_num_associated_conversations": null, "properties_hs_num_times_contacted": null, "properties_hs_object_id": 312972611, "properties_hs_object_source": "IMPORT", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "IMPORT", "properties_hs_object_source_user_id": null, "properties_hs_originating_channel_instance_id": null, "properties_hs_originating_email_engagement_id": null, "properties_hs_originating_generic_channel_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "0", "properties_hs_pipeline_stage": "2", "properties_hs_primary_company": null, "properties_hs_primary_company_id": null, "properties_hs_primary_company_name": null, "properties_hs_read_only": null, "properties_hs_resolution": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_thread_ids_to_restore": null, "properties_hs_ticket_category": null, "properties_hs_ticket_id": 312972611, "properties_hs_ticket_priority": "LOW", "properties_hs_time_in_1": 0, "properties_hs_time_in_151692305": null, "properties_hs_time_in_151692306": null, "properties_hs_time_in_151692307": null, "properties_hs_time_in_151692308": null, "properties_hs_time_in_2": 93215284226, "properties_hs_time_in_3": null, "properties_hs_time_in_4": null, "properties_hs_time_to_close_sla_at": null, "properties_hs_time_to_close_sla_status": null, "properties_hs_time_to_first_response_sla_at": null, "properties_hs_time_to_first_response_sla_status": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": true, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_last_engagement_date": null, "properties_last_reply_date": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_nps_follow_up_answer": null, "properties_nps_follow_up_question_version": null, "properties_nps_score": null, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_source_ref": null, "properties_source_thread_id": null, "properties_source_type": "FORM", "properties_subject": "Sales Starter", "properties_tags": null, "properties_time_to_close": null, "properties_time_to_first_agent_reply": null}, "emitted_at": 1707326213730} -{"stream": "tickets", "data": {"id": "312975112", "properties": {"closed_date": null, "content": null, "created_by": null, "createdate": "2021-02-23T20:08:49.603000+00:00", "first_agent_reply_date": null, "hs_all_accessible_team_ids": null, "hs_all_associated_contact_companies": null, "hs_all_associated_contact_emails": null, "hs_all_associated_contact_firstnames": null, "hs_all_associated_contact_lastnames": null, "hs_all_associated_contact_mobilephones": null, "hs_all_associated_contact_phones": null, "hs_all_conversation_mentions": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignment_method": null, "hs_auto_generated_from_thread_id": null, "hs_conversations_originating_message_id": null, "hs_conversations_originating_thread_id": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_custom_inbox": null, "hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_151692305": null, "hs_date_entered_151692306": null, "hs_date_entered_151692307": null, "hs_date_entered_151692308": null, "hs_date_entered_2": null, "hs_date_entered_3": null, "hs_date_entered_4": null, "hs_date_exited_1": null, "hs_date_exited_151692305": null, "hs_date_exited_151692306": null, "hs_date_exited_151692307": null, "hs_date_exited_151692308": null, "hs_date_exited_2": null, "hs_date_exited_3": null, "hs_date_exited_4": null, "hs_external_object_ids": null, "hs_feedback_last_ces_follow_up": null, "hs_feedback_last_ces_rating": null, "hs_feedback_last_survey_date": null, "hs_file_upload": null, "hs_first_agent_message_sent_at": null, "hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "hs_in_helpdesk": null, "hs_inbox_id": null, "hs_is_visible_in_help_desk": null, "hs_last_email_activity": null, "hs_last_email_date": null, "hs_last_message_from_visitor": false, "hs_last_message_received_at": null, "hs_last_message_sent_at": null, "hs_lastactivitydate": null, "hs_lastcontacted": null, "hs_lastmodifieddate": "2021-02-23T20:08:52.515000+00:00", "hs_latest_message_seen_by_agent_ids": null, "hs_merged_object_ids": null, "hs_most_relevant_sla_status": null, "hs_most_relevant_sla_type": null, "hs_msteams_message_id": null, "hs_nextactivitydate": null, "hs_num_associated_companies": 0, "hs_num_associated_conversations": null, "hs_num_times_contacted": null, "hs_object_id": 312975112, "hs_object_source": "IMPORT", "hs_object_source_id": null, "hs_object_source_label": "IMPORT", "hs_object_source_user_id": null, "hs_originating_channel_instance_id": null, "hs_originating_email_engagement_id": null, "hs_originating_generic_channel_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": "0", "hs_pipeline_stage": "1", "hs_primary_company": null, "hs_primary_company_id": null, "hs_primary_company_name": null, "hs_read_only": null, "hs_resolution": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_thread_ids_to_restore": null, "hs_ticket_category": null, "hs_ticket_id": 312975112, "hs_ticket_priority": "MEDIUM", "hs_time_in_1": 93215284227, "hs_time_in_151692305": null, "hs_time_in_151692306": null, "hs_time_in_151692307": null, "hs_time_in_151692308": null, "hs_time_in_2": null, "hs_time_in_3": null, "hs_time_in_4": null, "hs_time_to_close_sla_at": null, "hs_time_to_close_sla_status": null, "hs_time_to_first_response_sla_at": null, "hs_time_to_first_response_sla_status": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": true, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "last_engagement_date": null, "last_reply_date": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "nps_follow_up_answer": null, "nps_follow_up_question_version": null, "nps_score": null, "num_contacted_notes": null, "num_notes": null, "source_ref": null, "source_thread_id": null, "source_type": "PHONE", "subject": "Free CRM", "tags": null, "time_to_close": null, "time_to_first_agent_reply": null}, "createdAt": "2021-02-23T20:08:49.603Z", "updatedAt": "2021-02-23T20:08:52.515Z", "archived": false, "properties_closed_date": null, "properties_content": null, "properties_created_by": null, "properties_createdate": "2021-02-23T20:08:49.603000+00:00", "properties_first_agent_reply_date": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_associated_contact_companies": null, "properties_hs_all_associated_contact_emails": null, "properties_hs_all_associated_contact_firstnames": null, "properties_hs_all_associated_contact_lastnames": null, "properties_hs_all_associated_contact_mobilephones": null, "properties_hs_all_associated_contact_phones": null, "properties_hs_all_conversation_mentions": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignment_method": null, "properties_hs_auto_generated_from_thread_id": null, "properties_hs_conversations_originating_message_id": null, "properties_hs_conversations_originating_thread_id": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_custom_inbox": null, "properties_hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_151692305": null, "properties_hs_date_entered_151692306": null, "properties_hs_date_entered_151692307": null, "properties_hs_date_entered_151692308": null, "properties_hs_date_entered_2": null, "properties_hs_date_entered_3": null, "properties_hs_date_entered_4": null, "properties_hs_date_exited_1": null, "properties_hs_date_exited_151692305": null, "properties_hs_date_exited_151692306": null, "properties_hs_date_exited_151692307": null, "properties_hs_date_exited_151692308": null, "properties_hs_date_exited_2": null, "properties_hs_date_exited_3": null, "properties_hs_date_exited_4": null, "properties_hs_external_object_ids": null, "properties_hs_feedback_last_ces_follow_up": null, "properties_hs_feedback_last_ces_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_file_upload": null, "properties_hs_first_agent_message_sent_at": null, "properties_hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "properties_hs_in_helpdesk": null, "properties_hs_inbox_id": null, "properties_hs_is_visible_in_help_desk": null, "properties_hs_last_email_activity": null, "properties_hs_last_email_date": null, "properties_hs_last_message_from_visitor": false, "properties_hs_last_message_received_at": null, "properties_hs_last_message_sent_at": null, "properties_hs_lastactivitydate": null, "properties_hs_lastcontacted": null, "properties_hs_lastmodifieddate": "2021-02-23T20:08:52.515000+00:00", "properties_hs_latest_message_seen_by_agent_ids": null, "properties_hs_merged_object_ids": null, "properties_hs_most_relevant_sla_status": null, "properties_hs_most_relevant_sla_type": null, "properties_hs_msteams_message_id": null, "properties_hs_nextactivitydate": null, "properties_hs_num_associated_companies": 0, "properties_hs_num_associated_conversations": null, "properties_hs_num_times_contacted": null, "properties_hs_object_id": 312975112, "properties_hs_object_source": "IMPORT", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "IMPORT", "properties_hs_object_source_user_id": null, "properties_hs_originating_channel_instance_id": null, "properties_hs_originating_email_engagement_id": null, "properties_hs_originating_generic_channel_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "0", "properties_hs_pipeline_stage": "1", "properties_hs_primary_company": null, "properties_hs_primary_company_id": null, "properties_hs_primary_company_name": null, "properties_hs_read_only": null, "properties_hs_resolution": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_thread_ids_to_restore": null, "properties_hs_ticket_category": null, "properties_hs_ticket_id": 312975112, "properties_hs_ticket_priority": "MEDIUM", "properties_hs_time_in_1": 93215284227, "properties_hs_time_in_151692305": null, "properties_hs_time_in_151692306": null, "properties_hs_time_in_151692307": null, "properties_hs_time_in_151692308": null, "properties_hs_time_in_2": null, "properties_hs_time_in_3": null, "properties_hs_time_in_4": null, "properties_hs_time_to_close_sla_at": null, "properties_hs_time_to_close_sla_status": null, "properties_hs_time_to_first_response_sla_at": null, "properties_hs_time_to_first_response_sla_status": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": true, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_last_engagement_date": null, "properties_last_reply_date": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_nps_follow_up_answer": null, "properties_nps_follow_up_question_version": null, "properties_nps_score": null, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_source_ref": null, "properties_source_thread_id": null, "properties_source_type": "PHONE", "properties_subject": "Free CRM", "properties_tags": null, "properties_time_to_close": null, "properties_time_to_first_agent_reply": null}, "emitted_at": 1707326213732} +{"stream": "tickets", "data": {"id": "312929579", "properties": {"closed_date": "2021-02-23T20:08:49.603000+00:00", "content": null, "created_by": null, "createdate": "2021-02-23T20:08:49.603000+00:00", "first_agent_reply_date": null, "hs_all_accessible_team_ids": null, "hs_all_associated_contact_companies": null, "hs_all_associated_contact_emails": null, "hs_all_associated_contact_firstnames": null, "hs_all_associated_contact_lastnames": null, "hs_all_associated_contact_mobilephones": null, "hs_all_associated_contact_phones": null, "hs_all_conversation_mentions": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignment_method": null, "hs_auto_generated_from_thread_id": null, "hs_conversations_originating_message_id": null, "hs_conversations_originating_thread_id": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_custom_inbox": null, "hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_151692305": null, "hs_date_entered_151692306": null, "hs_date_entered_151692307": null, "hs_date_entered_151692308": null, "hs_date_entered_2": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_3": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_4": "2021-02-23T20:08:49.603000+00:00", "hs_date_exited_1": "2021-02-23T20:08:49.603000+00:00", "hs_date_exited_151692305": null, "hs_date_exited_151692306": null, "hs_date_exited_151692307": null, "hs_date_exited_151692308": null, "hs_date_exited_2": "2021-02-23T20:08:49.603000+00:00", "hs_date_exited_3": "2021-02-23T20:08:49.603000+00:00", "hs_date_exited_4": null, "hs_external_object_ids": null, "hs_feedback_last_ces_follow_up": null, "hs_feedback_last_ces_rating": null, "hs_feedback_last_survey_date": null, "hs_file_upload": null, "hs_first_agent_message_sent_at": null, "hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "hs_in_helpdesk": null, "hs_inbox_id": null, "hs_is_visible_in_help_desk": null, "hs_last_email_activity": null, "hs_last_email_date": null, "hs_last_message_from_visitor": false, "hs_last_message_received_at": null, "hs_last_message_sent_at": null, "hs_lastactivitydate": null, "hs_lastcontacted": null, "hs_lastmodifieddate": "2021-02-23T20:08:53.371000+00:00", "hs_latest_message_seen_by_agent_ids": null, "hs_merged_object_ids": null, "hs_most_relevant_sla_status": null, "hs_most_relevant_sla_type": null, "hs_msteams_message_id": null, "hs_nextactivitydate": null, "hs_num_associated_companies": 0, "hs_num_associated_conversations": null, "hs_num_times_contacted": null, "hs_object_id": 312929579, "hs_object_source": "IMPORT", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "IMPORT", "hs_object_source_user_id": null, "hs_originating_channel_instance_id": null, "hs_originating_email_engagement_id": null, "hs_originating_generic_channel_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": "0", "hs_pipeline_stage": "4", "hs_primary_company": null, "hs_primary_company_id": null, "hs_primary_company_name": null, "hs_read_only": null, "hs_resolution": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_thread_ids_to_restore": null, "hs_ticket_category": null, "hs_ticket_id": 312929579, "hs_ticket_priority": "LOW", "hs_time_in_1": 0, "hs_time_in_151692305": null, "hs_time_in_151692306": null, "hs_time_in_151692307": null, "hs_time_in_151692308": null, "hs_time_in_2": 0, "hs_time_in_3": 0, "hs_time_in_4": 93903870829, "hs_time_to_close_sla_at": null, "hs_time_to_close_sla_status": null, "hs_time_to_first_response_sla_at": null, "hs_time_to_first_response_sla_status": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": true, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "last_engagement_date": null, "last_reply_date": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "nps_follow_up_answer": null, "nps_follow_up_question_version": null, "nps_score": null, "num_contacted_notes": null, "num_notes": null, "source_ref": null, "source_thread_id": null, "source_type": "CHAT", "subject": "Marketing Starter", "tags": null, "time_to_close": 0, "time_to_first_agent_reply": null}, "createdAt": "2021-02-23T20:08:49.603Z", "updatedAt": "2021-02-23T20:08:53.371Z", "archived": false, "properties_closed_date": "2021-02-23T20:08:49.603000+00:00", "properties_content": null, "properties_created_by": null, "properties_createdate": "2021-02-23T20:08:49.603000+00:00", "properties_first_agent_reply_date": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_associated_contact_companies": null, "properties_hs_all_associated_contact_emails": null, "properties_hs_all_associated_contact_firstnames": null, "properties_hs_all_associated_contact_lastnames": null, "properties_hs_all_associated_contact_mobilephones": null, "properties_hs_all_associated_contact_phones": null, "properties_hs_all_conversation_mentions": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignment_method": null, "properties_hs_auto_generated_from_thread_id": null, "properties_hs_conversations_originating_message_id": null, "properties_hs_conversations_originating_thread_id": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_custom_inbox": null, "properties_hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_151692305": null, "properties_hs_date_entered_151692306": null, "properties_hs_date_entered_151692307": null, "properties_hs_date_entered_151692308": null, "properties_hs_date_entered_2": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_3": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_4": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_exited_1": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_exited_151692305": null, "properties_hs_date_exited_151692306": null, "properties_hs_date_exited_151692307": null, "properties_hs_date_exited_151692308": null, "properties_hs_date_exited_2": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_exited_3": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_exited_4": null, "properties_hs_external_object_ids": null, "properties_hs_feedback_last_ces_follow_up": null, "properties_hs_feedback_last_ces_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_file_upload": null, "properties_hs_first_agent_message_sent_at": null, "properties_hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "properties_hs_in_helpdesk": null, "properties_hs_inbox_id": null, "properties_hs_is_visible_in_help_desk": null, "properties_hs_last_email_activity": null, "properties_hs_last_email_date": null, "properties_hs_last_message_from_visitor": false, "properties_hs_last_message_received_at": null, "properties_hs_last_message_sent_at": null, "properties_hs_lastactivitydate": null, "properties_hs_lastcontacted": null, "properties_hs_lastmodifieddate": "2021-02-23T20:08:53.371000+00:00", "properties_hs_latest_message_seen_by_agent_ids": null, "properties_hs_merged_object_ids": null, "properties_hs_most_relevant_sla_status": null, "properties_hs_most_relevant_sla_type": null, "properties_hs_msteams_message_id": null, "properties_hs_nextactivitydate": null, "properties_hs_num_associated_companies": 0, "properties_hs_num_associated_conversations": null, "properties_hs_num_times_contacted": null, "properties_hs_object_id": 312929579, "properties_hs_object_source": "IMPORT", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "IMPORT", "properties_hs_object_source_user_id": null, "properties_hs_originating_channel_instance_id": null, "properties_hs_originating_email_engagement_id": null, "properties_hs_originating_generic_channel_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "0", "properties_hs_pipeline_stage": "4", "properties_hs_primary_company": null, "properties_hs_primary_company_id": null, "properties_hs_primary_company_name": null, "properties_hs_read_only": null, "properties_hs_resolution": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_thread_ids_to_restore": null, "properties_hs_ticket_category": null, "properties_hs_ticket_id": 312929579, "properties_hs_ticket_priority": "LOW", "properties_hs_time_in_1": 0, "properties_hs_time_in_151692305": null, "properties_hs_time_in_151692306": null, "properties_hs_time_in_151692307": null, "properties_hs_time_in_151692308": null, "properties_hs_time_in_2": 0, "properties_hs_time_in_3": 0, "properties_hs_time_in_4": 93903870829, "properties_hs_time_to_close_sla_at": null, "properties_hs_time_to_close_sla_status": null, "properties_hs_time_to_first_response_sla_at": null, "properties_hs_time_to_first_response_sla_status": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": true, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_last_engagement_date": null, "properties_last_reply_date": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_nps_follow_up_answer": null, "properties_nps_follow_up_question_version": null, "properties_nps_score": null, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_source_ref": null, "properties_source_thread_id": null, "properties_source_type": "CHAT", "properties_subject": "Marketing Starter", "properties_tags": null, "properties_time_to_close": 0, "properties_time_to_first_agent_reply": null}, "emitted_at": 1708014800593} +{"stream": "tickets", "data": {"id": "312972611", "properties": {"closed_date": null, "content": null, "created_by": null, "createdate": "2021-02-23T20:08:49.603000+00:00", "first_agent_reply_date": null, "hs_all_accessible_team_ids": null, "hs_all_associated_contact_companies": null, "hs_all_associated_contact_emails": null, "hs_all_associated_contact_firstnames": null, "hs_all_associated_contact_lastnames": null, "hs_all_associated_contact_mobilephones": null, "hs_all_associated_contact_phones": null, "hs_all_conversation_mentions": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignment_method": null, "hs_auto_generated_from_thread_id": null, "hs_conversations_originating_message_id": null, "hs_conversations_originating_thread_id": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_custom_inbox": null, "hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_151692305": null, "hs_date_entered_151692306": null, "hs_date_entered_151692307": null, "hs_date_entered_151692308": null, "hs_date_entered_2": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_3": null, "hs_date_entered_4": null, "hs_date_exited_1": "2021-02-23T20:08:49.603000+00:00", "hs_date_exited_151692305": null, "hs_date_exited_151692306": null, "hs_date_exited_151692307": null, "hs_date_exited_151692308": null, "hs_date_exited_2": null, "hs_date_exited_3": null, "hs_date_exited_4": null, "hs_external_object_ids": null, "hs_feedback_last_ces_follow_up": null, "hs_feedback_last_ces_rating": null, "hs_feedback_last_survey_date": null, "hs_file_upload": null, "hs_first_agent_message_sent_at": null, "hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "hs_in_helpdesk": null, "hs_inbox_id": null, "hs_is_visible_in_help_desk": null, "hs_last_email_activity": null, "hs_last_email_date": null, "hs_last_message_from_visitor": false, "hs_last_message_received_at": null, "hs_last_message_sent_at": null, "hs_lastactivitydate": null, "hs_lastcontacted": null, "hs_lastmodifieddate": "2021-02-23T20:08:52.663000+00:00", "hs_latest_message_seen_by_agent_ids": null, "hs_merged_object_ids": null, "hs_most_relevant_sla_status": null, "hs_most_relevant_sla_type": null, "hs_msteams_message_id": null, "hs_nextactivitydate": null, "hs_num_associated_companies": 0, "hs_num_associated_conversations": null, "hs_num_times_contacted": null, "hs_object_id": 312972611, "hs_object_source": "IMPORT", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "IMPORT", "hs_object_source_user_id": null, "hs_originating_channel_instance_id": null, "hs_originating_email_engagement_id": null, "hs_originating_generic_channel_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": "0", "hs_pipeline_stage": "2", "hs_primary_company": null, "hs_primary_company_id": null, "hs_primary_company_name": null, "hs_read_only": null, "hs_resolution": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_thread_ids_to_restore": null, "hs_ticket_category": null, "hs_ticket_id": 312972611, "hs_ticket_priority": "LOW", "hs_time_in_1": 0, "hs_time_in_151692305": null, "hs_time_in_151692306": null, "hs_time_in_151692307": null, "hs_time_in_151692308": null, "hs_time_in_2": 93903870829, "hs_time_in_3": null, "hs_time_in_4": null, "hs_time_to_close_sla_at": null, "hs_time_to_close_sla_status": null, "hs_time_to_first_response_sla_at": null, "hs_time_to_first_response_sla_status": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": true, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "last_engagement_date": null, "last_reply_date": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "nps_follow_up_answer": null, "nps_follow_up_question_version": null, "nps_score": null, "num_contacted_notes": null, "num_notes": null, "source_ref": null, "source_thread_id": null, "source_type": "FORM", "subject": "Sales Starter", "tags": null, "time_to_close": null, "time_to_first_agent_reply": null}, "createdAt": "2021-02-23T20:08:49.603Z", "updatedAt": "2021-02-23T20:08:52.663Z", "archived": false, "properties_closed_date": null, "properties_content": null, "properties_created_by": null, "properties_createdate": "2021-02-23T20:08:49.603000+00:00", "properties_first_agent_reply_date": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_associated_contact_companies": null, "properties_hs_all_associated_contact_emails": null, "properties_hs_all_associated_contact_firstnames": null, "properties_hs_all_associated_contact_lastnames": null, "properties_hs_all_associated_contact_mobilephones": null, "properties_hs_all_associated_contact_phones": null, "properties_hs_all_conversation_mentions": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignment_method": null, "properties_hs_auto_generated_from_thread_id": null, "properties_hs_conversations_originating_message_id": null, "properties_hs_conversations_originating_thread_id": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_custom_inbox": null, "properties_hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_151692305": null, "properties_hs_date_entered_151692306": null, "properties_hs_date_entered_151692307": null, "properties_hs_date_entered_151692308": null, "properties_hs_date_entered_2": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_3": null, "properties_hs_date_entered_4": null, "properties_hs_date_exited_1": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_exited_151692305": null, "properties_hs_date_exited_151692306": null, "properties_hs_date_exited_151692307": null, "properties_hs_date_exited_151692308": null, "properties_hs_date_exited_2": null, "properties_hs_date_exited_3": null, "properties_hs_date_exited_4": null, "properties_hs_external_object_ids": null, "properties_hs_feedback_last_ces_follow_up": null, "properties_hs_feedback_last_ces_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_file_upload": null, "properties_hs_first_agent_message_sent_at": null, "properties_hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "properties_hs_in_helpdesk": null, "properties_hs_inbox_id": null, "properties_hs_is_visible_in_help_desk": null, "properties_hs_last_email_activity": null, "properties_hs_last_email_date": null, "properties_hs_last_message_from_visitor": false, "properties_hs_last_message_received_at": null, "properties_hs_last_message_sent_at": null, "properties_hs_lastactivitydate": null, "properties_hs_lastcontacted": null, "properties_hs_lastmodifieddate": "2021-02-23T20:08:52.663000+00:00", "properties_hs_latest_message_seen_by_agent_ids": null, "properties_hs_merged_object_ids": null, "properties_hs_most_relevant_sla_status": null, "properties_hs_most_relevant_sla_type": null, "properties_hs_msteams_message_id": null, "properties_hs_nextactivitydate": null, "properties_hs_num_associated_companies": 0, "properties_hs_num_associated_conversations": null, "properties_hs_num_times_contacted": null, "properties_hs_object_id": 312972611, "properties_hs_object_source": "IMPORT", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "IMPORT", "properties_hs_object_source_user_id": null, "properties_hs_originating_channel_instance_id": null, "properties_hs_originating_email_engagement_id": null, "properties_hs_originating_generic_channel_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "0", "properties_hs_pipeline_stage": "2", "properties_hs_primary_company": null, "properties_hs_primary_company_id": null, "properties_hs_primary_company_name": null, "properties_hs_read_only": null, "properties_hs_resolution": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_thread_ids_to_restore": null, "properties_hs_ticket_category": null, "properties_hs_ticket_id": 312972611, "properties_hs_ticket_priority": "LOW", "properties_hs_time_in_1": 0, "properties_hs_time_in_151692305": null, "properties_hs_time_in_151692306": null, "properties_hs_time_in_151692307": null, "properties_hs_time_in_151692308": null, "properties_hs_time_in_2": 93903870829, "properties_hs_time_in_3": null, "properties_hs_time_in_4": null, "properties_hs_time_to_close_sla_at": null, "properties_hs_time_to_close_sla_status": null, "properties_hs_time_to_first_response_sla_at": null, "properties_hs_time_to_first_response_sla_status": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": true, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_last_engagement_date": null, "properties_last_reply_date": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_nps_follow_up_answer": null, "properties_nps_follow_up_question_version": null, "properties_nps_score": null, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_source_ref": null, "properties_source_thread_id": null, "properties_source_type": "FORM", "properties_subject": "Sales Starter", "properties_tags": null, "properties_time_to_close": null, "properties_time_to_first_agent_reply": null}, "emitted_at": 1708014800594} +{"stream": "tickets", "data": {"id": "312975112", "properties": {"closed_date": null, "content": null, "created_by": null, "createdate": "2021-02-23T20:08:49.603000+00:00", "first_agent_reply_date": null, "hs_all_accessible_team_ids": null, "hs_all_associated_contact_companies": null, "hs_all_associated_contact_emails": null, "hs_all_associated_contact_firstnames": null, "hs_all_associated_contact_lastnames": null, "hs_all_associated_contact_mobilephones": null, "hs_all_associated_contact_phones": null, "hs_all_conversation_mentions": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_assignment_method": null, "hs_auto_generated_from_thread_id": null, "hs_conversations_originating_message_id": null, "hs_conversations_originating_thread_id": null, "hs_created_by_user_id": null, "hs_createdate": null, "hs_custom_inbox": null, "hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "hs_date_entered_151692305": null, "hs_date_entered_151692306": null, "hs_date_entered_151692307": null, "hs_date_entered_151692308": null, "hs_date_entered_2": null, "hs_date_entered_3": null, "hs_date_entered_4": null, "hs_date_exited_1": null, "hs_date_exited_151692305": null, "hs_date_exited_151692306": null, "hs_date_exited_151692307": null, "hs_date_exited_151692308": null, "hs_date_exited_2": null, "hs_date_exited_3": null, "hs_date_exited_4": null, "hs_external_object_ids": null, "hs_feedback_last_ces_follow_up": null, "hs_feedback_last_ces_rating": null, "hs_feedback_last_survey_date": null, "hs_file_upload": null, "hs_first_agent_message_sent_at": null, "hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "hs_in_helpdesk": null, "hs_inbox_id": null, "hs_is_visible_in_help_desk": null, "hs_last_email_activity": null, "hs_last_email_date": null, "hs_last_message_from_visitor": false, "hs_last_message_received_at": null, "hs_last_message_sent_at": null, "hs_lastactivitydate": null, "hs_lastcontacted": null, "hs_lastmodifieddate": "2021-02-23T20:08:52.515000+00:00", "hs_latest_message_seen_by_agent_ids": null, "hs_merged_object_ids": null, "hs_most_relevant_sla_status": null, "hs_most_relevant_sla_type": null, "hs_msteams_message_id": null, "hs_nextactivitydate": null, "hs_num_associated_companies": 0, "hs_num_associated_conversations": null, "hs_num_times_contacted": null, "hs_object_id": 312975112, "hs_object_source": "IMPORT", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "IMPORT", "hs_object_source_user_id": null, "hs_originating_channel_instance_id": null, "hs_originating_email_engagement_id": null, "hs_originating_generic_channel_id": null, "hs_pinned_engagement_id": null, "hs_pipeline": "0", "hs_pipeline_stage": "1", "hs_primary_company": null, "hs_primary_company_id": null, "hs_primary_company_name": null, "hs_read_only": null, "hs_resolution": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_thread_ids_to_restore": null, "hs_ticket_category": null, "hs_ticket_id": 312975112, "hs_ticket_priority": "MEDIUM", "hs_time_in_1": 93903870829, "hs_time_in_151692305": null, "hs_time_in_151692306": null, "hs_time_in_151692307": null, "hs_time_in_151692308": null, "hs_time_in_2": null, "hs_time_in_3": null, "hs_time_in_4": null, "hs_time_to_close_sla_at": null, "hs_time_to_close_sla_status": null, "hs_time_to_first_response_sla_at": null, "hs_time_to_first_response_sla_status": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": null, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": true, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "last_engagement_date": null, "last_reply_date": null, "notes_last_contacted": null, "notes_last_updated": null, "notes_next_activity_date": null, "nps_follow_up_answer": null, "nps_follow_up_question_version": null, "nps_score": null, "num_contacted_notes": null, "num_notes": null, "source_ref": null, "source_thread_id": null, "source_type": "PHONE", "subject": "Free CRM", "tags": null, "time_to_close": null, "time_to_first_agent_reply": null}, "createdAt": "2021-02-23T20:08:49.603Z", "updatedAt": "2021-02-23T20:08:52.515Z", "archived": false, "properties_closed_date": null, "properties_content": null, "properties_created_by": null, "properties_createdate": "2021-02-23T20:08:49.603000+00:00", "properties_first_agent_reply_date": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_associated_contact_companies": null, "properties_hs_all_associated_contact_emails": null, "properties_hs_all_associated_contact_firstnames": null, "properties_hs_all_associated_contact_lastnames": null, "properties_hs_all_associated_contact_mobilephones": null, "properties_hs_all_associated_contact_phones": null, "properties_hs_all_conversation_mentions": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_assignment_method": null, "properties_hs_auto_generated_from_thread_id": null, "properties_hs_conversations_originating_message_id": null, "properties_hs_conversations_originating_thread_id": null, "properties_hs_created_by_user_id": null, "properties_hs_createdate": null, "properties_hs_custom_inbox": null, "properties_hs_date_entered_1": "2021-02-23T20:08:49.603000+00:00", "properties_hs_date_entered_151692305": null, "properties_hs_date_entered_151692306": null, "properties_hs_date_entered_151692307": null, "properties_hs_date_entered_151692308": null, "properties_hs_date_entered_2": null, "properties_hs_date_entered_3": null, "properties_hs_date_entered_4": null, "properties_hs_date_exited_1": null, "properties_hs_date_exited_151692305": null, "properties_hs_date_exited_151692306": null, "properties_hs_date_exited_151692307": null, "properties_hs_date_exited_151692308": null, "properties_hs_date_exited_2": null, "properties_hs_date_exited_3": null, "properties_hs_date_exited_4": null, "properties_hs_external_object_ids": null, "properties_hs_feedback_last_ces_follow_up": null, "properties_hs_feedback_last_ces_rating": null, "properties_hs_feedback_last_survey_date": null, "properties_hs_file_upload": null, "properties_hs_first_agent_message_sent_at": null, "properties_hs_helpdesk_sort_timestamp": "2021-02-23T20:08:49.603000+00:00", "properties_hs_in_helpdesk": null, "properties_hs_inbox_id": null, "properties_hs_is_visible_in_help_desk": null, "properties_hs_last_email_activity": null, "properties_hs_last_email_date": null, "properties_hs_last_message_from_visitor": false, "properties_hs_last_message_received_at": null, "properties_hs_last_message_sent_at": null, "properties_hs_lastactivitydate": null, "properties_hs_lastcontacted": null, "properties_hs_lastmodifieddate": "2021-02-23T20:08:52.515000+00:00", "properties_hs_latest_message_seen_by_agent_ids": null, "properties_hs_merged_object_ids": null, "properties_hs_most_relevant_sla_status": null, "properties_hs_most_relevant_sla_type": null, "properties_hs_msteams_message_id": null, "properties_hs_nextactivitydate": null, "properties_hs_num_associated_companies": 0, "properties_hs_num_associated_conversations": null, "properties_hs_num_times_contacted": null, "properties_hs_object_id": 312975112, "properties_hs_object_source": "IMPORT", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "IMPORT", "properties_hs_object_source_user_id": null, "properties_hs_originating_channel_instance_id": null, "properties_hs_originating_email_engagement_id": null, "properties_hs_originating_generic_channel_id": null, "properties_hs_pinned_engagement_id": null, "properties_hs_pipeline": "0", "properties_hs_pipeline_stage": "1", "properties_hs_primary_company": null, "properties_hs_primary_company_id": null, "properties_hs_primary_company_name": null, "properties_hs_read_only": null, "properties_hs_resolution": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_thread_ids_to_restore": null, "properties_hs_ticket_category": null, "properties_hs_ticket_id": 312975112, "properties_hs_ticket_priority": "MEDIUM", "properties_hs_time_in_1": 93903870829, "properties_hs_time_in_151692305": null, "properties_hs_time_in_151692306": null, "properties_hs_time_in_151692307": null, "properties_hs_time_in_151692308": null, "properties_hs_time_in_2": null, "properties_hs_time_in_3": null, "properties_hs_time_in_4": null, "properties_hs_time_to_close_sla_at": null, "properties_hs_time_to_close_sla_status": null, "properties_hs_time_to_first_response_sla_at": null, "properties_hs_time_to_first_response_sla_status": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": null, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": true, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_last_engagement_date": null, "properties_last_reply_date": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": null, "properties_notes_next_activity_date": null, "properties_nps_follow_up_answer": null, "properties_nps_follow_up_question_version": null, "properties_nps_score": null, "properties_num_contacted_notes": null, "properties_num_notes": null, "properties_source_ref": null, "properties_source_thread_id": null, "properties_source_type": "PHONE", "properties_subject": "Free CRM", "properties_tags": null, "properties_time_to_close": null, "properties_time_to_first_agent_reply": null}, "emitted_at": 1708014800595} {"stream": "workflows", "data": {"migrationStatus": {"portalId": 8727216, "workflowId": 21058115, "migrationStatus": "EXECUTION_MIGRATED", "enrollmentMigrationStatus": "PLATFORM_OWNED", "platformOwnsActions": true, "lastSuccessfulMigrationTimestamp": null, "enrollmentMigrationTimestamp": null, "flowId": 50206671}, "name": "Test Workflow", "id": 21058115, "type": "DRIP_DELAY", "enabled": false, "creationSource": {"sourceApplication": {"source": "DIRECT_API"}, "createdAt": 1610635826795}, "updateSource": {"sourceApplication": {"source": "DIRECT_API", "serviceName": "AutomationPlatformService-web_BackfillILSListIds"}, "updatedAt": 1611847907577}, "contactListIds": {"enrolled": 12, "active": 13, "completed": 14, "succeeded": 15}, "personaTagIds": [], "contactCounts": {"active": 0, "enrolled": 0}, "portalId": 8727216, "insertedAt": 1610635826921, "updatedAt": 1611847907577, "contactListIds_enrolled": 12, "contactListIds_active": 13, "contactListIds_completed": 14, "contactListIds_succeeded": 15}, "emitted_at": 1697714264418} {"stream": "workflows", "data": {"migrationStatus": {"portalId": 8727216, "workflowId": 21058121, "migrationStatus": "EXECUTION_MIGRATED", "enrollmentMigrationStatus": "PLATFORM_OWNED", "platformOwnsActions": true, "lastSuccessfulMigrationTimestamp": null, "enrollmentMigrationTimestamp": null, "flowId": 50205684}, "name": "Test Workflow 1", "id": 21058121, "type": "DRIP_DELAY", "enabled": false, "creationSource": {"sourceApplication": {"source": "DIRECT_API"}, "createdAt": 1610635850713}, "updateSource": {"sourceApplication": {"source": "DIRECT_API", "serviceName": "AutomationPlatformService-web_BackfillILSListIds"}, "updatedAt": 1611847907579}, "contactListIds": {"enrolled": 16, "active": 17, "completed": 18, "succeeded": 19}, "personaTagIds": [], "contactCounts": {"active": 0, "enrolled": 0}, "portalId": 8727216, "insertedAt": 1610635850758, "updatedAt": 1611847907579, "contactListIds_enrolled": 16, "contactListIds_active": 17, "contactListIds_completed": 18, "contactListIds_succeeded": 19}, "emitted_at": 1697714264419} {"stream": "workflows", "data": {"migrationStatus": {"portalId": 8727216, "workflowId": 21058122, "migrationStatus": "EXECUTION_MIGRATED", "enrollmentMigrationStatus": "PLATFORM_OWNED", "platformOwnsActions": true, "lastSuccessfulMigrationTimestamp": null, "enrollmentMigrationTimestamp": null, "flowId": 50205036}, "name": "Test Workflow 2", "id": 21058122, "type": "DRIP_DELAY", "enabled": false, "creationSource": {"sourceApplication": {"source": "DIRECT_API"}, "createdAt": 1610635859664}, "updateSource": {"sourceApplication": {"source": "DIRECT_API", "serviceName": "AutomationPlatformService-web_BackfillILSListIds"}, "updatedAt": 1611847907578}, "contactListIds": {"enrolled": 20, "active": 21, "completed": 22, "succeeded": 23}, "personaTagIds": [], "contactCounts": {"active": 0, "enrolled": 0}, "portalId": 8727216, "insertedAt": 1610635859748, "updatedAt": 1611847907578, "contactListIds_enrolled": 20, "contactListIds_active": 21, "contactListIds_completed": 22, "contactListIds_succeeded": 23}, "emitted_at": 1697714264420} -{"stream": "cars", "data": {"id": "5938880072", "properties": {"car_id": 1, "car_name": 3232324, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-12T17:57:15.836000+00:00", "hs_lastmodifieddate": "2023-04-12T17:59:20.189000+00:00", "hs_merged_object_ids": null, "hs_object_id": 5938880072, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_pinned_engagement_id": null, "hs_read_only": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null}, "createdAt": "2023-04-12T17:57:15.836Z", "updatedAt": "2023-04-12T17:59:20.189Z", "archived": false, "properties_car_id": 1, "properties_car_name": 3232324, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-12T17:57:15.836000+00:00", "properties_hs_lastmodifieddate": "2023-04-12T17:59:20.189000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 5938880072, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_pinned_engagement_id": null, "properties_hs_read_only": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null}, "emitted_at": 1703882548289} -{"stream": "cars", "data": {"id": "5938880073", "properties": {"car_id": 2, "car_name": 23232, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-12T17:57:20.583000+00:00", "hs_lastmodifieddate": "2023-04-12T17:59:20.189000+00:00", "hs_merged_object_ids": null, "hs_object_id": 5938880073, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_pinned_engagement_id": null, "hs_read_only": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null}, "createdAt": "2023-04-12T17:57:20.583Z", "updatedAt": "2023-04-12T17:59:20.189Z", "archived": false, "properties_car_id": 2, "properties_car_name": 23232, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-12T17:57:20.583000+00:00", "properties_hs_lastmodifieddate": "2023-04-12T17:59:20.189000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 5938880073, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_pinned_engagement_id": null, "properties_hs_read_only": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null}, "emitted_at": 1703882548293} -{"stream": "pets", "data": {"id": "5936415312", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-12T17:08:50.632000+00:00", "hs_lastmodifieddate": "2023-04-12T17:08:50.632000+00:00", "hs_merged_object_ids": null, "hs_object_id": 5936415312, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_pinned_engagement_id": null, "hs_read_only": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "pet_name": "Marcos Pet", "pet_type": "Dog"}, "createdAt": "2023-04-12T17:08:50.632Z", "updatedAt": "2023-04-12T17:08:50.632Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-12T17:08:50.632000+00:00", "properties_hs_lastmodifieddate": "2023-04-12T17:08:50.632000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 5936415312, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_pinned_engagement_id": null, "properties_hs_read_only": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_pet_name": "Marcos Pet", "properties_pet_type": "Dog"}, "emitted_at": 1703886126793} -{"stream": "pets", "data": {"id": "5938880054", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-12T17:53:12.692000+00:00", "hs_lastmodifieddate": "2023-04-12T17:53:12.692000+00:00", "hs_merged_object_ids": null, "hs_object_id": 5938880054, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_pinned_engagement_id": null, "hs_read_only": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "pet_name": "Integration Test Pet", "pet_type": "Unknown"}, "createdAt": "2023-04-12T17:53:12.692Z", "updatedAt": "2023-04-12T17:53:12.692Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-12T17:53:12.692000+00:00", "properties_hs_lastmodifieddate": "2023-04-12T17:53:12.692000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 5938880054, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_pinned_engagement_id": null, "properties_hs_read_only": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_pet_name": "Integration Test Pet", "properties_pet_type": "Unknown"}, "emitted_at": 1703886126795} +{"stream": "cars", "data": {"id": "5938880072", "properties": {"car_id": 1, "car_name": 3232324, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-12T17:57:15.836000+00:00", "hs_lastmodifieddate": "2023-04-12T17:59:20.189000+00:00", "hs_merged_object_ids": null, "hs_object_id": 5938880072, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_pinned_engagement_id": null, "hs_read_only": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null}, "createdAt": "2023-04-12T17:57:15.836Z", "updatedAt": "2023-04-12T17:59:20.189Z", "archived": false, "properties_car_id": 1, "properties_car_name": 3232324, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-12T17:57:15.836000+00:00", "properties_hs_lastmodifieddate": "2023-04-12T17:59:20.189000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 5938880072, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_pinned_engagement_id": null, "properties_hs_read_only": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null}, "emitted_at": 1708014961477} +{"stream": "cars", "data": {"id": "5938880073", "properties": {"car_id": 2, "car_name": 23232, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-12T17:57:20.583000+00:00", "hs_lastmodifieddate": "2023-04-12T17:59:20.189000+00:00", "hs_merged_object_ids": null, "hs_object_id": 5938880073, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_pinned_engagement_id": null, "hs_read_only": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null}, "createdAt": "2023-04-12T17:57:20.583Z", "updatedAt": "2023-04-12T17:59:20.189Z", "archived": false, "properties_car_id": 2, "properties_car_name": 23232, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-12T17:57:20.583000+00:00", "properties_hs_lastmodifieddate": "2023-04-12T17:59:20.189000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 5938880073, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_pinned_engagement_id": null, "properties_hs_read_only": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null}, "emitted_at": 1708014961480} +{"stream": "pets", "data": {"id": "5936415312", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-12T17:08:50.632000+00:00", "hs_lastmodifieddate": "2023-04-12T17:08:50.632000+00:00", "hs_merged_object_ids": null, "hs_object_id": 5936415312, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_pinned_engagement_id": null, "hs_read_only": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "pet_name": "Marcos Pet", "pet_type": "Dog"}, "createdAt": "2023-04-12T17:08:50.632Z", "updatedAt": "2023-04-12T17:08:50.632Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-12T17:08:50.632000+00:00", "properties_hs_lastmodifieddate": "2023-04-12T17:08:50.632000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 5936415312, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_pinned_engagement_id": null, "properties_hs_read_only": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_pet_name": "Marcos Pet", "properties_pet_type": "Dog"}, "emitted_at": 1708015148856} +{"stream": "pets", "data": {"id": "5938880054", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": null, "hs_all_team_ids": null, "hs_created_by_user_id": 12282590, "hs_createdate": "2023-04-12T17:53:12.692000+00:00", "hs_lastmodifieddate": "2023-04-12T17:53:12.692000+00:00", "hs_merged_object_ids": null, "hs_object_id": 5938880054, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_pinned_engagement_id": null, "hs_read_only": null, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": null, "hs_was_imported": null, "hubspot_owner_assigneddate": null, "hubspot_owner_id": null, "hubspot_team_id": null, "pet_name": "Integration Test Pet", "pet_type": "Unknown"}, "createdAt": "2023-04-12T17:53:12.692Z", "updatedAt": "2023-04-12T17:53:12.692Z", "archived": false, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": null, "properties_hs_all_team_ids": null, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-04-12T17:53:12.692000+00:00", "properties_hs_lastmodifieddate": "2023-04-12T17:53:12.692000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_object_id": 5938880054, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_pinned_engagement_id": null, "properties_hs_read_only": null, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": null, "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": null, "properties_hubspot_owner_id": null, "properties_hubspot_team_id": null, "properties_pet_name": "Integration Test Pet", "properties_pet_type": "Unknown"}, "emitted_at": 1708015148859} {"stream": "contacts_web_analytics", "data": {"objectType": "CONTACT", "objectId": "151", "eventType": "pe8727216_airbyte_contact_custom_event", "occurredAt": "2023-11-24T22:35:09.286Z", "id": "54338ee5-9db1-4ba3-afa8-1b052508fc8f"}, "emitted_at": 1707257902940} {"stream": "contacts_web_analytics", "data": {"objectType": "CONTACT", "objectId": "151", "eventType": "pe8727216_airbyte_contact_custom_event", "occurredAt": "2023-12-01T21:50:11.797Z", "id": "b850d903-254c-4df6-b159-9263b2b7eed0", "properties_hs_campaign_id": "illum quas dolor modi exercitationem", "properties_hs_operating_version": "Lorem ipsum culpa! illum elit. esse esse officiis", "properties_hs_tracking_name": "quas ipsum amet illum molestias,", "properties_hs_page_content_type": "elit. libero Lorem", "properties_hs_region": "consectetur ipsum, architecto ipsum Lorem nobis", "properties_hs_device_type": "accusantium dolor sit elit. veniam reprehenderit", "properties_hs_element_id": "culpa! sit ipsum sit Lorem consectetur quas odit", "properties_hs_device_name": "elit. molestias, elit. amet", "properties_hs_touchpoint_source": "dolor", "properties_hs_page_id": "magnam, magnam,", "properties_hs_link_href": "officiis exercitationem adipisicing odit dolor", "properties_hs_city": "reiciendis placeat dolor placeat architecto dolor", "properties_hs_language": "officiis adipisicing", "properties_hs_asset_description": "dolor architecto", "properties_hs_page_url": "accusantium quas architecto ipsum ipsum possimus", "properties_hs_utm_campaign": "magnam, Lorem modi culpa!", "properties_hs_utm_medium": "placeat dolor dolor consectetur elit.", "properties_hs_element_text": "Hic molestias, Lorem ipsum, possimus adipisicing", "properties_hs_operating_system": "magnam, molestias,"}, "emitted_at": 1707257902946} {"stream": "contacts_web_analytics", "data": {"objectType": "CONTACT", "objectId": "151", "eventType": "pe8727216_airbyte_contact_custom_event", "occurredAt": "2023-12-01T22:06:45.502Z", "id": "4265b60b-7873-45a6-8983-882134c51dc2", "properties_hs_campaign_id": "officiis quas nobis adipisicing sit", "properties_hs_operating_version": "repellendus esse", "properties_hs_page_content_type": "adipisicing consectetur repellendus consectetur", "properties_hs_region": "repellendus officiis odit esse", "properties_hs_device_name": "veniam", "properties_hs_touchpoint_source": "modi modi repellendus Lorem Lorem reiciendis Hic", "properties_hs_page_id": "officiis", "properties_hs_referrer": "consectetur placeat architecto libero elit. modi", "properties_hs_asset_type": "odit reprehenderit placeat", "properties_hs_screen_height": "2623.0", "properties_hs_screen_width": "4270.0", "properties_hs_language": "reprehenderit molestias, reiciendis magnam, Lorem", "properties_hs_page_url": "placeat amet officiis possimus veniam", "properties_hs_element_class": "repellendus magnam, ipsum, amet magnam, Hic ipsum", "properties_hs_country": "exercitationem", "properties_hs_utm_source": "architecto reiciendis sit illum odit ipsum nobis", "properties_hs_utm_medium": "ipsum, officiis magnam, odit modi reiciendis odit", "properties_hs_element_text": "veniam ipsum, consectetur reiciendis adipisicing", "properties_hs_operating_system": "dolor reprehenderit amet officiis exercitationem"}, "emitted_at": 1707257902951} {"stream": "form_submissions", "data": {"submittedAt": 1707094502866, "values": [{"name": "email", "value": "integration-test+hubspot_form_100@airbyte.io", "objectTypeId": "0-1"}], "pageUrl": "https://share.hsforms.com/17X1n1tQkRLOOmod8jZV67A571yo", "updatedAt": 1707094502866, "formId": "ed7d67d6-d424-44b3-8e9a-877c8d957aec"}, "emitted_at": 1707094528032} {"stream": "contacts_form_submissions", "data": {"canonical-vid": 3001, "conversion-id": "2ec044dd-5ba6-4bbf-b64d-2b3a561d8434", "timestamp": 1707094108543, "form-id": "49773438-eebc-4622-a70b-f2102839d416", "portal-id": 8727216, "page-url": "https://meetings.hubspot.com/team-1-airbyte", "title": "Meetings Link: team-1-airbyte", "form-type": "MEETING", "contact-associated-by": ["EMAIL"], "meta-data": []}, "emitted_at": 1707094509475} {"stream": "contacts_form_submissions", "data": {"canonical-vid": 3101, "conversion-id": "aed975ea-68dd-456a-aef1-c80ef08001e8", "timestamp": 1707094502866, "form-id": "ed7d67d6-d424-44b3-8e9a-877c8d957aec", "portal-id": 8727216, "page-url": "https://share.hsforms.com/17X1n1tQkRLOOmod8jZV67A571yo", "canonical-url": "https://share.hsforms.com/17X1n1tQkRLOOmod8jZV67A571yo", "page-title": "Form", "title": "New form 100", "form-type": "HUBSPOT", "meta-data": []}, "emitted_at": 1707094509476} -{"stream": "deals_archived", "data": {"id": "15165693770", "properties": {"amount": 0, "amount_in_home_currency": 0, "closed_lost_reason": null, "closed_won_reason": null, "closedate": "2023-09-15T09:08:03.642000+00:00", "createdate": "2023-09-15T09:08:20.208000+00:00", "days_to_close": 0, "dealname": "Test 1715 Deal Acrhived Line Items", "dealstage": "closedwon", "dealtype": "newbusiness", "description": null, "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "hs_acv": null, "hs_all_accessible_team_ids": null, "hs_all_collaborator_owner_ids": null, "hs_all_deal_split_owner_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_latest_source": null, "hs_analytics_latest_source_company": null, "hs_analytics_latest_source_contact": null, "hs_analytics_latest_source_data_1": null, "hs_analytics_latest_source_data_1_company": null, "hs_analytics_latest_source_data_1_contact": null, "hs_analytics_latest_source_data_2": null, "hs_analytics_latest_source_data_2_company": null, "hs_analytics_latest_source_data_2_contact": null, "hs_analytics_latest_source_timestamp": null, "hs_analytics_latest_source_timestamp_company": null, "hs_analytics_latest_source_timestamp_contact": null, "hs_analytics_source": null, "hs_analytics_source_data_1": null, "hs_analytics_source_data_2": null, "hs_arr": null, "hs_campaign": null, "hs_closed_amount": 0, "hs_closed_amount_in_home_currency": 0, "hs_closed_won_count": 1, "hs_closed_won_date": "2023-09-15T09:08:03.642000+00:00", "hs_created_by_user_id": 12282590, "hs_createdate": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_66894120": null, "hs_date_entered_9567448": null, "hs_date_entered_9567449": null, "hs_date_entered_appointmentscheduled": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_closedlost": null, "hs_date_entered_closedwon": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_contractsent": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_customclosedwonstage": null, "hs_date_entered_decisionmakerboughtin": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_presentationscheduled": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_qualifiedtobuy": "2023-09-15T09:08:20.208000+00:00", "hs_date_exited_66894120": null, "hs_date_exited_9567448": null, "hs_date_exited_9567449": null, "hs_date_exited_appointmentscheduled": "2023-09-15T09:08:20.208000+00:00", "hs_date_exited_closedlost": null, "hs_date_exited_closedwon": null, "hs_date_exited_contractsent": "2023-09-15T09:08:20.208000+00:00", "hs_date_exited_customclosedwonstage": null, "hs_date_exited_decisionmakerboughtin": "2023-09-15T09:08:20.208000+00:00", "hs_date_exited_presentationscheduled": "2023-09-15T09:08:20.208000+00:00", "hs_date_exited_qualifiedtobuy": "2023-09-15T09:08:20.208000+00:00", "hs_days_to_close_raw": 0, "hs_deal_amount_calculation_preference": null, "hs_deal_stage_probability": 1, "hs_deal_stage_probability_shadow": 1, "hs_exchange_rate": null, "hs_forecast_amount": 0, "hs_forecast_probability": null, "hs_is_closed": true, "hs_is_closed_won": true, "hs_is_deal_split": false, "hs_is_open_count": 0, "hs_lastmodifieddate": "2023-09-18T09:09:00.660000+00:00", "hs_latest_meeting_activity": null, "hs_likelihood_to_close": null, "hs_line_item_global_term_hs_discount_percentage": null, "hs_line_item_global_term_hs_discount_percentage_enabled": null, "hs_line_item_global_term_hs_recurring_billing_period": null, "hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "hs_line_item_global_term_hs_recurring_billing_start_date": null, "hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "hs_line_item_global_term_recurringbillingfrequency": null, "hs_line_item_global_term_recurringbillingfrequency_enabled": null, "hs_manual_forecast_category": null, "hs_merged_object_ids": null, "hs_mrr": null, "hs_next_step": null, "hs_num_associated_deal_splits": 0, "hs_num_of_associated_line_items": 0, "hs_num_target_accounts": 0, "hs_object_id": 15165693770, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_pinned_engagement_id": null, "hs_predicted_amount": null, "hs_predicted_amount_in_home_currency": null, "hs_priority": "low", "hs_projected_amount": 0, "hs_projected_amount_in_home_currency": 0, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_tcv": null, "hs_time_in_66894120": null, "hs_time_in_9567448": null, "hs_time_in_9567449": null, "hs_time_in_appointmentscheduled": 0, "hs_time_in_closedlost": null, "hs_time_in_closedwon": 12325830797, "hs_time_in_contractsent": 0, "hs_time_in_customclosedwonstage": null, "hs_time_in_decisionmakerboughtin": 0, "hs_time_in_presentationscheduled": 0, "hs_time_in_qualifiedtobuy": 0, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2023-09-15T09:08:20.208000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "notes_last_contacted": null, "notes_last_updated": "2023-09-18T09:08:59.252000+00:00", "notes_next_activity_date": null, "num_associated_contacts": 0, "num_contacted_notes": 0, "num_notes": 2, "pipeline": "default"}, "createdAt": "2023-09-15T09:08:20.208Z", "updatedAt": "2023-09-18T09:09:00.660Z", "archived": true, "archivedAt": "2024-02-05T00:58:23.662Z", "properties_amount": 0, "properties_amount_in_home_currency": 0, "properties_closed_lost_reason": null, "properties_closed_won_reason": null, "properties_closedate": "2023-09-15T09:08:03.642000+00:00", "properties_createdate": "2023-09-15T09:08:20.208000+00:00", "properties_days_to_close": 0, "properties_dealname": "Test 1715 Deal Acrhived Line Items", "properties_dealstage": "closedwon", "properties_dealtype": "newbusiness", "properties_description": null, "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_hs_acv": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_collaborator_owner_ids": null, "properties_hs_all_deal_split_owner_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_latest_source": null, "properties_hs_analytics_latest_source_company": null, "properties_hs_analytics_latest_source_contact": null, "properties_hs_analytics_latest_source_data_1": null, "properties_hs_analytics_latest_source_data_1_company": null, "properties_hs_analytics_latest_source_data_1_contact": null, "properties_hs_analytics_latest_source_data_2": null, "properties_hs_analytics_latest_source_data_2_company": null, "properties_hs_analytics_latest_source_data_2_contact": null, "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_latest_source_timestamp_company": null, "properties_hs_analytics_latest_source_timestamp_contact": null, "properties_hs_analytics_source": null, "properties_hs_analytics_source_data_1": null, "properties_hs_analytics_source_data_2": null, "properties_hs_arr": null, "properties_hs_campaign": null, "properties_hs_closed_amount": 0, "properties_hs_closed_amount_in_home_currency": 0, "properties_hs_closed_won_count": 1, "properties_hs_closed_won_date": "2023-09-15T09:08:03.642000+00:00", "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_66894120": null, "properties_hs_date_entered_9567448": null, "properties_hs_date_entered_9567449": null, "properties_hs_date_entered_appointmentscheduled": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_closedlost": null, "properties_hs_date_entered_closedwon": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_contractsent": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_customclosedwonstage": null, "properties_hs_date_entered_decisionmakerboughtin": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_presentationscheduled": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_qualifiedtobuy": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_exited_66894120": null, "properties_hs_date_exited_9567448": null, "properties_hs_date_exited_9567449": null, "properties_hs_date_exited_appointmentscheduled": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_exited_closedlost": null, "properties_hs_date_exited_closedwon": null, "properties_hs_date_exited_contractsent": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_exited_customclosedwonstage": null, "properties_hs_date_exited_decisionmakerboughtin": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_exited_presentationscheduled": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_exited_qualifiedtobuy": "2023-09-15T09:08:20.208000+00:00", "properties_hs_days_to_close_raw": 0, "properties_hs_deal_amount_calculation_preference": null, "properties_hs_deal_stage_probability": 1, "properties_hs_deal_stage_probability_shadow": 1, "properties_hs_exchange_rate": null, "properties_hs_forecast_amount": 0, "properties_hs_forecast_probability": null, "properties_hs_is_closed": true, "properties_hs_is_closed_won": true, "properties_hs_is_deal_split": false, "properties_hs_is_open_count": 0, "properties_hs_lastmodifieddate": "2023-09-18T09:09:00.660000+00:00", "properties_hs_latest_meeting_activity": null, "properties_hs_likelihood_to_close": null, "properties_hs_line_item_global_term_hs_discount_percentage": null, "properties_hs_line_item_global_term_hs_discount_percentage_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_period": null, "properties_hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "properties_hs_line_item_global_term_recurringbillingfrequency": null, "properties_hs_line_item_global_term_recurringbillingfrequency_enabled": null, "properties_hs_manual_forecast_category": null, "properties_hs_merged_object_ids": null, "properties_hs_mrr": null, "properties_hs_next_step": null, "properties_hs_num_associated_deal_splits": 0, "properties_hs_num_of_associated_line_items": 0, "properties_hs_num_target_accounts": 0, "properties_hs_object_id": 15165693770, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_pinned_engagement_id": null, "properties_hs_predicted_amount": null, "properties_hs_predicted_amount_in_home_currency": null, "properties_hs_priority": "low", "properties_hs_projected_amount": 0, "properties_hs_projected_amount_in_home_currency": 0, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_tcv": null, "properties_hs_time_in_66894120": null, "properties_hs_time_in_9567448": null, "properties_hs_time_in_9567449": null, "properties_hs_time_in_appointmentscheduled": 0, "properties_hs_time_in_closedlost": null, "properties_hs_time_in_closedwon": 12325830797, "properties_hs_time_in_contractsent": 0, "properties_hs_time_in_customclosedwonstage": null, "properties_hs_time_in_decisionmakerboughtin": 0, "properties_hs_time_in_presentationscheduled": 0, "properties_hs_time_in_qualifiedtobuy": 0, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2023-09-15T09:08:20.208000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": "2023-09-18T09:08:59.252000+00:00", "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_contacted_notes": 0, "properties_num_notes": 2, "properties_pipeline": "default"}, "emitted_at": 1707094731013} +{"stream": "deals_archived", "data": {"id": "15165693770", "properties": {"amount": 0, "amount_in_home_currency": 0, "closed_lost_reason": null, "closed_won_reason": null, "closedate": "2023-09-15T09:08:03.642000+00:00", "createdate": "2023-09-15T09:08:20.208000+00:00", "days_to_close": 0, "dealname": "Test 1715 Deal Acrhived Line Items", "dealstage": "closedwon", "dealtype": "newbusiness", "description": null, "engagements_last_meeting_booked": null, "engagements_last_meeting_booked_campaign": null, "engagements_last_meeting_booked_medium": null, "engagements_last_meeting_booked_source": null, "hs_acv": null, "hs_all_accessible_team_ids": null, "hs_all_collaborator_owner_ids": null, "hs_all_deal_split_owner_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_analytics_latest_source": null, "hs_analytics_latest_source_company": null, "hs_analytics_latest_source_contact": null, "hs_analytics_latest_source_data_1": null, "hs_analytics_latest_source_data_1_company": null, "hs_analytics_latest_source_data_1_contact": null, "hs_analytics_latest_source_data_2": null, "hs_analytics_latest_source_data_2_company": null, "hs_analytics_latest_source_data_2_contact": null, "hs_analytics_latest_source_timestamp": null, "hs_analytics_latest_source_timestamp_company": null, "hs_analytics_latest_source_timestamp_contact": null, "hs_analytics_source": null, "hs_analytics_source_data_1": null, "hs_analytics_source_data_2": null, "hs_arr": null, "hs_campaign": null, "hs_closed_amount": 0, "hs_closed_amount_in_home_currency": 0, "hs_closed_won_count": 1, "hs_closed_won_date": "2023-09-15T09:08:03.642000+00:00", "hs_created_by_user_id": 12282590, "hs_createdate": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_66894120": null, "hs_date_entered_9567448": null, "hs_date_entered_9567449": null, "hs_date_entered_appointmentscheduled": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_closedlost": null, "hs_date_entered_closedwon": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_contractsent": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_customclosedwonstage": null, "hs_date_entered_decisionmakerboughtin": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_presentationscheduled": "2023-09-15T09:08:20.208000+00:00", "hs_date_entered_qualifiedtobuy": "2023-09-15T09:08:20.208000+00:00", "hs_date_exited_66894120": null, "hs_date_exited_9567448": null, "hs_date_exited_9567449": null, "hs_date_exited_appointmentscheduled": "2023-09-15T09:08:20.208000+00:00", "hs_date_exited_closedlost": null, "hs_date_exited_closedwon": null, "hs_date_exited_contractsent": "2023-09-15T09:08:20.208000+00:00", "hs_date_exited_customclosedwonstage": null, "hs_date_exited_decisionmakerboughtin": "2023-09-15T09:08:20.208000+00:00", "hs_date_exited_presentationscheduled": "2023-09-15T09:08:20.208000+00:00", "hs_date_exited_qualifiedtobuy": "2023-09-15T09:08:20.208000+00:00", "hs_days_to_close_raw": 0, "hs_deal_amount_calculation_preference": null, "hs_deal_stage_probability": 1, "hs_deal_stage_probability_shadow": 1, "hs_exchange_rate": null, "hs_forecast_amount": 0, "hs_forecast_probability": null, "hs_is_closed": true, "hs_is_closed_won": true, "hs_is_deal_split": false, "hs_is_open_count": 0, "hs_lastmodifieddate": "2023-09-18T09:09:00.660000+00:00", "hs_latest_meeting_activity": null, "hs_likelihood_to_close": null, "hs_line_item_global_term_hs_discount_percentage": null, "hs_line_item_global_term_hs_discount_percentage_enabled": null, "hs_line_item_global_term_hs_recurring_billing_period": null, "hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "hs_line_item_global_term_hs_recurring_billing_start_date": null, "hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "hs_line_item_global_term_recurringbillingfrequency": null, "hs_line_item_global_term_recurringbillingfrequency_enabled": null, "hs_manual_forecast_category": null, "hs_merged_object_ids": null, "hs_mrr": null, "hs_next_step": null, "hs_num_associated_deal_splits": 0, "hs_num_of_associated_line_items": 0, "hs_num_target_accounts": 0, "hs_object_id": 15165693770, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_pinned_engagement_id": null, "hs_predicted_amount": null, "hs_predicted_amount_in_home_currency": null, "hs_priority": "low", "hs_projected_amount": 0, "hs_projected_amount_in_home_currency": 0, "hs_read_only": null, "hs_sales_email_last_replied": null, "hs_tag_ids": null, "hs_tcv": null, "hs_time_in_66894120": null, "hs_time_in_9567448": null, "hs_time_in_9567449": null, "hs_time_in_appointmentscheduled": 0, "hs_time_in_closedlost": null, "hs_time_in_closedwon": 13246483990, "hs_time_in_contractsent": 0, "hs_time_in_customclosedwonstage": null, "hs_time_in_decisionmakerboughtin": 0, "hs_time_in_presentationscheduled": 0, "hs_time_in_qualifiedtobuy": 0, "hs_unique_creation_key": null, "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2023-09-15T09:08:20.208000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null, "notes_last_contacted": null, "notes_last_updated": "2023-09-18T09:08:59.252000+00:00", "notes_next_activity_date": null, "num_associated_contacts": 0, "num_contacted_notes": 0, "num_notes": 2, "pipeline": "default"}, "createdAt": "2023-09-15T09:08:20.208Z", "updatedAt": "2023-09-18T09:09:00.660Z", "archived": true, "archivedAt": "2024-02-05T00:58:23.662Z", "properties_amount": 0, "properties_amount_in_home_currency": 0, "properties_closed_lost_reason": null, "properties_closed_won_reason": null, "properties_closedate": "2023-09-15T09:08:03.642000+00:00", "properties_createdate": "2023-09-15T09:08:20.208000+00:00", "properties_days_to_close": 0, "properties_dealname": "Test 1715 Deal Acrhived Line Items", "properties_dealstage": "closedwon", "properties_dealtype": "newbusiness", "properties_description": null, "properties_engagements_last_meeting_booked": null, "properties_engagements_last_meeting_booked_campaign": null, "properties_engagements_last_meeting_booked_medium": null, "properties_engagements_last_meeting_booked_source": null, "properties_hs_acv": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_collaborator_owner_ids": null, "properties_hs_all_deal_split_owner_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_analytics_latest_source": null, "properties_hs_analytics_latest_source_company": null, "properties_hs_analytics_latest_source_contact": null, "properties_hs_analytics_latest_source_data_1": null, "properties_hs_analytics_latest_source_data_1_company": null, "properties_hs_analytics_latest_source_data_1_contact": null, "properties_hs_analytics_latest_source_data_2": null, "properties_hs_analytics_latest_source_data_2_company": null, "properties_hs_analytics_latest_source_data_2_contact": null, "properties_hs_analytics_latest_source_timestamp": null, "properties_hs_analytics_latest_source_timestamp_company": null, "properties_hs_analytics_latest_source_timestamp_contact": null, "properties_hs_analytics_source": null, "properties_hs_analytics_source_data_1": null, "properties_hs_analytics_source_data_2": null, "properties_hs_arr": null, "properties_hs_campaign": null, "properties_hs_closed_amount": 0, "properties_hs_closed_amount_in_home_currency": 0, "properties_hs_closed_won_count": 1, "properties_hs_closed_won_date": "2023-09-15T09:08:03.642000+00:00", "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_66894120": null, "properties_hs_date_entered_9567448": null, "properties_hs_date_entered_9567449": null, "properties_hs_date_entered_appointmentscheduled": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_closedlost": null, "properties_hs_date_entered_closedwon": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_contractsent": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_customclosedwonstage": null, "properties_hs_date_entered_decisionmakerboughtin": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_presentationscheduled": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_entered_qualifiedtobuy": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_exited_66894120": null, "properties_hs_date_exited_9567448": null, "properties_hs_date_exited_9567449": null, "properties_hs_date_exited_appointmentscheduled": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_exited_closedlost": null, "properties_hs_date_exited_closedwon": null, "properties_hs_date_exited_contractsent": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_exited_customclosedwonstage": null, "properties_hs_date_exited_decisionmakerboughtin": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_exited_presentationscheduled": "2023-09-15T09:08:20.208000+00:00", "properties_hs_date_exited_qualifiedtobuy": "2023-09-15T09:08:20.208000+00:00", "properties_hs_days_to_close_raw": 0, "properties_hs_deal_amount_calculation_preference": null, "properties_hs_deal_stage_probability": 1, "properties_hs_deal_stage_probability_shadow": 1, "properties_hs_exchange_rate": null, "properties_hs_forecast_amount": 0, "properties_hs_forecast_probability": null, "properties_hs_is_closed": true, "properties_hs_is_closed_won": true, "properties_hs_is_deal_split": false, "properties_hs_is_open_count": 0, "properties_hs_lastmodifieddate": "2023-09-18T09:09:00.660000+00:00", "properties_hs_latest_meeting_activity": null, "properties_hs_likelihood_to_close": null, "properties_hs_line_item_global_term_hs_discount_percentage": null, "properties_hs_line_item_global_term_hs_discount_percentage_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_period": null, "properties_hs_line_item_global_term_hs_recurring_billing_period_enabled": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date": null, "properties_hs_line_item_global_term_hs_recurring_billing_start_date_enabled": null, "properties_hs_line_item_global_term_recurringbillingfrequency": null, "properties_hs_line_item_global_term_recurringbillingfrequency_enabled": null, "properties_hs_manual_forecast_category": null, "properties_hs_merged_object_ids": null, "properties_hs_mrr": null, "properties_hs_next_step": null, "properties_hs_num_associated_deal_splits": 0, "properties_hs_num_of_associated_line_items": 0, "properties_hs_num_target_accounts": 0, "properties_hs_object_id": 15165693770, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_pinned_engagement_id": null, "properties_hs_predicted_amount": null, "properties_hs_predicted_amount_in_home_currency": null, "properties_hs_priority": "low", "properties_hs_projected_amount": 0, "properties_hs_projected_amount_in_home_currency": 0, "properties_hs_read_only": null, "properties_hs_sales_email_last_replied": null, "properties_hs_tag_ids": null, "properties_hs_tcv": null, "properties_hs_time_in_66894120": null, "properties_hs_time_in_9567448": null, "properties_hs_time_in_9567449": null, "properties_hs_time_in_appointmentscheduled": 0, "properties_hs_time_in_closedlost": null, "properties_hs_time_in_closedwon": 13246483990, "properties_hs_time_in_contractsent": 0, "properties_hs_time_in_customclosedwonstage": null, "properties_hs_time_in_decisionmakerboughtin": 0, "properties_hs_time_in_presentationscheduled": 0, "properties_hs_time_in_qualifiedtobuy": 0, "properties_hs_unique_creation_key": null, "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2023-09-15T09:08:20.208000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null, "properties_notes_last_contacted": null, "properties_notes_last_updated": "2023-09-18T09:08:59.252000+00:00", "properties_notes_next_activity_date": null, "properties_num_associated_contacts": 0, "properties_num_contacted_notes": 0, "properties_num_notes": 2, "properties_pipeline": "default"}, "emitted_at": 1708015384348} {"stream": "ticket_pipelines", "data": {"label": "Test_ticket_pipeline", "displayOrder": 1, "id": "80068448", "stages": [{"label": "New", "displayOrder": 0, "metadata": {"ticketState": "OPEN", "isClosed": "false"}, "id": "151692305", "createdAt": "2024-02-05T01:01:42.937Z", "updatedAt": "2024-02-05T01:01:42.937Z", "archived": false, "writePermissions": "CRM_PERMISSIONS_ENFORCEMENT"}, {"label": "Waiting on contact", "displayOrder": 1, "metadata": {"ticketState": "OPEN", "isClosed": "false"}, "id": "151692306", "createdAt": "2024-02-05T01:01:42.937Z", "updatedAt": "2024-02-05T01:01:42.937Z", "archived": false, "writePermissions": "CRM_PERMISSIONS_ENFORCEMENT"}, {"label": "Waiting on us", "displayOrder": 2, "metadata": {"ticketState": "OPEN", "isClosed": "false"}, "id": "151692307", "createdAt": "2024-02-05T01:01:42.937Z", "updatedAt": "2024-02-05T01:01:42.937Z", "archived": false, "writePermissions": "CRM_PERMISSIONS_ENFORCEMENT"}, {"label": "Closed", "displayOrder": 3, "metadata": {"ticketState": "CLOSED", "isClosed": "true"}, "id": "151692308", "createdAt": "2024-02-05T01:01:42.937Z", "updatedAt": "2024-02-05T01:01:42.937Z", "archived": false, "writePermissions": "CRM_PERMISSIONS_ENFORCEMENT"}], "createdAt": "2024-02-05T01:01:42.937Z", "updatedAt": "2024-02-05T01:01:42.937Z", "archived": false}, "emitted_at": 1707258209328} -{"stream": "engagements_emails", "data": {"id": "46838275228", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_body_preview": "test body -- Prefer fewer emails from me? Click here", "hs_body_preview_html": "\n \n \n
\n test body \n
\n
\n -- \n
\n Prefer fewer emails from me? Click here \n
\n
\n \n", "hs_body_preview_is_truncated": false, "hs_created_by": "12282590", "hs_created_by_user_id": 12282590, "hs_createdate": "2024-02-05T01:13:21.505000+00:00", "hs_direction_and_unique_id": "EMAIL:432a7d905bf8fc42ba938819a9e6e291", "hs_email_attached_video_id": null, "hs_email_attached_video_name": null, "hs_email_attached_video_opened": false, "hs_email_attached_video_watched": false, "hs_email_bcc_email": null, "hs_email_bcc_firstname": null, "hs_email_bcc_lastname": null, "hs_email_bcc_raw": null, "hs_email_bounce_error_detail_message": null, "hs_email_bounce_error_detail_status_code": null, "hs_email_cc_email": null, "hs_email_cc_firstname": null, "hs_email_cc_lastname": null, "hs_email_cc_raw": null, "hs_email_click_count": null, "hs_email_direction": "EMAIL", "hs_email_encoded_email_associations_request": null, "hs_email_error_message": null, "hs_email_facsimile_send_id": "6b0d1024453e0b541501565ae69498c7", "hs_email_from_email": "integration-test-user@airbyte.io", "hs_email_from_firstname": "Team-1", "hs_email_from_lastname": "Airbyte", "hs_email_from_raw": null, "hs_email_has_inline_images_stripped": null, "hs_email_headers": "{\"from\":{\"email\":\"integration-test-user@airbyte.io\",\"firstName\":\"Team-1\",\"lastName\":\"Airbyte\"},\"to\":[{\"raw\":\"gl_serhii.lazebnyi@airbyte.io\",\"email\":\"gl_serhii.lazebnyi@airbyte.io\"}],\"cc\":[],\"bcc\":[],\"sender\":{\"email\":\"integration-test-user@airbyte.io\"}}", "hs_email_html": "
test body
--
Prefer fewer emails from me? Click here

", "hs_email_logged_from": "CRM", "hs_email_media_processing_status": "SKIPPED", "hs_email_member_of_forwarded_subthread": null, "hs_email_message_id": "CAK4c3Gyf4xNPCtrON3BFLN9WOWUpfe+sfb+7wh5qYuCD-K71AA@mail.gmail.com", "hs_email_migrated_via_portal_data_migration": null, "hs_email_open_count": null, "hs_email_pending_inline_image_ids": null, "hs_email_post_send_status": "SENT", "hs_email_recipient_drop_reasons": null, "hs_email_reply_count": null, "hs_email_send_event_id": null, "hs_email_send_event_id_created": null, "hs_email_sender_email": "integration-test-user@airbyte.io", "hs_email_sender_firstname": null, "hs_email_sender_lastname": null, "hs_email_sender_raw": null, "hs_email_sent_count": 1.0, "hs_email_sent_via": "GMAIL", "hs_email_status": "SENT", "hs_email_stripped_attachment_count": null, "hs_email_subject": "test deal ", "hs_email_text": "test body\n-- \nPrefer fewer emails from me? Click here: https://d11qV604.na1.hs-salescrm-sub.com/preferences/en/manage?data=W2nXS-N30h-MkW3DX4xr38lXTKW2KXbZn3H3ZTKW4kt7Y_3XR2G0W30sn1g2zt_2NW47kvvy23ncKnW47Vmcy4pxy7cW41tzTm1X87X1W364bL-36tRLFW30J_Vy36F403W45FGpL3XHz-RW4ftDwZ4msYq_W24-jyc2HCSCvW3VGBr52TLG1vW2nFrmM3P2tStW43Skr81VxgJXW3z26wT4pc1KRW1Vpb_f3d3w7qW36dtk_4rCSHJW3F507n1_6v4MW2CWCvk49rVZpW23jtn51St_bDW2RKdYG2RNzKSW47znqq1_dHnNW4mGNp33Y1JRBW25m60s1Nk9WFW2MMKcf2F-zTNW4kddlH1NFHhxW25nrXX2KQX5rW3GJy1x2Yh7XsW2Pnx-93f_bXGW47SgSp1XqcMJW2FTQ1Z2KPBb6W32kvXr2KnzH9W3HcvHw3LRJmmW2MLX-W3LBLBJW3Q-74Q2KYV0CW1_9nCQ2r36_S0", "hs_email_thread_id": "3b2bf39b9ed8cfc53310ee557627d073", "hs_email_thread_summary": null, "hs_email_to_email": "gl_serhii.lazebnyi@airbyte.io", "hs_email_to_firstname": null, "hs_email_to_lastname": null, "hs_email_to_raw": "gl_serhii.lazebnyi@airbyte.io", "hs_email_tracker_key": "87989bf6-7771-4486-b3d7-73a31af32b2c", "hs_email_validation_skipped": null, "hs_engagement_source": "EMAIL_INTEGRATION", "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_lastmodifieddate": "2024-02-05T01:13:26.539000+00:00", "hs_merged_object_ids": null, "hs_modified_by": "12282590", "hs_object_id": 46838275228, "hs_object_source": "CRM_UI", "hs_object_source_id": null, "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_owner_ids_bcc": null, "hs_owner_ids_cc": null, "hs_owner_ids_from": "52550153", "hs_owner_ids_to": null, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_scs_association_status": null, "hs_scs_audit_id": null, "hs_timestamp": "2024-02-05T01:13:21.109000+00:00", "hs_unique_creation_key": null, "hs_unique_id": "432a7d905bf8fc42ba938819a9e6e291", "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2024-02-05T01:13:21.505000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2024-02-05T01:13:21.505Z", "updatedAt": "2024-02-05T01:13:26.539Z", "archived": false, "companies": ["5000526215"], "deals": ["5388306989"], "contacts": ["3251"], "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_body_preview": "test body -- Prefer fewer emails from me? Click here", "properties_hs_body_preview_html": "\n \n \n
\n test body \n
\n
\n -- \n
\n Prefer fewer emails from me? Click here \n
\n
\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_created_by": "12282590", "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2024-02-05T01:13:21.505000+00:00", "properties_hs_direction_and_unique_id": "EMAIL:432a7d905bf8fc42ba938819a9e6e291", "properties_hs_email_attached_video_id": null, "properties_hs_email_attached_video_name": null, "properties_hs_email_attached_video_opened": false, "properties_hs_email_attached_video_watched": false, "properties_hs_email_bcc_email": null, "properties_hs_email_bcc_firstname": null, "properties_hs_email_bcc_lastname": null, "properties_hs_email_bcc_raw": null, "properties_hs_email_bounce_error_detail_message": null, "properties_hs_email_bounce_error_detail_status_code": null, "properties_hs_email_cc_email": null, "properties_hs_email_cc_firstname": null, "properties_hs_email_cc_lastname": null, "properties_hs_email_cc_raw": null, "properties_hs_email_click_count": null, "properties_hs_email_direction": "EMAIL", "properties_hs_email_encoded_email_associations_request": null, "properties_hs_email_error_message": null, "properties_hs_email_facsimile_send_id": "6b0d1024453e0b541501565ae69498c7", "properties_hs_email_from_email": "integration-test-user@airbyte.io", "properties_hs_email_from_firstname": "Team-1", "properties_hs_email_from_lastname": "Airbyte", "properties_hs_email_from_raw": null, "properties_hs_email_has_inline_images_stripped": null, "properties_hs_email_headers": "{\"from\":{\"email\":\"integration-test-user@airbyte.io\",\"firstName\":\"Team-1\",\"lastName\":\"Airbyte\"},\"to\":[{\"raw\":\"gl_serhii.lazebnyi@airbyte.io\",\"email\":\"gl_serhii.lazebnyi@airbyte.io\"}],\"cc\":[],\"bcc\":[],\"sender\":{\"email\":\"integration-test-user@airbyte.io\"}}", "properties_hs_email_html": "
test body
--
Prefer fewer emails from me? Click here

", "properties_hs_email_logged_from": "CRM", "properties_hs_email_media_processing_status": "SKIPPED", "properties_hs_email_member_of_forwarded_subthread": null, "properties_hs_email_message_id": "CAK4c3Gyf4xNPCtrON3BFLN9WOWUpfe+sfb+7wh5qYuCD-K71AA@mail.gmail.com", "properties_hs_email_migrated_via_portal_data_migration": null, "properties_hs_email_open_count": null, "properties_hs_email_pending_inline_image_ids": null, "properties_hs_email_post_send_status": "SENT", "properties_hs_email_recipient_drop_reasons": null, "properties_hs_email_reply_count": null, "properties_hs_email_send_event_id": null, "properties_hs_email_send_event_id_created": null, "properties_hs_email_sender_email": "integration-test-user@airbyte.io", "properties_hs_email_sender_firstname": null, "properties_hs_email_sender_lastname": null, "properties_hs_email_sender_raw": null, "properties_hs_email_sent_count": 1.0, "properties_hs_email_sent_via": "GMAIL", "properties_hs_email_status": "SENT", "properties_hs_email_stripped_attachment_count": null, "properties_hs_email_subject": "test deal ", "properties_hs_email_text": "test body\n-- \nPrefer fewer emails from me? Click here: https://d11qV604.na1.hs-salescrm-sub.com/preferences/en/manage?data=W2nXS-N30h-MkW3DX4xr38lXTKW2KXbZn3H3ZTKW4kt7Y_3XR2G0W30sn1g2zt_2NW47kvvy23ncKnW47Vmcy4pxy7cW41tzTm1X87X1W364bL-36tRLFW30J_Vy36F403W45FGpL3XHz-RW4ftDwZ4msYq_W24-jyc2HCSCvW3VGBr52TLG1vW2nFrmM3P2tStW43Skr81VxgJXW3z26wT4pc1KRW1Vpb_f3d3w7qW36dtk_4rCSHJW3F507n1_6v4MW2CWCvk49rVZpW23jtn51St_bDW2RKdYG2RNzKSW47znqq1_dHnNW4mGNp33Y1JRBW25m60s1Nk9WFW2MMKcf2F-zTNW4kddlH1NFHhxW25nrXX2KQX5rW3GJy1x2Yh7XsW2Pnx-93f_bXGW47SgSp1XqcMJW2FTQ1Z2KPBb6W32kvXr2KnzH9W3HcvHw3LRJmmW2MLX-W3LBLBJW3Q-74Q2KYV0CW1_9nCQ2r36_S0", "properties_hs_email_thread_id": "3b2bf39b9ed8cfc53310ee557627d073", "properties_hs_email_thread_summary": null, "properties_hs_email_to_email": "gl_serhii.lazebnyi@airbyte.io", "properties_hs_email_to_firstname": null, "properties_hs_email_to_lastname": null, "properties_hs_email_to_raw": "gl_serhii.lazebnyi@airbyte.io", "properties_hs_email_tracker_key": "87989bf6-7771-4486-b3d7-73a31af32b2c", "properties_hs_email_validation_skipped": null, "properties_hs_engagement_source": "EMAIL_INTEGRATION", "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_lastmodifieddate": "2024-02-05T01:13:26.539000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": "12282590", "properties_hs_object_id": 46838275228, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_owner_ids_bcc": null, "properties_hs_owner_ids_cc": null, "properties_hs_owner_ids_from": "52550153", "properties_hs_owner_ids_to": null, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_scs_association_status": null, "properties_hs_scs_audit_id": null, "properties_hs_timestamp": "2024-02-05T01:13:21.109000+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": "432a7d905bf8fc42ba938819a9e6e291", "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2024-02-05T01:13:21.505000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1707095613649} -{"stream": "engagements_meetings", "data": {"id": "46837884323", "properties": {"hs_activity_type": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_attendee_owner_ids": null, "hs_body_preview": null, "hs_body_preview_html": null, "hs_body_preview_is_truncated": false, "hs_contact_first_outreach_date": null, "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2024-02-05T01:08:01.995000+00:00", "hs_engagement_source": "MEETINGS", "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_guest_emails": null, "hs_i_cal_uid": "imqqv2eda8h5rh74gabnagl60o@google.com", "hs_include_description_in_reminder": null, "hs_internal_meeting_notes": null, "hs_lastmodifieddate": "2024-02-05T01:40:30.343000+00:00", "hs_meeting_body": null, "hs_meeting_calendar_event_hash": "7e8970ad5f400444979d9c979d5369b4", "hs_meeting_change_id": "7231dcd51227b02a05d158f5e7a602f3", "hs_meeting_created_from_link_id": "6678679", "hs_meeting_end_time": "2024-02-05T14:15:00+00:00", "hs_meeting_external_url": "https://www.google.com/calendar/event?eid=aW1xcXYyZWRhOGg1cmg3NGdhYm5hZ2w2MG8gaW50ZWdyYXRpb24tdGVzdC11c2VyQGFpcmJ5dGUuaW8", "hs_meeting_location": null, "hs_meeting_location_type": null, "hs_meeting_outcome": "SCHEDULED", "hs_meeting_payments_session_id": null, "hs_meeting_pre_meeting_prospect_reminders": null, "hs_meeting_source": "MEETINGS_PUBLIC", "hs_meeting_source_id": "imqqv2eda8h5rh74gabnagl60o", "hs_meeting_start_time": "2024-02-05T14:00:00+00:00", "hs_meeting_title": "Test User and Team-1 Airbyte", "hs_meeting_web_conference_meeting_id": null, "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_object_id": 46837884323, "hs_object_source": "MEETINGS", "hs_object_source_id": null, "hs_object_source_label": "MEETINGS", "hs_object_source_user_id": 12282590, "hs_outcome_canceled_count": 0, "hs_outcome_completed_count": 0, "hs_outcome_no_show_count": 0, "hs_outcome_rescheduled_count": 0, "hs_outcome_scheduled_count": 1, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_roster_object_coordinates": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46837884323,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707139800000,\"uuid\":\"MEETING:7a71d47b-0a87-40c4-8e1a-a140184a29d0\"}]}", "hs_time_to_book_meeting_from_first_contact": 0, "hs_timestamp": "2024-02-05T14:00:00+00:00", "hs_timezone": "Europe/Warsaw", "hs_unique_creation_key": null, "hs_unique_id": "imqqv2eda8h5rh74gabnagl60o", "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2024-02-05T01:08:10.888000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2024-02-05T01:08:01.995Z", "updatedAt": "2024-02-05T01:40:30.343Z", "archived": false, "properties_hs_activity_type": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_attendee_owner_ids": null, "properties_hs_body_preview": null, "properties_hs_body_preview_html": null, "properties_hs_body_preview_is_truncated": false, "properties_hs_contact_first_outreach_date": null, "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2024-02-05T01:08:01.995000+00:00", "properties_hs_engagement_source": "MEETINGS", "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_guest_emails": null, "properties_hs_i_cal_uid": "imqqv2eda8h5rh74gabnagl60o@google.com", "properties_hs_include_description_in_reminder": null, "properties_hs_internal_meeting_notes": null, "properties_hs_lastmodifieddate": "2024-02-05T01:40:30.343000+00:00", "properties_hs_meeting_body": null, "properties_hs_meeting_calendar_event_hash": "7e8970ad5f400444979d9c979d5369b4", "properties_hs_meeting_change_id": "7231dcd51227b02a05d158f5e7a602f3", "properties_hs_meeting_created_from_link_id": "6678679", "properties_hs_meeting_end_time": "2024-02-05T14:15:00+00:00", "properties_hs_meeting_external_url": "https://www.google.com/calendar/event?eid=aW1xcXYyZWRhOGg1cmg3NGdhYm5hZ2w2MG8gaW50ZWdyYXRpb24tdGVzdC11c2VyQGFpcmJ5dGUuaW8", "properties_hs_meeting_location": null, "properties_hs_meeting_location_type": null, "properties_hs_meeting_outcome": "SCHEDULED", "properties_hs_meeting_payments_session_id": null, "properties_hs_meeting_pre_meeting_prospect_reminders": null, "properties_hs_meeting_source": "MEETINGS_PUBLIC", "properties_hs_meeting_source_id": "imqqv2eda8h5rh74gabnagl60o", "properties_hs_meeting_start_time": "2024-02-05T14:00:00+00:00", "properties_hs_meeting_title": "Test User and Team-1 Airbyte", "properties_hs_meeting_web_conference_meeting_id": null, "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_object_id": 46837884323, "properties_hs_object_source": "MEETINGS", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "MEETINGS", "properties_hs_object_source_user_id": 12282590, "properties_hs_outcome_canceled_count": 0, "properties_hs_outcome_completed_count": 0, "properties_hs_outcome_no_show_count": 0, "properties_hs_outcome_rescheduled_count": 0, "properties_hs_outcome_scheduled_count": 1, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_roster_object_coordinates": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46837884323,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707139800000,\"uuid\":\"MEETING:7a71d47b-0a87-40c4-8e1a-a140184a29d0\"}]}", "properties_hs_time_to_book_meeting_from_first_contact": 0, "properties_hs_timestamp": "2024-02-05T14:00:00+00:00", "properties_hs_timezone": "Europe/Warsaw", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": "imqqv2eda8h5rh74gabnagl60o", "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2024-02-05T01:08:10.888000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1707331461940} -{"stream": "engagements_meetings", "data": {"id": "46838182245", "properties": {"hs_activity_type": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_attendee_owner_ids": null, "hs_body_preview": null, "hs_body_preview_html": null, "hs_body_preview_is_truncated": false, "hs_contact_first_outreach_date": "2024-02-05T15:15:00+00:00", "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2024-02-05T01:08:32.416000+00:00", "hs_engagement_source": "MEETINGS", "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_guest_emails": null, "hs_i_cal_uid": null, "hs_include_description_in_reminder": null, "hs_internal_meeting_notes": null, "hs_lastmodifieddate": "2024-02-05T01:08:37.402000+00:00", "hs_meeting_body": null, "hs_meeting_calendar_event_hash": "0b24520e196b77a0db079ab0357565e8", "hs_meeting_change_id": "9cc62faac2139a8ae373f992facb9504", "hs_meeting_created_from_link_id": "6678679", "hs_meeting_end_time": "2024-02-05T15:30:00+00:00", "hs_meeting_external_url": "https://www.google.com/calendar/event?eid=amg5N3RhcWppbjEzaGg4NDI0aXZoc3I0M2MgaW50ZWdyYXRpb24tdGVzdC11c2VyQGFpcmJ5dGUuaW8", "hs_meeting_location": null, "hs_meeting_location_type": null, "hs_meeting_outcome": "SCHEDULED", "hs_meeting_payments_session_id": null, "hs_meeting_pre_meeting_prospect_reminders": null, "hs_meeting_source": "MEETINGS_PUBLIC", "hs_meeting_source_id": "jh97taqjin13hh8424ivhsr43c", "hs_meeting_start_time": "2024-02-05T15:15:00+00:00", "hs_meeting_title": "Test User and Team-1 Airbyte", "hs_meeting_web_conference_meeting_id": null, "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_object_id": 46838182245, "hs_object_source": "MEETINGS", "hs_object_source_id": null, "hs_object_source_label": "MEETINGS", "hs_object_source_user_id": 12282590, "hs_outcome_canceled_count": 0, "hs_outcome_completed_count": 0, "hs_outcome_no_show_count": 0, "hs_outcome_rescheduled_count": 0, "hs_outcome_scheduled_count": 1, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_roster_object_coordinates": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46838182245,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707144300000,\"uuid\":\"MEETING:dc82686f-39ac-416f-ad15-4f2d706047c9\"}]}", "hs_time_to_book_meeting_from_first_contact": 0, "hs_timestamp": "2024-02-05T15:15:00+00:00", "hs_timezone": "Europe/Warsaw", "hs_unique_creation_key": null, "hs_unique_id": "jh97taqjin13hh8424ivhsr43c", "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2024-02-05T01:08:33.582000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2024-02-05T01:08:32.416Z", "updatedAt": "2024-02-05T01:08:37.402Z", "archived": false, "contacts": ["3201"], "properties_hs_activity_type": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_attendee_owner_ids": null, "properties_hs_body_preview": null, "properties_hs_body_preview_html": null, "properties_hs_body_preview_is_truncated": false, "properties_hs_contact_first_outreach_date": "2024-02-05T15:15:00+00:00", "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2024-02-05T01:08:32.416000+00:00", "properties_hs_engagement_source": "MEETINGS", "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_guest_emails": null, "properties_hs_i_cal_uid": null, "properties_hs_include_description_in_reminder": null, "properties_hs_internal_meeting_notes": null, "properties_hs_lastmodifieddate": "2024-02-05T01:08:37.402000+00:00", "properties_hs_meeting_body": null, "properties_hs_meeting_calendar_event_hash": "0b24520e196b77a0db079ab0357565e8", "properties_hs_meeting_change_id": "9cc62faac2139a8ae373f992facb9504", "properties_hs_meeting_created_from_link_id": "6678679", "properties_hs_meeting_end_time": "2024-02-05T15:30:00+00:00", "properties_hs_meeting_external_url": "https://www.google.com/calendar/event?eid=amg5N3RhcWppbjEzaGg4NDI0aXZoc3I0M2MgaW50ZWdyYXRpb24tdGVzdC11c2VyQGFpcmJ5dGUuaW8", "properties_hs_meeting_location": null, "properties_hs_meeting_location_type": null, "properties_hs_meeting_outcome": "SCHEDULED", "properties_hs_meeting_payments_session_id": null, "properties_hs_meeting_pre_meeting_prospect_reminders": null, "properties_hs_meeting_source": "MEETINGS_PUBLIC", "properties_hs_meeting_source_id": "jh97taqjin13hh8424ivhsr43c", "properties_hs_meeting_start_time": "2024-02-05T15:15:00+00:00", "properties_hs_meeting_title": "Test User and Team-1 Airbyte", "properties_hs_meeting_web_conference_meeting_id": null, "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_object_id": 46838182245, "properties_hs_object_source": "MEETINGS", "properties_hs_object_source_id": null, "properties_hs_object_source_label": "MEETINGS", "properties_hs_object_source_user_id": 12282590, "properties_hs_outcome_canceled_count": 0, "properties_hs_outcome_completed_count": 0, "properties_hs_outcome_no_show_count": 0, "properties_hs_outcome_rescheduled_count": 0, "properties_hs_outcome_scheduled_count": 1, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_roster_object_coordinates": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46838182245,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707144300000,\"uuid\":\"MEETING:dc82686f-39ac-416f-ad15-4f2d706047c9\"}]}", "properties_hs_time_to_book_meeting_from_first_contact": 0, "properties_hs_timestamp": "2024-02-05T15:15:00+00:00", "properties_hs_timezone": "Europe/Warsaw", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": "jh97taqjin13hh8424ivhsr43c", "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2024-02-05T01:08:33.582000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1707331461941} -{"stream": "engagements_meetings", "data": {"id": "46838579861", "properties": {"hs_activity_type": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_attendee_owner_ids": null, "hs_body_preview": "attendee description", "hs_body_preview_html": "\n \n \n

attendee description

\n \n", "hs_body_preview_is_truncated": false, "hs_contact_first_outreach_date": null, "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2024-02-05T01:15:53.269000+00:00", "hs_engagement_source": "CRM_UI", "hs_engagement_source_id": "12282590", "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_guest_emails": null, "hs_i_cal_uid": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g@google.com", "hs_include_description_in_reminder": true, "hs_internal_meeting_notes": "

test note

", "hs_lastmodifieddate": "2024-02-05T01:15:53.749000+00:00", "hs_meeting_body": "

attendee description

", "hs_meeting_calendar_event_hash": null, "hs_meeting_change_id": null, "hs_meeting_created_from_link_id": null, "hs_meeting_end_time": "2024-02-06T10:45:00+00:00", "hs_meeting_external_url": "https://www.google.com/calendar/event?eid=YzRyamFkcG82OG8zY2JiM2NwajM0YjlrY2dzNjJiYjJja3JtOGI5bjY4cTM4ZDMzNnRobTZjMWg2ZyBpbnRlZ3JhdGlvbi10ZXN0LXVzZXJAYWlyYnl0ZS5pbw", "hs_meeting_location": "test address location", "hs_meeting_location_type": "ADDRESS", "hs_meeting_outcome": "SCHEDULED", "hs_meeting_payments_session_id": null, "hs_meeting_pre_meeting_prospect_reminders": null, "hs_meeting_source": "BIDIRECTIONAL_API", "hs_meeting_source_id": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g", "hs_meeting_start_time": "2024-02-06T10:15:00+00:00", "hs_meeting_title": "test hubspot deal meeting ", "hs_meeting_web_conference_meeting_id": null, "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_object_id": 46838579861, "hs_object_source": "CRM_UI", "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_outcome_canceled_count": 0, "hs_outcome_completed_count": 0, "hs_outcome_no_show_count": 0, "hs_outcome_rescheduled_count": 0, "hs_outcome_scheduled_count": 1, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_roster_object_coordinates": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46838579861,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707212700000,\"uuid\":\"MEETING:cfda6fc6-d8ae-4e46-971a-4c483a6aec5c\"}]}", "hs_time_to_book_meeting_from_first_contact": 0, "hs_timestamp": "2024-02-06T10:15:00+00:00", "hs_timezone": "Europe/Warsaw", "hs_unique_creation_key": null, "hs_unique_id": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g", "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2024-02-05T01:15:53.269000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2024-02-05T01:15:53.269Z", "updatedAt": "2024-02-05T01:15:53.749Z", "archived": false, "companies": ["5000526215"], "deals": ["5388306989"], "properties_hs_activity_type": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_attendee_owner_ids": null, "properties_hs_body_preview": "attendee description", "properties_hs_body_preview_html": "\n \n \n

attendee description

\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_contact_first_outreach_date": null, "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2024-02-05T01:15:53.269000+00:00", "properties_hs_engagement_source": "CRM_UI", "properties_hs_engagement_source_id": "12282590", "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_guest_emails": null, "properties_hs_i_cal_uid": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g@google.com", "properties_hs_include_description_in_reminder": true, "properties_hs_internal_meeting_notes": "

test note

", "properties_hs_lastmodifieddate": "2024-02-05T01:15:53.749000+00:00", "properties_hs_meeting_body": "

attendee description

", "properties_hs_meeting_calendar_event_hash": null, "properties_hs_meeting_change_id": null, "properties_hs_meeting_created_from_link_id": null, "properties_hs_meeting_end_time": "2024-02-06T10:45:00+00:00", "properties_hs_meeting_external_url": "https://www.google.com/calendar/event?eid=YzRyamFkcG82OG8zY2JiM2NwajM0YjlrY2dzNjJiYjJja3JtOGI5bjY4cTM4ZDMzNnRobTZjMWg2ZyBpbnRlZ3JhdGlvbi10ZXN0LXVzZXJAYWlyYnl0ZS5pbw", "properties_hs_meeting_location": "test address location", "properties_hs_meeting_location_type": "ADDRESS", "properties_hs_meeting_outcome": "SCHEDULED", "properties_hs_meeting_payments_session_id": null, "properties_hs_meeting_pre_meeting_prospect_reminders": null, "properties_hs_meeting_source": "BIDIRECTIONAL_API", "properties_hs_meeting_source_id": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g", "properties_hs_meeting_start_time": "2024-02-06T10:15:00+00:00", "properties_hs_meeting_title": "test hubspot deal meeting ", "properties_hs_meeting_web_conference_meeting_id": null, "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_object_id": 46838579861, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_outcome_canceled_count": 0, "properties_hs_outcome_completed_count": 0, "properties_hs_outcome_no_show_count": 0, "properties_hs_outcome_rescheduled_count": 0, "properties_hs_outcome_scheduled_count": 1, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_roster_object_coordinates": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46838579861,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707212700000,\"uuid\":\"MEETING:cfda6fc6-d8ae-4e46-971a-4c483a6aec5c\"}]}", "properties_hs_time_to_book_meeting_from_first_contact": 0, "properties_hs_timestamp": "2024-02-06T10:15:00+00:00", "properties_hs_timezone": "Europe/Warsaw", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g", "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2024-02-05T01:15:53.269000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1707331461942} +{"stream": "engagements_emails", "data": {"id": "46838275228", "properties": {"hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_body_preview": "test body -- Prefer fewer emails from me? Click here", "hs_body_preview_html": "\n \n \n
\n test body \n
\n
\n -- \n
\n Prefer fewer emails from me? Click here \n
\n
\n \n", "hs_body_preview_is_truncated": false, "hs_created_by": "12282590", "hs_created_by_user_id": 12282590, "hs_createdate": "2024-02-05T01:13:21.505000+00:00", "hs_direction_and_unique_id": "EMAIL:432a7d905bf8fc42ba938819a9e6e291", "hs_email_attached_video_id": null, "hs_email_attached_video_name": null, "hs_email_attached_video_opened": false, "hs_email_attached_video_watched": false, "hs_email_bcc_email": null, "hs_email_bcc_firstname": null, "hs_email_bcc_lastname": null, "hs_email_bcc_raw": null, "hs_email_bounce_error_detail_message": null, "hs_email_bounce_error_detail_status_code": null, "hs_email_cc_email": null, "hs_email_cc_firstname": null, "hs_email_cc_lastname": null, "hs_email_cc_raw": null, "hs_email_click_count": null, "hs_email_direction": "EMAIL", "hs_email_encoded_email_associations_request": null, "hs_email_error_message": null, "hs_email_facsimile_send_id": "6b0d1024453e0b541501565ae69498c7", "hs_email_from_email": "integration-test-user@airbyte.io", "hs_email_from_firstname": "Team-1", "hs_email_from_lastname": "Airbyte", "hs_email_from_raw": null, "hs_email_has_inline_images_stripped": null, "hs_email_headers": "{\"from\":{\"email\":\"integration-test-user@airbyte.io\",\"firstName\":\"Team-1\",\"lastName\":\"Airbyte\"},\"to\":[{\"raw\":\"gl_serhii.lazebnyi@airbyte.io\",\"email\":\"gl_serhii.lazebnyi@airbyte.io\"}],\"cc\":[],\"bcc\":[],\"sender\":{\"email\":\"integration-test-user@airbyte.io\"}}", "hs_email_html": "
test body
--
Prefer fewer emails from me? Click here

", "hs_email_logged_from": "CRM", "hs_email_media_processing_status": "SKIPPED", "hs_email_member_of_forwarded_subthread": null, "hs_email_message_id": "CAK4c3Gyf4xNPCtrON3BFLN9WOWUpfe+sfb+7wh5qYuCD-K71AA@mail.gmail.com", "hs_email_migrated_via_portal_data_migration": null, "hs_email_ms_teams_payload": null, "hs_email_open_count": null, "hs_email_pending_inline_image_ids": null, "hs_email_post_send_status": "SENT", "hs_email_recipient_drop_reasons": null, "hs_email_reply_count": null, "hs_email_send_event_id": null, "hs_email_send_event_id_created": null, "hs_email_sender_email": "integration-test-user@airbyte.io", "hs_email_sender_firstname": null, "hs_email_sender_lastname": null, "hs_email_sender_raw": null, "hs_email_sent_count": 1.0, "hs_email_sent_via": "GMAIL", "hs_email_status": "SENT", "hs_email_stripped_attachment_count": null, "hs_email_subject": "test deal ", "hs_email_text": "test body\n-- \nPrefer fewer emails from me? Click here: https://d11qV604.na1.hs-salescrm-sub.com/preferences/en/manage?data=W2nXS-N30h-MkW3DX4xr38lXTKW2KXbZn3H3ZTKW4kt7Y_3XR2G0W30sn1g2zt_2NW47kvvy23ncKnW47Vmcy4pxy7cW41tzTm1X87X1W364bL-36tRLFW30J_Vy36F403W45FGpL3XHz-RW4ftDwZ4msYq_W24-jyc2HCSCvW3VGBr52TLG1vW2nFrmM3P2tStW43Skr81VxgJXW3z26wT4pc1KRW1Vpb_f3d3w7qW36dtk_4rCSHJW3F507n1_6v4MW2CWCvk49rVZpW23jtn51St_bDW2RKdYG2RNzKSW47znqq1_dHnNW4mGNp33Y1JRBW25m60s1Nk9WFW2MMKcf2F-zTNW4kddlH1NFHhxW25nrXX2KQX5rW3GJy1x2Yh7XsW2Pnx-93f_bXGW47SgSp1XqcMJW2FTQ1Z2KPBb6W32kvXr2KnzH9W3HcvHw3LRJmmW2MLX-W3LBLBJW3Q-74Q2KYV0CW1_9nCQ2r36_S0", "hs_email_thread_id": "3b2bf39b9ed8cfc53310ee557627d073", "hs_email_thread_summary": null, "hs_email_to_email": "gl_serhii.lazebnyi@airbyte.io", "hs_email_to_firstname": null, "hs_email_to_lastname": null, "hs_email_to_raw": "gl_serhii.lazebnyi@airbyte.io", "hs_email_tracker_key": "87989bf6-7771-4486-b3d7-73a31af32b2c", "hs_email_validation_skipped": null, "hs_engagement_source": "EMAIL_INTEGRATION", "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_lastmodifieddate": "2024-02-05T01:13:26.539000+00:00", "hs_merged_object_ids": null, "hs_modified_by": "12282590", "hs_object_id": 46838275228, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_owner_ids_bcc": null, "hs_owner_ids_cc": null, "hs_owner_ids_from": "52550153", "hs_owner_ids_to": null, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_scs_association_status": null, "hs_scs_audit_id": null, "hs_timestamp": "2024-02-05T01:13:21.109000+00:00", "hs_unique_creation_key": null, "hs_unique_id": "432a7d905bf8fc42ba938819a9e6e291", "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2024-02-05T01:13:21.505000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2024-02-05T01:13:21.505Z", "updatedAt": "2024-02-05T01:13:26.539Z", "archived": false, "companies": ["5000526215"], "deals": ["5388306989"], "contacts": ["3251"], "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_body_preview": "test body -- Prefer fewer emails from me? Click here", "properties_hs_body_preview_html": "\n \n \n
\n test body \n
\n
\n -- \n
\n Prefer fewer emails from me? Click here \n
\n
\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_created_by": "12282590", "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2024-02-05T01:13:21.505000+00:00", "properties_hs_direction_and_unique_id": "EMAIL:432a7d905bf8fc42ba938819a9e6e291", "properties_hs_email_attached_video_id": null, "properties_hs_email_attached_video_name": null, "properties_hs_email_attached_video_opened": false, "properties_hs_email_attached_video_watched": false, "properties_hs_email_bcc_email": null, "properties_hs_email_bcc_firstname": null, "properties_hs_email_bcc_lastname": null, "properties_hs_email_bcc_raw": null, "properties_hs_email_bounce_error_detail_message": null, "properties_hs_email_bounce_error_detail_status_code": null, "properties_hs_email_cc_email": null, "properties_hs_email_cc_firstname": null, "properties_hs_email_cc_lastname": null, "properties_hs_email_cc_raw": null, "properties_hs_email_click_count": null, "properties_hs_email_direction": "EMAIL", "properties_hs_email_encoded_email_associations_request": null, "properties_hs_email_error_message": null, "properties_hs_email_facsimile_send_id": "6b0d1024453e0b541501565ae69498c7", "properties_hs_email_from_email": "integration-test-user@airbyte.io", "properties_hs_email_from_firstname": "Team-1", "properties_hs_email_from_lastname": "Airbyte", "properties_hs_email_from_raw": null, "properties_hs_email_has_inline_images_stripped": null, "properties_hs_email_headers": "{\"from\":{\"email\":\"integration-test-user@airbyte.io\",\"firstName\":\"Team-1\",\"lastName\":\"Airbyte\"},\"to\":[{\"raw\":\"gl_serhii.lazebnyi@airbyte.io\",\"email\":\"gl_serhii.lazebnyi@airbyte.io\"}],\"cc\":[],\"bcc\":[],\"sender\":{\"email\":\"integration-test-user@airbyte.io\"}}", "properties_hs_email_html": "
test body
--
Prefer fewer emails from me? Click here

", "properties_hs_email_logged_from": "CRM", "properties_hs_email_media_processing_status": "SKIPPED", "properties_hs_email_member_of_forwarded_subthread": null, "properties_hs_email_message_id": "CAK4c3Gyf4xNPCtrON3BFLN9WOWUpfe+sfb+7wh5qYuCD-K71AA@mail.gmail.com", "properties_hs_email_migrated_via_portal_data_migration": null, "properties_hs_email_ms_teams_payload": null, "properties_hs_email_open_count": null, "properties_hs_email_pending_inline_image_ids": null, "properties_hs_email_post_send_status": "SENT", "properties_hs_email_recipient_drop_reasons": null, "properties_hs_email_reply_count": null, "properties_hs_email_send_event_id": null, "properties_hs_email_send_event_id_created": null, "properties_hs_email_sender_email": "integration-test-user@airbyte.io", "properties_hs_email_sender_firstname": null, "properties_hs_email_sender_lastname": null, "properties_hs_email_sender_raw": null, "properties_hs_email_sent_count": 1.0, "properties_hs_email_sent_via": "GMAIL", "properties_hs_email_status": "SENT", "properties_hs_email_stripped_attachment_count": null, "properties_hs_email_subject": "test deal ", "properties_hs_email_text": "test body\n-- \nPrefer fewer emails from me? Click here: https://d11qV604.na1.hs-salescrm-sub.com/preferences/en/manage?data=W2nXS-N30h-MkW3DX4xr38lXTKW2KXbZn3H3ZTKW4kt7Y_3XR2G0W30sn1g2zt_2NW47kvvy23ncKnW47Vmcy4pxy7cW41tzTm1X87X1W364bL-36tRLFW30J_Vy36F403W45FGpL3XHz-RW4ftDwZ4msYq_W24-jyc2HCSCvW3VGBr52TLG1vW2nFrmM3P2tStW43Skr81VxgJXW3z26wT4pc1KRW1Vpb_f3d3w7qW36dtk_4rCSHJW3F507n1_6v4MW2CWCvk49rVZpW23jtn51St_bDW2RKdYG2RNzKSW47znqq1_dHnNW4mGNp33Y1JRBW25m60s1Nk9WFW2MMKcf2F-zTNW4kddlH1NFHhxW25nrXX2KQX5rW3GJy1x2Yh7XsW2Pnx-93f_bXGW47SgSp1XqcMJW2FTQ1Z2KPBb6W32kvXr2KnzH9W3HcvHw3LRJmmW2MLX-W3LBLBJW3Q-74Q2KYV0CW1_9nCQ2r36_S0", "properties_hs_email_thread_id": "3b2bf39b9ed8cfc53310ee557627d073", "properties_hs_email_thread_summary": null, "properties_hs_email_to_email": "gl_serhii.lazebnyi@airbyte.io", "properties_hs_email_to_firstname": null, "properties_hs_email_to_lastname": null, "properties_hs_email_to_raw": "gl_serhii.lazebnyi@airbyte.io", "properties_hs_email_tracker_key": "87989bf6-7771-4486-b3d7-73a31af32b2c", "properties_hs_email_validation_skipped": null, "properties_hs_engagement_source": "EMAIL_INTEGRATION", "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_lastmodifieddate": "2024-02-05T01:13:26.539000+00:00", "properties_hs_merged_object_ids": null, "properties_hs_modified_by": "12282590", "properties_hs_object_id": 46838275228, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_owner_ids_bcc": null, "properties_hs_owner_ids_cc": null, "properties_hs_owner_ids_from": "52550153", "properties_hs_owner_ids_to": null, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_scs_association_status": null, "properties_hs_scs_audit_id": null, "properties_hs_timestamp": "2024-02-05T01:13:21.109000+00:00", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": "432a7d905bf8fc42ba938819a9e6e291", "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2024-02-05T01:13:21.505000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1708015555151} +{"stream": "engagements_meetings", "data": {"id": "46837884323", "properties": {"hs_activity_type": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_attendee_owner_ids": null, "hs_body_preview": null, "hs_body_preview_html": null, "hs_body_preview_is_truncated": false, "hs_contact_first_outreach_date": null, "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2024-02-05T01:08:01.995000+00:00", "hs_engagement_source": "MEETINGS", "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_guest_emails": null, "hs_i_cal_uid": "imqqv2eda8h5rh74gabnagl60o@google.com", "hs_include_description_in_reminder": null, "hs_internal_meeting_notes": null, "hs_lastmodifieddate": "2024-02-05T01:40:30.343000+00:00", "hs_meeting_body": null, "hs_meeting_calendar_event_hash": "7e8970ad5f400444979d9c979d5369b4", "hs_meeting_change_id": "7231dcd51227b02a05d158f5e7a602f3", "hs_meeting_created_from_link_id": "6678679", "hs_meeting_end_time": "2024-02-05T14:15:00+00:00", "hs_meeting_external_url": "https://www.google.com/calendar/event?eid=aW1xcXYyZWRhOGg1cmg3NGdhYm5hZ2w2MG8gaW50ZWdyYXRpb24tdGVzdC11c2VyQGFpcmJ5dGUuaW8", "hs_meeting_location": null, "hs_meeting_location_type": null, "hs_meeting_ms_teams_payload": null, "hs_meeting_outcome": "SCHEDULED", "hs_meeting_payments_session_id": null, "hs_meeting_pre_meeting_prospect_reminders": null, "hs_meeting_source": "MEETINGS_PUBLIC", "hs_meeting_source_id": "imqqv2eda8h5rh74gabnagl60o", "hs_meeting_start_time": "2024-02-05T14:00:00+00:00", "hs_meeting_title": "Test User and Team-1 Airbyte", "hs_meeting_web_conference_meeting_id": null, "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_object_id": 46837884323, "hs_object_source": "MEETINGS", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "MEETINGS", "hs_object_source_user_id": 12282590, "hs_outcome_canceled_count": 0, "hs_outcome_completed_count": 0, "hs_outcome_no_show_count": 0, "hs_outcome_rescheduled_count": 0, "hs_outcome_scheduled_count": 1, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_roster_object_coordinates": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46837884323,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707139800000,\"uuid\":\"MEETING:7a71d47b-0a87-40c4-8e1a-a140184a29d0\"}]}", "hs_time_to_book_meeting_from_first_contact": 0, "hs_timestamp": "2024-02-05T14:00:00+00:00", "hs_timezone": "Europe/Warsaw", "hs_unique_creation_key": null, "hs_unique_id": "imqqv2eda8h5rh74gabnagl60o", "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2024-02-05T01:08:10.888000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2024-02-05T01:08:01.995Z", "updatedAt": "2024-02-05T01:40:30.343Z", "archived": false, "properties_hs_activity_type": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_attendee_owner_ids": null, "properties_hs_body_preview": null, "properties_hs_body_preview_html": null, "properties_hs_body_preview_is_truncated": false, "properties_hs_contact_first_outreach_date": null, "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2024-02-05T01:08:01.995000+00:00", "properties_hs_engagement_source": "MEETINGS", "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_guest_emails": null, "properties_hs_i_cal_uid": "imqqv2eda8h5rh74gabnagl60o@google.com", "properties_hs_include_description_in_reminder": null, "properties_hs_internal_meeting_notes": null, "properties_hs_lastmodifieddate": "2024-02-05T01:40:30.343000+00:00", "properties_hs_meeting_body": null, "properties_hs_meeting_calendar_event_hash": "7e8970ad5f400444979d9c979d5369b4", "properties_hs_meeting_change_id": "7231dcd51227b02a05d158f5e7a602f3", "properties_hs_meeting_created_from_link_id": "6678679", "properties_hs_meeting_end_time": "2024-02-05T14:15:00+00:00", "properties_hs_meeting_external_url": "https://www.google.com/calendar/event?eid=aW1xcXYyZWRhOGg1cmg3NGdhYm5hZ2w2MG8gaW50ZWdyYXRpb24tdGVzdC11c2VyQGFpcmJ5dGUuaW8", "properties_hs_meeting_location": null, "properties_hs_meeting_location_type": null, "properties_hs_meeting_ms_teams_payload": null, "properties_hs_meeting_outcome": "SCHEDULED", "properties_hs_meeting_payments_session_id": null, "properties_hs_meeting_pre_meeting_prospect_reminders": null, "properties_hs_meeting_source": "MEETINGS_PUBLIC", "properties_hs_meeting_source_id": "imqqv2eda8h5rh74gabnagl60o", "properties_hs_meeting_start_time": "2024-02-05T14:00:00+00:00", "properties_hs_meeting_title": "Test User and Team-1 Airbyte", "properties_hs_meeting_web_conference_meeting_id": null, "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_object_id": 46837884323, "properties_hs_object_source": "MEETINGS", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "MEETINGS", "properties_hs_object_source_user_id": 12282590, "properties_hs_outcome_canceled_count": 0, "properties_hs_outcome_completed_count": 0, "properties_hs_outcome_no_show_count": 0, "properties_hs_outcome_rescheduled_count": 0, "properties_hs_outcome_scheduled_count": 1, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_roster_object_coordinates": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46837884323,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707139800000,\"uuid\":\"MEETING:7a71d47b-0a87-40c4-8e1a-a140184a29d0\"}]}", "properties_hs_time_to_book_meeting_from_first_contact": 0, "properties_hs_timestamp": "2024-02-05T14:00:00+00:00", "properties_hs_timezone": "Europe/Warsaw", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": "imqqv2eda8h5rh74gabnagl60o", "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2024-02-05T01:08:10.888000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1708015722269} +{"stream": "engagements_meetings", "data": {"id": "46838182245", "properties": {"hs_activity_type": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_attendee_owner_ids": null, "hs_body_preview": null, "hs_body_preview_html": null, "hs_body_preview_is_truncated": false, "hs_contact_first_outreach_date": "2024-02-05T15:15:00+00:00", "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2024-02-05T01:08:32.416000+00:00", "hs_engagement_source": "MEETINGS", "hs_engagement_source_id": null, "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_guest_emails": null, "hs_i_cal_uid": null, "hs_include_description_in_reminder": null, "hs_internal_meeting_notes": null, "hs_lastmodifieddate": "2024-02-05T01:08:37.402000+00:00", "hs_meeting_body": null, "hs_meeting_calendar_event_hash": "0b24520e196b77a0db079ab0357565e8", "hs_meeting_change_id": "9cc62faac2139a8ae373f992facb9504", "hs_meeting_created_from_link_id": "6678679", "hs_meeting_end_time": "2024-02-05T15:30:00+00:00", "hs_meeting_external_url": "https://www.google.com/calendar/event?eid=amg5N3RhcWppbjEzaGg4NDI0aXZoc3I0M2MgaW50ZWdyYXRpb24tdGVzdC11c2VyQGFpcmJ5dGUuaW8", "hs_meeting_location": null, "hs_meeting_location_type": null, "hs_meeting_ms_teams_payload": null, "hs_meeting_outcome": "SCHEDULED", "hs_meeting_payments_session_id": null, "hs_meeting_pre_meeting_prospect_reminders": null, "hs_meeting_source": "MEETINGS_PUBLIC", "hs_meeting_source_id": "jh97taqjin13hh8424ivhsr43c", "hs_meeting_start_time": "2024-02-05T15:15:00+00:00", "hs_meeting_title": "Test User and Team-1 Airbyte", "hs_meeting_web_conference_meeting_id": null, "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_object_id": 46838182245, "hs_object_source": "MEETINGS", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": null, "hs_object_source_label": "MEETINGS", "hs_object_source_user_id": 12282590, "hs_outcome_canceled_count": 0, "hs_outcome_completed_count": 0, "hs_outcome_no_show_count": 0, "hs_outcome_rescheduled_count": 0, "hs_outcome_scheduled_count": 1, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_roster_object_coordinates": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46838182245,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707144300000,\"uuid\":\"MEETING:dc82686f-39ac-416f-ad15-4f2d706047c9\"}]}", "hs_time_to_book_meeting_from_first_contact": 0, "hs_timestamp": "2024-02-05T15:15:00+00:00", "hs_timezone": "Europe/Warsaw", "hs_unique_creation_key": null, "hs_unique_id": "jh97taqjin13hh8424ivhsr43c", "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2024-02-05T01:08:33.582000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2024-02-05T01:08:32.416Z", "updatedAt": "2024-02-05T01:08:37.402Z", "archived": false, "contacts": ["3201"], "properties_hs_activity_type": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_attendee_owner_ids": null, "properties_hs_body_preview": null, "properties_hs_body_preview_html": null, "properties_hs_body_preview_is_truncated": false, "properties_hs_contact_first_outreach_date": "2024-02-05T15:15:00+00:00", "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2024-02-05T01:08:32.416000+00:00", "properties_hs_engagement_source": "MEETINGS", "properties_hs_engagement_source_id": null, "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_guest_emails": null, "properties_hs_i_cal_uid": null, "properties_hs_include_description_in_reminder": null, "properties_hs_internal_meeting_notes": null, "properties_hs_lastmodifieddate": "2024-02-05T01:08:37.402000+00:00", "properties_hs_meeting_body": null, "properties_hs_meeting_calendar_event_hash": "0b24520e196b77a0db079ab0357565e8", "properties_hs_meeting_change_id": "9cc62faac2139a8ae373f992facb9504", "properties_hs_meeting_created_from_link_id": "6678679", "properties_hs_meeting_end_time": "2024-02-05T15:30:00+00:00", "properties_hs_meeting_external_url": "https://www.google.com/calendar/event?eid=amg5N3RhcWppbjEzaGg4NDI0aXZoc3I0M2MgaW50ZWdyYXRpb24tdGVzdC11c2VyQGFpcmJ5dGUuaW8", "properties_hs_meeting_location": null, "properties_hs_meeting_location_type": null, "properties_hs_meeting_ms_teams_payload": null, "properties_hs_meeting_outcome": "SCHEDULED", "properties_hs_meeting_payments_session_id": null, "properties_hs_meeting_pre_meeting_prospect_reminders": null, "properties_hs_meeting_source": "MEETINGS_PUBLIC", "properties_hs_meeting_source_id": "jh97taqjin13hh8424ivhsr43c", "properties_hs_meeting_start_time": "2024-02-05T15:15:00+00:00", "properties_hs_meeting_title": "Test User and Team-1 Airbyte", "properties_hs_meeting_web_conference_meeting_id": null, "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_object_id": 46838182245, "properties_hs_object_source": "MEETINGS", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": null, "properties_hs_object_source_label": "MEETINGS", "properties_hs_object_source_user_id": 12282590, "properties_hs_outcome_canceled_count": 0, "properties_hs_outcome_completed_count": 0, "properties_hs_outcome_no_show_count": 0, "properties_hs_outcome_rescheduled_count": 0, "properties_hs_outcome_scheduled_count": 1, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_roster_object_coordinates": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46838182245,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707144300000,\"uuid\":\"MEETING:dc82686f-39ac-416f-ad15-4f2d706047c9\"}]}", "properties_hs_time_to_book_meeting_from_first_contact": 0, "properties_hs_timestamp": "2024-02-05T15:15:00+00:00", "properties_hs_timezone": "Europe/Warsaw", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": "jh97taqjin13hh8424ivhsr43c", "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2024-02-05T01:08:33.582000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1708015722270} +{"stream": "engagements_meetings", "data": {"id": "46838579861", "properties": {"hs_activity_type": null, "hs_all_accessible_team_ids": null, "hs_all_assigned_business_unit_ids": null, "hs_all_owner_ids": "52550153", "hs_all_team_ids": null, "hs_at_mentioned_owner_ids": null, "hs_attachment_ids": null, "hs_attendee_owner_ids": null, "hs_body_preview": "attendee description", "hs_body_preview_html": "\n \n \n

attendee description

\n \n", "hs_body_preview_is_truncated": false, "hs_contact_first_outreach_date": null, "hs_created_by": 12282590, "hs_created_by_user_id": 12282590, "hs_createdate": "2024-02-05T01:15:53.269000+00:00", "hs_engagement_source": "CRM_UI", "hs_engagement_source_id": "12282590", "hs_follow_up_action": null, "hs_gdpr_deleted": null, "hs_guest_emails": null, "hs_i_cal_uid": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g@google.com", "hs_include_description_in_reminder": true, "hs_internal_meeting_notes": "

test note

", "hs_lastmodifieddate": "2024-02-05T01:15:53.749000+00:00", "hs_meeting_body": "

attendee description

", "hs_meeting_calendar_event_hash": null, "hs_meeting_change_id": null, "hs_meeting_created_from_link_id": null, "hs_meeting_end_time": "2024-02-06T10:45:00+00:00", "hs_meeting_external_url": "https://www.google.com/calendar/event?eid=YzRyamFkcG82OG8zY2JiM2NwajM0YjlrY2dzNjJiYjJja3JtOGI5bjY4cTM4ZDMzNnRobTZjMWg2ZyBpbnRlZ3JhdGlvbi10ZXN0LXVzZXJAYWlyYnl0ZS5pbw", "hs_meeting_location": "test address location", "hs_meeting_location_type": "ADDRESS", "hs_meeting_ms_teams_payload": null, "hs_meeting_outcome": "SCHEDULED", "hs_meeting_payments_session_id": null, "hs_meeting_pre_meeting_prospect_reminders": null, "hs_meeting_source": "BIDIRECTIONAL_API", "hs_meeting_source_id": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g", "hs_meeting_start_time": "2024-02-06T10:15:00+00:00", "hs_meeting_title": "test hubspot deal meeting ", "hs_meeting_web_conference_meeting_id": null, "hs_merged_object_ids": null, "hs_modified_by": 12282590, "hs_object_id": 46838579861, "hs_object_source": "CRM_UI", "hs_object_source_detail_1": null, "hs_object_source_detail_2": null, "hs_object_source_detail_3": null, "hs_object_source_id": "userId:12282590", "hs_object_source_label": "CRM_UI", "hs_object_source_user_id": 12282590, "hs_outcome_canceled_count": 0, "hs_outcome_completed_count": 0, "hs_outcome_no_show_count": 0, "hs_outcome_rescheduled_count": 0, "hs_outcome_scheduled_count": 1, "hs_product_name": null, "hs_queue_membership_ids": null, "hs_read_only": null, "hs_roster_object_coordinates": null, "hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46838579861,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707212700000,\"uuid\":\"MEETING:cfda6fc6-d8ae-4e46-971a-4c483a6aec5c\"}]}", "hs_time_to_book_meeting_from_first_contact": 0, "hs_timestamp": "2024-02-06T10:15:00+00:00", "hs_timezone": "Europe/Warsaw", "hs_unique_creation_key": null, "hs_unique_id": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g", "hs_updated_by_user_id": 12282590, "hs_user_ids_of_all_notification_followers": null, "hs_user_ids_of_all_notification_unfollowers": null, "hs_user_ids_of_all_owners": "12282590", "hs_was_imported": null, "hubspot_owner_assigneddate": "2024-02-05T01:15:53.269000+00:00", "hubspot_owner_id": "52550153", "hubspot_team_id": null}, "createdAt": "2024-02-05T01:15:53.269Z", "updatedAt": "2024-02-05T01:15:53.749Z", "archived": false, "companies": ["5000526215"], "deals": ["5388306989"], "properties_hs_activity_type": null, "properties_hs_all_accessible_team_ids": null, "properties_hs_all_assigned_business_unit_ids": null, "properties_hs_all_owner_ids": "52550153", "properties_hs_all_team_ids": null, "properties_hs_at_mentioned_owner_ids": null, "properties_hs_attachment_ids": null, "properties_hs_attendee_owner_ids": null, "properties_hs_body_preview": "attendee description", "properties_hs_body_preview_html": "\n \n \n

attendee description

\n \n", "properties_hs_body_preview_is_truncated": false, "properties_hs_contact_first_outreach_date": null, "properties_hs_created_by": 12282590, "properties_hs_created_by_user_id": 12282590, "properties_hs_createdate": "2024-02-05T01:15:53.269000+00:00", "properties_hs_engagement_source": "CRM_UI", "properties_hs_engagement_source_id": "12282590", "properties_hs_follow_up_action": null, "properties_hs_gdpr_deleted": null, "properties_hs_guest_emails": null, "properties_hs_i_cal_uid": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g@google.com", "properties_hs_include_description_in_reminder": true, "properties_hs_internal_meeting_notes": "

test note

", "properties_hs_lastmodifieddate": "2024-02-05T01:15:53.749000+00:00", "properties_hs_meeting_body": "

attendee description

", "properties_hs_meeting_calendar_event_hash": null, "properties_hs_meeting_change_id": null, "properties_hs_meeting_created_from_link_id": null, "properties_hs_meeting_end_time": "2024-02-06T10:45:00+00:00", "properties_hs_meeting_external_url": "https://www.google.com/calendar/event?eid=YzRyamFkcG82OG8zY2JiM2NwajM0YjlrY2dzNjJiYjJja3JtOGI5bjY4cTM4ZDMzNnRobTZjMWg2ZyBpbnRlZ3JhdGlvbi10ZXN0LXVzZXJAYWlyYnl0ZS5pbw", "properties_hs_meeting_location": "test address location", "properties_hs_meeting_location_type": "ADDRESS", "properties_hs_meeting_ms_teams_payload": null, "properties_hs_meeting_outcome": "SCHEDULED", "properties_hs_meeting_payments_session_id": null, "properties_hs_meeting_pre_meeting_prospect_reminders": null, "properties_hs_meeting_source": "BIDIRECTIONAL_API", "properties_hs_meeting_source_id": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g", "properties_hs_meeting_start_time": "2024-02-06T10:15:00+00:00", "properties_hs_meeting_title": "test hubspot deal meeting ", "properties_hs_meeting_web_conference_meeting_id": null, "properties_hs_merged_object_ids": null, "properties_hs_modified_by": 12282590, "properties_hs_object_id": 46838579861, "properties_hs_object_source": "CRM_UI", "properties_hs_object_source_detail_1": null, "properties_hs_object_source_detail_2": null, "properties_hs_object_source_detail_3": null, "properties_hs_object_source_id": "userId:12282590", "properties_hs_object_source_label": "CRM_UI", "properties_hs_object_source_user_id": 12282590, "properties_hs_outcome_canceled_count": 0, "properties_hs_outcome_completed_count": 0, "properties_hs_outcome_no_show_count": 0, "properties_hs_outcome_rescheduled_count": 0, "properties_hs_outcome_scheduled_count": 1, "properties_hs_product_name": null, "properties_hs_queue_membership_ids": null, "properties_hs_read_only": null, "properties_hs_roster_object_coordinates": null, "properties_hs_scheduled_tasks": "{\"scheduledTasks\":[{\"engagementId\":46838579861,\"portalId\":8727216,\"engagementType\":\"MEETING\",\"taskType\":\"PRE_MEETING_NOTIFICATION\",\"timestamp\":1707212700000,\"uuid\":\"MEETING:cfda6fc6-d8ae-4e46-971a-4c483a6aec5c\"}]}", "properties_hs_time_to_book_meeting_from_first_contact": 0, "properties_hs_timestamp": "2024-02-06T10:15:00+00:00", "properties_hs_timezone": "Europe/Warsaw", "properties_hs_unique_creation_key": null, "properties_hs_unique_id": "c4rjadpo68o3cbb3cpj34b9kcgs62bb2ckrm8b9n68q38d336thm6c1h6g", "properties_hs_updated_by_user_id": 12282590, "properties_hs_user_ids_of_all_notification_followers": null, "properties_hs_user_ids_of_all_notification_unfollowers": null, "properties_hs_user_ids_of_all_owners": "12282590", "properties_hs_was_imported": null, "properties_hubspot_owner_assigneddate": "2024-02-05T01:15:53.269000+00:00", "properties_hubspot_owner_id": "52550153", "properties_hubspot_team_id": null}, "emitted_at": 1708015722271} diff --git a/airbyte-integrations/connectors/source-hubspot/metadata.yaml b/airbyte-integrations/connectors/source-hubspot/metadata.yaml index 54fb2c5eff17..38f03af7a246 100644 --- a/airbyte-integrations/connectors/source-hubspot/metadata.yaml +++ b/airbyte-integrations/connectors/source-hubspot/metadata.yaml @@ -10,7 +10,7 @@ data: connectorSubtype: api connectorType: source definitionId: 36c891d9-4bd9-43ac-bad2-10e12756272c - dockerImageTag: 3.1.1 + dockerImageTag: 3.2.0 dockerRepository: airbyte/source-hubspot documentationUrl: https://docs.airbyte.com/integrations/sources/hubspot githubIssueLabel: source-hubspot diff --git a/airbyte-integrations/connectors/source-hubspot/source_hubspot/schemas/marketing_emails.json b/airbyte-integrations/connectors/source-hubspot/source_hubspot/schemas/marketing_emails.json index f36b58d95e6f..d4f888288aa8 100644 --- a/airbyte-integrations/connectors/source-hubspot/source_hubspot/schemas/marketing_emails.json +++ b/airbyte-integrations/connectors/source-hubspot/source_hubspot/schemas/marketing_emails.json @@ -700,6 +700,18 @@ }, "rssEmailEntryTemplateEnabled": { "type": ["null", "boolean"] + }, + "mailingIlsListsExcluded": { + "type": ["null", "array"], + "items": { + "type": ["null", "integer"] + } + }, + "mailingIlsListsIncluded": { + "type": ["null", "array"], + "items": { + "type": ["null", "integer"] + } } } } diff --git a/docs/integrations/sources/hubspot.md b/docs/integrations/sources/hubspot.md index 0db5152bc2df..9304a709827f 100644 --- a/docs/integrations/sources/hubspot.md +++ b/docs/integrations/sources/hubspot.md @@ -322,7 +322,8 @@ The connector is restricted by normal HubSpot [rate limitations](https://legacyd | Version | Date | Pull Request | Subject | |:--------|:-----------|:---------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| 3.1.1 | 2024-02-12 | [35165](https://github.com/airbytehq/airbyte/pull/35165) | Manage dependencies with Poetry. | +| 3.2.0 | 2024-02-15 | [35328](https://github.com/airbytehq/airbyte/pull/35328) | Add mailingIlsListsIncluded and mailingIlsListsExcluded fields to Marketing emails stream schema | +| 3.1.1 | 2024-02-12 | [35165](https://github.com/airbytehq/airbyte/pull/35165) | Manage dependencies with Poetry. | | 3.1.0 | 2024-02-05 | [34829](https://github.com/airbytehq/airbyte/pull/34829) | Add `Contacts Form Submissions` stream | | 3.0.1 | 2024-01-29 | [34635](https://github.com/airbytehq/airbyte/pull/34635) | Fix pagination for `CompaniesPropertyHistory` stream | | 3.0.0 | 2024-01-25 | [34492](https://github.com/airbytehq/airbyte/pull/34492) | Update `marketing_emails` stream schema | From dc088bc3a9acbf6064ba33a5e3c36ef500b2c91e Mon Sep 17 00:00:00 2001 From: Marius Posta Date: Fri, 16 Feb 2024 04:39:14 -0800 Subject: [PATCH 06/43] gradle: split off python cdk (#35306) --- .../publish-cdk-command-manually.yml | 2 +- .../python/bin/build_code_generator_image.sh | 11 + airbyte-cdk/python/build.gradle | 121 ++++++- .../python}/code-generator/Dockerfile | 0 airbyte-cdk/python/gradle.properties | 11 + .../python/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63721 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + airbyte-cdk/python/gradlew | 249 +++++++++++++ airbyte-cdk/python/gradlew.bat | 92 +++++ airbyte-cdk/python/pyproject.toml | 36 ++ airbyte-cdk/python/settings.gradle | 29 ++ .../destination-harness/build.gradle | 1 - .../source-harness/build.gradle | 1 - buildSrc/src/main/groovy/DockerHelpers.groovy | 23 -- .../main/groovy/airbyte-docker-legacy.gradle | 331 ------------------ .../src/main/groovy/airbyte-python.gradle | 185 ---------- settings.gradle | 3 - tools/code-generator/build.gradle | 3 - 18 files changed, 551 insertions(+), 554 deletions(-) create mode 100755 airbyte-cdk/python/bin/build_code_generator_image.sh rename {tools => airbyte-cdk/python}/code-generator/Dockerfile (100%) create mode 100644 airbyte-cdk/python/gradle.properties create mode 100644 airbyte-cdk/python/gradle/wrapper/gradle-wrapper.jar create mode 100644 airbyte-cdk/python/gradle/wrapper/gradle-wrapper.properties create mode 100755 airbyte-cdk/python/gradlew create mode 100644 airbyte-cdk/python/gradlew.bat create mode 100644 airbyte-cdk/python/settings.gradle delete mode 100644 buildSrc/src/main/groovy/DockerHelpers.groovy delete mode 100644 buildSrc/src/main/groovy/airbyte-docker-legacy.gradle delete mode 100644 buildSrc/src/main/groovy/airbyte-python.gradle delete mode 100644 tools/code-generator/build.gradle diff --git a/.github/workflows/publish-cdk-command-manually.yml b/.github/workflows/publish-cdk-command-manually.yml index afce576b72d0..4f206f609bab 100644 --- a/.github/workflows/publish-cdk-command-manually.yml +++ b/.github/workflows/publish-cdk-command-manually.yml @@ -73,7 +73,7 @@ jobs: repository: ${{ github.event.inputs.repo }} ref: ${{ github.event.inputs.gitref }} - name: Build CDK Package - run: ./gradlew --no-daemon --no-build-cache :airbyte-cdk:python:build + run: (cd airbyte-cdk/python; ./gradlew --no-daemon --no-build-cache :build) - name: Post failure to Slack channel dev-connectors-extensibility if: ${{ failure() }} uses: slackapi/slack-github-action@v1.23.0 diff --git a/airbyte-cdk/python/bin/build_code_generator_image.sh b/airbyte-cdk/python/bin/build_code_generator_image.sh new file mode 100755 index 000000000000..f73c318317c5 --- /dev/null +++ b/airbyte-cdk/python/bin/build_code_generator_image.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e + +DOCKER_BUILD_ARCH="${DOCKER_BUILD_ARCH:-amd64}" +# https://docs.docker.com/develop/develop-images/build_enhancements/ +export DOCKER_BUILDKIT=1 + +CODE_GENERATOR_DOCKERFILE="$(dirname $0)/../code-generator/Dockerfile" +test -f $CODE_GENERATOR_DOCKERFILE +docker build --build-arg DOCKER_BUILD_ARCH="$DOCKER_BUILD_ARCH" -t "airbyte/code-generator:dev" - < $CODE_GENERATOR_DOCKERFILE diff --git a/airbyte-cdk/python/build.gradle b/airbyte-cdk/python/build.gradle index 63cc9992a73b..61f355742382 100644 --- a/airbyte-cdk/python/build.gradle +++ b/airbyte-cdk/python/build.gradle @@ -1,25 +1,134 @@ +import ru.vyarus.gradle.plugin.python.task.PythonTask + plugins { - id 'airbyte-python' - id 'airbyte-docker-legacy' + id 'base' + id 'ru.vyarus.use-python' version '2.3.0' } +def generateCodeGeneratorImage = tasks.register('generateCodeGeneratorImage', Exec) { + commandLine 'bin/build_code_generator_image.sh' +} def generateComponentManifestClassFiles = tasks.register('generateComponentManifestClassFiles', Exec) { - environment 'ROOT_DIR', rootDir.absolutePath + environment 'ROOT_DIR', rootDir.parentFile.parentFile.absolutePath commandLine 'bin/generate-component-manifest-files.sh' } generateComponentManifestClassFiles.configure { - dependsOn project(':tools:code-generator').tasks.named('assemble') + dependsOn generateCodeGeneratorImage } tasks.register('generate').configure { dependsOn generateComponentManifestClassFiles } tasks.register('validateSourceYamlManifest', Exec) { - environment 'ROOT_DIR', rootDir.absolutePath + environment 'ROOT_DIR', rootDir.parentFile.parentFile.absolutePath commandLine 'bin/validate-yaml-schema.sh' } tasks.register('runLowCodeConnectorUnitTests', Exec) { - environment 'ROOT_DIR', rootDir.absolutePath + environment 'ROOT_DIR', rootDir.parentFile.parentFile.absolutePath commandLine 'bin/low-code-unit-tests.sh' } + +def venvDirectoryName = '.venv' + +// Add a task that allows cleaning up venvs to every python project +def cleanPythonVenv = tasks.register('cleanPythonVenv', Exec) { + commandLine 'rm' + args '-rf', "${projectDir.absolutePath}/${venvDirectoryName}" +} + +tasks.named('clean').configure { + dependsOn cleanPythonVenv +} + +// Configure gradle python plugin. +python { + envPath = venvDirectoryName + minPythonVersion '3.10' + + // Amazon Linux support. + // The airbyte-ci tool runs gradle tasks in AL2023-based containers. + // In AL2023, `python3` is necessarily v3.9, and later pythons need to be installed and named explicitly. + // See https://github.com/amazonlinux/amazon-linux-2023/issues/459 for details. + try { + if ("python3.11 --version".execute().waitFor() == 0) { + // python3.11 definitely exists at this point, use it instead of 'python3'. + pythonBinary "python3.11" + } + } catch (IOException _) { + // Swallow exception if python3.11 is not installed. + } + // Pyenv support. + try { + def pyenvRoot = "pyenv root".execute() + def pyenvLatest = "pyenv latest ${minPythonVersion}".execute() + // Pyenv definitely exists at this point: use 'python' instead of 'python3' in all cases. + pythonBinary "python" + if (pyenvRoot.waitFor() == 0 && pyenvLatest.waitFor() == 0) { + pythonPath "${pyenvRoot.text.trim()}/versions/${pyenvLatest.text.trim()}/bin" + } + } catch (IOException _) { + // Swallow exception if pyenv is not installed. + } + + scope 'VIRTUALENV' + installVirtualenv = true + pip 'pip:23.2.1' + pip 'mccabe:0.6.1' + // https://github.com/csachs/pyproject-flake8/issues/13 + pip 'flake8:4.0.1' + // flake8 doesn't support pyproject.toml files + // and thus there is the wrapper "pyproject-flake8" for this + pip 'pyproject-flake8:0.0.1a2' + pip 'pytest:6.2.5' + pip 'coverage[toml]:6.3.1' +} + +def installLocalReqs = tasks.register('installLocalReqs', PythonTask) { + module = "pip" + command = "install .[dev,tests]" + inputs.file('setup.py') + outputs.file('build/installedlocalreqs.txt') +} + +def flakeCheck = tasks.register('flakeCheck', PythonTask) { + module = "pflake8" + command = "--config pyproject.toml ./" +} + +def installReqs = tasks.register('installReqs', PythonTask) { + module = "pip" + command = "install .[main]" + inputs.file('setup.py') + outputs.file('build/installedreqs.txt') +} +installReqs.configure { + dependsOn installLocalReqs +} + +tasks.named('check').configure { + dependsOn installReqs + dependsOn flakeCheck +} + +def installTestReqs = tasks.register('installTestReqs', PythonTask) { + module = "pip" + command = "install .[tests]" + inputs.file('setup.py') + outputs.file('build/installedtestreqs.txt') +} +installTestReqs.configure { + dependsOn installReqs +} + +def testTask = tasks.register('testPython', PythonTask) { + module = "coverage" + command = "run --data-file=unit_tests/.coverage.testPython --rcfile=pyproject.toml -m pytest -s unit_tests -c pytest.ini" +} +testTask.configure { + dependsOn installTestReqs +} + +tasks.named('check').configure { + dependsOn testTask +} diff --git a/tools/code-generator/Dockerfile b/airbyte-cdk/python/code-generator/Dockerfile similarity index 100% rename from tools/code-generator/Dockerfile rename to airbyte-cdk/python/code-generator/Dockerfile diff --git a/airbyte-cdk/python/gradle.properties b/airbyte-cdk/python/gradle.properties new file mode 100644 index 000000000000..a458cfe27eb9 --- /dev/null +++ b/airbyte-cdk/python/gradle.properties @@ -0,0 +1,11 @@ +# NOTE: some of these values are overwritten in CI! +# NOTE: if you want to override this for your local machine, set overrides in ~/.gradle/gradle.properties + +org.gradle.parallel=true +org.gradle.caching=true + +# Note, this might have issues on the normal Github runner. +org.gradle.vfs.watch=true + +# Tune # of cores Gradle uses. +# org.gradle.workers.max=3 diff --git a/airbyte-cdk/python/gradle/wrapper/gradle-wrapper.jar b/airbyte-cdk/python/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7f93135c49b765f8051ef9d0a6055ff8e46073d8 GIT binary patch literal 63721 zcmb5Wb9gP!wgnp7wrv|bwr$&XvSZt}Z6`anZSUAlc9NHKf9JdJ;NJVr`=eI(_pMp0 zy1VAAG3FfAOI`{X1O)&90s;U4K;XLp008~hCjbEC_fbYfS%6kTR+JtXK>nW$ZR+`W ze|#J8f4A@M|F5BpfUJb5h>|j$jOe}0oE!`Zf6fM>CR?!y@zU(cL8NsKk`a z6tx5mAkdjD;J=LcJ;;Aw8p!v#ouk>mUDZF@ zK>yvw%+bKu+T{Nk@LZ;zkYy0HBKw06_IWcMHo*0HKpTsEFZhn5qCHH9j z)|XpN&{`!0a>Vl+PmdQc)Yg4A(AG-z!+@Q#eHr&g<9D?7E)_aEB?s_rx>UE9TUq|? z;(ggJt>9l?C|zoO@5)tu?EV0x_7T17q4fF-q3{yZ^ipUbKcRZ4Qftd!xO(#UGhb2y>?*@{xq%`(-`2T^vc=#< zx!+@4pRdk&*1ht2OWk^Z5IAQ0YTAXLkL{(D*$gENaD)7A%^XXrCchN&z2x+*>o2FwPFjWpeaL=!tzv#JOW#( z$B)Nel<+$bkH1KZv3&-}=SiG~w2sbDbAWarg%5>YbC|}*d9hBjBkR(@tyM0T)FO$# zPtRXukGPnOd)~z=?avu+4Co@wF}1T)-uh5jI<1$HLtyDrVak{gw`mcH@Q-@wg{v^c zRzu}hMKFHV<8w}o*yg6p@Sq%=gkd~;`_VGTS?L@yVu`xuGy+dH6YOwcP6ZE`_0rK% zAx5!FjDuss`FQ3eF|mhrWkjux(Pny^k$u_)dyCSEbAsecHsq#8B3n3kDU(zW5yE|( zgc>sFQywFj5}U*qtF9Y(bi*;>B7WJykcAXF86@)z|0-Vm@jt!EPoLA6>r)?@DIobIZ5Sx zsc@OC{b|3%vaMbyeM|O^UxEYlEMHK4r)V-{r)_yz`w1*xV0|lh-LQOP`OP`Pk1aW( z8DSlGN>Ts|n*xj+%If~+E_BxK)~5T#w6Q1WEKt{!Xtbd`J;`2a>8boRo;7u2M&iOop4qcy<)z023=oghSFV zST;?S;ye+dRQe>ygiJ6HCv4;~3DHtJ({fWeE~$H@mKn@Oh6Z(_sO>01JwH5oA4nvK zr5Sr^g+LC zLt(i&ecdmqsIJGNOSUyUpglvhhrY8lGkzO=0USEKNL%8zHshS>Qziu|`eyWP^5xL4 zRP122_dCJl>hZc~?58w~>`P_s18VoU|7(|Eit0-lZRgLTZKNq5{k zE?V=`7=R&ro(X%LTS*f+#H-mGo_j3dm@F_krAYegDLk6UV{`UKE;{YSsn$ z(yz{v1@p|p!0>g04!eRSrSVb>MQYPr8_MA|MpoGzqyd*$@4j|)cD_%^Hrd>SorF>@ zBX+V<@vEB5PRLGR(uP9&U&5=(HVc?6B58NJT_igiAH*q~Wb`dDZpJSKfy5#Aag4IX zj~uv74EQ_Q_1qaXWI!7Vf@ZrdUhZFE;L&P_Xr8l@GMkhc#=plV0+g(ki>+7fO%?Jb zl+bTy7q{w^pTb{>(Xf2q1BVdq?#f=!geqssXp z4pMu*q;iiHmA*IjOj4`4S&|8@gSw*^{|PT}Aw~}ZXU`6=vZB=GGeMm}V6W46|pU&58~P+?LUs%n@J}CSrICkeng6YJ^M? zS(W?K4nOtoBe4tvBXs@@`i?4G$S2W&;$z8VBSM;Mn9 zxcaEiQ9=vS|bIJ>*tf9AH~m&U%2+Dim<)E=}KORp+cZ^!@wI`h1NVBXu{@%hB2Cq(dXx_aQ9x3mr*fwL5!ZryQqi|KFJuzvP zK1)nrKZ7U+B{1ZmJub?4)Ln^J6k!i0t~VO#=q1{?T)%OV?MN}k5M{}vjyZu#M0_*u z8jwZKJ#Df~1jcLXZL7bnCEhB6IzQZ-GcoQJ!16I*39iazoVGugcKA{lhiHg4Ta2fD zk1Utyc5%QzZ$s3;p0N+N8VX{sd!~l*Ta3|t>lhI&G`sr6L~G5Lul`>m z{!^INm?J|&7X=;{XveF!(b*=?9NAp4y&r&N3(GKcW4rS(Ejk|Lzs1PrxPI_owB-`H zg3(Rruh^&)`TKA6+_!n>RdI6pw>Vt1_j&+bKIaMTYLiqhZ#y_=J8`TK{Jd<7l9&sY z^^`hmi7^14s16B6)1O;vJWOF$=$B5ONW;;2&|pUvJlmeUS&F;DbSHCrEb0QBDR|my zIs+pE0Y^`qJTyH-_mP=)Y+u^LHcuZhsM3+P||?+W#V!_6E-8boP#R-*na4!o-Q1 zVthtYhK{mDhF(&7Okzo9dTi03X(AE{8cH$JIg%MEQca`S zy@8{Fjft~~BdzWC(di#X{ny;!yYGK9b@=b|zcKZ{vv4D8i+`ilOPl;PJl{!&5-0!w z^fOl#|}vVg%=n)@_e1BrP)`A zKPgs`O0EO}Y2KWLuo`iGaKu1k#YR6BMySxQf2V++Wo{6EHmK>A~Q5o73yM z-RbxC7Qdh0Cz!nG+7BRZE>~FLI-?&W_rJUl-8FDIaXoNBL)@1hwKa^wOr1($*5h~T zF;%f^%<$p8Y_yu(JEg=c_O!aZ#)Gjh$n(hfJAp$C2he555W5zdrBqjFmo|VY+el;o z=*D_w|GXG|p0**hQ7~9-n|y5k%B}TAF0iarDM!q-jYbR^us(>&y;n^2l0C%@2B}KM zyeRT9)oMt97Agvc4sEKUEy%MpXr2vz*lb zh*L}}iG>-pqDRw7ud{=FvTD?}xjD)w{`KzjNom-$jS^;iw0+7nXSnt1R@G|VqoRhE%12nm+PH?9`(4rM0kfrZzIK9JU=^$YNyLvAIoxl#Q)xxDz!^0@zZ zSCs$nfcxK_vRYM34O<1}QHZ|hp4`ioX3x8(UV(FU$J@o%tw3t4k1QPmlEpZa2IujG&(roX_q*%e`Hq|);0;@k z0z=fZiFckp#JzW0p+2A+D$PC~IsakhJJkG(c;CqAgFfU0Z`u$PzG~-9I1oPHrCw&)@s^Dc~^)#HPW0Ra}J^=|h7Fs*<8|b13ZzG6MP*Q1dkoZ6&A^!}|hbjM{2HpqlSXv_UUg1U4gn z3Q)2VjU^ti1myodv+tjhSZp%D978m~p& z43uZUrraHs80Mq&vcetqfQpQP?m!CFj)44t8Z}k`E798wxg&~aCm+DBoI+nKq}&j^ zlPY3W$)K;KtEajks1`G?-@me7C>{PiiBu+41#yU_c(dITaqE?IQ(DBu+c^Ux!>pCj zLC|HJGU*v+!it1(;3e`6igkH(VA)-S+k(*yqxMgUah3$@C zz`7hEM47xr>j8^g`%*f=6S5n>z%Bt_Fg{Tvmr+MIsCx=0gsu_sF`q2hlkEmisz#Fy zj_0;zUWr;Gz}$BS%Y`meb(=$d%@Crs(OoJ|}m#<7=-A~PQbyN$x%2iXP2@e*nO0b7AwfH8cCUa*Wfu@b)D_>I*%uE4O3 z(lfnB`-Xf*LfC)E}e?%X2kK7DItK6Tf<+M^mX0Ijf_!IP>7c8IZX%8_#0060P{QMuV^B9i<^E`_Qf0pv9(P%_s8D`qvDE9LK9u-jB}J2S`(mCO&XHTS04Z5Ez*vl^T%!^$~EH8M-UdwhegL>3IQ*)(MtuH2Xt1p!fS4o~*rR?WLxlA!sjc2(O znjJn~wQ!Fp9s2e^IWP1C<4%sFF}T4omr}7+4asciyo3DntTgWIzhQpQirM$9{EbQd z3jz9vS@{aOqTQHI|l#aUV@2Q^Wko4T0T04Me4!2nsdrA8QY1%fnAYb~d2GDz@lAtfcHq(P7 zaMBAGo}+NcE-K*@9y;Vt3*(aCaMKXBB*BJcD_Qnxpt75r?GeAQ}*|>pYJE=uZb73 zC>sv)18)q#EGrTG6io*}JLuB_jP3AU1Uiu$D7r|2_zlIGb9 zjhst#ni)Y`$)!fc#reM*$~iaYoz~_Cy7J3ZTiPm)E?%`fbk`3Tu-F#`{i!l5pNEn5 zO-Tw-=TojYhzT{J=?SZj=Z8#|eoF>434b-DXiUsignxXNaR3 zm_}4iWU$gt2Mw5NvZ5(VpF`?X*f2UZDs1TEa1oZCif?Jdgr{>O~7}-$|BZ7I(IKW`{f;@|IZFX*R8&iT= zoWstN8&R;}@2Ka%d3vrLtR|O??ben;k8QbS-WB0VgiCz;<$pBmIZdN!aalyCSEm)crpS9dcD^Y@XT1a3+zpi-`D}e#HV<} z$Y(G&o~PvL-xSVD5D?JqF3?B9rxGWeb=oEGJ3vRp5xfBPlngh1O$yI95EL+T8{GC@ z98i1H9KhZGFl|;`)_=QpM6H?eDPpw~^(aFQWwyXZ8_EEE4#@QeT_URray*mEOGsGc z6|sdXtq!hVZo=d#+9^@lm&L5|q&-GDCyUx#YQiccq;spOBe3V+VKdjJA=IL=Zn%P} zNk=_8u}VhzFf{UYZV0`lUwcD&)9AFx0@Fc6LD9A6Rd1=ga>Mi0)_QxM2ddCVRmZ0d z+J=uXc(?5JLX3=)e)Jm$HS2yF`44IKhwRnm2*669_J=2LlwuF5$1tAo@ROSU@-y+;Foy2IEl2^V1N;fk~YR z?&EP8#t&m0B=?aJeuz~lHjAzRBX>&x=A;gIvb>MD{XEV zV%l-+9N-)i;YH%nKP?>f`=?#`>B(`*t`aiPLoQM(a6(qs4p5KFjDBN?8JGrf3z8>= zi7sD)c)Nm~x{e<^jy4nTx${P~cwz_*a>%0_;ULou3kHCAD7EYkw@l$8TN#LO9jC( z1BeFW`k+bu5e8Ns^a8dPcjEVHM;r6UX+cN=Uy7HU)j-myRU0wHd$A1fNI~`4;I~`zC)3ul#8#^rXVSO*m}Ag>c%_;nj=Nv$rCZ z*~L@C@OZg%Q^m)lc-kcX&a*a5`y&DaRxh6O*dfhLfF+fU5wKs(1v*!TkZidw*)YBP za@r`3+^IHRFeO%!ai%rxy;R;;V^Fr=OJlpBX;(b*3+SIw}7= zIq$*Thr(Zft-RlY)D3e8V;BmD&HOfX+E$H#Y@B3?UL5L~_fA-@*IB-!gItK7PIgG9 zgWuGZK_nuZjHVT_Fv(XxtU%)58;W39vzTI2n&)&4Dmq7&JX6G>XFaAR{7_3QB6zsT z?$L8c*WdN~nZGiscY%5KljQARN;`w$gho=p006z;n(qIQ*Zu<``TMO3n0{ARL@gYh zoRwS*|Niw~cR!?hE{m*y@F`1)vx-JRfqET=dJ5_(076st(=lFfjtKHoYg`k3oNmo_ zNbQEw8&sO5jAYmkD|Zaz_yUb0rC})U!rCHOl}JhbYIDLzLvrZVw0~JO`d*6f;X&?V=#T@ND*cv^I;`sFeq4 z##H5;gpZTb^0Hz@3C*~u0AqqNZ-r%rN3KD~%Gw`0XsIq$(^MEb<~H(2*5G^<2(*aI z%7}WB+TRlMIrEK#s0 z93xn*Ohb=kWFc)BNHG4I(~RPn-R8#0lqyBBz5OM6o5|>x9LK@%HaM}}Y5goCQRt2C z{j*2TtT4ne!Z}vh89mjwiSXG=%DURar~=kGNNaO_+Nkb+tRi~Rkf!7a$*QlavziD( z83s4GmQ^Wf*0Bd04f#0HX@ua_d8 z23~z*53ePD6@xwZ(vdl0DLc=>cPIOPOdca&MyR^jhhKrdQO?_jJh`xV3GKz&2lvP8 zEOwW6L*ufvK;TN{=S&R@pzV^U=QNk^Ec}5H z+2~JvEVA{`uMAr)?Kf|aW>33`)UL@bnfIUQc~L;TsTQ6>r-<^rB8uoNOJ>HWgqMI8 zSW}pZmp_;z_2O5_RD|fGyTxaxk53Hg_3Khc<8AUzV|ZeK{fp|Ne933=1&_^Dbv5^u zB9n=*)k*tjHDRJ@$bp9mrh}qFn*s}npMl5BMDC%Hs0M0g-hW~P*3CNG06G!MOPEQ_ zi}Qs-6M8aMt;sL$vlmVBR^+Ry<64jrm1EI1%#j?c?4b*7>)a{aDw#TfTYKq+SjEFA z(aJ&z_0?0JB83D-i3Vh+o|XV4UP+YJ$9Boid2^M2en@APw&wx7vU~t$r2V`F|7Qfo z>WKgI@eNBZ-+Og<{u2ZiG%>YvH2L3fNpV9J;WLJoBZda)01Rn;o@){01{7E#ke(7U zHK>S#qZ(N=aoae*4X!0A{)nu0R_sKpi1{)u>GVjC+b5Jyl6#AoQ-1_3UDovNSo`T> z?c-@7XX*2GMy?k?{g)7?Sv;SJkmxYPJPs!&QqB12ejq`Lee^-cDveVWL^CTUldb(G zjDGe(O4P=S{4fF=#~oAu>LG>wrU^z_?3yt24FOx>}{^lCGh8?vtvY$^hbZ)9I0E3r3NOlb9I?F-Yc=r$*~l`4N^xzlV~N zl~#oc>U)Yjl0BxV>O*Kr@lKT{Z09OXt2GlvE38nfs+DD7exl|&vT;)>VFXJVZp9Np zDK}aO;R3~ag$X*|hRVY3OPax|PG`@_ESc8E!mHRByJbZQRS38V2F__7MW~sgh!a>98Q2%lUNFO=^xU52|?D=IK#QjwBky-C>zOWlsiiM&1n z;!&1((Xn1$9K}xabq~222gYvx3hnZPg}VMF_GV~5ocE=-v>V=T&RsLBo&`)DOyIj* zLV{h)JU_y*7SdRtDajP_Y+rBkNN*1_TXiKwHH2&p51d(#zv~s#HwbNy?<+(=9WBvo zw2hkk2Dj%kTFhY+$T+W-b7@qD!bkfN#Z2ng@Pd=i3-i?xYfs5Z*1hO?kd7Sp^9`;Y zM2jeGg<-nJD1er@Pc_cSY7wo5dzQX44=%6rn}P_SRbpzsA{6B+!$3B0#;}qwO37G^ zL(V_5JK`XT?OHVk|{_$vQ|oNEpab*BO4F zUTNQ7RUhnRsU`TK#~`)$icsvKh~(pl=3p6m98@k3P#~upd=k*u20SNcb{l^1rUa)>qO997)pYRWMncC8A&&MHlbW?7i^7M`+B$hH~Y|J zd>FYOGQ;j>Zc2e7R{KK7)0>>nn_jYJy&o@sK!4G>-rLKM8Hv)f;hi1D2fAc$+six2 zyVZ@wZ6x|fJ!4KrpCJY=!Mq0;)X)OoS~{Lkh6u8J`eK%u0WtKh6B>GW_)PVc zl}-k`p09qwGtZ@VbYJC!>29V?Dr>>vk?)o(x?!z*9DJ||9qG-&G~#kXxbw{KKYy}J zQKa-dPt~M~E}V?PhW0R26xdA%1T*%ra6SguGu50YHngOTIv)@N|YttEXo#OZfgtP7;H?EeZZxo<}3YlYxtBq znJ!WFR^tmGf0Py}N?kZ(#=VtpC@%xJkDmfcCoBTxq zr_|5gP?u1@vJZbxPZ|G0AW4=tpb84gM2DpJU||(b8kMOV1S3|(yuwZJ&rIiFW(U;5 zUtAW`O6F6Zy+eZ1EDuP~AAHlSY-+A_eI5Gx)%*uro5tljy}kCZU*_d7)oJ>oQSZ3* zneTn`{gnNC&uJd)0aMBzAg021?YJ~b(fmkwZAd696a=0NzBAqBN54KuNDwa*no(^O z6p05bioXUR^uXjpTol*ppHp%1v9e)vkoUAUJyBx3lw0UO39b0?^{}yb!$yca(@DUn zCquRF?t=Zb9`Ed3AI6|L{eX~ijVH`VzSMheKoP7LSSf4g>md>`yi!TkoG5P>Ofp+n z(v~rW+(5L96L{vBb^g51B=(o)?%%xhvT*A5btOpw(TKh^g^4c zw>0%X!_0`{iN%RbVk+A^f{w-4-SSf*fu@FhruNL##F~sF24O~u zyYF<3el2b$$wZ_|uW#@Ak+VAGk#e|kS8nL1g>2B-SNMjMp^8;-FfeofY2fphFHO!{ z*!o4oTb{4e;S<|JEs<1_hPsmAlVNk?_5-Fp5KKU&d#FiNW~Y+pVFk@Cua1I{T+1|+ zHx6rFMor)7L)krbilqsWwy@T+g3DiH5MyVf8Wy}XbEaoFIDr~y;@r&I>FMW{ z?Q+(IgyebZ)-i4jNoXQhq4Muy9Fv+OxU;9_Jmn+<`mEC#%2Q_2bpcgzcinygNI!&^ z=V$)o2&Yz04~+&pPWWn`rrWxJ&}8khR)6B(--!9Q zubo}h+1T)>a@c)H^i``@<^j?|r4*{;tQf78(xn0g39IoZw0(CwY1f<%F>kEaJ zp9u|IeMY5mRdAlw*+gSN^5$Q)ShM<~E=(c8QM+T-Qk)FyKz#Sw0EJ*edYcuOtO#~Cx^(M7w5 z3)rl#L)rF|(Vun2LkFr!rg8Q@=r>9p>(t3Gf_auiJ2Xx9HmxYTa|=MH_SUlYL`mz9 zTTS$`%;D-|Jt}AP1&k7PcnfFNTH0A-*FmxstjBDiZX?}%u%Yq94$fUT&z6od+(Uk> zuqsld#G(b$G8tus=M!N#oPd|PVFX)?M?tCD0tS%2IGTfh}3YA3f&UM)W$_GNV8 zQo+a(ml2Km4o6O%gKTCSDNq+#zCTIQ1*`TIJh~k6Gp;htHBFnne))rlFdGqwC6dx2+La1&Mnko*352k0y z+tQcwndQlX`nc6nb$A9?<-o|r*%aWXV#=6PQic0Ok_D;q>wbv&j7cKc!w4~KF#-{6 z(S%6Za)WpGIWf7jZ3svNG5OLs0>vCL9{V7cgO%zevIVMH{WgP*^D9ws&OqA{yr|m| zKD4*07dGXshJHd#e%x%J+qmS^lS|0Bp?{drv;{@{l9ArPO&?Q5=?OO9=}h$oVe#3b z3Yofj&Cb}WC$PxmRRS)H%&$1-)z7jELS}!u!zQ?A^Y{Tv4QVt*vd@uj-^t2fYRzQj zfxGR>-q|o$3sGn^#VzZ!QQx?h9`njeJry}@x?|k0-GTTA4y3t2E`3DZ!A~D?GiJup z)8%PK2^9OVRlP(24P^4_<|D=H^7}WlWu#LgsdHzB%cPy|f8dD3|A^mh4WXxhLTVu_ z@abE{6Saz|Y{rXYPd4$tfPYo}ef(oQWZ=4Bct-=_9`#Qgp4ma$n$`tOwq#&E18$B; z@Bp)bn3&rEi0>fWWZ@7k5WazfoX`SCO4jQWwVuo+$PmSZn^Hz?O(-tW@*DGxuf)V1 zO_xm&;NVCaHD4dqt(-MlszI3F-p?0!-e$fbiCeuaw66h^TTDLWuaV<@C-`=Xe5WL) zwooG7h>4&*)p3pKMS3O!4>-4jQUN}iAMQ)2*70?hP~)TzzR?-f@?Aqy$$1Iy8VGG$ zMM?8;j!pUX7QQD$gRc_#+=raAS577ga-w?jd`vCiN5lu)dEUkkUPl9!?{$IJNxQys z*E4e$eF&n&+AMRQR2gcaFEjAy*r)G!s(P6D&TfoApMFC_*Ftx0|D0@E-=B7tezU@d zZ{hGiN;YLIoSeRS;9o%dEua4b%4R3;$SugDjP$x;Z!M!@QibuSBb)HY!3zJ7M;^jw zlx6AD50FD&p3JyP*>o+t9YWW8(7P2t!VQQ21pHJOcG_SXQD;(5aX#M6x##5H_Re>6lPyDCjxr*R(+HE%c&QN+b^tbT zXBJk?p)zhJj#I?&Y2n&~XiytG9!1ox;bw5Rbj~)7c(MFBb4>IiRATdhg zmiEFlj@S_hwYYI(ki{}&<;_7(Z0Qkfq>am z&LtL=2qc7rWguk3BtE4zL41@#S;NN*-jWw|7Kx7H7~_%7fPt;TIX}Ubo>;Rmj94V> zNB1=;-9AR7s`Pxn}t_6^3ahlq53e&!Lh85uG zec0vJY_6e`tg7LgfrJ3k!DjR)Bi#L@DHIrZ`sK=<5O0Ip!fxGf*OgGSpP@Hbbe&$9 z;ZI}8lEoC2_7;%L2=w?tb%1oL0V+=Z`7b=P&lNGY;yVBazXRYu;+cQDKvm*7NCxu&i;zub zAJh#11%?w>E2rf2e~C4+rAb-&$^vsdACs7 z@|Ra!OfVM(ke{vyiqh7puf&Yp6cd6{DptUteYfIRWG3pI+5< zBVBI_xkBAc<(pcb$!Y%dTW(b;B;2pOI-(QCsLv@U-D1XJ z(Gk8Q3l7Ws46Aktuj>|s{$6zA&xCPuXL-kB`CgYMs}4IeyG*P51IDwW?8UNQd+$i~ zlxOPtSi5L|gJcF@DwmJA5Ju8HEJ>o{{upwIpb!f{2(vLNBw`7xMbvcw<^{Fj@E~1( z?w`iIMieunS#>nXlmUcSMU+D3rX28f?s7z;X=se6bo8;5vM|O^(D6{A9*ChnGH!RG zP##3>LDC3jZPE4PH32AxrqPk|yIIrq~`aL-=}`okhNu9aT%q z1b)7iJ)CN=V#Ly84N_r7U^SH2FGdE5FpTO2 z630TF$P>GNMu8`rOytb(lB2};`;P4YNwW1<5d3Q~AX#P0aX}R2b2)`rgkp#zTxcGj zAV^cvFbhP|JgWrq_e`~exr~sIR$6p5V?o4Wym3kQ3HA+;Pr$bQ0(PmADVO%MKL!^q z?zAM8j1l4jrq|5X+V!8S*2Wl@=7*pPgciTVK6kS1Ge zMsd_u6DFK$jTnvVtE;qa+8(1sGBu~n&F%dh(&c(Zs4Fc#A=gG^^%^AyH}1^?|8quj zl@Z47h$){PlELJgYZCIHHL= z{U8O>Tw4x3<1{?$8>k-P<}1y9DmAZP_;(3Y*{Sk^H^A=_iSJ@+s5ktgwTXz_2$~W9>VVZsfwCm@s0sQ zeB50_yu@uS+e7QoPvdCwDz{prjo(AFwR%C?z`EL{1`|coJHQTk^nX=tvs1<0arUOJ z!^`*x&&BvTYmemyZ)2p~{%eYX=JVR?DYr(rNgqRMA5E1PR1Iw=prk=L2ldy3r3Vg@27IZx43+ywyzr-X*p*d@tZV+!U#~$-q=8c zgdSuh#r?b4GhEGNai)ayHQpk>5(%j5c@C1K3(W1pb~HeHpaqijJZa-e6vq_8t-^M^ zBJxq|MqZc?pjXPIH}70a5vt!IUh;l}<>VX<-Qcv^u@5(@@M2CHSe_hD$VG-eiV^V( zj7*9T0?di?P$FaD6oo?)<)QT>Npf6Og!GO^GmPV(Km0!=+dE&bk#SNI+C9RGQ|{~O*VC+tXK3!n`5 zHfl6>lwf_aEVV3`0T!aHNZLsj$paS$=LL(?b!Czaa5bbSuZ6#$_@LK<(7yrrl+80| z{tOFd=|ta2Z`^ssozD9BINn45NxUeCQis?-BKmU*Kt=FY-NJ+)8S1ecuFtN-M?&42 zl2$G>u!iNhAk*HoJ^4v^9#ORYp5t^wDj6|lx~5w45#E5wVqI1JQ~9l?nPp1YINf++ zMAdSif~_ETv@Er(EFBI^@L4BULFW>)NI+ejHFP*T}UhWNN`I)RRS8za? z*@`1>9ZB}An%aT5K=_2iQmfE;GcBVHLF!$`I99o5GO`O%O_zLr9AG18>&^HkG(;=V z%}c!OBQ~?MX(9h~tajX{=x)+!cbM7$YzTlmsPOdp2L-?GoW`@{lY9U3f;OUo*BwRB z8A+nv(br0-SH#VxGy#ZrgnGD(=@;HME;yd46EgWJ`EL%oXc&lFpc@Y}^>G(W>h_v_ zlN!`idhX+OjL+~T?19sroAFVGfa5tX-D49w$1g2g_-T|EpHL6}K_aX4$K=LTvwtlF zL*z}j{f+Uoe7{-px3_5iKPA<_7W=>Izkk)!l9ez2w%vi(?Y;i8AxRNLSOGDzNoqoI zP!1uAl}r=_871(G?y`i&)-7{u=%nxk7CZ_Qh#!|ITec zwQn`33GTUM`;D2POWnkqngqJhJRlM>CTONzTG}>^Q0wUunQyn|TAiHzyX2_%ATx%P z%7gW)%4rA9^)M<_%k@`Y?RbC<29sWU&5;@|9thf2#zf8z12$hRcZ!CSb>kUp=4N#y zl3hE#y6>kkA8VY2`W`g5Ip?2qC_BY$>R`iGQLhz2-S>x(RuWv)SPaGdl^)gGw7tjR zH@;jwk!jIaCgSg_*9iF|a);sRUTq30(8I(obh^|}S~}P4U^BIGYqcz;MPpC~Y@k_m zaw4WG1_vz2GdCAX!$_a%GHK**@IrHSkGoN>)e}>yzUTm52on`hYot7cB=oA-h1u|R ztH$11t?54Qg2L+i33FPFKKRm1aOjKST{l1*(nps`>sv%VqeVMWjl5+Gh+9);hIP8? zA@$?}Sc z3qIRpba+y5yf{R6G(u8Z^vkg0Fu&D-7?1s=QZU`Ub{-!Y`I?AGf1VNuc^L3v>)>i# z{DV9W$)>34wnzAXUiV^ZpYKw>UElrN_5Xj6{r_3| z$X5PK`e5$7>~9Dj7gK5ash(dvs`vwfk}&RD`>04;j62zoXESkFBklYaKm5seyiX(P zqQ-;XxlV*yg?Dhlx%xt!b0N3GHp@(p$A;8|%# zZ5m2KL|{on4nr>2_s9Yh=r5ScQ0;aMF)G$-9-Ca6%wA`Pa)i?NGFA|#Yi?{X-4ZO_ z^}%7%vkzvUHa$-^Y#aA+aiR5sa%S|Ebyn`EV<3Pc?ax_f>@sBZF1S;7y$CXd5t5=WGsTKBk8$OfH4v|0?0I=Yp}7c=WBSCg!{0n)XmiU;lfx)**zZaYqmDJelxk$)nZyx5`x$6R|fz(;u zEje5Dtm|a%zK!!tk3{i9$I2b{vXNFy%Bf{50X!x{98+BsDr_u9i>G5%*sqEX|06J0 z^IY{UcEbj6LDwuMh7cH`H@9sVt1l1#8kEQ(LyT@&+K}(ReE`ux8gb0r6L_#bDUo^P z3Ka2lRo52Hdtl_%+pwVs14=q`{d^L58PsU@AMf(hENumaxM{7iAT5sYmWh@hQCO^ zK&}ijo=`VqZ#a3vE?`7QW0ZREL17ZvDfdqKGD?0D4fg{7v%|Yj&_jcKJAB)>=*RS* zto8p6@k%;&^ZF>hvXm&$PCuEp{uqw3VPG$9VMdW5$w-fy2CNNT>E;>ejBgy-m_6`& z97L1p{%srn@O_JQgFpa_#f(_)eb#YS>o>q3(*uB;uZb605(iqM$=NK{nHY=+X2*G) zO3-_Xh%aG}fHWe*==58zBwp%&`mge<8uq8;xIxOd=P%9EK!34^E9sk|(Zq1QSz-JVeP12Fp)-`F|KY$LPwUE?rku zY@OJ)Z9A!ojfzfeyJ9;zv2EM7ZQB)AR5xGa-tMn^bl)FmoIiVyJ@!~@%{}qXXD&Ns zPnfe5U+&ohKefILu_1mPfLGuapX@btta5C#gPB2cjk5m4T}Nfi+Vfka!Yd(L?-c~5 z#ZK4VeQEXNPc4r$K00Fg>g#_W!YZ)cJ?JTS<&68_$#cZT-ME`}tcwqg3#``3M3UPvn+pi}(VNNx6y zFIMVb6OwYU(2`at$gHba*qrMVUl8xk5z-z~fb@Q3Y_+aXuEKH}L+>eW__!IAd@V}L zkw#s%H0v2k5-=vh$^vPCuAi22Luu3uKTf6fPo?*nvj$9(u)4$6tvF-%IM+3pt*cgs z_?wW}J7VAA{_~!?))?s6{M=KPpVhg4fNuU*|3THp@_(q!b*hdl{fjRVFWtu^1dV(f z6iOux9hi&+UK=|%M*~|aqFK{Urfl!TA}UWY#`w(0P!KMe1Si{8|o))Gy6d7;!JQYhgMYmXl?3FfOM2nQGN@~Ap6(G z3+d_5y@=nkpKAhRqf{qQ~k7Z$v&l&@m7Ppt#FSNzKPZM z8LhihcE6i=<(#87E|Wr~HKvVWhkll4iSK$^mUHaxgy8*K$_Zj;zJ`L$naPj+^3zTi z-3NTaaKnD5FPY-~?Tq6QHnmDDRxu0mh0D|zD~Y=vv_qig5r-cIbCpxlju&8Sya)@{ zsmv6XUSi)@(?PvItkiZEeN*)AE~I_?#+Ja-r8$(XiXei2d@Hi7Rx8+rZZb?ZLa{;@*EHeRQ-YDadz~M*YCM4&F-r;E#M+@CSJMJ0oU|PQ^ z=E!HBJDMQ2TN*Y(Ag(ynAL8%^v;=~q?s4plA_hig&5Z0x_^Oab!T)@6kRN$)qEJ6E zNuQjg|G7iwU(N8pI@_6==0CL;lRh1dQF#wePhmu@hADFd3B5KIH#dx(2A zp~K&;Xw}F_N6CU~0)QpQk7s$a+LcTOj1%=WXI(U=Dv!6 z{#<#-)2+gCyyv=Jw?Ab#PVkxPDeH|sAxyG`|Ys}A$PW4TdBv%zDz z^?lwrxWR<%Vzc8Sgt|?FL6ej_*e&rhqJZ3Y>k=X(^dytycR;XDU16}Pc9Vn0>_@H+ zQ;a`GSMEG64=JRAOg%~L)x*w{2re6DVprNp+FcNra4VdNjiaF0M^*>CdPkt(m150rCue?FVdL0nFL$V%5y6N z%eLr5%YN7D06k5ji5*p4v$UMM)G??Q%RB27IvH7vYr_^3>1D-M66#MN8tWGw>WED} z5AhlsanO=STFYFs)Il_0i)l)f<8qn|$DW7ZXhf5xI;m+7M5-%P63XFQrG9>DMqHc} zsgNU9nR`b}E^mL5=@7<1_R~j@q_2U^3h|+`7YH-?C=vme1C3m`Fe0HC>pjt6f_XMh zy~-i-8R46QNYneL4t@)<0VU7({aUO?aH`z4V2+kxgH5pYD5)wCh75JqQY)jIPN=U6 z+qi8cGiOtXG2tXm;_CfpH9ESCz#i5B(42}rBJJF$jh<1sbpj^8&L;gzGHb8M{of+} zzF^8VgML2O9nxBW7AvdEt90vp+#kZxWf@A)o9f9}vKJy9NDBjBW zSt=Hcs=YWCwnfY1UYx*+msp{g!w0HC<_SM!VL1(I2PE?CS}r(eh?{I)mQixmo5^p# zV?2R!R@3GV6hwTCrfHiK#3Orj>I!GS2kYhk1S;aFBD_}u2v;0HYFq}Iz1Z(I4oca4 zxquja8$+8JW_EagDHf$a1OTk5S97umGSDaj)gH=fLs9>_=XvVj^Xj9a#gLdk=&3tl zfmK9MNnIX9v{?%xdw7568 zNrZ|roYs(vC4pHB5RJ8>)^*OuyNC>x7ad)tB_}3SgQ96+-JT^Qi<`xi=)_=$Skwv~ zdqeT9Pa`LYvCAn&rMa2aCDV(TMI#PA5g#RtV|CWpgDYRA^|55LLN^uNh*gOU>Z=a06qJ;$C9z8;n-Pq=qZnc1zUwJ@t)L;&NN+E5m zRkQ(SeM8=l-aoAKGKD>!@?mWTW&~)uF2PYUJ;tB^my`r9n|Ly~0c%diYzqs9W#FTjy?h&X3TnH zXqA{QI82sdjPO->f=^K^f>N`+B`q9&rN0bOXO79S&a9XX8zund(kW7O76f4dcWhIu zER`XSMSFbSL>b;Rp#`CuGJ&p$s~G|76){d?xSA5wVg##_O0DrmyEYppyBr%fyWbbv zp`K84JwRNP$d-pJ!Qk|(RMr?*!wi1if-9G#0p>>1QXKXWFy)eB3ai)l3601q8!9JC zvU#ZWWDNKq9g6fYs?JQ)Q4C_cgTy3FhgKb8s&m)DdmL5zhNK#8wWg!J*7G7Qhe9VU zha?^AQTDpYcuN!B+#1dE*X{<#!M%zfUQbj=zLE{dW0XeQ7-oIsGY6RbkP2re@Q{}r_$iiH0xU%iN*ST`A)-EH6eaZB$GA#v)cLi z*MpA(3bYk$oBDKAzu^kJoSUsDd|856DApz={3u8sbQV@JnRkp2nC|)m;#T=DvIL-O zI4vh;g7824l}*`_p@MT4+d`JZ2%6NQh=N9bmgJ#q!hK@_<`HQq3}Z8Ij>3%~<*= zcv=!oT#5xmeGI92lqm9sGVE%#X$ls;St|F#u!?5Y7syhx6q#MVRa&lBmmn%$C0QzU z);*ldgwwCmzM3uglr}!Z2G+?& zf%Dpo&mD%2ZcNFiN-Z0f;c_Q;A%f@>26f?{d1kxIJD}LxsQkB47SAdwinfMILZdN3 zfj^HmTzS3Ku5BxY>ANutS8WPQ-G>v4^_Qndy==P3pDm+Xc?>rUHl-4+^%Sp5atOja z2oP}ftw-rqnb}+khR3CrRg^ibi6?QYk1*i^;kQGirQ=uB9Sd1NTfT-Rbv;hqnY4neE5H1YUrjS2m+2&@uXiAo- zrKUX|Ohg7(6F(AoP~tj;NZlV#xsfo-5reuQHB$&EIAhyZk;bL;k9ouDmJNBAun;H& zn;Of1z_Qj`x&M;5X;{s~iGzBQTY^kv-k{ksbE*Dl%Qf%N@hQCfY~iUw!=F-*$cpf2 z3wix|aLBV0b;W@z^%7S{>9Z^T^fLOI68_;l@+Qzaxo`nAI8emTV@rRhEKZ z?*z_{oGdI~R*#<2{bkz$G~^Qef}$*4OYTgtL$e9q!FY7EqxJ2`zk6SQc}M(k(_MaV zSLJnTXw&@djco1~a(vhBl^&w=$fa9{Sru>7g8SHahv$&Bl(D@(Zwxo_3r=;VH|uc5 zi1Ny)J!<(KN-EcQ(xlw%PNwK8U>4$9nVOhj(y0l9X^vP1TA>r_7WtSExIOsz`nDOP zs}d>Vxb2Vo2e5x8p(n~Y5ggAyvib>d)6?)|E@{FIz?G3PVGLf7-;BxaP;c?7ddH$z zA+{~k^V=bZuXafOv!RPsE1GrR3J2TH9uB=Z67gok+u`V#}BR86hB1xl}H4v`F+mRfr zYhortD%@IGfh!JB(NUNSDh+qDz?4ztEgCz&bIG-Wg7w-ua4ChgQR_c+z8dT3<1?uX z*G(DKy_LTl*Ea!%v!RhpCXW1WJO6F`bgS-SB;Xw9#! z<*K}=#wVu9$`Yo|e!z-CPYH!nj7s9dEPr-E`DXUBu0n!xX~&|%#G=BeM?X@shQQMf zMvr2!y7p_gD5-!Lnm|a@z8Of^EKboZsTMk%5VsJEm>VsJ4W7Kv{<|#4f-qDE$D-W>gWT%z-!qXnDHhOvLk=?^a1*|0j z{pW{M0{#1VcR5;F!!fIlLVNh_Gj zbnW(_j?0c2q$EHIi@fSMR{OUKBcLr{Y&$hrM8XhPByyZaXy|dd&{hYQRJ9@Fn%h3p7*VQolBIV@Eq`=y%5BU~3RPa^$a?ixp^cCg z+}Q*X+CW9~TL29@OOng(#OAOd!)e$d%sr}^KBJ-?-X&|4HTmtemxmp?cT3uA?md4% zT8yZ0U;6Rg6JHy3fJae{6TMGS?ZUX6+gGTT{Q{)SI85$5FD{g-eR%O0KMpWPY`4@O zx!hen1*8^E(*}{m^V_?}(b5k3hYo=T+$&M32+B`}81~KKZhY;2H{7O-M@vbCzuX0n zW-&HXeyr1%I3$@ns-V1~Lb@wIpkmx|8I~ob1Of7i6BTNysEwI}=!nU%q7(V_^+d*G z7G;07m(CRTJup!`cdYi93r^+LY+`M*>aMuHJm(A8_O8C#A*$!Xvddgpjx5)?_EB*q zgE8o5O>e~9IiSC@WtZpF{4Bj2J5eZ>uUzY%TgWF7wdDE!fSQIAWCP)V{;HsU3ap?4 znRsiiDbtN7i9hapO;(|Ew>Ip2TZSvK9Z^N21%J?OiA_&eP1{(Pu_=%JjKy|HOardq ze?zK^K zA%sjF64*Wufad%H<) z^|t>e*h+Z1#l=5wHexzt9HNDNXgM=-OPWKd^5p!~%SIl>Fo&7BvNpbf8{NXmH)o{r zO=aBJ;meX1^{O%q;kqdw*5k!Y7%t_30 zy{nGRVc&5qt?dBwLs+^Sfp;f`YVMSB#C>z^a9@fpZ!xb|b-JEz1LBX7ci)V@W+kvQ89KWA0T~Lj$aCcfW#nD5bt&Y_< z-q{4ZXDqVg?|0o)j1%l0^_it0WF*LCn-+)c!2y5yS7aZIN$>0LqNnkujV*YVes(v$ zY@_-!Q;!ZyJ}Bg|G-~w@or&u0RO?vlt5*9~yeoPV_UWrO2J54b4#{D(D>jF(R88u2 zo#B^@iF_%S>{iXSol8jpmsZuJ?+;epg>k=$d`?GSegAVp3n$`GVDvK${N*#L_1`44 z{w0fL{2%)0|E+qgZtjX}itZz^KJt4Y;*8uSK}Ft38+3>j|K(PxIXXR-t4VopXo#9# zt|F{LWr-?34y`$nLBVV_*UEgA6AUI65dYIbqpNq9cl&uLJ0~L}<=ESlOm?Y-S@L*d z<7vt}`)TW#f%Rp$Q}6@3=j$7Tze@_uZO@aMn<|si{?S}~maII`VTjs&?}jQ4_cut9$)PEqMukwoXobzaKx^MV z2fQwl+;LSZ$qy%Tys0oo^K=jOw$!YwCv^ei4NBVauL)tN%=wz9M{uf{IB(BxK|lT*pFkmNK_1tV`nb%jH=a0~VNq2RCKY(rG7jz!-D^k)Ec)yS%17pE#o6&eY+ z^qN(hQT$}5F(=4lgNQhlxj?nB4N6ntUY6(?+R#B?W3hY_a*)hnr4PA|vJ<6p`K3Z5Hy z{{8(|ux~NLUW=!?9Qe&WXMTAkQnLXg(g=I@(VG3{HE13OaUT|DljyWXPs2FE@?`iU z4GQlM&Q=T<4&v@Fe<+TuXiZQT3G~vZ&^POfmI1K2h6t4eD}Gk5XFGpbj1n_g*{qmD6Xy z`6Vv|lLZtLmrnv*{Q%xxtcWVj3K4M%$bdBk_a&ar{{GWyu#ljM;dII;*jP;QH z#+^o-A4np{@|Mz+LphTD0`FTyxYq#wY)*&Ls5o{0z9yg2K+K7ZN>j1>N&;r+Z`vI| zDzG1LJZ+sE?m?>x{5LJx^)g&pGEpY=fQ-4}{x=ru;}FL$inHemOg%|R*ZXPodU}Kh zFEd5#+8rGq$Y<_?k-}r5zgQ3jRV=ooHiF|@z_#D4pKVEmn5CGV(9VKCyG|sT9nc=U zEoT67R`C->KY8Wp-fEcjjFm^;Cg(ls|*ABVHq8clBE(;~K^b+S>6uj70g? z&{XQ5U&!Z$SO7zfP+y^8XBbiu*Cv-yJG|l-oe*!s5$@Lh_KpxYL2sx`B|V=dETN>5K+C+CU~a_3cI8{vbu$TNVdGf15*>D zz@f{zIlorkY>TRh7mKuAlN9A0>N>SV`X)+bEHms=mfYTMWt_AJtz_h+JMmrgH?mZt zm=lfdF`t^J*XLg7v+iS)XZROygK=CS@CvUaJo&w2W!Wb@aa?~Drtf`JV^cCMjngVZ zv&xaIBEo8EYWuML+vxCpjjY^s1-ahXJzAV6hTw%ZIy!FjI}aJ+{rE&u#>rs)vzuxz z+$5z=7W?zH2>Eb32dvgHYZtCAf!=OLY-pb4>Ae79rd68E2LkVPj-|jFeyqtBCCwiW zkB@kO_(3wFq)7qwV}bA=zD!*@UhT`geq}ITo%@O(Z5Y80nEX~;0-8kO{oB6|(4fQh z);73T!>3@{ZobPwRv*W?7m0Ml9GmJBCJd&6E?hdj9lV= z4flNfsc(J*DyPv?RCOx!MSvk(M952PJ-G|JeVxWVjN~SNS6n-_Ge3Q;TGE;EQvZg86%wZ`MB zSMQua(i*R8a75!6$QRO^(o7sGoomb+Y{OMy;m~Oa`;P9Yqo>?bJAhqXxLr7_3g_n>f#UVtxG!^F#1+y@os6x(sg z^28bsQ@8rw%Gxk-stAEPRbv^}5sLe=VMbkc@Jjimqjvmd!3E7+QnL>|(^3!R} zD-l1l7*Amu@j+PWLGHXXaFG0Ct2Q=}5YNUxEQHCAU7gA$sSC<5OGylNnQUa>>l%sM zyu}z6i&({U@x^hln**o6r2s-(C-L50tQvz|zHTqW!ir?w&V23tuYEDJVV#5pE|OJu z7^R!A$iM$YCe?8n67l*J-okwfZ+ZTkGvZ)tVPfR;|3gyFjF)8V zyXXN=!*bpyRg9#~Bg1+UDYCt0 ztp4&?t1X0q>uz;ann$OrZs{5*r`(oNvw=$7O#rD|Wuv*wIi)4b zGtq4%BX+kkagv3F9Id6~-c+1&?zny%w5j&nk9SQfo0k4LhdSU_kWGW7axkfpgR`8* z!?UTG*Zi_baA1^0eda8S|@&F z{)Rad0kiLjB|=}XFJhD(S3ssKlveFFmkN{Vl^_nb!o5M!RC=m)V&v2%e?ZoRC@h3> zJ(?pvToFd`*Zc@HFPL#=otWKwtuuQ_dT-Hr{S%pQX<6dqVJ8;f(o)4~VM_kEQkMR+ zs1SCVi~k>M`u1u2xc}>#D!V&6nOOh-E$O&SzYrjJdZpaDv1!R-QGA141WjQe2s0J~ zQ;AXG)F+K#K8_5HVqRoRM%^EduqOnS(j2)|ctA6Q^=|s_WJYU;Z%5bHp08HPL`YF2 zR)Ad1z{zh`=sDs^&V}J z%$Z$!jd7BY5AkT?j`eqMs%!Gm@T8)4w3GYEX~IwgE~`d|@T{WYHkudy(47brgHXx& zBL1yFG6!!!VOSmDxBpefy2{L_u5yTwja&HA!mYA#wg#bc-m%~8aRR|~AvMnind@zs zy>wkShe5&*un^zvSOdlVu%kHsEo>@puMQ`b1}(|)l~E{5)f7gC=E$fP(FC2=F<^|A zxeIm?{EE!3sO!Gr7e{w)Dx(uU#3WrFZ>ibmKSQ1tY?*-Nh1TDHLe+k*;{Rp!Bmd_m zb#^kh`Y*8l|9Cz2e{;RL%_lg{#^Ar+NH|3z*Zye>!alpt{z;4dFAw^^H!6ING*EFc z_yqhr8d!;%nHX9AKhFQZBGrSzfzYCi%C!(Q5*~hX>)0N`vbhZ@N|i;_972WSx*>LH z87?en(;2_`{_JHF`Sv6Wlps;dCcj+8IJ8ca6`DsOQCMb3n# z3)_w%FuJ3>fjeOOtWyq)ag|PmgQbC-s}KRHG~enBcIwqIiGW8R8jFeBNY9|YswRY5 zjGUxdGgUD26wOpwM#8a!Nuqg68*dG@VM~SbOroL_On0N6QdT9?)NeB3@0FCC?Z|E0 z6TPZj(AsPtwCw>*{eDEE}Gby>0q{*lI+g2e&(YQrsY&uGM{O~}(oM@YWmb*F zA0^rr5~UD^qmNljq$F#ARXRZ1igP`MQx4aS6*MS;Ot(1L5jF2NJ;de!NujUYg$dr# z=TEL_zTj2@>ZZN(NYCeVX2==~=aT)R30gETO{G&GM4XN<+!&W&(WcDP%oL8PyIVUC zs5AvMgh6qr-2?^unB@mXK*Dbil^y-GTC+>&N5HkzXtozVf93m~xOUHn8`HpX=$_v2 z61H;Z1qK9o;>->tb8y%#4H)765W4E>TQ1o0PFj)uTOPEvv&}%(_mG0ISmyhnQV33Z$#&yd{ zc{>8V8XK$3u8}04CmAQ#I@XvtmB*s4t8va?-IY4@CN>;)mLb_4!&P3XSw4pA_NzDb zORn!blT-aHk1%Jpi>T~oGLuh{DB)JIGZ9KOsciWs2N7mM1JWM+lna4vkDL?Q)z_Ct z`!mi0jtr+4*L&N7jk&LodVO#6?_qRGVaucqVB8*us6i3BTa^^EI0x%EREQSXV@f!lak6Wf1cNZ8>*artIJ(ADO*=<-an`3zB4d*oO*8D1K!f z*A@P1bZCNtU=p!742MrAj%&5v%Xp_dSX@4YCw%F|%Dk=u|1BOmo)HsVz)nD5USa zR~??e61sO(;PR)iaxK{M%QM_rIua9C^4ppVS$qCT9j2%?*em?`4Z;4@>I(c%M&#cH z>4}*;ej<4cKkbCAjjDsyKS8rIm90O)Jjgyxj5^venBx&7B!xLmzxW3jhj7sR(^3Fz z84EY|p1NauwXUr;FfZjdaAfh%ivyp+^!jBjJuAaKa!yCq=?T_)R!>16?{~p)FQ3LDoMyG%hL#pR!f@P%*;#90rs_y z@9}@r1BmM-SJ#DeuqCQk=J?ixDSwL*wh|G#us;dd{H}3*-Y7Tv5m=bQJMcH+_S`zVtf;!0kt*(zwJ zs+kedTm!A}cMiM!qv(c$o5K%}Yd0|nOd0iLjus&;s0Acvoi-PFrWm?+q9f^FslxGi z6ywB`QpL$rJzWDg(4)C4+!2cLE}UPCTBLa*_=c#*$b2PWrRN46$y~yST3a2$7hEH= zNjux+wna^AzQ=KEa_5#9Ph=G1{S0#hh1L3hQ`@HrVnCx{!fw_a0N5xV(iPdKZ-HOM za)LdgK}1ww*C_>V7hbQnTzjURJL`S%`6nTHcgS+dB6b_;PY1FsrdE8(2K6FN>37!62j_cBlui{jO^$dPkGHV>pXvW0EiOA zqW`YaSUBWg_v^Y5tPJfWLcLpsA8T zG)!x>pKMpt!lv3&KV!-um= zKCir6`bEL_LCFx4Z5bAFXW$g3Cq`?Q%)3q0r852XI*Der*JNuKUZ`C{cCuu8R8nkt z%pnF>R$uY8L+D!V{s^9>IC+bmt<05h**>49R*#vpM*4i0qRB2uPbg8{{s#9yC;Z18 zD7|4m<9qneQ84uX|J&f-g8a|nFKFt34@Bt{CU`v(SYbbn95Q67*)_Esl_;v291s=9 z+#2F2apZU4Tq=x+?V}CjwD(P=U~d<=mfEFuyPB`Ey82V9G#Sk8H_Ob_RnP3s?)S_3 zr%}Pb?;lt_)Nf>@zX~D~TBr;-LS<1I##8z`;0ZCvI_QbXNh8Iv)$LS=*gHr;}dgb=w5$3k2la1keIm|=7<-JD>)U%=Avl0Vj@+&vxn zt-)`vJxJr88D&!}2^{GPXc^nmRf#}nb$4MMkBA21GzB`-Or`-3lq^O^svO7Vs~FdM zv`NvzyG+0T!P8l_&8gH|pzE{N(gv_tgDU7SWeiI-iHC#0Ai%Ixn4&nt{5y3(GQs)i z&uA;~_0shP$0Wh0VooIeyC|lak__#KVJfxa7*mYmZ22@(<^W}FdKjd*U1CqSjNKW% z*z$5$=t^+;Ui=MoDW~A7;)Mj%ibX1_p4gu>RC}Z_pl`U*{_z@+HN?AF{_W z?M_X@o%w8fgFIJ$fIzBeK=v#*`mtY$HC3tqw7q^GCT!P$I%=2N4FY7j9nG8aIm$c9 zeKTxVKN!UJ{#W)zxW|Q^K!3s;(*7Gbn;e@pQBCDS(I|Y0euK#dSQ_W^)sv5pa%<^o zyu}3d?Lx`)3-n5Sy9r#`I{+t6x%I%G(iewGbvor&I^{lhu-!#}*Q3^itvY(^UWXgvthH52zLy&T+B)Pw;5>4D6>74 zO_EBS)>l!zLTVkX@NDqyN2cXTwsUVao7$HcqV2%t$YzdAC&T)dwzExa3*kt9d(}al zA~M}=%2NVNUjZiO7c>04YH)sRelXJYpWSn^aC$|Ji|E13a^-v2MB!Nc*b+=KY7MCm zqIteKfNkONq}uM;PB?vvgQvfKLPMB8u5+Am=d#>g+o&Ysb>dX9EC8q?D$pJH!MTAqa=DS5$cb+;hEvjwVfF{4;M{5U&^_+r zvZdu_rildI!*|*A$TzJ&apQWV@p{!W`=?t(o0{?9y&vM)V)ycGSlI3`;ps(vf2PUq zX745#`cmT*ra7XECC0gKkpu2eyhFEUb?;4@X7weEnLjXj_F~?OzL1U1L0|s6M+kIhmi%`n5vvDALMagi4`wMc=JV{XiO+^ z?s9i7;GgrRW{Mx)d7rj)?(;|b-`iBNPqdwtt%32se@?w4<^KU&585_kZ=`Wy^oLu9 z?DQAh5z%q;UkP48jgMFHTf#mj?#z|=w= z(q6~17Vn}P)J3M?O)x))%a5+>TFW3No~TgP;f}K$#icBh;rSS+R|}l鯊%1Et zwk~hMkhq;MOw^Q5`7oC{CUUyTw9x>^%*FHx^qJw(LB+E0WBX@{Ghw;)6aA-KyYg8p z7XDveQOpEr;B4je@2~usI5BlFadedX^ma{b{ypd|RNYqo#~d*mj&y`^iojR}s%~vF z(H!u`yx68D1Tj(3(m;Q+Ma}s2n#;O~bcB1`lYk%Irx60&-nWIUBr2x&@}@76+*zJ5 ze&4?q8?m%L9c6h=J$WBzbiTf1Z-0Eb5$IZs>lvm$>1n_Mezp*qw_pr8<8$6f)5f<@ zyV#tzMCs51nTv_5ca`x`yfE5YA^*%O_H?;tWYdM_kHPubA%vy47i=9>Bq) zRQ&0UwLQHeswmB1yP)+BiR;S+Vc-5TX84KUA;8VY9}yEj0eESSO`7HQ4lO z4(CyA8y1G7_C;6kd4U3K-aNOK!sHE}KL_-^EDl(vB42P$2Km7$WGqNy=%fqB+ zSLdrlcbEH=T@W8V4(TgoXZ*G1_aq$K^@ek=TVhoKRjw;HyI&coln|uRr5mMOy2GXP zwr*F^Y|!Sjr2YQXX(Fp^*`Wk905K%$bd03R4(igl0&7IIm*#f`A!DCarW9$h$z`kYk9MjjqN&5-DsH@8xh63!fTNPxWsFQhNv z#|3RjnP$Thdb#Ys7M+v|>AHm0BVTw)EH}>x@_f4zca&3tXJhTZ8pO}aN?(dHo)44Z z_5j+YP=jMlFqwvf3lq!57-SAuRV2_gJ*wsR_!Y4Z(trO}0wmB9%f#jNDHPdQGHFR; zZXzS-$`;7DQ5vF~oSgP3bNV$6Z(rwo6W(U07b1n3UHqml>{=6&-4PALATsH@Bh^W? z)ob%oAPaiw{?9HfMzpGb)@Kys^J$CN{uf*HX?)z=g`J(uK1YO^8~s1(ZIbG%Et(|q z$D@_QqltVZu9Py4R0Ld8!U|#`5~^M=b>fnHthzKBRr=i+w@0Vr^l|W;=zFT#PJ?*a zbC}G#It}rQP^Ait^W&aa6B;+0gNvz4cWUMzpv(1gvfw-X4xJ2Sv;mt;zb2Tsn|kSS zo*U9N?I{=-;a-OybL4r;PolCfiaL=y@o9{%`>+&FI#D^uy#>)R@b^1ue&AKKwuI*` zx%+6r48EIX6nF4o;>)zhV_8(IEX})NGU6Vs(yslrx{5fII}o3SMHW7wGtK9oIO4OM&@@ECtXSICLcPXoS|{;=_yj>hh*%hP27yZwOmj4&Lh z*Nd@OMkd!aKReoqNOkp5cW*lC)&C$P?+H3*%8)6HcpBg&IhGP^77XPZpc%WKYLX$T zsSQ$|ntaVVOoRat$6lvZO(G-QM5s#N4j*|N_;8cc2v_k4n6zx9c1L4JL*83F-C1Cn zaJhd;>rHXB%%ZN=3_o3&Qd2YOxrK~&?1=UuN9QhL$~OY-Qyg&})#ez*8NpQW_*a&kD&ANjedxT0Ar z<6r{eaVz3`d~+N~vkMaV8{F?RBVemN(jD@S8qO~L{rUw#=2a$V(7rLE+kGUZ<%pdr z?$DP|Vg#gZ9S}w((O2NbxzQ^zTot=89!0^~hE{|c9q1hVzv0?YC5s42Yx($;hAp*E zyoGuRyphQY{Q2ee0Xx`1&lv(l-SeC$NEyS~8iil3_aNlnqF_G|;zt#F%1;J)jnPT& z@iU0S;wHJ2$f!juqEzPZeZkjcQ+Pa@eERSLKsWf=`{R@yv7AuRh&ALRTAy z8=g&nxsSJCe!QLchJ=}6|LshnXIK)SNd zRkJNiqHwKK{SO;N5m5wdL&qK`v|d?5<4!(FAsDxR>Ky#0#t$8XCMptvNo?|SY?d8b z`*8dVBlXTUanlh6n)!EHf2&PDG8sXNAt6~u-_1EjPI1|<=33T8 zEnA00E!`4Ave0d&VVh0e>)Dc}=FfAFxpsC1u9ATfQ`-Cu;mhc8Z>2;uyXtqpLb7(P zd2F9<3cXS} znMg?{&8_YFTGRQZEPU-XPq55%51}RJpw@LO_|)CFAt62-_!u_Uq$csc+7|3+TV_!h z+2a7Yh^5AA{q^m|=KSJL+w-EWDBc&I_I1vOr^}P8i?cKMhGy$CP0XKrQzCheG$}G# zuglf8*PAFO8%xop7KSwI8||liTaQ9NCAFarr~psQt)g*pC@9bORZ>m`_GA`_K@~&% zijH0z;T$fd;-Liw8%EKZas>BH8nYTqsK7F;>>@YsE=Rqo?_8}UO-S#|6~CAW0Oz1} z3F(1=+#wrBJh4H)9jTQ_$~@#9|Bc1Pd3rAIA_&vOpvvbgDJOM(yNPhJJq2%PCcMaI zrbe~toYzvkZYQ{ea(Wiyu#4WB#RRN%bMe=SOk!CbJZv^m?Flo5p{W8|0i3`hI3Np# zvCZqY%o258CI=SGb+A3yJe~JH^i{uU`#U#fvSC~rWTq+K`E%J@ zasU07&pB6A4w3b?d?q}2=0rA#SA7D`X+zg@&zm^iA*HVi z009#PUH<%lk4z~p^l0S{lCJk1Uxi=F4e_DwlfHA`X`rv(|JqWKAA5nH+u4Da+E_p+ zVmH@lg^n4ixs~*@gm_dgQ&eDmE1mnw5wBz9Yg?QdZwF|an67Xd*x!He)Gc8&2!urh z4_uXzbYz-aX)X1>&iUjGp;P1u8&7TID0bTH-jCL&Xk8b&;;6p2op_=y^m@Nq*0{#o!!A;wNAFG@0%Z9rHo zcJs?Th>Ny6+hI`+1XoU*ED$Yf@9f91m9Y=#N(HJP^Y@ZEYR6I?oM{>&Wq4|v0IB(p zqX#Z<_3X(&{H+{3Tr|sFy}~=bv+l=P;|sBz$wk-n^R`G3p0(p>p=5ahpaD7>r|>pm zv;V`_IR@tvZreIuv2EM7ZQHhO+qUgw#kOs%*ekY^n|=1#x9&c;Ro&I~{rG-#_3ZB1 z?|9}IFdbP}^DneP*T-JaoYHt~r@EfvnPE5EKUwIxjPbsr$% zfWW83pgWST7*B(o=kmo)74$8UU)v0{@4DI+ci&%=#90}!CZz|rnH+Mz=HN~97G3~@ z;v5(9_2%eca(9iu@J@aqaMS6*$TMw!S>H(b z4(*B!|H|8&EuB%mITr~O?vVEf%(Gr)6E=>H~1VR z&1YOXluJSG1!?TnT)_*YmJ*o_Q@om~(GdrhI{$Fsx_zrkupc#y{DK1WOUR>tk>ZE) ziOLoBkhZZ?0Uf}cm>GsA>Rd6V8@JF)J*EQlQ<=JD@m<)hyElXR0`pTku*3MU`HJn| zIf7$)RlK^pW-$87U;431;Ye4Ie+l~_B3*bH1>*yKzn23cH0u(i5pXV! z4K?{3oF7ZavmmtTq((wtml)m6i)8X6ot_mrE-QJCW}Yn!(3~aUHYG=^fA<^~`e3yc z-NWTb{gR;DOUcK#zPbN^D*e=2eR^_!(!RKkiwMW@@yYtEoOp4XjOGgzi`;=8 zi3`Ccw1%L*y(FDj=C7Ro-V?q)-%p?Ob2ZElu`eZ99n14-ZkEV#y5C+{Pq87Gu3&>g zFy~Wk7^6v*)4pF3@F@rE__k3ikx(hzN3@e*^0=KNA6|jC^B5nf(XaoQaZN?Xi}Rn3 z$8&m*KmWvPaUQ(V<#J+S&zO|8P-#!f%7G+n_%sXp9=J%Z4&9OkWXeuZN}ssgQ#Tcj z8p6ErJQJWZ+fXLCco=RN8D{W%+*kko*2-LEb))xcHwNl~Xmir>kmAxW?eW50Osw3# zki8Fl$#fvw*7rqd?%E?}ZX4`c5-R&w!Y0#EBbelVXSng+kUfeUiqofPehl}$ormli zg%r)}?%=?_pHb9`Cq9Z|B`L8b>(!+8HSX?`5+5mm81AFXfnAt1*R3F z%b2RPIacKAddx%JfQ8l{3U|vK@W7KB$CdLqn@wP^?azRks@x8z59#$Q*7q!KilY-P zHUbs(IFYRGG1{~@RF;Lqyho$~7^hNC`NL3kn^Td%A7dRgr_&`2k=t+}D-o9&C!y^? z6MsQ=tc3g0xkK(O%DzR9nbNB(r@L;1zQrs8mzx&4dz}?3KNYozOW5;=w18U6$G4U2 z#2^qRLT*Mo4bV1Oeo1PKQ2WQS2Y-hv&S|C7`xh6=Pj7MNLC5K-zokZ67S)C;(F0Dd zloDK2_o1$Fmza>EMj3X9je7e%Q`$39Dk~GoOj89-6q9|_WJlSl!!+*{R=tGp z8u|MuSwm^t7K^nUe+^0G3dkGZr3@(X+TL5eah)K^Tn zXEtHmR9UIaEYgD5Nhh(s*fcG_lh-mfy5iUF3xxpRZ0q3nZ=1qAtUa?(LnT9I&~uxX z`pV?+=|-Gl(kz?w!zIieXT}o}7@`QO>;u$Z!QB${a08_bW0_o@&9cjJUXzVyNGCm8 zm=W+$H!;_Kzp6WQqxUI;JlPY&`V}9C$8HZ^m?NvI*JT@~BM=()T()Ii#+*$y@lTZBkmMMda>7s#O(1YZR+zTG@&}!EXFG{ zEWPSDI5bFi;NT>Yj*FjH((=oe%t%xYmE~AGaOc4#9K_XsVpl<4SP@E!TgC0qpe1oi zNpxU2b0(lEMcoibQ-G^cxO?ySVW26HoBNa;n0}CWL*{k)oBu1>F18X061$SP{Gu67 z-v-Fa=Fl^u3lnGY^o5v)Bux}bNZ~ z5pL+7F_Esoun8^5>z8NFoIdb$sNS&xT8_|`GTe8zSXQzs4r^g0kZjg(b0bJvz`g<70u9Z3fQILX1Lj@;@+##bP|FAOl)U^9U>0rx zGi)M1(Hce)LAvQO-pW!MN$;#ZMX?VE(22lTlJrk#pB0FJNqVwC+*%${Gt#r_tH9I_ z;+#)#8cWAl?d@R+O+}@1A^hAR1s3UcW{G+>;X4utD2d9X(jF555}!TVN-hByV6t+A zdFR^aE@GNNgSxxixS2p=on4(+*+f<8xrwAObC)D5)4!z7)}mTpb7&ofF3u&9&wPS< zB62WHLGMhmrmOAgmJ+|c>qEWTD#jd~lHNgT0?t-p{T=~#EMcB| z=AoDKOL+qXCfk~F)-Rv**V}}gWFl>liXOl7Uec_8v)(S#av99PX1sQIVZ9eNLkhq$ zt|qu0b?GW_uo}TbU8!jYn8iJeIP)r@;!Ze_7mj{AUV$GEz6bDSDO=D!&C9!M@*S2! zfGyA|EPlXGMjkH6x7OMF?gKL7{GvGfED=Jte^p=91FpCu)#{whAMw`vSLa`K#atdN zThnL+7!ZNmP{rc=Z>%$meH;Qi1=m1E3Lq2D_O1-X5C;!I0L>zur@tPAC9*7Jeh)`;eec}1`nkRP(%iv-`N zZ@ip-g|7l6Hz%j%gcAM}6-nrC8oA$BkOTz^?dakvX?`^=ZkYh%vUE z9+&)K1UTK=ahYiaNn&G5nHUY5niLGus@p5E2@RwZufRvF{@$hW{;{3QhjvEHMvduO z#Wf-@oYU4ht?#uP{N3utVzV49mEc9>*TV_W2TVC`6+oI)zAjy$KJrr=*q##&kobiQ z1vNbya&OVjK`2pdRrM?LuK6BgrLN7H_3m z!qpNKg~87XgCwb#I=Q&0rI*l$wM!qTkXrx1ko5q-f;=R2fImRMwt5Qs{P*p^z@9ex z`2#v(qE&F%MXlHpdO#QEZyZftn4f05ab^f2vjxuFaat2}jke{j?5GrF=WYBR?gS(^ z9SBiNi}anzBDBRc+QqizTTQuJrzm^bNA~A{j%ugXP7McZqJ}65l10({wk++$=e8O{ zxWjG!Qp#5OmI#XRQQM?n6?1ztl6^D40hDJr?4$Wc&O_{*OfMfxe)V0=e{|N?J#fgE>j9jAajze$iN!*yeF%jJU#G1c@@rm zolGW!j?W6Q8pP=lkctNFdfgUMg92wlM4E$aks1??M$~WQfzzzXtS)wKrr2sJeCN4X zY(X^H_c^PzfcO8Bq(Q*p4c_v@F$Y8cHLrH$`pJ2}=#*8%JYdqsqnGqEdBQMpl!Ot04tUGSXTQdsX&GDtjbWD=prcCT9(+ z&UM%lW%Q3yrl1yiYs;LxzIy>2G}EPY6|sBhL&X&RAQrSAV4Tlh2nITR?{6xO9ujGu zr*)^E`>o!c=gT*_@6S&>0POxcXYNQd&HMw6<|#{eSute2C3{&h?Ah|cw56-AP^f8l zT^kvZY$YiH8j)sk7_=;gx)vx-PW`hbSBXJGCTkpt;ap(}G2GY=2bbjABU5)ty%G#x zAi07{Bjhv}>OD#5zh#$0w;-vvC@^}F! z#X$@)zIs1L^E;2xDAwEjaXhTBw2<{&JkF*`;c3<1U@A4MaLPe{M5DGGkL}#{cHL%* zYMG+-Fm0#qzPL#V)TvQVI|?_M>=zVJr9>(6ib*#z8q@mYKXDP`k&A4A};xMK0h=yrMp~JW{L?mE~ph&1Y1a#4%SO)@{ zK2juwynUOC)U*hVlJU17%llUxAJFuKZh3K0gU`aP)pc~bE~mM!i1mi!~LTf>1Wp< zuG+ahp^gH8g8-M$u{HUWh0m^9Rg@cQ{&DAO{PTMudV6c?ka7+AO& z746QylZ&Oj`1aqfu?l&zGtJnpEQOt;OAFq19MXTcI~`ZcoZmyMrIKDFRIDi`FH)w; z8+*8tdevMDv*VtQi|e}CnB_JWs>fhLOH-+Os2Lh!&)Oh2utl{*AwR)QVLS49iTp{6 z;|172Jl!Ml17unF+pd+Ff@jIE-{Oxv)5|pOm@CkHW?{l}b@1>Pe!l}VccX#xp@xgJ zyE<&ep$=*vT=}7vtvif0B?9xw_3Gej7mN*dOHdQPtW5kA5_zGD zpA4tV2*0E^OUimSsV#?Tg#oiQ>%4D@1F5@AHwT8Kgen$bSMHD3sXCkq8^(uo7CWk`mT zuslYq`6Yz;L%wJh$3l1%SZv#QnG3=NZ=BK4yzk#HAPbqXa92;3K5?0kn4TQ`%E%X} z&>Lbt!!QclYKd6+J7Nl@xv!uD%)*bY-;p`y^ZCC<%LEHUi$l5biu!sT3TGGSTPA21 zT8@B&a0lJHVn1I$I3I1I{W9fJAYc+8 zVj8>HvD}&O`TqU2AAb={?eT;0hyL(R{|h23=4fDSZKC32;wWxsVj`P z3J3{M$PwdH!ro*Cn!D&=jnFR>BNGR<<|I8CI@+@658Dy(lhqbhXfPTVecY@L8%`3Q z1Fux2w?2C3th60jI~%OC9BtpNF$QPqcG+Pz96qZJ71_`0o0w_q7|h&O>`6U+^BA&5 zXd5Zp1Xkw~>M%RixTm&OqpNl8Q+ue=92Op_>T~_9UON?ZM2c0aGm=^A4ejrXj3dV9 zhh_bCt-b9`uOX#cFLj!vhZ#lS8Tc47OH>*)y#{O9?AT~KR9LntM|#l#Dlm^8{nZdk zjMl#>ZM%#^nK2TPzLcKxqx24P7R1FPlBy7LSBrRvx>fE$9AJ;7{PQm~^LBX^k#6Zq zw*Z(zJC|`!6_)EFR}8|n8&&Rbj8y028~P~sFXBFRt+tmqH-S3<%N;C&WGH!f3{7cm zy_fCAb9@HqaXa1Y5vFbxWf%#zg6SI$C+Uz5=CTO}e|2fjWkZ;Dx|84Ow~bkI=LW+U zuq;KSv9VMboRvs9)}2PAO|b(JCEC_A0wq{uEj|3x@}*=bOd zwr{TgeCGG>HT<@Zeq8y}vTpwDg#UBvD)BEs@1KP$^3$sh&_joQPn{hjBXmLPJ{tC) z*HS`*2+VtJO{|e$mM^|qv1R*8i(m1`%)}g=SU#T#0KlTM2RSvYUc1fP+va|4;5}Bfz98UvDCpq7}+SMV&;nX zQw~N6qOX{P55{#LQkrZk(e5YGzr|(B;Q;ju;2a`q+S9bsEH@i1{_Y0;hWYn1-79jl z5c&bytD*k)GqrVcHn6t-7kinadiD>B{Tl`ZY@`g|b~pvHh5!gKP4({rp?D0aFd_cN zhHRo4dd5^S6ViN(>(28qZT6E>??aRhc($kP`>@<+lIKS5HdhjVU;>f7<4))E*5|g{ z&d1}D|vpuV^eRj5j|xx9nwaCxXFG?Qbjn~_WSy=N}P0W>MP zG-F%70lX5Xr$a)2i6?i|iMyM|;Jtf*hO?=Jxj12oz&>P=1#h~lf%#fc73M2_(SUM- zf&qnjS80|_Y0lDgl&I?*eMumUklLe_=Td!9G@eR*tcPOgIShJipp3{A10u(4eT~DY zHezEj8V+7m!knn7)W!-5QI3=IvC^as5+TW1@Ern@yX| z7Nn~xVx&fGSr+L%4iohtS3w^{-H1A_5=r&x8}R!YZvp<2T^YFvj8G_vm}5q;^UOJf ztl=X3iL;;^^a#`t{Ae-%5Oq{?M#s6Npj+L(n-*LMI-yMR{)qki!~{5z{&`-iL}lgW zxo+tnvICK=lImjV$Z|O_cYj_PlEYCzu-XBz&XC-JVxUh9;6*z4fuBG+H{voCC;`~GYV|hj%j_&I zDZCj>Q_0RCwFauYoVMiUSB+*Mx`tg)bWmM^SwMA+?lBg12QUF_x2b)b?qb88K-YUd z0dO}3k#QirBV<5%jL$#wlf!60dizu;tsp(7XLdI=eQs?P`tOZYMjVq&jE)qK*6B^$ zBe>VvH5TO>s>izhwJJ$<`a8fakTL!yM^Zfr2hV9`f}}VVUXK39p@G|xYRz{fTI+Yq z20d=)iwjuG9RB$%$^&8#(c0_j0t_C~^|n+c`Apu|x7~;#cS-s=X1|C*YxX3ailhg_|0`g!E&GZJEr?bh#Tpb8siR=JxWKc{#w7g zWznLwi;zLFmM1g8V5-P#RsM@iX>TK$xsWuujcsVR^7TQ@!+vCD<>Bk9tdCo7Mzgq5 zv8d>dK9x8C@Qoh01u@3h0X_`SZluTb@5o;{4{{eF!-4405x8X7hewZWpz z2qEi4UTiXTvsa(0X7kQH{3VMF>W|6;6iTrrYD2fMggFA&-CBEfSqPlQDxqsa>{e2M z(R5PJ7uOooFc|9GU0ELA%m4&4Ja#cQpNw8i8ACAoK6?-px+oBl_yKmenZut#Xumjz zk8p^OV2KY&?5MUwGrBOo?ki`Sxo#?-Q4gw*Sh0k`@ zFTaYK2;}%Zk-68`#5DXU$2#=%YL#S&MTN8bF+!J2VT6x^XBci6O)Q#JfW{YMz) zOBM>t2rSj)n#0a3cjvu}r|k3od6W(SN}V-cL?bi*Iz-8uOcCcsX0L>ZXjLqk zZu2uHq5B|Kt>e+=pPKu=1P@1r9WLgYFq_TNV1p9pu0erHGd!+bBp!qGi+~4A(RsYN@CyXNrC&hxGmW)u5m35OmWwX`I+0yByglO`}HC4nGE^_HUs^&A(uaM zKPj^=qI{&ayOq#z=p&pnx@@k&I1JI>cttJcu@Ihljt?6p^6{|ds`0MoQwp+I{3l6` zB<9S((RpLG^>=Kic`1LnhpW2=Gu!x`m~=y;A`Qk!-w`IN;S8S930#vBVMv2vCKi}u z6<-VPrU0AnE&vzwV(CFC0gnZYcpa-l5T0ZS$P6(?9AM;`Aj~XDvt;Jua=jIgF=Fm? zdp=M$>`phx%+Gu};;-&7T|B1AcC#L4@mW5SV_^1BRbo6;2PWe$r+npRV`yc;T1mo& z+~_?7rA+(Um&o@Tddl zL_hxvWk~a)yY}%j`Y+200D%9$bWHy&;(yj{jpi?Rtz{J66ANw)UyPOm;t6FzY3$hx zcn)Ir79nhFvNa7^a{SHN7XH*|Vlsx`CddPnA&Qvh8aNhEA;mPVv;Ah=k<*u!Zq^7 z<=xs*iQTQOMMcg|(NA_auh@x`3#_LFt=)}%SQppP{E>mu_LgquAWvh<>L7tf9+~rO znwUDS52u)OtY<~!d$;m9+87aO+&`#2ICl@Y>&F{jI=H(K+@3M1$rr=*H^dye#~TyD z!){#Pyfn+|ugUu}G;a~!&&0aqQ59U@UT3|_JuBlYUpT$2+11;}JBJ`{+lQN9T@QFY z5+`t;6(TS0F?OlBTE!@7D`8#URDNqx2t6`GZ{ZgXeS@v%-eJzZOHz18aS|svxII$a zZeFjrJ*$IwX$f-Rzr_G>xbu@euGl)B7pC&S+CmDJBg$BoV~jxSO#>y z33`bupN#LDoW0feZe0%q8un0rYN|eRAnwDHQ6e_)xBTbtoZtTA=Fvk){q}9Os~6mQ zKB80VI_&6iSq`LnK7*kfHZoeX6?WE}8yjuDn=2#JG$+;-TOA1%^=DnXx%w{b=w}tS zQbU3XxtOI8E(!%`64r2`zog;5<0b4i)xBmGP^jiDZ2%HNSxIf3@wKs~uk4%3Mxz;~ zts_S~E4>W+YwI<-*-$U8*^HKDEa8oLbmqGg?3vewnaNg%Mm)W=)lcC_J+1ov^u*N3 zXJ?!BrH-+wGYziJq2Y#vyry6Z>NPgkEk+Ke`^DvNRdb>Q2Nlr#v%O@<5hbflI6EKE z9dWc0-ORk^T}jP!nkJ1imyjdVX@GrjOs%cpgA8-c&FH&$(4od#x6Y&=LiJZPINVyW z0snY$8JW@>tc2}DlrD3StQmA0Twck~@>8dSix9CyQOALcREdxoM$Sw*l!}bXKq9&r zysMWR@%OY24@e`?+#xV2bk{T^C_xSo8v2ZI=lBI*l{RciPwuE>L5@uhz@{!l)rtVlWC>)6(G)1~n=Q|S!{E9~6*fdpa*n z!()-8EpTdj=zr_Lswi;#{TxbtH$8*G=UM`I+icz7sr_SdnHXrv=?iEOF1UL+*6O;% zPw>t^kbW9X@oEXx<97%lBm-9?O_7L!DeD)Me#rwE54t~UBu9VZ zl_I1tBB~>jm@bw0Aljz8! zXBB6ATG6iByKIxs!qr%pz%wgqbg(l{65DP4#v(vqhhL{0b#0C8mq`bnqZ1OwFV z7mlZZJFMACm>h9v^2J9+^_zc1=JjL#qM5ZHaThH&n zXPTsR8(+)cj&>Un{6v*z?@VTLr{TmZ@-fY%*o2G}*G}#!bmqpoo*Ay@U!JI^Q@7gj;Kg-HIrLj4}#ec4~D2~X6vo;ghep-@&yOivYP zC19L0D`jjKy1Yi-SGPAn94(768Tcf$urAf{)1)9W58P`6MA{YG%O?|07!g9(b`8PXG1B1Sh0?HQmeJtP0M$O$hI z{5G`&9XzYhh|y@qsF1GnHN|~^ru~HVf#)lOTSrv=S@DyR$UKQk zjdEPFDz{uHM&UM;=mG!xKvp;xAGHOBo~>_=WFTmh$chpC7c`~7?36h)7$fF~Ii}8q zF|YXxH-Z?d+Q+27Rs3X9S&K3N+)OBxMHn1u(vlrUC6ckBY@@jl+mgr#KQUKo#VeFm zFwNYgv0<%~Wn}KeLeD9e1$S>jhOq&(e*I@L<=I5b(?G(zpqI*WBqf|Zge0&aoDUsC zngMRA_Kt0>La+Erl=Uv_J^p(z=!?XHpenzn$%EA`JIq#yYF?JLDMYiPfM(&Csr#f{ zdd+LJL1by?xz|D8+(fgzRs~(N1k9DSyK@LJygwaYX8dZl0W!I&c^K?7)z{2is;OkE zd$VK-(uH#AUaZrp=1z;O*n=b?QJkxu`Xsw&7yrX0?(CX=I-C#T;yi8a<{E~?vr3W> zQrpPqOW2M+AnZ&p{hqmHZU-;Q(7?- zP8L|Q0RM~sB0w1w53f&Kd*y}ofx@c z5Y6B8qGel+uT1JMot$nT1!Tim6{>oZzJXdyA+4euOLME?5Fd_85Uk%#E*ln%y{u8Q z$|?|R@Hpb~yTVK-Yr_S#%NUy7EBfYGAg>b({J|5b+j-PBpPy$Ns`PaJin4JdRfOaS zE|<HjH%NuJgsd2wOlv>~y=np%=2)$M9LS|>P)zJ+Fei5vYo_N~B0XCn+GM76 z)Xz3tg*FRVFgIl9zpESgdpWAavvVViGlU8|UFY{{gVJskg*I!ZjWyk~OW-Td4(mZ6 zB&SQreAAMqwp}rjy`HsG({l2&q5Y52<@AULVAu~rWI$UbFuZs>Sc*x+XI<+ez%$U)|a^unjpiW0l0 zj1!K0(b6$8LOjzRqQ~K&dfbMIE=TF}XFAi)$+h}5SD3lo z%%Qd>p9se=VtQG{kQ;N`sI)G^u|DN#7{aoEd zkksYP%_X$Rq08);-s6o>CGJ<}v`qs%eYf+J%DQ^2k68C%nvikRsN?$ap--f+vCS`K z#&~)f7!N^;sdUXu54gl3L=LN>FB^tuK=y2e#|hWiWUls__n@L|>xH{%8lIJTd5`w? zSwZbnS;W~DawT4OwSJVdAylbY+u5S+ZH{4hAi2&}Iv~W(UvHg(1GTZRPz`@{SOqzy z(8g&Dz=$PfRV=6FgxN~zo+G8OoPI&d-thcGVR*_^(R8COTM@bq?fDwY{}WhsQS1AK zF6R1t8!RdFmfocpJ6?9Yv~;WYi~XPgs(|>{5})j!AR!voO7y9&cMPo#80A(`za@t>cx<0;qxM@S*m(jYP)dMXr*?q0E`oL;12}VAep179uEr8c<=D zr5?A*C{eJ`z9Ee;E$8)MECqatHkbHH z&Y+ho0B$31MIB-xm&;xyaFCtg<{m~M-QDbY)fQ>Q*Xibb~8ytxZQ?QMf9!%cV zU0_X1@b4d+Pg#R!`OJ~DOrQz3@cpiGy~XSKjZQQ|^4J1puvwKeScrH8o{bscBsowomu z^f12kTvje`yEI3eEXDHJ6L+O{Jv$HVj%IKb|J{IvD*l6IG8WUgDJ*UGz z3!C%>?=dlfSJ>4U88)V+`U-!9r^@AxJBx8R;)J4Fn@`~k>8>v0M9xp90OJElWP&R5 zM#v*vtT}*Gm1^)Bv!s72T3PB0yVIjJW)H7a)ilkAvoaH?)jjb`MP>2z{%Y?}83 zUIwBKn`-MSg)=?R)1Q0z3b>dHE^)D8LFs}6ASG1|daDly_^lOSy&zIIhm*HXm1?VS=_iacG);_I9c zUQH1>i#*?oPIwBMJkzi_*>HoUe}_4o>2(SHWzqQ=;TyhAHS;Enr7!#8;sdlty&(>d zl%5cjri8`2X^Ds`jnw7>A`X|bl=U8n+3LKLy(1dAu8`g@9=5iw$R0qk)w8Vh_Dt^U zIglK}sn^)W7aB(Q>HvrX=rxB z+*L)3DiqpQ_%~|m=44LcD4-bxO3OO*LPjsh%p(k?&jvLp0py57oMH|*IMa(<|{m1(0S|x)?R-mqJ=I;_YUZA>J z62v*eSK;5w!h8J+6Z2~oyGdZ68waWfy09?4fU&m7%u~zi?YPHPgK6LDwphgaYu%0j zurtw)AYOpYKgHBrkX189mlJ`q)w-f|6>IER{5Lk97%P~a-JyCRFjejW@L>n4vt6#hq;!|m;hNE||LK3nw1{bJOy+eBJjK=QqNjI;Q6;Rp5 z&035pZDUZ#%Oa;&_7x0T<7!RW`#YBOj}F380Bq?MjjEhrvlCATPdkCTTl+2efTX$k zH&0zR1n^`C3ef~^sXzJK-)52(T}uTG%OF8yDhT76L~|^+hZ2hiSM*QA9*D5odI1>& z9kV9jC~twA5MwyOx(lsGD_ggYmztXPD`2=_V|ks_FOx!_J8!zM zTzh^cc+=VNZ&(OdN=y4Juw)@8-85lwf_#VMN!Ed(eQiRiLB2^2e`4dp286h@v@`O%_b)Y~A; zv}r6U?zs&@uD_+(_4bwoy7*uozNvp?bXFoB8?l8yG0qsm1JYzIvB_OH4_2G*IIOwT zVl%HX1562vLVcxM_RG*~w_`FbIc!(T=3>r528#%mwwMK}uEhJ()3MEby zQQjzqjWkwfI~;Fuj(Lj=Ug0y`>~C7`w&wzjK(rPw+Hpd~EvQ-ufQOiB4OMpyUKJhw zqEt~jle9d7S~LI~$6Z->J~QJ{Vdn3!c}g9}*KG^Kzr^(7VI5Gk(mHLL{itj_hG?&K4Ws0+T4gLfi3eu$N=`s36geNC?c zm!~}vG6lx9Uf^5M;bWntF<-{p^bruy~f?sk9 zcETAPQZLoJ8JzMMg<-=ju4keY@SY%Wo?u9Gx=j&dfa6LIAB|IrbORLV1-H==Z1zCM zeZcOYpm5>U2fU7V*h;%n`8 zN95QhfD994={1*<2vKLCNF)feKOGk`R#K~G=;rfq}|)s20&MCa65 zUM?xF5!&e0lF%|U!#rD@I{~OsS_?=;s_MQ_b_s=PuWdC)q|UQ&ea)DMRh5>fpQjXe z%9#*x=7{iRCtBKT#H>#v%>77|{4_slZ)XCY{s3j_r{tdpvb#|r|sbS^dU1x70$eJMU!h{Y7Kd{dl}9&vxQl6Jt1a` zHQZrWyY0?!vqf@u-fxU_@+}u(%Wm>0I#KP48tiAPYY!TdW(o|KtVI|EUB9V`CBBNaBLVih7+yMVF|GSoIQD0Jfb{ z!OXq;(>Z?O`1gap(L~bUcp>Lc@Jl-})^=6P%<~~9ywY=$iu8pJ0m*hOPzr~q`23eX zgbs;VOxxENe0UMVeN*>uCn9Gk!4siN-e>x)pIKAbQz!G)TcqIJ0`JBBaX>1-4_XO_-HCS^vr2vjv#7KltDZdyQ{tlWh4$Gm zB>|O1cBDC)yG(sbnc*@w6e%e}r*|IhpXckx&;sQCwGdKH+3oSG-2)Bf#x`@<4ETAr z0My%7RFh6ZLiZ_;X6Mu1YmXx7C$lSZ^}1h;j`EZd6@%JNUe=btBE z%s=Xmo1Ps?8G`}9+6>iaB8bgjUdXT?=trMu|4yLX^m0Dg{m7rpKNJey|EwHI+nN1e zL^>qN%5Fg)dGs4DO~uwIdXImN)QJ*Jhpj7$fq_^`{3fwpztL@WBB}OwQ#Epo-mqMO zsM$UgpFiG&d#)lzEQ{3Q;)&zTw;SzGOah-Dpm{!q7<8*)Ti_;xvV2TYXa}=faXZy? z3y?~GY@kl)>G&EvEijk9y1S`*=zBJSB1iet>0;x1Ai)*`^{pj0JMs)KAM=@UyOGtO z3y0BouW$N&TnwU6!%zS%nIrnANvZF&vB1~P5_d`x-giHuG zPJ;>XkVoghm#kZXRf>qxxEix;2;D1CC~NrbO6NBX!`&_$iXwP~P*c($EVV|669kDO zKoTLZNF4Cskh!Jz5ga9uZ`3o%7Pv`d^;a=cXI|>y;zC3rYPFLQkF*nv(r>SQvD*## z(Vo%^9g`%XwS0t#94zPq;mYGLKu4LU3;txF26?V~A0xZbU4Lmy`)>SoQX^m7fd^*E z+%{R4eN!rIk~K)M&UEzxp9dbY;_I^c} zOc{wlIrN_P(PPqi51k_$>Lt|X6A^|CGYgKAmoI#Li?;Wq%q~q*L7ehZkUrMxW67Jl zhsb~+U?33QS>eqyN{(odAkbopo=Q$Az?L+NZW>j;#~@wCDX?=L5SI|OxI~7!Pli;e zELMFcZtJY3!|=Gr2L4>z8yQ-{To>(f80*#;6`4IAiqUw`=Pg$%C?#1 z_g@hIGerILSU>=P>z{gM|DS91A4cT@PEIB^hSop!uhMo#2G;+tQSpDO_6nOnPWSLU zS;a9m^DFMXR4?*X=}d7l;nXuHk&0|m`NQn%d?8|Ab3A9l9Jh5s120ibWBdB z$5YwsK3;wvp!Kn@)Qae{ef`0#NwlRpQ}k^r>yos_Ne1;xyKLO?4)t_G4eK~wkUS2A&@_;)K0-03XGBzU+5f+uMDxC z(s8!8!RvdC#@`~fx$r)TKdLD6fWEVdEYtV#{ncT-ZMX~eI#UeQ-+H(Z43vVn%Yj9X zLdu9>o%wnWdvzA-#d6Z~vzj-}V3FQ5;axDIZ;i(95IIU=GQ4WuU{tl-{gk!5{l4_d zvvb&uE{%!iFwpymz{wh?bKr1*qzeZb5f6e6m_ozRF&zux2mlK=v_(_s^R6b5lu?_W4W3#<$zeG~Pd)^!4tzhs}-Sx$FJP>)ZGF(hVTH|C3(U zs0PO&*h_ zNA-&qZpTP$$LtIgfiCn07}XDbK#HIXdmv8zdz4TY;ifNIH-0jy(gMSByG2EF~Th#eb_TueZC` zE?3I>UTMpKQ})=C;6p!?G)M6w^u*A57bD?2X`m3X^6;&4%i_m(uGJ3Z5h`nwxM<)H z$I5m?wN>O~8`BGnZ=y^p6;0+%_0K}Dcg|K;+fEi|qoBqvHj(M&aHGqNF48~XqhtU? z^ogwBzRlOfpAJ+Rw7IED8lRbTdBdyEK$gPUpUG}j-M42xDj_&qEAQEtbs>D#dRd7Y z<&TpSZ(quQDHiCFn&0xsrz~4`4tz!CdL8m~HxZM_agu@IrBpyeL1Ft}V$HX_ZqDPm z-f89)pjuEzGdq-PRu`b1m+qBGY{zr_>{6Ss>F|xHZlJj9dt5HD$u`1*WZe)qEIuDSR)%z+|n zatVlhQ?$w#XRS7xUrFE;Y8vMGhQS5*T{ZnY=q1P?w5g$OKJ#M&e??tAmPWHMj3xhS ziGxapy?kn@$~2%ZY;M8Bc@%$pkl%Rvj!?o%agBvpQ-Q61n9kznC4ttrRNQ4%GFR5u zyv%Yo9~yxQJWJSfj z?#HY$y=O~F|2pZs22pu|_&Ajd+D(Mt!nPUG{|1nlvP`=R#kKH zO*s$r_%ss5h1YO7k0bHJ2CXN)Yd6CHn~W!R=SqkWe=&nAZu(Q1G!xgcUilM@YVei@2@a`8he z9@pM`)VB*=e7-MWgLlXlc)t;fF&-AwM{E-EX}pViFn0I0CNw2bNEnN2dj!^4(^zS3 zobUm1uQnpqk_4q{pl*n06=TfK_C>UgurKFjRXsK_LEn};=79`TB12tv6KzwSu*-C8 z;=~ohDLZylHQ|Mpx-?yql>|e=vI1Z!epyUpAcDCp4T|*RV&X`Q$0ogNwy6mFALo^@ z9=&(9txO8V@E!@6^(W0{*~CT>+-MA~vnJULBxCTUW>X5>r7*eXYUT0B6+w@lzw%n> z_VjJ<2qf|(d6jYq2(x$(ZDf!yVkfnbvNmb5c|hhZ^2TV_LBz`9w!e_V*W_(MiA7|= z&EeIIkw*+$Xd!)j8<@_<}A5;~A_>3JT*kX^@}cDoLd>Qj<`Se^wdUa(j0dp+Tl8EptwBm{9OGsdFEq zM`!pjf(Lm(`$e3FLOjqA5LnN5o!}z{ zNf}rJuZh@yUtq&ErjHeGzX4(!luV!jB&;FAP|!R_QHYw#^Z1LwTePAKJ6X&IDNO#; z)#I@Xnnzyij~C@UH~X51JCgQeF0&hTXnuoElz#m{heZRexWc0k4<>0+ClX7%0 zEBqCCld1tD9Zwkr4{?Nor19#E5-YKfB8d?qgR82-Ow2^AuNevly2*tHA|sK!ybYkX zm-sLQH72P&{vEAW6+z~O5d0qd=xW~rua~5a?ymYFSD@8&gV)E5@RNNBAj^C99+Z5Z zR@Pq55mbCQbz+Mn$d_CMW<-+?TU960agEk1J<>d>0K=pF19yN))a~4>m^G&tc*xR+yMD*S=yip-q=H zIlredHpsJV8H(32@Zxc@bX6a21dUV95Th--8pE6C&3F>pk=yv$yd6@Haw;$v4+Fcb zRwn{Qo@0`7aPa2LQOP}j9v>sjOo5Kqvn|`FLizX zB+@-u4Lw|jsvz{p^>n8Vo8H2peIqJJnMN}A)q6%$Tmig7eu^}K2 zrh$X?T|ZMsoh{6pdw1G$_T<`Ds-G=jc;qcGdK4{?dN2-XxjDNbb(7pk|3JUVCU4y; z)?LXR>f+AAu)JEiti_Zy#z5{RgsC}R(@jl%9YZ>zu~hKQ*AxbvhC378-I@{~#%Y`Z zy=a=9YpewPIC+gkEUUwtUL7|RU7=!^Aa}Mk^6uxOgRGA#JXjWLsjFUnix|Mau{hDT z7mn*z1m5g`vP(#tjT0Zy4eAY(br&!RiiXE=ZI!{sE1#^#%x^Z7t1U)b<;%Y}Q9=5v z;wpDCEZ@OE36TWT=|gxigT@VaW9BvHS05;_P(#s z8zI4XFQys}q)<`tkX$WnSarn{3e!s}4(J!=Yf>+Y>cP3f;vr63f2{|S^`_pWc)^5_!R z*(x-fuBxL51@xe!lnDBKi}Br$c$BMZ3%f2Sa6kLabiBS{pq*yj;q|k(86x`PiC{p6 z_bxCW{>Q2BA8~Ggz&0jkrcU+-$ANBsOop*ms>34K9lNYil@}jC;?cYP(m^P}nR6FV zk(M%48Z&%2Rx$A&FhOEirEhY0(dn;-k(qkTU)sFQ`+-ih+s@A8g?r8Pw+}2;35WYf zi}VO`jS`p(tc)$X$a>-#WXoW!phhatC*$}|rk>|wUU71eUJG^$c6_jwX?iSHM@6__ zvV|6%U*$sSXJu9SX?2%M^kK|}a2QJ8AhF{fuXrHZxXsI~O zGKX45!K7p*MCPEQ=gp?eu&#AW*pR{lhQR##P_*{c_DjMGL|3T3-bSJ(o$|M{ytU}> zAV>wq*uE*qFo9KvnA^@juy{x<-u*#2NvkV={Ly}ysKYB-k`K3@K#^S1Bb$8Y#0L0# z`6IkSG&|Z$ODy|VLS+y5pFJx&8tvPmMd8c9FhCyiU8~k6FwkakUd^(_ml8`rnl>JS zZV){9G*)xBqPz^LDqRwyS6w86#D^~xP4($150M)SOZRe9sn=>V#aG0Iy(_^YcPpIz8QYM-#s+n% z@Jd?xQq?Xk6=<3xSY7XYP$$yd&Spu{A#uafiIfy8gRC`o0nk{ezEDjb=q_qRAlR1d zFq^*9Gn)yTG4b}R{!+3hWQ+u3GT~8nwl2S1lpw`s0X_qpxv)g+JIkVKl${sYf_nV~B>Em>M;RlqGb5WVil(89 zs=ld@|#;dq1*vQGz=7--Br-|l) zZ%Xh@v8>B7P?~}?Cg$q9_={59l%m~O&*a6TKsCMAzG&vD>k2WDzJ6!tc!V)+oxF;h zJH;apM=wO?r_+*#;ulohuP=E>^zon}a$NnlcQ{1$SO*i=jnGVcQa^>QOILc)e6;eNTI>os=eaJ{*^DE+~jc zS}TYeOykDmJ=6O%>m`i*>&pO_S;qMySJIyP=}4E&J%#1zju$RpVAkZbEl+p%?ZP^C z*$$2b4t%a(e+%>a>d_f_<JjxI#J1x;=hPd1zFPx=6T$;;X1TD*2(edZ3f46zaAoW>L53vS_J*N8TMB|n+;LD| zC=GkQPpyDY#Am4l49chDv*gojhRj_?63&&8#doW`INATAo(qY#{q}%nf@eTIXmtU< zdB<7YWfyCmBs|c)cK>1)v&M#!yNj#4d$~pVfDWQc_ke1?fw{T1Nce_b`v|Vp5ig(H zJvRD^+ps46^hLX;=e2!2e;w9y1D@!D$c@Jc&%%%IL=+xzw55&2?darw=9g~>P z9>?Kdc$r?6c$m%x2S$sdpPl>GQZ{rC9mPS63*qjCVa?OIBj!fW zm|g?>CVfGXNjOfcyqImXR_(tXS(F{FcoNzKvG5R$IgGaxC@)i(e+$ME}vPVIhd|mx2IIE+f zM?9opQHIVgBWu)^A|RzXw!^??S!x)SZOwZaJkGjc<_}2l^eSBm!eAJG9T>EC6I_sy z?bxzDIAn&K5*mX)$RQzDA?s)-no-XF(g*yl4%+GBf`##bDXJ==AQk*xmnatI;SsLp zP9XTHq5mmS=iWu~9ES>b%Q=1aMa|ya^vj$@qz9S!ih{T8_PD%Sf_QrNKwgrXw9ldm zHRVR98*{C?_XNpJn{abA!oix_mowRMu^2lV-LPi;0+?-F(>^5#OHX-fPED zCu^l7u3E%STI}c4{J2!)9SUlGP_@!d?5W^QJXOI-Ea`hFMKjR7TluLvzC-ozCPn1`Tpy z!vlv@_Z58ILX6>nDjTp-1LlFMx~-%GA`aJvG$?8*Ihn;mH37eK**rmOEwqegf-Ccx zrIX4;{c~RK>XuTXxYo5kMiWMy)!IC{*DHG@E$hx?RwP@+wuad(P1{@%tRkyJRqD)3 zMHHHZ4boqDn>-=DgR5VlhQTpfVy182Gk;A_S8A1-;U1RR>+$62>(MUx@Nox$vTjHq z%QR=j!6Gdyb5wu7y(YUktwMuW5<@jl?m4cv4BODiT5o8qVdC0MBqGr@-YBIwnpZAY znX9(_uQjP}JJ=!~Ve9#5I~rUnN|P_3D$LqZcvBnywYhjlMSFHm`;u9GPla{5QD7(7*6Tb3Svr8;(nuAd81q$*uq6HC_&~je*Ca7hP4sJp0av{M8480wF zxASi7Qv+~@2U%Nu1Ud;s-G4CTVWIPyx!sg&8ZG0Wq zG_}i3C(6_1>q3w!EH7$Kwq8uBp2F2N7}l65mk1p*9v0&+;th=_E-W)E;w}P(j⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc literal 0 HcmV?d00001 diff --git a/airbyte-cdk/python/gradle/wrapper/gradle-wrapper.properties b/airbyte-cdk/python/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000000..a80b22ce5cff --- /dev/null +++ b/airbyte-cdk/python/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/airbyte-cdk/python/gradlew b/airbyte-cdk/python/gradlew new file mode 100755 index 000000000000..1aa94a426907 --- /dev/null +++ b/airbyte-cdk/python/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/airbyte-cdk/python/gradlew.bat b/airbyte-cdk/python/gradlew.bat new file mode 100644 index 000000000000..6689b85beecd --- /dev/null +++ b/airbyte-cdk/python/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/airbyte-cdk/python/pyproject.toml b/airbyte-cdk/python/pyproject.toml index b5e8c83ca37b..f03d6cbcbe01 100644 --- a/airbyte-cdk/python/pyproject.toml +++ b/airbyte-cdk/python/pyproject.toml @@ -6,3 +6,39 @@ requires = [ ] build-backend = "setuptools.build_meta" + +[tool.coverage.report] +fail_under = 0 +skip_empty = true +sort = "-cover" +omit = [ + ".venv/*", + "main.py", + "setup.py", + "unit_tests/*", + "integration_tests/*", + "**/generated/*", +] + +[tool.flake8] +extend-exclude = [ + "*/lib/*/site-packages", + ".venv", + "build", + "models", + ".eggs", + "airbyte-cdk/python/airbyte_cdk/models/__init__.py", + "airbyte-cdk/python/airbyte_cdk/sources/declarative/models/__init__.py", + ".tox", + "airbyte_api_client", + "**/generated/*", +] +max-complexity = 20 +max-line-length = 140 + +extend-ignore = [ + "E203", # whitespace before ':' (conflicts with Black) + "E231", # Bad trailing comma (conflicts with Black) + "E501", # line too long (conflicts with Black) + "W503", # line break before binary operator (conflicts with Black) +] \ No newline at end of file diff --git a/airbyte-cdk/python/settings.gradle b/airbyte-cdk/python/settings.gradle new file mode 100644 index 000000000000..02e3dd9a6724 --- /dev/null +++ b/airbyte-cdk/python/settings.gradle @@ -0,0 +1,29 @@ +import com.gradle.scan.plugin.PublishedBuildScan + +pluginManagement { + repositories { + // # Gradle looks for dependency artifacts in repositories listed in 'repositories' blocks in descending order. + gradlePluginPortal() + } +} + +// Configure the gradle enterprise plugin to enable build scans. Enabling the plugin at the top of the settings file allows the build scan to record +// as much information as possible. +plugins { + id "com.gradle.enterprise" version "3.15.1" +} + +ext.isCiServer = System.getenv().containsKey("CI") + +gradleEnterprise { + buildScan { + termsOfServiceUrl = "https://gradle.com/terms-of-service" + termsOfServiceAgree = "yes" + uploadInBackground = !isCiServer // Disable in CI or scan URLs may not work. + buildScanPublished { PublishedBuildScan scan -> + file("scan-journal.log") << "${new Date()} - ${scan.buildScanId} - ${scan.buildScanUri}\n" + } + } +} + +rootProject.name = 'airbyte-cdk-python' diff --git a/airbyte-integrations/connectors-performance/destination-harness/build.gradle b/airbyte-integrations/connectors-performance/destination-harness/build.gradle index e5a3c4ca264a..fd6bb54d0aed 100644 --- a/airbyte-integrations/connectors-performance/destination-harness/build.gradle +++ b/airbyte-integrations/connectors-performance/destination-harness/build.gradle @@ -1,6 +1,5 @@ plugins { id 'application' - id 'airbyte-docker-legacy' } application { diff --git a/airbyte-integrations/connectors-performance/source-harness/build.gradle b/airbyte-integrations/connectors-performance/source-harness/build.gradle index abfeaa794b41..667e5af0a9a5 100644 --- a/airbyte-integrations/connectors-performance/source-harness/build.gradle +++ b/airbyte-integrations/connectors-performance/source-harness/build.gradle @@ -1,6 +1,5 @@ plugins { id 'application' - id 'airbyte-docker-legacy' } application { diff --git a/buildSrc/src/main/groovy/DockerHelpers.groovy b/buildSrc/src/main/groovy/DockerHelpers.groovy deleted file mode 100644 index 875f6320de9e..000000000000 --- a/buildSrc/src/main/groovy/DockerHelpers.groovy +++ /dev/null @@ -1,23 +0,0 @@ -import java.nio.file.Paths - -class DockerHelpers { - static String extractLabelValue(String dockerFile, String labelName) { - def file = dockerFile instanceof File ? dockerFile : new File(dockerFile) - return file.readLines() - .grep({ it.startsWith('LABEL') && it.contains(labelName) }) - .get(0) - .split('=')[1] - } - - static String extractImageName(String dockerFile) { - return extractLabelValue(dockerFile, "io.airbyte.name") - } - - static String extractImageVersion(String dockerFile) { - return extractLabelValue(dockerFile, "io.airbyte.version") - } - - static String getDevTaggedImage(projectDir, dockerfileName) { - return "${extractImageName(Paths.get(projectDir.absolutePath, dockerfileName).toString())}:dev" - } -} diff --git a/buildSrc/src/main/groovy/airbyte-docker-legacy.gradle b/buildSrc/src/main/groovy/airbyte-docker-legacy.gradle deleted file mode 100644 index e323cf7c95cc..000000000000 --- a/buildSrc/src/main/groovy/airbyte-docker-legacy.gradle +++ /dev/null @@ -1,331 +0,0 @@ -import java.nio.file.Paths -import java.security.MessageDigest -import java.util.concurrent.ConcurrentHashMap -import org.apache.commons.text.StringSubstitutor -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.file.ConfigurableFileTree -import org.gradle.api.file.FileCollection -import org.gradle.api.tasks.CacheableTask -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.PathSensitive -import org.gradle.api.tasks.PathSensitivity -import org.gradle.api.tasks.TaskAction - -/** - * AirbyteDockerLegacyTask is the task which builds a docker image based on a Dockerfile. - * - * It and the other classes in this file have "Legacy" in their name because we want to get rid of this plugin in favor - * of dagger-pipeline-based tooling like `airbyte-ci`. As of the time of this writing this is already the case for - * connectors. There are still a few remaining usages outside of connectors and they are useful to support a smooth - * local java-centric development experience with gradle, especially around integration tests. - * - * Issue https://github.com/airbytehq/airbyte/issues/30708 tracks the complete removal of this plugin. - */ -@CacheableTask -abstract class AirbyteDockerLegacyTask extends DefaultTask { - - @InputFiles - @PathSensitive(PathSensitivity.RELATIVE) - FileCollection filesInDockerImage - - @Input - Map baseImageHashes - - @InputFile - @PathSensitive(PathSensitivity.RELATIVE) - File dockerFile - - @OutputFile - File idFileOutput - - @InputFile - @PathSensitive(PathSensitivity.RELATIVE) - File buildScript = project.rootProject.file('tools/bin/build_image.sh') - - @TaskAction - def dockerTask() { - project.exec { - commandLine( - buildScript.absolutePath, - project.rootDir.absolutePath, - project.projectDir.absolutePath, - dockerFile.name, - DockerHelpers.getDevTaggedImage(project.projectDir, dockerFile.name), - idFileOutput.absolutePath, - ) - } - } -} - -/** - * AirbyteDockerLegacyTaskFactory is a convenience object to avoid passing the current project around. - */ -class AirbyteDockerLegacyTaskFactory { - - private AirbyteDockerLegacyTaskFactory() {} - - Project project - String dockerFileName - - File dockerFile() { - return project.file(dockerFileName) - } - - // This hash of the full path to the Dockerfile is the name of the task's output file. - String dockerfilePathHash() { - return MessageDigest.getInstance("MD5") - .digest(dockerFile().absolutePath.getBytes()) - .encodeHex() - .toString() - } - - // A superset of the files which are COPYed into the image, defined as the project file set - // with the .dockerignore rules applied to it. - // We could be more precise by parsing the Dockerfile but this is good enough in practice. - FileCollection filteredProjectFiles() { - ConfigurableFileTree files = project.fileTree(project.projectDir) - def dockerignore = project.file('.dockerignore') - if (!dockerignore.exists()) { - return files.filter { - file -> !file.toString().contains(".venv") - } - } - for (def rule : dockerignore.readLines()) { - if (rule.startsWith("#")) { - continue - } - rule = rule.trim() - files = (rule.startsWith("!") ? files.include(rule.substring(1)) : files.exclude(rule)) as ConfigurableFileTree - } - return files - } - - // Queries docker for all images and their hashes. - static synchronized Map collectKnownImageHashes(Project project) { - def stdout = new ByteArrayOutputStream() - project.rootProject.exec { - commandLine "docker", "images", "--no-trunc", "-f", "dangling=false", "--format", "{{.Repository}}:{{.Tag}} {{.ID}}" - standardOutput = stdout - } - Map map = [:] - stdout.toString().eachLine {line -> - def splits = line.split() - map.put(splits[0], splits[1].trim()) - } - return map - } - - // Query all docker images at most once for all tasks, at task creation time. - static def lazyImageHashesAtTaskCreationTime = new LazyImageHashesCache() - - static class LazyImageHashesCache { - private Map lazyValue - - synchronized Map get(Project project) { - if (lazyValue == null) { - lazyValue = collectKnownImageHashes(project) - } - return lazyValue - } - } - - // Global mapping of tagged image name to gradle project. - // This is populated at configuration time and accessed at task creation time. - // All keys verify isTaggedImageOwnedByThisRepo. - static def taggedImageToProject = new ConcurrentHashMap() - - static boolean isTaggedImageOwnedByThisRepo(String taggedImage) { - if (!taggedImage.startsWith("airbyte/")) { - // Airbyte's docker images are all prefixed like this. - // Anything not with this prefix is therefore not owned by this repo. - return false - } - if (taggedImage.startsWith("airbyte/base-airbyte-protocol-python:")) { - // Special case: this image is not built by this repo. - return false - } - if (!taggedImage.endsWith(":dev")) { - // Special case: this image is owned by this repo but built separate. e.g. source-file-secure - return false - } - // Otherwise, assume the image is built by this repo. - return true - } - - // Returns a mapping of each base image referenced in the Dockerfile to the corresponding hash - // in the results of collectKnownImageHashes(). If no hash was found, map to "???" instead. - Map baseTaggedImagesAndHashes(Map allKnownImageHashes) { - def taggedImages = new HashSet() - - // Look for "FROM foo AS bar" directives, and add them to the map with .put("bar", "foo") - Map imageAliases = [:] - dockerFile().eachLine { line -> - def parts = line.split() - if (parts.length >= 4 && parts[0].equals("FROM") && parts[parts.length - 2].equals("AS")) { - imageAliases.put(parts[parts.length - 1], parts[1]) - } - } - - dockerFile().eachLine { line -> - if (line.startsWith("FROM ")) { - def image = line.split()[1] - assert !image.isEmpty() - taggedImages.add(image) - } else if (line.startsWith("COPY --from=")) { - def image = line.substring("COPY --from=".length()).split()[0] - assert !image.isEmpty() - if (imageAliases[image] != null) { - taggedImages.add(imageAliases[image]) - } else { - taggedImages.add(image) - } - } - } - - Map result = [:] - for (def taggedImage : taggedImages) { - // Some image tags rely on environment variables (e.g. "FROM amazoncorretto:${JDK_VERSION}"). - taggedImage = new StringSubstitutor(System.getenv()).replace(taggedImage).trim() - result.put(taggedImage, allKnownImageHashes.getOrDefault(taggedImage, "???")) - } - return result - } - - // Create the task lazily: we shouldn't invoke 'docker' unless the task is created as part of the build. - def createTask(String taskName) { - if (!dockerFile().exists()) { - // This might not actually be necessary. It doesn't seem harmful either. - return project.tasks.register(taskName) { - logger.info "Skipping ${taskName} because ${dockerFile()} does not exist." - } - } - - // Tagged name of the image to be built by this task. - def taggedImage = DockerHelpers.getDevTaggedImage(project.projectDir, dockerFileName) - // Map this project to the tagged name of the image built by this task. - taggedImageToProject.put(taggedImage, project) - // Path to the ID file to be generated by this task. - // The ID file contains the hash of the image. - def idFilePath = Paths.get(project.rootProject.rootDir.absolutePath, '.dockerversions', dockerfilePathHash()) - // Register the task (lazy creation). - def airbyteDockerTask = project.tasks.register(taskName, AirbyteDockerLegacyTask) { task -> - // Set inputs. - task.filesInDockerImage = filteredProjectFiles() - task.dockerFile = this.dockerFile() - task.baseImageHashes = baseTaggedImagesAndHashes(lazyImageHashesAtTaskCreationTime.get(project)) - // Set dependencies on base images built by this repo. - for (String taggedImageDependency : task.baseImageHashes.keySet()) { - if (isTaggedImageOwnedByThisRepo(taggedImageDependency)) { - task.logger.info("adding airbyteDocker task dependency: image ${taggedImage} is based on ${taggedImageDependency}") - def dependentProject = taggedImageToProject.get(taggedImageDependency) - if (dependentProject == null) { - throw new GradleException("no known project for image ${taggedImageDependency}") - } - // Depend on 'assemble' instead of 'airbyteDocker' or 'airbyteDockerTest', it's simpler that way. - task.dependsOn(dependentProject.tasks.named('assemble')) - } - } - // Set outputs. - task.idFileOutput = idFilePath.toFile() - task.outputs.upToDateWhen { - // Because the baseImageHashes is computed at task creation time, it may be stale - // at task execution time. Let's double-check. - - // Missing dependency declarations in the gradle build may result in the airbyteDocker tasks - // to be created in the wrong order. Not worth breaking the build over. - for (Map.Entry e : task.baseImageHashes) { - if (isTaggedImageOwnedByThisRepo(e.key) && e.value == "???") { - task.logger.info "Not up to date: missing at least one airbyte base image in docker" - return false - } - } - // Fetch the hashes of the required based images anew. - def allImageHashes = collectKnownImageHashes(task.project) - // If the image to be built by this task doesn't exist in docker, then it definitely should - // be built regardless of the status of the ID file. - // For instance, it's possible that a `docker image rm` occurred between consecutive - // identical gradle builds: the ID file remains untouched but the image still needs to be rebuilt. - if (!allImageHashes.containsKey(taggedImage)) { - task.logger.info "Not up to date: ID file exists but target image not found in docker" - return false - } - // If the depended-upon base images have changed in the meantime, then it follows that the target - // image needs to be rebuilt regardless of the status of the ID file. - def currentBaseImageHashes = baseTaggedImagesAndHashes(allImageHashes) - if (!task.baseImageHashes.equals(currentBaseImageHashes)) { - task.logger.info "Not up to date: at last one base image has changed in docker since task creation" - return false - } - // In all other cases, if the ID file hasn't been touched, then the task can be skipped. - return true - } - } - - airbyteDockerTask.configure { - // Images for java projects always rely on the distribution tarball. - dependsOn project.tasks.matching { it.name == 'distTar' } - // Ensure that all files exist beforehand. - dependsOn project.tasks.matching { it.name == 'generate' } - } - project.tasks.named('assemble').configure { - // We may revisit the dependency on assemble but the dependency should always be on a base task. - dependsOn airbyteDockerTask - } - // Add a task to clean up when doing a gradle clean. - // Don't actually mess with docker, just delete the output file. - def airbyteDockerCleanTask = project.tasks.register(taskName + "Clean", Delete) { - delete idFilePath - } - project.tasks.named('clean').configure { - dependsOn airbyteDockerCleanTask - } - return airbyteDockerTask - } - - static def build(Project project, String taskName, String dockerFileName) { - def f = new AirbyteDockerLegacyTaskFactory() - f.project = project - f.dockerFileName = dockerFileName - f.createTask(taskName) - } -} - -/** - * AirbyteDockerLegacyPlugin creates an airbyteDocker task for the project when a Dockerfile is present. - * - * Following the same logic, it creates airbyteDockerTest when Dockerfile.test is present, though - * that behavior is not used anywhere except in the source-mongo connector and is therefore deprecated - * through the use of airbyte-ci. - */ -class AirbyteDockerLegacyPlugin implements Plugin { - - void apply(Project project) { - AirbyteDockerLegacyTaskFactory.build(project, 'airbyteDocker', 'Dockerfile') - - // Used only for source-mongodb. Consider removing entirely. - if (project.name.endsWith('source-mongodb')) { - AirbyteDockerLegacyTaskFactory.build(project, 'airbyteDockerTest', 'Dockerfile.test') - } - - // Used for base-normalization. - if (project.name.endsWith('base-normalization')) { - ['airbyteDockerMSSql' : 'mssql', - 'airbyteDockerMySql' : 'mysql', - 'airbyteDockerOracle' : 'oracle', - 'airbyteDockerClickhouse': 'clickhouse', - 'airbyteDockerSnowflake' : 'snowflake', - 'airbyteDockerRedshift' : 'redshift', - 'airbyteDockerTiDB' : 'tidb', - 'airbyteDockerDuckDB' : 'duckdb' - ].forEach {taskName, customConnector -> - AirbyteDockerLegacyTaskFactory.build(project, taskName, "${customConnector}.Dockerfile") - } - } - } -} diff --git a/buildSrc/src/main/groovy/airbyte-python.gradle b/buildSrc/src/main/groovy/airbyte-python.gradle deleted file mode 100644 index 59f14890c75b..000000000000 --- a/buildSrc/src/main/groovy/airbyte-python.gradle +++ /dev/null @@ -1,185 +0,0 @@ -import groovy.io.FileType -import groovy.io.FileVisitResult -import org.gradle.api.GradleException -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.tasks.Exec -import ru.vyarus.gradle.plugin.python.task.PythonTask - -class Helpers { - static addTestTaskIfTestFilesFound(Project project, String testFilesDirectory, String taskName, taskDependencies) { - """ - This method verifies if there are test files in a directory before adding the pytest task to run tests on that directory. This is needed - because if there are no tests in that dir and we run pytest on it, it exits with exit code 5 which gradle takes to mean that the process - failed, since it's non-zero. This means that if a module doesn't need a unit or integration test, it still needs to add a dummy test file - like: - - ``` - def make_ci_pass_test(): - assert True - ``` - - So we use this method to leverage pytest's test discovery rules (https://docs.pytest.org/en/6.2.x/goodpractices.html#conventions-for-python-test-discovery) - to selectively run pytest based on whether there seem to be test files in that directory. - Namely, if the directory contains a file whose name is test_*.py or *_test.py then it's a test. - - See https://github.com/airbytehq/airbyte/issues/4979 for original context - """ - - boolean requiresTasks = false - if (project.file(testFilesDirectory).exists()) { - def testDir = project.projectDir.toPath().resolve(testFilesDirectory) - testDir.traverse(type: FileType.FILES, nameFilter: ~/(^test_.*|.*_test)\.py$/) {file -> - requiresTasks = true - // If a file is found, terminate the traversal, thus causing this task to be declared at most once - return FileVisitResult.TERMINATE - } - } - if (!requiresTasks) { - return - } - - def coverageTask = project.tasks.register(taskName, PythonTask) { - def dataFile = "${testFilesDirectory}/.coverage.${taskName}" - def rcFile = project.rootProject.file('pyproject.toml').absolutePath - def testConfig = project.file('pytest.ini').exists() ? 'pytest.ini' : project.rootProject.file('pyproject.toml').absolutePath - - module = "coverage" - command = "run --data-file=${dataFile} --rcfile=${rcFile} -m pytest -s ${testFilesDirectory} -c ${testConfig}" - } - coverageTask.configure { - dependsOn taskDependencies - } - } -} - -class AirbytePythonPlugin implements Plugin { - - void apply(Project project) { - - def venvDirectoryName = '.venv' - - // Add a task that allows cleaning up venvs to every python project - def cleanPythonVenv = project.tasks.register('cleanPythonVenv', Exec) { - commandLine 'rm' - args '-rf', "${project.projectDir.absolutePath}/${venvDirectoryName}" - } - project.tasks.named('clean').configure { - dependsOn cleanPythonVenv - } - - project.plugins.apply 'ru.vyarus.use-python' - - // Configure gradle python plugin. - project.python { - envPath = venvDirectoryName - minPythonVersion '3.10' - - // Amazon Linux support. - // The airbyte-ci tool runs gradle tasks in AL2023-based containers. - // In AL2023, `python3` is necessarily v3.9, and later pythons need to be installed and named explicitly. - // See https://github.com/amazonlinux/amazon-linux-2023/issues/459 for details. - try { - if ("python3.11 --version".execute().waitFor() == 0) { - // python3.11 definitely exists at this point, use it instead of 'python3'. - pythonBinary "python3.11" - } - } catch (IOException _) { - // Swallow exception if python3.11 is not installed. - } - // Pyenv support. - try { - def pyenvRoot = "pyenv root".execute() - def pyenvLatest = "pyenv latest ${minPythonVersion}".execute() - // Pyenv definitely exists at this point: use 'python' instead of 'python3' in all cases. - pythonBinary "python" - if (pyenvRoot.waitFor() == 0 && pyenvLatest.waitFor() == 0) { - pythonPath "${pyenvRoot.text.trim()}/versions/${pyenvLatest.text.trim()}/bin" - } - } catch (IOException _) { - // Swallow exception if pyenv is not installed. - } - - scope 'VIRTUALENV' - installVirtualenv = true - pip 'pip:23.2.1' - pip 'mccabe:0.6.1' - // https://github.com/csachs/pyproject-flake8/issues/13 - pip 'flake8:4.0.1' - // flake8 doesn't support pyproject.toml files - // and thus there is the wrapper "pyproject-flake8" for this - pip 'pyproject-flake8:0.0.1a2' - pip 'pytest:6.2.5' - pip 'coverage[toml]:6.3.1' - } - - // Attempt to install anything in requirements.txt. - // By convention this should only be dependencies whose source is located in the project. - if (project.file('requirements.txt').exists()) { - project.tasks.register('installLocalReqs', PythonTask) { - module = "pip" - command = "install -r requirements.txt" - inputs.file('requirements.txt') - outputs.file('build/installedlocalreqs.txt') - } - } else if (project.file('setup.py').exists()) { - // If requirements.txt does not exists, install from setup.py instead, assume a dev or "tests" profile exists. - // In this case, there is no need to depend on the base python modules since everything should be contained in the setup.py. - project.tasks.register('installLocalReqs', PythonTask) { - module = "pip" - command = "install .[dev,tests]" - inputs.file('setup.py') - outputs.file('build/installedlocalreqs.txt') - } - } else { - return - } - - def installLocalReqs = project.tasks.named('installLocalReqs') - - def flakeCheck = project.tasks.register('flakeCheck', PythonTask) { - module = "pflake8" - command = "--config ${project.rootProject.file('pyproject.toml').absolutePath} ./" - } - - def installReqs = project.tasks.register('installReqs', PythonTask) { - module = "pip" - command = "install .[main]" - inputs.file('setup.py') - outputs.file('build/installedreqs.txt') - } - installReqs.configure { - dependsOn installLocalReqs - } - - project.tasks.named('check').configure { - dependsOn installReqs - dependsOn flakeCheck - } - - def installTestReqs = project.tasks.register('installTestReqs', PythonTask) { - module = "pip" - command = "install .[tests]" - inputs.file('setup.py') - outputs.file('build/installedtestreqs.txt') - } - installTestReqs.configure { - dependsOn installReqs - } - - Helpers.addTestTaskIfTestFilesFound(project, 'unit_tests', 'testPython', installTestReqs) - project.tasks.named('check').configure { - dependsOn project.tasks.matching { it.name == 'testPython' } - } - - Helpers.addTestTaskIfTestFilesFound(project, 'integration_tests', 'integrationTestPython', installTestReqs) - def integrationTestTasks = project.tasks.matching { it.name == 'integrationTestPython' } - integrationTestTasks.configureEach { - dependsOn project.tasks.named('assemble') - mustRunAfter project.tasks.named('check') - } - project.tasks.named('build').configure { - dependsOn integrationTestTasks - } - } -} diff --git a/settings.gradle b/settings.gradle index 1f46f13439b7..03b647e67635 100644 --- a/settings.gradle +++ b/settings.gradle @@ -159,9 +159,6 @@ if (isCiServer || isAirbyteCI) { rootProject.name = 'airbyte' -include ':tools:code-generator' - -include ':airbyte-cdk:python' include ':airbyte-cdk:java:airbyte-cdk' include ':airbyte-cdk:java:airbyte-cdk:dependencies' include ':airbyte-cdk:java:airbyte-cdk:core' diff --git a/tools/code-generator/build.gradle b/tools/code-generator/build.gradle deleted file mode 100644 index 0c2de175e2cc..000000000000 --- a/tools/code-generator/build.gradle +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id 'airbyte-docker-legacy' -} From f93c0df33122d9527fea45e9e2ba43c145cf720f Mon Sep 17 00:00:00 2001 From: Marius Posta Date: Fri, 16 Feb 2024 04:46:32 -0800 Subject: [PATCH 07/43] gradle: overall simplification (#35307) --- .github/workflows/gradle.yml | 76 +--- .github/workflows/legacy-test-command.yml | 3 - .../workflows/publish-java-cdk-command.yml | 3 - airbyte-cdk/java/airbyte-cdk/build.gradle | 79 +--- airbyte-cdk/java/airbyte-cdk/settings.gradle | 13 - airbyte-integrations/connectors/build.gradle | 104 ++++++ build.gradle | 352 +++--------------- buildSrc/build.gradle | 13 - .../airbyte-integration-test-java.gradle | 62 --- .../src/main/groovy/airbyte-java-cdk.gradle | 70 ---- .../main/groovy/airbyte-java-connector.gradle | 100 ++++- .../airbyte-performance-test-java.gradle | 48 --- settings.gradle | 46 +-- 13 files changed, 286 insertions(+), 683 deletions(-) delete mode 100644 airbyte-cdk/java/airbyte-cdk/settings.gradle create mode 100644 airbyte-integrations/connectors/build.gradle delete mode 100644 buildSrc/src/main/groovy/airbyte-integration-test-java.gradle delete mode 100644 buildSrc/src/main/groovy/airbyte-java-cdk.gradle delete mode 100644 buildSrc/src/main/groovy/airbyte-performance-test-java.gradle diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 340d60499059..732f0e506695 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,4 +1,4 @@ -name: Airbyte CI - Repository Health Check +name: Connector Ops CI - Gradle Check concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -20,47 +20,18 @@ on: - synchronize jobs: - # In case of self-hosted EC2 errors, remove this block. - start-check-runner: - name: Start EC2 Runner - timeout-minutes: 10 - runs-on: ubuntu-latest - outputs: - label: ${{ steps.start-ec2-runner.outputs.label }} - ec2-instance-id: ${{ steps.start-ec2-runner.outputs.ec2-instance-id }} - steps: - - name: Checkout Airbyte - uses: actions/checkout@v3 - - name: Check PAT rate limits - run: | - ./tools/bin/find_non_rate_limited_PAT \ - ${{ secrets.GH_PAT_BUILD_RUNNER_OSS }} \ - ${{ secrets.GH_PAT_BUILD_RUNNER_BACKUP }} - - name: Start AWS Runner - id: start-ec2-runner - uses: ./.github/actions/start-aws-runner - with: - aws-access-key-id: ${{ secrets.SELF_RUNNER_AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.SELF_RUNNER_AWS_SECRET_ACCESS_KEY }} - # Use a beefier instance type than the default c5.2xlarge, but with the same per-core cost. - # When gradle runs on this instance, it will use up all the available cores anyway. - # There should be little to no difference in total cost, however the job latency will be improved. - # At the time of this writing, the latency doesn't improve much beyond this instance size (approx 5 minutes). - # This is largely thanks to the gradle cache. - ec2-instance-type: "c5.4xlarge" - github-token: ${{ env.PAT }} - run-check: - # In case of self-hosted EC2 errors, removed the `needs` line and switch back to running on ubuntu-latest. - needs: start-check-runner # required to start the main job when the runner is ready - runs-on: ${{ needs.start-check-runner.outputs.label }} # run the job on the newly created runner + # The gradle check task which we will run is embarrassingly parallelizable. + # We therefore run this on a machine with a maximum number of cores. + # We pay per time and per core, so there should be little difference in total cost. + # The latency overhead of setting up gradle prior to running the actual task adds up to about a minute. + runs-on: connector-test-xxlarge name: Gradle Check timeout-minutes: 30 steps: - name: Checkout Airbyte uses: actions/checkout@v3 - - # IMPORTANT! This is nessesary to make sure that a status is reported on the PR + # IMPORTANT! This is necessary to make sure that a status is reported on the PR # even if the workflow is skipped. If we used github actions filters, the workflow # would not be reported as skipped, but instead would be forever pending. # @@ -106,39 +77,6 @@ jobs: # TODO: be able to remove the skipSlowTests property arguments: --scan --no-daemon --no-watch-fs check -DskipSlowTests=true - # In case of self-hosted EC2 errors, remove this block. - stop-check-runner: - name: Stop EC2 Runner - timeout-minutes: 10 - needs: - - start-check-runner # required to get output from the start-runner job - - run-check # required to wait when the main job is done - runs-on: ubuntu-latest - # Always is required to stop the runner even if the previous job has errors. However always() runs even if the previous step is skipped. - # Thus, we check for skipped here. - if: ${{ always() && needs.start-check-runner.result != 'skipped'}} - steps: - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.SELF_RUNNER_AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.SELF_RUNNER_AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-2 - - name: Checkout Airbyte - uses: actions/checkout@v3 - - name: Check PAT rate limits - run: | - ./tools/bin/find_non_rate_limited_PAT \ - ${{ secrets.GH_PAT_BUILD_RUNNER_OSS }} \ - ${{ secrets.GH_PAT_BUILD_RUNNER_BACKUP }} - - name: Stop EC2 runner - uses: supertopher/ec2-github-runner@base64v1.0.10 - with: - mode: stop - github-token: ${{ env.PAT }} - label: ${{ needs.start-check-runner.outputs.label }} - ec2-instance-id: ${{ needs.start-check-runner.outputs.ec2-instance-id }} - set-instatus-incident-on-failure: name: Create Instatus Incident on Failure runs-on: ubuntu-latest diff --git a/.github/workflows/legacy-test-command.yml b/.github/workflows/legacy-test-command.yml index 20e7c593d492..3d530b81e143 100644 --- a/.github/workflows/legacy-test-command.yml +++ b/.github/workflows/legacy-test-command.yml @@ -113,9 +113,6 @@ jobs: fi env: GCP_GSM_CREDENTIALS: ${{ secrets.GCP_GSM_CREDENTIALS }} - - name: Build Java CDK Snapshot if Needed - # If a snapshot version is specified for the Java CDK, build publish locally. Otherwise, do nothing. - run: ./gradlew :airbyte-cdk:java:airbyte-cdk:publishSnapshotIfNeeded - name: Test ${{ github.event.inputs.connector }} id: test env: diff --git a/.github/workflows/publish-java-cdk-command.yml b/.github/workflows/publish-java-cdk-command.yml index b72a80a82b6b..bce9961372bd 100644 --- a/.github/workflows/publish-java-cdk-command.yml +++ b/.github/workflows/publish-java-cdk-command.yml @@ -122,9 +122,6 @@ jobs: run: ./gradlew :airbyte-cdk:java:airbyte-cdk:assertCdkVersionNotPublished - name: Build Java CDK run: ./gradlew --no-daemon :airbyte-cdk:java:airbyte-cdk:build - - name: Publish Java Modules to MavenLocal (Dry-Run) - if: ${{ !(env.DRY_RUN == 'false') }} - run: ./gradlew --no-daemon :airbyte-cdk:java:airbyte-cdk:publishToMavenLocal - name: Upload jars as artifacts if: ${{ !(env.DRY_RUN == 'false') }} uses: actions/upload-artifact@v2 diff --git a/airbyte-cdk/java/airbyte-cdk/build.gradle b/airbyte-cdk/java/airbyte-cdk/build.gradle index 1523d78df648..18b8028bc095 100644 --- a/airbyte-cdk/java/airbyte-cdk/build.gradle +++ b/airbyte-cdk/java/airbyte-cdk/build.gradle @@ -1,17 +1,11 @@ allprojects { apply plugin: 'java-library' apply plugin: 'maven-publish' - apply plugin: 'airbyte-java-cdk' - apply plugin: 'airbyte-integration-test-java' - apply plugin: 'airbyte-performance-test-java' apply plugin: 'java-test-fixtures' group 'io.airbyte.cdk' - version = getCdkTargetVersion() -} -subprojects { subproject -> - def artifactBaseName = 'airbyte-cdk-' + subproject.name + def artifactBaseName = 'airbyte-cdk-' + project.name // E.g. airbyte-cdk-core, airbyte-cdk-db-sources, airbyte-cdk-db-destinations, etc. publishing { @@ -25,7 +19,7 @@ subprojects { subproject -> groupId = 'io.airbyte.cdk' artifactId = artifactBaseName + '-test-fixtures' version = project.version - artifact subproject.tasks.testFixturesJar + artifact project.tasks.testFixturesJar } } // This repository is only defined and used in the context of an artifact publishing @@ -52,69 +46,30 @@ subprojects { subproject -> description = "Airbyte Connector Development Kit (CDK) for Java." -def recursiveTasks = [ - 'assemble', - 'build', - 'integrationTestJava', - 'publish', - 'publishToMavenLocal', - 'test', -] -recursiveTasks.each { taskName -> - tasks.named(taskName).configure { - dependsOn subprojects.collect { it.tasks.named(taskName) } - } -} - -// The `publishSnapshotIfNeeded` task will be a no-op if CDK version does not end with '-SNAPSHOT'. -task publishSnapshotIfNeeded {} - -if (version.endsWith("-SNAPSHOT")) { - logger.lifecycle("Version ${version} ends with '-SNAPSHOT'. Enqueing 'publishToMavenLocal'...") - publishSnapshotIfNeeded.dependsOn publishToMavenLocal -} else { - // Uncomment as needed for debugging: - // logger.lifecycle("Version ${version} does not end with '-SNAPSHOT'. Skipping task 'publishToMavenLocal'.") -} - -task assertCdkVersionNotPublished { +tasks.register('assertCdkVersionNotPublished') { doLast { - def checkGroupId = "io.airbyte.cdk" - def checkArtifactId = "airbyte-cdk-core" - def checkVersion = getCdkTargetVersion() - def repoUrl = "https://airbyte.mycloudrepo.io/public/repositories/airbyte-public-jars" - def groupIdUrl = checkGroupId.replace('.', '/') - def artifactUrl = "${repoUrl}/${groupIdUrl}/${checkArtifactId}/${checkVersion}/${checkArtifactId}-${checkVersion}.pom" + var props = new Properties() + file("core/src/main/resources/version.properties").withInputStream(props::load) - def connection = artifactUrl.toURL().openConnection() as HttpURLConnection + var checkGroupId = "io.airbyte.cdk" + var checkArtifactId = "airbyte-cdk-core" + var checkVersion = props.getProperty('version') ?: 'undefined' + var repoUrl = "https://airbyte.mycloudrepo.io/public/repositories/airbyte-public-jars" + var groupIdUrl = "${repoUrl}/${checkGroupId.replace('.', '/')}" + var artifactUrl = "${groupIdUrl}/${checkArtifactId}/${checkVersion}/${checkArtifactId}-${checkVersion}.pom" + + var connection = artifactUrl.toURL().openConnection() as HttpURLConnection connection.setRequestMethod("HEAD") connection.connect() - def responseCode = connection.getResponseCode() + var responseCode = connection.getResponseCode() if (responseCode == 200) { - throw new GradleException("Assert failed. Java CDK '${checkVersion}' already published at: ${artifactUrl}") + throw new GradleException("Java CDK '${checkVersion}' already published at ${groupIdUrl}") } else if (responseCode == 404) { - logger.lifecycle( - "Assert succeeded. Version ${checkVersion} of ${checkArtifactId} has not been published. " + - "Checked: ${artifactUrl}" - ) + logger.lifecycle("Java CDK '${checkVersion}' not yet published at ${groupIdUrl}.") } else { - logger.error("Received unexpected HTTP response code ${responseCode}. Ensure the repository is accessible.") - throw new GradleException("Error during assertion. Received unexpected HTTP response code ${responseCode}.") + throw new GradleException("Unexpected HTTP response code ${responseCode} from ${artifactUrl}, expected either 200 or 404.") } } } - -def cleanLocalCache = tasks.register('cleanLocalCache') { - def userHome = System.getProperty("user.home") - doLast { - delete '.gradle' - delete '${userHome}/.m2/repository/io/airbyte/' - delete '${userHome}/.gradle/caches/modules-2/files-2.1/io.airbyte.cdk/' - } -} -cleanLocalCache.configure { - dependsOn tasks.named('clean') - dependsOn subprojects.collect { it.tasks.named('clean') } -} diff --git a/airbyte-cdk/java/airbyte-cdk/settings.gradle b/airbyte-cdk/java/airbyte-cdk/settings.gradle deleted file mode 100644 index 53055cc5241c..000000000000 --- a/airbyte-cdk/java/airbyte-cdk/settings.gradle +++ /dev/null @@ -1,13 +0,0 @@ -rootProject.name = 'airbyte' - -include ':airbyte-cdk:java:airbyte-cdk:dependencies' -include ':airbyte-cdk:java:airbyte-cdk:core' -include ':airbyte-cdk:java:airbyte-cdk:db-sources' -include ':airbyte-cdk:java:airbyte-cdk:db-destinations' -include ':airbyte-cdk:java:airbyte-cdk:s3-destinations' -include ':airbyte-cdk:java:airbyte-cdk:typing-deduping' -include ':airbyte-cdk:java:airbyte-cdk:azure-destinations' -include ':airbyte-cdk:java:airbyte-cdk:gcs-destinations' -include ':airbyte-cdk:java:airbyte-cdk:datastore-bigquery' -include ':airbyte-cdk:java:airbyte-cdk:datastore-mongo' -include ':airbyte-cdk:java:airbyte-cdk:datastore-postgres' diff --git a/airbyte-integrations/connectors/build.gradle b/airbyte-integrations/connectors/build.gradle new file mode 100644 index 000000000000..9c9abf6535f8 --- /dev/null +++ b/airbyte-integrations/connectors/build.gradle @@ -0,0 +1,104 @@ +plugins { + id 'base' + id 'ru.vyarus.use-python' version '2.3.0' +} + +// Pyenv support. +try { + def pyenvRoot = "pyenv root".execute() + if (pyenvRoot.waitFor() == 0) { + ext.pyenvRoot = pyenvRoot.text.trim() + } +} catch (IOException _) { + // Swallow exception if pyenv is not installed. +} + +def pythonBin = layout.buildDirectory.file('.venv/bin/python').get().asFile.absolutePath + +// python is required by the connectors project to run airbyte-ci from source to build connector images. +python { + envPath = layout.buildDirectory.file('.venv').get().asFile + minPythonVersion = '3.10' // should be 3.10 for local development + + // Pyenv support. + try { + def pyenvRoot = "pyenv root".execute() + def pyenvLatest = "pyenv latest ${minPythonVersion}".execute() + // Pyenv definitely exists at this point: use 'python' instead of 'python3' in all cases. + pythonBinary "python" + if (pyenvRoot.waitFor() == 0 && pyenvLatest.waitFor() == 0) { + pythonPath "${pyenvRoot.text.trim()}/versions/${pyenvLatest.text.trim()}/bin" + } + } catch (IOException _) { + // Swallow exception if pyenv is not installed. + } + + scope = 'VIRTUALENV' + installVirtualenv = true + // poetry is required for installing and running airbyte-ci + pip 'poetry:1.5.1' +} + +def poetryInstallAirbyteCI = tasks.register('poetryInstallAirbyteCI', Exec) { + workingDir rootProject.file('airbyte-ci/connectors/pipelines') + commandLine pythonBin + args "-m", "poetry", "install", "--no-cache" +} +poetryInstallAirbyteCI.configure { + dependsOn tasks.named('pipInstall') +} +def poetryCleanVirtualenv = tasks.register('cleanPoetryVirtualenv', Exec) { + workingDir rootProject.file('airbyte-ci/connectors/pipelines') + commandLine pythonBin + args "-m", "poetry", "env", "remove", "--all" + onlyIf { + layout.buildDirectory.file('venv/bin/python').get().asFile.exists() + } +} +tasks.named('clean').configure { + dependsOn poetryCleanVirtualenv +} + +allprojects { + // Evaluate CDK project before evaluating the connector. + evaluationDependsOn(':airbyte-cdk:java:airbyte-cdk') + + // Adds airbyte-ci task. + def airbyteCIConnectorsTask = { String taskName, String... connectorsArgs -> + def task = tasks.register(taskName, Exec) { + workingDir rootDir + environment "CI", "1" // set to use more suitable logging format + commandLine pythonBin + args "-m", "poetry" + args "--directory", "${rootProject.file('airbyte-ci/connectors/pipelines').absolutePath}" + args "run" + args "airbyte-ci", "connectors", "--name=${project.name}" + args connectorsArgs + // Forbid these kinds of tasks from running concurrently. + // We can induce serial execution by giving them all a common output directory. + outputs.dir rootProject.file("${rootProject.buildDir}/airbyte-ci-lock") + outputs.upToDateWhen { false } + } + task.configure { dependsOn poetryInstallAirbyteCI } + return task + } + + // Build connector image as part of 'assemble' task. + // This is required for local 'integrationTest' execution. + def buildConnectorImage = airbyteCIConnectorsTask( + 'buildConnectorImage', '--disable-report-auto-open', 'build', '--use-host-gradle-dist-tar') + buildConnectorImage.configure { + // Images for java projects always rely on the distribution tarball. + dependsOn tasks.matching { it.name == 'distTar' } + // Ensure that all files exist beforehand. + dependsOn tasks.matching { it.name == 'generate' } + } + tasks.named('assemble').configure { + // We may revisit the dependency on assemble but the dependency should always be on a base task. + dependsOn buildConnectorImage + } + + // Convenience tasks for local airbyte-ci execution. + airbyteCIConnectorsTask('airbyteCIConnectorBuild', 'build') + airbyteCIConnectorsTask('airbyteCIConnectorTest', 'test') +} diff --git a/build.gradle b/build.gradle index b45507cfbfa8..befdc9deaa13 100644 --- a/build.gradle +++ b/build.gradle @@ -5,183 +5,41 @@ import com.github.spotbugs.snom.SpotBugsTask plugins { id 'base' id 'com.github.spotbugs' version '6.0.7' - id 'version-catalog' - id 'ru.vyarus.use-python' -} - - -Properties env = new Properties() -rootProject.file('gradle.properties').withInputStream { env.load(it) } - -if (!env.containsKey('VERSION')) { - throw new Exception('Version not specified in .env file...') -} - -// `version` is used as the application build version for artifacts like jars -// `image_tag` is used as the docker tag applied to built images. -// These values are the same for building an specific Airbyte release or branch via the 'VERSION' environment variable. -// For local development builds, the 'VERSION' environment variable is unset, and built images are tagged with 'dev'. -ext { - version = System.getenv("VERSION") ?: env.VERSION - image_tag = System.getenv("VERSION") ?: 'dev' - skipSlowTests = (System.getProperty('skipSlowTests', 'false') != 'false') -} -// Pyenv support. -try { - def pyenvRoot = "pyenv root".execute() - if (pyenvRoot.waitFor() == 0) { - ext.pyenvRoot = pyenvRoot.text.trim() - } -} catch (IOException _) { - // Swallow exception if pyenv is not installed. -} - -def isConnectorProject = { Project project -> - if (project.parent == null || project.parent.name != 'connectors') { - return false - } - return project.name.startsWith("source-") || project.name.startsWith("destination-") } allprojects { apply plugin: 'base' + apply plugin: 'java' + apply plugin: 'java-test-fixtures' + apply plugin: 'com.github.spotbugs' - // by default gradle uses directory as the project name. That works very well in a single project environment but + // By default gradle uses directory as the project name. That works very well in a single project environment but // projects clobber each other in an environments with subprojects when projects are in directories named identically. def sub = rootDir.relativePath(projectDir.parentFile).replace('/', '.') group = "io.${rootProject.name}${sub.isEmpty() ? '' : ".$sub"}" project.base.archivesName = "${project.group}-${project.name}" - version = rootProject.ext.version -} - -// python is required by the root project to run CAT tests for connectors -python { - envPath = '.venv' - minPythonVersion = '3.10' // should be 3.10 for local development - - // Amazon Linux support. - // The airbyte-ci tool runs gradle tasks in AL2023-based containers. - // In AL2023, `python3` is necessarily v3.9, and later pythons need to be installed and named explicitly. - // See https://github.com/amazonlinux/amazon-linux-2023/issues/459 for details. - try { - if ("python3.11 --version".execute().waitFor() == 0) { - // python3.11 definitely exists at this point, use it instead of 'python3'. - pythonBinary "python3.11" - } - } catch (IOException _) { - // Swallow exception if python3.11 is not installed. + // Produce reproducible archives + // (see https://docs.gradle.org/current/userguide/working_with_files.html#sec:reproducible_archives) + tasks.withType(AbstractArchiveTask).configureEach { + preserveFileTimestamps = false + reproducibleFileOrder = true } - // Pyenv support. - try { - def pyenvRoot = "pyenv root".execute() - def pyenvLatest = "pyenv latest ${minPythonVersion}".execute() - // Pyenv definitely exists at this point: use 'python' instead of 'python3' in all cases. - pythonBinary "python" - if (pyenvRoot.waitFor() == 0 && pyenvLatest.waitFor() == 0) { - pythonPath "${pyenvRoot.text.trim()}/versions/${pyenvLatest.text.trim()}/bin" - } - } catch (IOException _) { - // Swallow exception if pyenv is not installed. - } - - scope = 'VIRTUALENV' - installVirtualenv = true - // poetry is required for installing and running airbyte-ci - pip 'poetry:1.5.1' -} - -def cleanPythonVenv = rootProject.tasks.register('cleanPythonVenv', Exec) { - commandLine 'rm' - args '-rf', "${rootProject.projectDir.absolutePath}/.venv" -} -rootProject.tasks.named('clean').configure { - dependsOn cleanPythonVenv -} - - -def getCDKTargetVersion() { - def props = new Properties() - file("airbyte-cdk/java/airbyte-cdk/src/main/resources/version.properties").withInputStream { props.load(it) } - return props.getProperty('version') -} -static def getLatestFileModifiedTimeFromFiles(files) { - if (files.isEmpty()) { - return null - } - return files.findAll { it.isFile() } - .collect { it.lastModified() } - .max() -} -def checkCDKJarExists(requiredSnapshotVersion) { - if (requiredSnapshotVersion == null) { - // Connector does not require CDK snapshot. - return - } - final boolean checkFileChanges = true - final cdkTargetVersion = getCDKTargetVersion() - if (requiredSnapshotVersion != cdkTargetVersion) { - if (!cdkTargetVersion.contains("-SNAPSHOT")) { - throw new GradleException( - "CDK JAR version is not publishing snapshot but connector requires version ${requiredSnapshotVersion}.\n" + - "Please check that the version in the CDK properties file matches the connector build.gradle." - ) - } - throw new GradleException( - "CDK JAR version ${cdkTargetVersion} does not match connector's required version ${requiredSnapshotVersion}.\n" + - "Please check that the version in the CDK properties file matches the connector build.gradle." - ) - } - - def cdkJar = file("${System.properties['user.home']}/.m2/repository/io/airbyte/airbyte-cdk/${cdkTargetVersion}/airbyte-cdk-${cdkTargetVersion}.jar") - if (!cdkJar.exists()) { - println("WARNING: CDK JAR does not exist at ${cdkJar.path}.\nPlease run './gradlew :airbyte-cdk:java:airbyte-cdk:build'.") - } - if (checkFileChanges) { - def latestJavaFileTimestamp = getLatestFileModifiedTimeFromFiles(file("${rootDir}/airbyte-cdk/java/airbyte-cdk/src").listFiles().findAll { it.isFile() }) - if (cdkJar.lastModified() < latestJavaFileTimestamp) { - throw new GradleException("CDK JAR is out of date. Please run './gradlew :airbyte-cdk:java:airbyte-cdk:build'.") - } - } -} -static def getCDKSnapshotRequirement(dependenciesList) { - def cdkSnapshotRequirement = dependenciesList.find { - it.requested instanceof ModuleComponentSelector && - it.requested.group == 'io.airbyte' && - it.requested.module == 'airbyte-cdk' && - it.requested.version.endsWith('-SNAPSHOT') - } - if (cdkSnapshotRequirement == null) { - return null - } else { - return cdkSnapshotRequirement.requested.version - } -} - -// Common configurations for 'assemble'. -allprojects { + // Common configurations for 'assemble'. tasks.withType(Tar).configureEach { duplicatesStrategy DuplicatesStrategy.INCLUDE } - tasks.withType(Zip).configureEach { duplicatesStrategy DuplicatesStrategy.INCLUDE // Disabling distZip causes the build to break for some reason, so: instead of disabling it, make it fast. entryCompression ZipEntryCompression.STORED } -} -// Java projects common configurations. -subprojects { subproj -> - - if (!subproj.file('src/main/java').directory) { - return - } + // Convenience task to list all dependencies per project + tasks.register('listAllDependencies', DependencyReportTask) {} - apply plugin: 'java' - apply plugin: 'java-test-fixtures' - apply plugin: 'com.github.spotbugs' + // Common java configurations java { sourceCompatibility = JavaVersion.VERSION_21 @@ -200,26 +58,9 @@ subprojects { subproj -> } } - if (isConnectorProject(subproj)) { - // This is a Java connector project. - - // Evaluate CDK project before evaluating the connector. - evaluationDependsOn(':airbyte-cdk:java:airbyte-cdk') - - if (!gradle.startParameter.taskNames.any { it.contains(':airbyte-cdk:') } && - gradle.startParameter.taskNames.any { it.contains(':source-') || it.contains(':destination-') }) { - // We are building a connector. Warn if the CDK JAR is missing or out of date. - final String cdkRelativePath = 'airbyte-cdk/java/airbyte-cdk' - afterEvaluate { - def cdkVersionNeeded = getCDKSnapshotRequirement(configurations.compileClasspath.incoming.resolutionResult.allDependencies) - checkCDKJarExists(cdkVersionNeeded) - } - } - } - spotbugs { ignoreFailures = false - effort = Effort.valueOf(rootProject.ext.skipSlowTests ? 'MIN' : 'MAX') + effort = Effort.valueOf(System.getProperty('skipSlowTests', 'false') == 'false' ? 'MAX' : 'MIN') excludeFilter.set rootProject.file('spotbugs-exclude-filter-file.xml') reportLevel = Confidence.valueOf('HIGH') showProgress = false @@ -264,7 +105,7 @@ subprojects { subproj -> // Order test classes by annotation. systemProperty 'junit.jupiter.testclass.order.default', 'org.junit.jupiter.api.ClassOrderer$OrderAnnotation' - if (!subproj.hasProperty('testExecutionConcurrency')) { + if (!project.hasProperty('testExecutionConcurrency')) { // By default, let gradle spawn as many independent workers as it wants. maxParallelForks = Runtime.runtime.availableProcessors() maxHeapSize = '3G' @@ -274,7 +115,7 @@ subprojects { subproj -> maxParallelForks = 1 maxHeapSize = '8G' // Manage test execution concurrency in JUnit. - String concurrency = subproj.property('testExecutionConcurrency').toString() + String concurrency = project.property('testExecutionConcurrency').toString() if (concurrency.isInteger() && (concurrency as int) > 0) { // Define a fixed number of threads when the property is set to a positive integer. systemProperty 'junit.jupiter.execution.parallel.config.fixed.parallelism', concurrency @@ -283,34 +124,41 @@ subprojects { subproj -> systemProperty 'junit.jupiter.execution.parallel.config.strategy', 'dynamic' } } - - // Exclude all connector unit tests upon request. - if (rootProject.ext.skipSlowTests) { - exclude '**/io/airbyte/integrations/source/**' - exclude '**/io/airbyte/integrations/destination/**' - } } dependencies { - // Lombok dependencies - compileOnly libs.lombok - annotationProcessor libs.lombok - testCompileOnly libs.lombok - testAnnotationProcessor libs.lombok - testFixturesCompileOnly libs.lombok - testFixturesAnnotationProcessor libs.lombok - - // JUnit dependencies - testRuntimeOnly libs.junit.jupiter.engine - testImplementation libs.bundles.junit - testImplementation libs.assertj.core - testImplementation libs.junit.pioneer - testFixturesImplementation libs.bundles.junit - testFixturesImplementation libs.assertj.core - testFixturesImplementation libs.junit.pioneer - - // adds owasp plugin - implementation 'com.github.spotbugs:spotbugs-annotations:4.8.3' + // Lombok dependencies. + def lombok = "org.projectlombok:lombok:1.18.30" + compileOnly lombok + annotationProcessor lombok + testCompileOnly lombok + testAnnotationProcessor lombok + testFixturesCompileOnly lombok + testFixturesAnnotationProcessor lombok + + // JUnit dependencies. + def vAssertJ = "3.21.0" + def vJUnit = "5.9.1" + def vJUnitJupiter = "5.10.0" + def vJUnitPioneer = "1.7.1" + + testFixturesImplementation "org.junit.jupiter:junit-jupiter-api:${vJUnit}" + testFixturesImplementation "org.junit.jupiter:junit-jupiter-params:${vJUnit}" + testFixturesImplementation "org.mockito:mockito-junit-jupiter:${vJUnitJupiter}" + testFixturesImplementation "org.assertj:assertj-core:${vAssertJ}" + testFixturesImplementation "org.junit-pioneer:junit-pioneer:${vJUnitPioneer}" + + testImplementation "org.junit.jupiter:junit-jupiter-api:${vJUnit}" + testImplementation "org.junit.jupiter:junit-jupiter-params:${vJUnit}" + testImplementation "org.mockito:mockito-junit-jupiter:${vJUnitJupiter}" + testImplementation "org.assertj:assertj-core:${vAssertJ}" + testImplementation "org.junit-pioneer:junit-pioneer:${vJUnitPioneer}" + + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${vJUnit}" + + // Spotbugs dependencies. + def vSpotbugs = "4.8.3" + implementation "com.github.spotbugs:spotbugs-annotations:${vSpotbugs}" } tasks.withType(SpotBugsTask).configureEach { @@ -323,107 +171,3 @@ subprojects { subproj -> javadoc.options.addStringOption('Xdoclint:none', '-quiet') } - -// integration and performance test tasks per project -allprojects { - tasks.register('integrationTest') { - dependsOn tasks.matching { - [ - 'integrationTestJava', - 'integrationTestPython', - ].contains(it.name) - } - } - - tasks.register('performanceTest') { - dependsOn tasks.matching { - [ - 'performanceTestJava', - ].contains(it.name) - } - } -} - - -// convenience task to list all dependencies per project -subprojects { - tasks.register('listAllDependencies', DependencyReportTask) {} -} - -// airbyte-ci tasks for local development -def poetryInstallAirbyteCI = tasks.register('poetryInstallAirbyteCI', Exec) { - workingDir rootProject.file('airbyte-ci/connectors/pipelines') - commandLine rootProject.file('.venv/bin/python').absolutePath - args "-m", "poetry", "install", "--no-cache" -} -poetryInstallAirbyteCI.configure { - dependsOn tasks.named('pipInstall') -} -def poetryCleanVirtualenv = tasks.register('cleanVirtualenv', Exec) { - workingDir rootProject.file('airbyte-ci/connectors/pipelines') - commandLine rootProject.file('.venv/bin/python').absolutePath - args "-m", "poetry", "env", "remove", "--all" - onlyIf { - rootProject.file('.venv/bin/python').exists() - } -} -cleanPythonVenv.configure { - dependsOn poetryCleanVirtualenv -} - -subprojects { - if (!isConnectorProject(project)) { - return - } - def airbyteCIConnectorsTask = { String taskName, String... connectorsArgs -> - def task = tasks.register(taskName, Exec) { - workingDir rootDir - environment "CI", "1" // set to use more suitable logging format - commandLine rootProject.file('.venv/bin/python').absolutePath - args "-m", "poetry" - args "--directory", "${rootProject.file('airbyte-ci/connectors/pipelines').absolutePath}" - args "run" - args "airbyte-ci", "connectors", "--name=${project.name}" - args connectorsArgs - // Forbid these kinds of tasks from running concurrently. - // We can induce serial execution by giving them all a common output directory. - outputs.dir rootProject.file("${rootProject.buildDir}/airbyte-ci-lock") - outputs.upToDateWhen { false } - } - task.configure { dependsOn poetryInstallAirbyteCI } - return task - } - - // Build connector image as part of 'assemble' task. - // This is required for local 'integrationTest' execution. - def buildConnectorImage = airbyteCIConnectorsTask( - 'buildConnectorImage', '--disable-report-auto-open', 'build', '--use-host-gradle-dist-tar') - buildConnectorImage.configure { - // Images for java projects always rely on the distribution tarball. - dependsOn tasks.matching { it.name == 'distTar' } - // Ensure that all files exist beforehand. - dependsOn tasks.matching { it.name == 'generate' } - } - tasks.named('assemble').configure { - // We may revisit the dependency on assemble but the dependency should always be on a base task. - dependsOn buildConnectorImage - } - - // Convenience tasks for local airbyte-ci execution. - airbyteCIConnectorsTask('airbyteCIConnectorBuild', 'build') - airbyteCIConnectorsTask('airbyteCIConnectorTest', 'test') -} - -// produce reproducible archives -// (see https://docs.gradle.org/current/userguide/working_with_files.html#sec:reproducible_archives) -tasks.withType(AbstractArchiveTask).configureEach { - preserveFileTimestamps = false - reproducibleFileOrder = true -} - -// pin dependency versions according to ./deps.toml -catalog { - versionCatalog { - from(files("deps.toml")) - } -} diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 0e2dd4d1f248..21109a19fa65 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -4,20 +4,7 @@ plugins { repositories { // # Gradle looks for dependency artifacts in repositories listed in 'repositories' blocks in descending order. - - // ## Prefer repos controlled by Airbyte. - // TODO: add airbyte-controlled proxy repos here - - // ## Look into other, public repos. - // Gradle plugin portal. gradlePluginPortal() - // Maven Central has most of everything. - mavenCentral() -} - -dependencies { - implementation 'ru.vyarus:gradle-use-python-plugin:2.3.0' - implementation 'org.apache.commons:commons-text:1.10.0' } tasks.withType(Jar).configureEach { diff --git a/buildSrc/src/main/groovy/airbyte-integration-test-java.gradle b/buildSrc/src/main/groovy/airbyte-integration-test-java.gradle deleted file mode 100644 index ba5dab9a405c..000000000000 --- a/buildSrc/src/main/groovy/airbyte-integration-test-java.gradle +++ /dev/null @@ -1,62 +0,0 @@ -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.tasks.testing.Test - -class AirbyteIntegrationTestJavaPlugin implements Plugin { - void apply(Project project) { - project.sourceSets { - integrationTestJava { - java { - srcDir 'src/test-integration/java' - } - resources { - srcDir 'src/test-integration/resources' - } - } - } - project.tasks.named('check').configure { - dependsOn project.tasks.matching { it.name == 'compileIntegrationTestJavaJava' } - dependsOn project.tasks.matching { it.name == 'spotbugsIntegrationTestJava' } - } - - project.configurations { - integrationTestJavaImplementation.extendsFrom testImplementation - integrationTestJavaRuntimeOnly.extendsFrom testRuntimeOnly - } - - def integrationTestJava = project.tasks.register('integrationTestJava', Test) { - testClassesDirs = project.sourceSets.integrationTestJava.output.classesDirs - classpath += project.sourceSets.integrationTestJava.runtimeClasspath - - useJUnitPlatform() - testLogging() { - events 'skipped', 'started', 'passed', 'failed' - exceptionFormat 'full' - // Swallow the logs when running in airbyte-ci, rely on test reports instead. - showStandardStreams = !System.getenv().containsKey("RUN_IN_AIRBYTE_CI") - } - - jvmArgs = project.test.jvmArgs - systemProperties = project.test.systemProperties - maxParallelForks = project.test.maxParallelForks - maxHeapSize = project.test.maxHeapSize - - // Tone down the JIT when running the containerized connector to improve overall performance. - // The JVM default settings are optimized for long-lived processes in steady-state operation. - // Unlike in production, the connector containers in these tests are always short-lived. - // It's very much worth injecting a JAVA_OPTS environment variable into the container with - // flags which will reduce startup time at the detriment of long-term performance. - environment 'JOB_DEFAULT_ENV_JAVA_OPTS', '-XX:TieredStopAtLevel=1' - - // Always re-run integration tests no matter what. - outputs.upToDateWhen { false } - } - integrationTestJava.configure { - mustRunAfter project.tasks.named('check') - dependsOn project.tasks.matching { it.name == 'assemble' } - } - project.tasks.named('build').configure { - dependsOn integrationTestJava - } - } -} diff --git a/buildSrc/src/main/groovy/airbyte-java-cdk.gradle b/buildSrc/src/main/groovy/airbyte-java-cdk.gradle deleted file mode 100644 index 68f1c95fdeb6..000000000000 --- a/buildSrc/src/main/groovy/airbyte-java-cdk.gradle +++ /dev/null @@ -1,70 +0,0 @@ -/* -This class facilites detecting the Java CDK target version via readCdkTargetVersion(). -*/ - -import java.util.Properties -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.tasks.testing.Test - -class AirbyteJavaCdkPlugin implements Plugin { - - static String CDK_VERSION_FILE = "airbyte-cdk/java/airbyte-cdk/core/src/main/resources/version.properties" - - String readCdkTargetVersion(Project project) { - Properties cdkVersionProps = new Properties() - project.file("${project.rootDir}/${CDK_VERSION_FILE}").withInputStream { - cdkVersionProps.load(it) - } - return cdkVersionProps.getProperty('version') ?: 'undefined' - } - - @Override - void apply(Project project) { - project.ext.getCdkTargetVersion = { - return readCdkTargetVersion(project) - } - project.getTasks().create("disableLocalCdkRefs", DisableLocalCdkRefsTask.class) - project.getTasks().create("assertNotUsingLocalCdk", AssertNotUsingLocalCdkTask.class) - } - - public static class DisableLocalCdkRefsTask extends DefaultTask { - @TaskAction - public void disableLocalCdkRefs() { - // Step through the project tree and set useLocalCdk to false on all connectors - getProject().rootProject.fileTree(dir: '.', include: '**/build.gradle').forEach(file -> { - String content = file.getText() - if (content.contains("useLocalCdk = true")) { - content = content.replace("useLocalCdk = true", "useLocalCdk = false") - file.setText(content) - System.out.println("Updated " + file.getPath()) - } - }) - } - } - - public static class AssertNotUsingLocalCdkTask extends DefaultTask { - @TaskAction - public void assertNotUsingLocalCdk() { - List foundPaths = new ArrayList<>() - - for (File file : getProject().rootProject.fileTree(dir: '.', include: '**/build.gradle')) { - String content = file.getText() - if (content.contains("useLocalCdk = true")) { - System.err.println("Found usage of 'useLocalCdk = true' in " + file.getPath()) - foundPaths.add(file.getPath()) - } - } - - if (!foundPaths.isEmpty()) { - String errorMessage = String.format( - "Detected usage of 'useLocalCdk = true' in the following files:\n%s\n" + - "This must be set to 'false' before merging to the main branch. \n" + - "NOTE: You can run './gradlew disableLocalCdkRefs' to automatically set it to 'false' on all projects.", - String.join("\n", foundPaths) - ) - throw new RuntimeException(errorMessage) - } - } - } -} diff --git a/buildSrc/src/main/groovy/airbyte-java-connector.gradle b/buildSrc/src/main/groovy/airbyte-java-connector.gradle index 1e35a6129316..d7626c8e5f11 100644 --- a/buildSrc/src/main/groovy/airbyte-java-connector.gradle +++ b/buildSrc/src/main/groovy/airbyte-java-connector.gradle @@ -5,6 +5,7 @@ Also facilitates importing and working with the Java CDK. import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.tasks.testing.Test class AirbyteJavaConnectorExtension { @@ -125,13 +126,106 @@ class AirbyteJavaConnectorPlugin implements Plugin { void apply(Project project) { project.plugins.apply('application') - project.plugins.apply('java-test-fixtures') - project.plugins.apply(AirbyteIntegrationTestJavaPlugin) - project.plugins.apply(AirbytePerformanceTestJavaPlugin) + + project.sourceSets { + integrationTestJava { + java { + srcDir 'src/test-integration/java' + } + resources { + srcDir 'src/test-integration/resources' + } + } + performanceTestJava { + java { + srcDir 'src/test-performance/java' + } + resources { + srcDir 'src/test-performance/resources' + } + } + } + + project.tasks.named('check').configure { + dependsOn project.tasks.matching { it.name ==~ /(compile|spotbugs)[a-zA-Z]*Java/ } + } project.configurations { testFixturesImplementation.extendsFrom implementation testFixturesRuntimeOnly.extendsFrom runtimeOnly + integrationTestJavaImplementation.extendsFrom testImplementation + integrationTestJavaRuntimeOnly.extendsFrom testRuntimeOnly + performanceTestJavaImplementation.extendsFrom testImplementation + performanceTestJavaRuntimeOnly.extendsFrom testRuntimeOnly + } + + boolean withSlowTests = System.getProperty('skipSlowTests', 'false') == 'false' + project.test { + onlyIf { withSlowTests } + } + + def integrationTestJava = project.tasks.register('integrationTestJava', Test) { + testClassesDirs = project.sourceSets.integrationTestJava.output.classesDirs + classpath += project.sourceSets.integrationTestJava.runtimeClasspath + + useJUnitPlatform() + testLogging() { + events 'skipped', 'started', 'passed', 'failed' + exceptionFormat 'full' + // Swallow the logs when running in airbyte-ci, rely on test reports instead. + showStandardStreams = !System.getenv().containsKey("RUN_IN_AIRBYTE_CI") + } + + jvmArgs = project.test.jvmArgs + systemProperties = project.test.systemProperties + maxParallelForks = project.test.maxParallelForks + maxHeapSize = project.test.maxHeapSize + + // Tone down the JIT when running the containerized connector to improve overall performance. + // The JVM default settings are optimized for long-lived processes in steady-state operation. + // Unlike in production, the connector containers in these tests are always short-lived. + // It's very much worth injecting a JAVA_OPTS environment variable into the container with + // flags which will reduce startup time at the detriment of long-term performance. + environment 'JOB_DEFAULT_ENV_JAVA_OPTS', '-XX:TieredStopAtLevel=1' + + // Always re-run integration tests no matter what. + outputs.upToDateWhen { false } + } + integrationTestJava.configure { + mustRunAfter project.tasks.named('check') + dependsOn project.tasks.matching { it.name == 'assemble' } + onlyIf { withSlowTests } + } + project.tasks.register('integrationTest').configure { + dependsOn integrationTestJava + } + project.tasks.named('build').configure { + dependsOn integrationTestJava + } + + def performanceTestJava = project.tasks.register('performanceTestJava', Test) { + testClassesDirs = project.sourceSets.performanceTestJava.output.classesDirs + classpath += project.sourceSets.performanceTestJava.runtimeClasspath + + systemProperty "cpuLimit", System.getProperty("cpuLimit") + systemProperty "memoryLimit", System.getProperty("memoryLimit") + useJUnitPlatform() + testLogging() { + events "passed", "failed" + exceptionFormat "full" + showStandardStreams = true + } + + outputs.upToDateWhen { false } + maxHeapSize = '3g' + } + performanceTestJava.configure { + mustRunAfter project.tasks.named('check') + dependsOn project.tasks.matching { it.name == 'assemble' } + onlyIf { withSlowTests } + } + project.tasks.register('performanceTest').configure { + dependsOn performanceTestJava } project.dependencies { diff --git a/buildSrc/src/main/groovy/airbyte-performance-test-java.gradle b/buildSrc/src/main/groovy/airbyte-performance-test-java.gradle deleted file mode 100644 index d5ccbbbd0bea..000000000000 --- a/buildSrc/src/main/groovy/airbyte-performance-test-java.gradle +++ /dev/null @@ -1,48 +0,0 @@ -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.tasks.testing.Test - -class AirbytePerformanceTestJavaPlugin implements Plugin { - void apply(Project project) { - project.sourceSets { - performanceTestJava { - java { - srcDir 'src/test-performance/java' - } - resources { - srcDir 'src/test-performance/resources' - } - } - } - project.tasks.named('check').configure { - dependsOn project.tasks.matching { it.name == 'compilePerformanceTestJavaJava' } - dependsOn project.tasks.matching { it.name == 'spotbugsPerformanceTestJava' } - } - - project.configurations { - performanceTestJavaImplementation.extendsFrom testImplementation - performanceTestJavaRuntimeOnly.extendsFrom testRuntimeOnly - } - - def performanceTestJava = project.tasks.register('performanceTestJava', Test) { - testClassesDirs = project.sourceSets.performanceTestJava.output.classesDirs - classpath += project.sourceSets.performanceTestJava.runtimeClasspath - - systemProperty "cpuLimit", System.getProperty("cpuLimit") - systemProperty "memoryLimit", System.getProperty("memoryLimit") - useJUnitPlatform() - testLogging() { - events "passed", "failed" - exceptionFormat "full" - showStandardStreams = true - } - - outputs.upToDateWhen { false } - maxHeapSize = '3g' - } - performanceTestJava.configure { - mustRunAfter project.tasks.named('check') - dependsOn project.tasks.matching { it.name == 'assemble' } - } - } -} diff --git a/settings.gradle b/settings.gradle index 03b647e67635..17f8450c9a95 100644 --- a/settings.gradle +++ b/settings.gradle @@ -32,9 +32,6 @@ dependencyResolutionManagement { repositories { // # Gradle looks for dependency artifacts in repositories listed in 'repositories' blocks in descending order. - // ## Start with the local filesystem. - mavenLocal() - // ## Prefer repos controlled by Airbyte. maven { @@ -105,20 +102,6 @@ dependencyResolutionManagement { includeGroup 'org.apache.kafka' } } - // Node.js download repository, required only by com.github.node-gradle.node plugin. - ivy { - name = "Node.js" - setUrl("https://nodejs.org/dist/") - patternLayout { - artifact("v[revision]/[artifact](-v[revision]-[classifier]).[ext]") - } - metadataSources { - artifact() - } - content { - includeModule("org.nodejs", "node") - } - } } versionCatalogs { @@ -159,22 +142,14 @@ if (isCiServer || isAirbyteCI) { rootProject.name = 'airbyte' -include ':airbyte-cdk:java:airbyte-cdk' -include ':airbyte-cdk:java:airbyte-cdk:dependencies' -include ':airbyte-cdk:java:airbyte-cdk:core' -include ':airbyte-cdk:java:airbyte-cdk:db-destinations' -include ':airbyte-cdk:java:airbyte-cdk:db-sources' -include ':airbyte-cdk:java:airbyte-cdk:s3-destinations' -include ':airbyte-cdk:java:airbyte-cdk:typing-deduping' -include ':airbyte-cdk:java:airbyte-cdk:azure-destinations' -include ':airbyte-cdk:java:airbyte-cdk:gcs-destinations' -include ':airbyte-cdk:java:airbyte-cdk:datastore-bigquery' -include ':airbyte-cdk:java:airbyte-cdk:datastore-mongo' -include ':airbyte-cdk:java:airbyte-cdk:datastore-postgres' - -include ':airbyte-integrations:connector-templates:generator' -include ':airbyte-integrations:connectors-performance:source-harness' -include ':airbyte-integrations:connectors-performance:destination-harness' +// Include all java CDK modules. +def cdkPath = rootDir.toPath().resolve('airbyte-cdk/java/airbyte-cdk') +cdkPath.eachDir { dir -> + def buildFiles = file(dir).list { file, name -> name == "build.gradle" } + if (buildFiles.length == 1) { + include ":airbyte-cdk:java:airbyte-cdk:${dir.getFileName()}" + } +} // Include all java connector projects. def integrationsPath = rootDir.toPath().resolve('airbyte-integrations/connectors') @@ -184,3 +159,8 @@ integrationsPath.eachDir { dir -> include ":airbyte-integrations:connectors:${dir.getFileName()}" } } + +// Include miscellaneous modules. +include ':airbyte-integrations:connector-templates:generator' +include ':airbyte-integrations:connectors-performance:source-harness' +include ':airbyte-integrations:connectors-performance:destination-harness' From 6aba7506bbb9eaf5aa0cab5d7e88ffd1416e50bc Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Fri, 16 Feb 2024 09:31:12 -0800 Subject: [PATCH 08/43] docs: typos (#35302) --- docs/using-airbyte/getting-started/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/using-airbyte/getting-started/readme.md b/docs/using-airbyte/getting-started/readme.md index 72d422d7b1b5..7b43f108ed9a 100644 --- a/docs/using-airbyte/getting-started/readme.md +++ b/docs/using-airbyte/getting-started/readme.md @@ -30,7 +30,7 @@ When self-managing Airbyte, your data never leaves your premises. Get started im With Airbyte Self-Managed Community (Open Source), you can use one of the following options in your infrastructure: - [Local Deployment](/deploying-airbyte/local-deployment.md) (recommended when trying out Airbyte) -- [On Aws](/deploying-airbyte/on-aws-ec2.md) +- [On AWS](/deploying-airbyte/on-aws-ec2.md) - [On Azure VM Cloud Shell](/deploying-airbyte/on-azure-vm-cloud-shell.md) - [On Digital Ocean Droplet](/deploying-airbyte/on-digitalocean-droplet.md) - [On GCP](/deploying-airbyte/on-gcp-compute-engine.md) @@ -43,4 +43,4 @@ With Airbyte Self-Managed Community (Open Source), you can use one of the follow ### Self-Managed Enterprise Airbyte Self-Managed Enterprise is the best way to run Airbyte yourself. You get all 300+ pre-built connectors, data never leaves your environment, and Airbyte becomes self-serve in your organization with new tools to manage multiple users, and multiple teams using Airbyte all in one place. -To start with Self-Managed Enterprrise, navigate to our [Enterprise setup guide](/enterprise-setup/README.md). +To start with Self-Managed Enterprise, navigate to our [Enterprise setup guide](/enterprise-setup/README.md). From ea5e388c8e26b0b14bb841b623f521bdac43968f Mon Sep 17 00:00:00 2001 From: TornadoContre <37258495+TornadoContre@users.noreply.github.com> Date: Fri, 16 Feb 2024 17:51:50 +0000 Subject: [PATCH 09/43] Docs: Update stripe.md (#35142) --- docs/integrations/sources/stripe.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/integrations/sources/stripe.md b/docs/integrations/sources/stripe.md index b00cf3c455c3..2e5bb5e957c3 100644 --- a/docs/integrations/sources/stripe.md +++ b/docs/integrations/sources/stripe.md @@ -224,7 +224,6 @@ Each record is marked with `is_deleted` flag when the appropriate event happens | Version | Date | Pull Request | Subject | | :------ | :--------- | :-------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 5.2.4 | 2024-02-12 | [35137](https://github.com/airbytehq/airbyte/pull/35137) | Fix license in `pyproject.toml` | - | 5.2.3 | 2024-02-09 | [35068](https://github.com/airbytehq/airbyte/pull/35068) | Manage dependencies with Poetry. | | 5.2.2 | 2024-01-31 | [34619](https://github.com/airbytehq/airbyte/pull/34619) | Events stream concurrent on incremental syncs | | 5.2.1 | 2024-01-18 | [34495](https://github.com/airbytehq/airbyte/pull/34495) | Fix deadlock issue | From e420ae269d401c36f8982b77800a720d5be0119c Mon Sep 17 00:00:00 2001 From: Natik Gadzhi Date: Fri, 16 Feb 2024 10:57:45 -0800 Subject: [PATCH 10/43] Test PR to check Slack notifications (#35363) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bdf4db5d1544..af1cd195469c 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ See the [LICENSE](docs/project-overview/licenses/) file for licensing informatio ### Thank You -Airbyte would not be possible without the support and assistance of other open-source tools and companies. Visit our [thank you page](THANK-YOU.md) to learn more about how we build Airbyte. +Airbyte would not be possible without the support and assistance of other open-source tools and companies! Visit our [thank you page](THANK-YOU.md) to learn more about how we build Airbyte. From 08119e652969eebcd141a44fe27a9f17272e1edb Mon Sep 17 00:00:00 2001 From: Marius Posta Date: Fri, 16 Feb 2024 11:25:26 -0800 Subject: [PATCH 11/43] airbyte-ci: remove reference to buildConnectorImage (#35364) --- airbyte-ci/connectors/pipelines/README.md | 1 + .../airbyte_ci/connectors/test/steps/java_connectors.py | 6 +++++- airbyte-ci/connectors/pipelines/pyproject.toml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/airbyte-ci/connectors/pipelines/README.md b/airbyte-ci/connectors/pipelines/README.md index aa67c0ae4296..44f862c15427 100644 --- a/airbyte-ci/connectors/pipelines/README.md +++ b/airbyte-ci/connectors/pipelines/README.md @@ -640,6 +640,7 @@ E.G.: running Poe tasks on the modified internal packages of the current branch: | Version | PR | Description | | ------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| 4.2.2 | [#35364](https://github.com/airbytehq/airbyte/pull/35364) | Fix connector tests following gradle changes in #35307. | | 4.2.1 | [#35204](https://github.com/airbytehq/airbyte/pull/35204) | Run `poetry check` before `poetry install` on poetry package install. | | 4.2.0 | [#35103](https://github.com/airbytehq/airbyte/pull/35103) | Java 21 support. | | 4.1.4 | [#35039](https://github.com/airbytehq/airbyte/pull/35039) | Fix bug which prevented gradle test reports from being added. | diff --git a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/java_connectors.py b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/java_connectors.py index f944db98ead4..c69a0ac4fb42 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/java_connectors.py +++ b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/java_connectors.py @@ -43,7 +43,11 @@ class IntegrationTests(GradleTask): @property def default_params(self) -> STEP_PARAMS: return super().default_params | { - "-x": ["buildConnectorImage", "assemble"], # Exclude the buildConnectorImage and assemble tasks + # Exclude the assemble task to avoid a circular dependency on airbyte-ci. + # The integrationTestJava gradle task depends on assemble, which in turns + # depends on buildConnectorImage to build the connector's docker image. + # At this point, the docker image has already been built. + "-x": ["assemble"], } async def _load_normalization_image(self, normalization_tar_file: File) -> None: diff --git a/airbyte-ci/connectors/pipelines/pyproject.toml b/airbyte-ci/connectors/pipelines/pyproject.toml index 43720530cfa0..36c99f486ee4 100644 --- a/airbyte-ci/connectors/pipelines/pyproject.toml +++ b/airbyte-ci/connectors/pipelines/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "pipelines" -version = "4.2.1" +version = "4.2.2" description = "Packaged maintained by the connector operations team to perform CI for connectors' pipelines" authors = ["Airbyte "] From ee7da12dacff962852d6253e9d7437b2e2e929f6 Mon Sep 17 00:00:00 2001 From: Catherine Noll Date: Fri, 16 Feb 2024 14:52:23 -0500 Subject: [PATCH 12/43] Source S3: revert rollback to 4.4.1 (#35055) Co-authored-by: Augustin --- .../connectors/source-s3/metadata.yaml | 3 +- .../connectors/source-s3/poetry.lock | 96 +++++++++---------- .../connectors/source-s3/pyproject.toml | 4 +- .../source-s3/source_s3/v4/source.py | 2 - docs/integrations/sources/s3.md | 3 +- poetry.lock | 22 ++--- 6 files changed, 64 insertions(+), 66 deletions(-) diff --git a/airbyte-integrations/connectors/source-s3/metadata.yaml b/airbyte-integrations/connectors/source-s3/metadata.yaml index 637b11a4c171..f74b6ac72f2a 100644 --- a/airbyte-integrations/connectors/source-s3/metadata.yaml +++ b/airbyte-integrations/connectors/source-s3/metadata.yaml @@ -10,7 +10,7 @@ data: connectorSubtype: file connectorType: source definitionId: 69589781-7828-43c5-9f63-8925b1c1ccc2 - dockerImageTag: 4.5.3 + dockerImageTag: 4.5.4 dockerRepository: airbyte/source-s3 documentationUrl: https://docs.airbyte.com/integrations/sources/s3 githubIssueLabel: source-s3 @@ -23,7 +23,6 @@ data: packageName: airbyte-source-s3 registries: cloud: - dockerImageTag: 4.4.1 enabled: true oss: enabled: true diff --git a/airbyte-integrations/connectors/source-s3/poetry.lock b/airbyte-integrations/connectors/source-s3/poetry.lock index bd8384646005..168bad963884 100644 --- a/airbyte-integrations/connectors/source-s3/poetry.lock +++ b/airbyte-integrations/connectors/source-s3/poetry.lock @@ -1,14 +1,14 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "airbyte-cdk" -version = "0.61.0" +version = "0.63.1" description = "A framework for writing Airbyte Connectors." optional = false python-versions = ">=3.8" files = [ - {file = "airbyte-cdk-0.61.0.tar.gz", hash = "sha256:8beda008c5a177041ac02860a431ce7b1ecd00062a4a8f31fe6ac446cbed3e70"}, - {file = "airbyte_cdk-0.61.0-py3-none-any.whl", hash = "sha256:3f989bfe692c9519d61f9120ddb744ab82c432c2caf25374d4d6f5cdc374a1e9"}, + {file = "airbyte-cdk-0.63.1.tar.gz", hash = "sha256:e1442e2219d8620ee1716c6830b17de51190cf81061381e42c7a362cc5a63501"}, + {file = "airbyte_cdk-0.63.1-py3-none-any.whl", hash = "sha256:d699012515939c8bae82d7f83a8e6d66306ef3da6904def4c8a90e0d371e09e2"}, ] [package.dependencies] @@ -140,17 +140,17 @@ lxml = ["lxml"] [[package]] name = "boto3" -version = "1.34.39" +version = "1.34.43" description = "The AWS SDK for Python" optional = false python-versions = ">= 3.8" files = [ - {file = "boto3-1.34.39-py3-none-any.whl", hash = "sha256:476896e70d36c9134d4125834280c597c17b54bff4902baf2e5fcde74f8acec8"}, - {file = "boto3-1.34.39.tar.gz", hash = "sha256:35bcbecf1b5d3620c93f0062d2994177f8bda25a9d2cba144d6462793c16065b"}, + {file = "boto3-1.34.43-py3-none-any.whl", hash = "sha256:179cdcff2dee116ff0bbe10c21a374fff8ae0d9ea3842bd8dd2c9f69e8185d91"}, + {file = "boto3-1.34.43.tar.gz", hash = "sha256:ed646f600b76939d54fa1ff868415793551a5a08b9de0a09696b46d116da7da5"}, ] [package.dependencies] -botocore = ">=1.34.39,<1.35.0" +botocore = ">=1.34.43,<1.35.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -159,13 +159,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.39" +version = "1.34.43" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">= 3.8" files = [ - {file = "botocore-1.34.39-py3-none-any.whl", hash = "sha256:e175360445424b83b0e28ae20d301b99cf44ff2c9d5ab1d8670899bec05a9753"}, - {file = "botocore-1.34.39.tar.gz", hash = "sha256:9f00bd5e4698bcdd37ce6e224a896baf58d209678ed92834944b767de9061cc5"}, + {file = "botocore-1.34.43-py3-none-any.whl", hash = "sha256:ab7d8046a8c3326ecf3d9f9884e79aa77fed864416ed8af52b9e22ab055acf4e"}, + {file = "botocore-1.34.43.tar.gz", hash = "sha256:00dea9fd602dc97420318d373079bdfcc8da34501aaa908ab98b477526bdefec"}, ] [package.dependencies] @@ -438,43 +438,43 @@ files = [ [[package]] name = "cryptography" -version = "42.0.2" +version = "42.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be"}, - {file = "cryptography-42.0.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529"}, - {file = "cryptography-42.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9"}, - {file = "cryptography-42.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2"}, - {file = "cryptography-42.0.2-cp37-abi3-win32.whl", hash = "sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee"}, - {file = "cryptography-42.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee"}, - {file = "cryptography-42.0.2-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90"}, - {file = "cryptography-42.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea"}, - {file = "cryptography-42.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33"}, - {file = "cryptography-42.0.2-cp39-abi3-win32.whl", hash = "sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635"}, - {file = "cryptography-42.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2"}, - {file = "cryptography-42.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a"}, - {file = "cryptography-42.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65"}, - {file = "cryptography-42.0.2.tar.gz", hash = "sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888"}, + {file = "cryptography-42.0.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:de5086cd475d67113ccb6f9fae6d8fe3ac54a4f9238fd08bfdb07b03d791ff0a"}, + {file = "cryptography-42.0.3-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:935cca25d35dda9e7bd46a24831dfd255307c55a07ff38fd1a92119cffc34857"}, + {file = "cryptography-42.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20100c22b298c9eaebe4f0b9032ea97186ac2555f426c3e70670f2517989543b"}, + {file = "cryptography-42.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eb6368d5327d6455f20327fb6159b97538820355ec00f8cc9464d617caecead"}, + {file = "cryptography-42.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:39d5c93e95bcbc4c06313fc6a500cee414ee39b616b55320c1904760ad686938"}, + {file = "cryptography-42.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d96ea47ce6d0055d5b97e761d37b4e84195485cb5a38401be341fabf23bc32a"}, + {file = "cryptography-42.0.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d1998e545081da0ab276bcb4b33cce85f775adb86a516e8f55b3dac87f469548"}, + {file = "cryptography-42.0.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93fbee08c48e63d5d1b39ab56fd3fdd02e6c2431c3da0f4edaf54954744c718f"}, + {file = "cryptography-42.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:90147dad8c22d64b2ff7331f8d4cddfdc3ee93e4879796f837bdbb2a0b141e0c"}, + {file = "cryptography-42.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4dcab7c25e48fc09a73c3e463d09ac902a932a0f8d0c568238b3696d06bf377b"}, + {file = "cryptography-42.0.3-cp37-abi3-win32.whl", hash = "sha256:1e935c2900fb53d31f491c0de04f41110351377be19d83d908c1fd502ae8daa5"}, + {file = "cryptography-42.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:762f3771ae40e111d78d77cbe9c1035e886ac04a234d3ee0856bf4ecb3749d54"}, + {file = "cryptography-42.0.3-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3ec384058b642f7fb7e7bff9664030011ed1af8f852540c76a1317a9dd0d20"}, + {file = "cryptography-42.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35772a6cffd1f59b85cb670f12faba05513446f80352fe811689b4e439b5d89e"}, + {file = "cryptography-42.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04859aa7f12c2b5f7e22d25198ddd537391f1695df7057c8700f71f26f47a129"}, + {file = "cryptography-42.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c3d1f5a1d403a8e640fa0887e9f7087331abb3f33b0f2207d2cc7f213e4a864c"}, + {file = "cryptography-42.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df34312149b495d9d03492ce97471234fd9037aa5ba217c2a6ea890e9166f151"}, + {file = "cryptography-42.0.3-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:de4ae486041878dc46e571a4c70ba337ed5233a1344c14a0790c4c4be4bbb8b4"}, + {file = "cryptography-42.0.3-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0fab2a5c479b360e5e0ea9f654bcebb535e3aa1e493a715b13244f4e07ea8eec"}, + {file = "cryptography-42.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25b09b73db78facdfd7dd0fa77a3f19e94896197c86e9f6dc16bce7b37a96504"}, + {file = "cryptography-42.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d5cf11bc7f0b71fb71af26af396c83dfd3f6eed56d4b6ef95d57867bf1e4ba65"}, + {file = "cryptography-42.0.3-cp39-abi3-win32.whl", hash = "sha256:0fea01527d4fb22ffe38cd98951c9044400f6eff4788cf52ae116e27d30a1ba3"}, + {file = "cryptography-42.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:2619487f37da18d6826e27854a7f9d4d013c51eafb066c80d09c63cf24505306"}, + {file = "cryptography-42.0.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ead69ba488f806fe1b1b4050febafdbf206b81fa476126f3e16110c818bac396"}, + {file = "cryptography-42.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:20180da1b508f4aefc101cebc14c57043a02b355d1a652b6e8e537967f1e1b46"}, + {file = "cryptography-42.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5fbf0f3f0fac7c089308bd771d2c6c7b7d53ae909dce1db52d8e921f6c19bb3a"}, + {file = "cryptography-42.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c23f03cfd7d9826cdcbad7850de67e18b4654179e01fe9bc623d37c2638eb4ef"}, + {file = "cryptography-42.0.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:db0480ffbfb1193ac4e1e88239f31314fe4c6cdcf9c0b8712b55414afbf80db4"}, + {file = "cryptography-42.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:6c25e1e9c2ce682d01fc5e2dde6598f7313027343bd14f4049b82ad0402e52cd"}, + {file = "cryptography-42.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9541c69c62d7446539f2c1c06d7046aef822940d248fa4b8962ff0302862cc1f"}, + {file = "cryptography-42.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b797099d221df7cce5ff2a1d272761d1554ddf9a987d3e11f6459b38cd300fd"}, + {file = "cryptography-42.0.3.tar.gz", hash = "sha256:069d2ce9be5526a44093a0991c450fe9906cdf069e0e7cd67d9dee49a62b9ebe"}, ] [package.dependencies] @@ -2119,13 +2119,13 @@ test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "tes [[package]] name = "responses" -version = "0.24.1" +version = "0.25.0" description = "A utility library for mocking out the `requests` Python library." optional = false python-versions = ">=3.8" files = [ - {file = "responses-0.24.1-py3-none-any.whl", hash = "sha256:a2b43f4c08bfb9c9bd242568328c65a34b318741d3fab884ac843c5ceeb543f9"}, - {file = "responses-0.24.1.tar.gz", hash = "sha256:b127c6ca3f8df0eb9cc82fd93109a3007a86acb24871834c47b77765152ecf8c"}, + {file = "responses-0.25.0-py3-none-any.whl", hash = "sha256:2f0b9c2b6437db4b528619a77e5d565e4ec2a9532162ac1a131a83529db7be1a"}, + {file = "responses-0.25.0.tar.gz", hash = "sha256:01ae6a02b4f34e39bffceb0fc6786b67a25eae919c6368d05eabc8d9576c2a66"}, ] [package.dependencies] @@ -2588,4 +2588,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9,<3.12" -content-hash = "1c63ed55c4051023e9b025d719780f61e6e88f6baa7c00ebfba1c5d532a00a49" +content-hash = "e1d8b49218f24ab7ceb86c74a9374287891f17e6481215e1049163a61df28f85" diff --git a/airbyte-integrations/connectors/source-s3/pyproject.toml b/airbyte-integrations/connectors/source-s3/pyproject.toml index d1bece884901..aaa22997c6f0 100644 --- a/airbyte-integrations/connectors/source-s3/pyproject.toml +++ b/airbyte-integrations/connectors/source-s3/pyproject.toml @@ -3,7 +3,7 @@ requires = [ "poetry-core>=1.0.0",] build-backend = "poetry.core.masonry.api" [tool.poetry] -version = "4.5.3" +version = "4.5.4" name = "source-s3" description = "Source implementation for S3." authors = [ "Airbyte ",] @@ -27,7 +27,7 @@ source-s3 = "source_s3.run:run" [tool.poetry.dependencies.airbyte-cdk] extras = [ "file-based",] -version = "==0.61.0" +version = "^0" [tool.poetry.dependencies.smart-open] extras = [ "s3",] diff --git a/airbyte-integrations/connectors/source-s3/source_s3/v4/source.py b/airbyte-integrations/connectors/source-s3/source_s3/v4/source.py index 22a801597aaa..30eff74f7694 100644 --- a/airbyte-integrations/connectors/source-s3/source_s3/v4/source.py +++ b/airbyte-integrations/connectors/source-s3/source_s3/v4/source.py @@ -21,8 +21,6 @@ class SourceS3(FileBasedSource): - _concurrency_level = DEFAULT_CONCURRENCY - @classmethod def read_config(cls, config_path: str) -> Mapping[str, Any]: """ diff --git a/docs/integrations/sources/s3.md b/docs/integrations/sources/s3.md index ee1ea400a196..d225bba5909a 100644 --- a/docs/integrations/sources/s3.md +++ b/docs/integrations/sources/s3.md @@ -260,7 +260,8 @@ To perform the text extraction from PDF and Docx files, the connector uses the [ | Version | Date | Pull Request | Subject | |:--------|:-----------|:----------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------| -| 4.5.3 | 2024-02-12 | [35164](https://github.com/airbytehq/airbyte/pull/35164) | Manage dependencies with Poetry. | +| 4.5.4 | 2024-02-15 | [35055](https://github.com/airbytehq/airbyte/pull/35055) | Temporarily revert concurrency | +| 4.5.3 | 2024-02-12 | [35164](https://github.com/airbytehq/airbyte/pull/35164) | Manage dependencies with Poetry. | | 4.5.2 | 2024-02-06 | [34930](https://github.com/airbytehq/airbyte/pull/34930) | Bump CDK version to fix issue when SyncMode is missing from catalog | | 4.5.1 | 2024-02-02 | [31701](https://github.com/airbytehq/airbyte/pull/31701) | Add `region` support | | 4.5.0 | 2024-02-01 | [34591](https://github.com/airbytehq/airbyte/pull/34591) | Run full refresh syncs concurrently | diff --git a/poetry.lock b/poetry.lock index 7e3ee153c35a..ee642ef6ca8c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "black" @@ -99,29 +99,29 @@ files = [ [[package]] name = "pathspec" -version = "0.11.2" +version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] name = "platformdirs" -version = "3.11.0" +version = "4.2.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, - {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [[package]] name = "tomli" From eb16b58d99e5a71f8f76c74bc6422cb50d680164 Mon Sep 17 00:00:00 2001 From: Thomas Dippel Date: Fri, 16 Feb 2024 21:07:39 +0100 Subject: [PATCH 13/43] =?UTF-8?q?=F0=9F=90=9B=20Source=20OpsGenie:=20fix?= =?UTF-8?q?=20parsing=20of=20updated=5Fat=20timestamps=20from=20OpsGenie?= =?UTF-8?q?=20(#35269)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: marcosmarxm --- airbyte-integrations/connectors/source-opsgenie/Dockerfile | 2 +- airbyte-integrations/connectors/source-opsgenie/metadata.yaml | 2 +- .../connectors/source-opsgenie/source_opsgenie/manifest.yaml | 1 + docs/integrations/sources/opsgenie.md | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/airbyte-integrations/connectors/source-opsgenie/Dockerfile b/airbyte-integrations/connectors/source-opsgenie/Dockerfile index b8cc08291b97..2e6395d06e2e 100644 --- a/airbyte-integrations/connectors/source-opsgenie/Dockerfile +++ b/airbyte-integrations/connectors/source-opsgenie/Dockerfile @@ -34,5 +34,5 @@ COPY source_opsgenie ./source_opsgenie ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.3.0 +LABEL io.airbyte.version=0.3.1 LABEL io.airbyte.name=airbyte/source-opsgenie diff --git a/airbyte-integrations/connectors/source-opsgenie/metadata.yaml b/airbyte-integrations/connectors/source-opsgenie/metadata.yaml index 995487473494..1c7f9af426a1 100644 --- a/airbyte-integrations/connectors/source-opsgenie/metadata.yaml +++ b/airbyte-integrations/connectors/source-opsgenie/metadata.yaml @@ -2,7 +2,7 @@ data: connectorSubtype: api connectorType: source definitionId: 06bdb480-2598-40b8-8b0f-fc2e2d2abdda - dockerImageTag: 0.3.0 + dockerImageTag: 0.3.1 dockerRepository: airbyte/source-opsgenie githubIssueLabel: source-opsgenie license: MIT diff --git a/airbyte-integrations/connectors/source-opsgenie/source_opsgenie/manifest.yaml b/airbyte-integrations/connectors/source-opsgenie/source_opsgenie/manifest.yaml index a1c6b1e07e72..83473e392ca4 100644 --- a/airbyte-integrations/connectors/source-opsgenie/source_opsgenie/manifest.yaml +++ b/airbyte-integrations/connectors/source-opsgenie/source_opsgenie/manifest.yaml @@ -107,6 +107,7 @@ definitions: cursor_field: updatedAt cursor_datetime_formats: - "%Y-%m-%dT%H:%M:%S.%fZ" + - "%Y-%m-%dT%H:%M:%SZ" datetime_format: "%s" start_datetime: datetime: "{{ config['start_date'] }}" diff --git a/docs/integrations/sources/opsgenie.md b/docs/integrations/sources/opsgenie.md index 088d27f21988..a40bdc02de50 100644 --- a/docs/integrations/sources/opsgenie.md +++ b/docs/integrations/sources/opsgenie.md @@ -51,6 +51,7 @@ The Opsgenie connector uses the most recent API version for each source of data. | Version | Date | Pull Request | Subject | |:--------|:-----------|:-----------------------------------------------------| :--- | +| 0.3.1 | 2024-02-14 | [35269](https://github.com/airbytehq/airbyte/pull/35269) | Fix parsing of updated_at timestamps in alerts | | 0.3.0 | 2023-10-19 | [31552](https://github.com/airbytehq/airbyte/pull/31552) | Migrated to Low Code | | 0.2.0 | 2023-10-24 | [31777](https://github.com/airbytehq/airbyte/pull/31777) | Fix schema | | 0.1.0 | 2022-09-14 | [16768](https://github.com/airbytehq/airbyte/pull/16768) | Initial Release | From 588ce5627e75430c16bc09f336f5c7e17e2b68bc Mon Sep 17 00:00:00 2001 From: Evan Tahler Date: Fri, 16 Feb 2024 13:04:06 -0800 Subject: [PATCH 14/43] Archive `destination-kvdb` (#35370) --- .../connectors/destination-kvdb/.dockerignore | 5 - .../connectors/destination-kvdb/Dockerfile | 16 -- .../connectors/destination-kvdb/README.md | 118 --------------- .../destination_kvdb/__init__.py | 26 ---- .../destination_kvdb/client.py | 78 ---------- .../destination_kvdb/destination.py | 72 --------- .../destination_kvdb/spec.json | 26 ---- .../destination_kvdb/writer.py | 46 ------ .../integration_tests/integration_test.py | 138 ------------------ .../connectors/destination-kvdb/main.py | 11 -- .../destination-kvdb/requirements.txt | 1 - .../connectors/destination-kvdb/setup.py | 26 ---- .../destination-kvdb/unit_tests/unit_test.py | 7 - docs/integrations/destinations/kvdb.md | 2 +- 14 files changed, 1 insertion(+), 571 deletions(-) delete mode 100644 airbyte-integrations/connectors/destination-kvdb/.dockerignore delete mode 100644 airbyte-integrations/connectors/destination-kvdb/Dockerfile delete mode 100644 airbyte-integrations/connectors/destination-kvdb/README.md delete mode 100644 airbyte-integrations/connectors/destination-kvdb/destination_kvdb/__init__.py delete mode 100644 airbyte-integrations/connectors/destination-kvdb/destination_kvdb/client.py delete mode 100644 airbyte-integrations/connectors/destination-kvdb/destination_kvdb/destination.py delete mode 100644 airbyte-integrations/connectors/destination-kvdb/destination_kvdb/spec.json delete mode 100644 airbyte-integrations/connectors/destination-kvdb/destination_kvdb/writer.py delete mode 100644 airbyte-integrations/connectors/destination-kvdb/integration_tests/integration_test.py delete mode 100644 airbyte-integrations/connectors/destination-kvdb/main.py delete mode 100644 airbyte-integrations/connectors/destination-kvdb/requirements.txt delete mode 100644 airbyte-integrations/connectors/destination-kvdb/setup.py delete mode 100644 airbyte-integrations/connectors/destination-kvdb/unit_tests/unit_test.py diff --git a/airbyte-integrations/connectors/destination-kvdb/.dockerignore b/airbyte-integrations/connectors/destination-kvdb/.dockerignore deleted file mode 100644 index 1b4b5767b554..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/.dockerignore +++ /dev/null @@ -1,5 +0,0 @@ -* -!Dockerfile -!main.py -!destination_kvdb -!setup.py diff --git a/airbyte-integrations/connectors/destination-kvdb/Dockerfile b/airbyte-integrations/connectors/destination-kvdb/Dockerfile deleted file mode 100644 index fba4f5cb3d41..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/Dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM python:3.9.11-alpine3.15 - -# Bash is installed for more convenient debugging. -RUN apt-get update && apt-get install -y bash && rm -rf /var/lib/apt/lists/* - -WORKDIR /airbyte/integration_code -COPY destination_kvdb ./destination_kvdb -COPY main.py ./ -COPY setup.py ./ -RUN pip install . - -ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" -ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] - -LABEL io.airbyte.version=0.1.0 -LABEL io.airbyte.name=airbyte/destination-kvdb diff --git a/airbyte-integrations/connectors/destination-kvdb/README.md b/airbyte-integrations/connectors/destination-kvdb/README.md deleted file mode 100644 index b834894111b6..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/README.md +++ /dev/null @@ -1,118 +0,0 @@ -# Kvdb Destination - -This is the repository for the [Kvdb](https://kvdb.io) destination connector, written in Python. It is intended to be an example for how to write a Python destination. KvDB is a very simple key value store, which makes it great for the purposes of illustrating how to write a Python destination connector. - -## Local development - -### Prerequisites -**To iterate on this connector, make sure to complete this prerequisites section.** - -#### Minimum Python version required `= 3.7.0` - -#### Build & Activate Virtual Environment and install dependencies -From this connector directory, create a virtual environment: -``` -python -m venv .venv -``` - -This will generate a virtualenv for this module in `.venv/`. Make sure this venv is active in your -development environment of choice. To activate it from the terminal, run: -``` -source .venv/bin/activate -pip install -r requirements.txt -``` -If you are in an IDE, follow your IDE's instructions to activate the virtualenv. - -Note that while we are installing dependencies from `requirements.txt`, you should only edit `setup.py` for your dependencies. `requirements.txt` is -used for editable installs (`pip install -e`) to pull in Python dependencies from the monorepo and will call `setup.py`. -If this is mumbo jumbo to you, don't worry about it, just put your deps in `setup.py` but install using `pip install -r requirements.txt` and everything -should work as you expect. - -#### Building via Gradle -From the Airbyte repository root, run: -``` -./gradlew :airbyte-integrations:connectors:destination-kvdb:build -``` - -#### Create credentials -**If you are a community contributor**, generate the necessary credentials from [Kvdb](https://kvdb.io/docs/api/), and then create a file `secrets/config.json` conforming to the `destination_kvdb/spec.json` file. -Note that the `secrets` directory is gitignored by default, so there is no danger of accidentally checking in sensitive information. -See `integration_tests/sample_config.json` for a sample config file. - -**If you are an Airbyte core member**, copy the credentials in Lastpass under the secret name `destination kvdb test creds` -and place them into `secrets/config.json`. - -### Locally running the connector -``` -python main.py spec -python main.py check --config secrets/config.json -python main.py discover --config secrets/config.json -python main.py read --config secrets/config.json --catalog integration_tests/configured_catalog.json -``` - -### Locally running the connector docker image - - - -#### Build -**Via [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md) (recommended):** -```bash -airbyte-ci connectors --name=destination-kvdb build -``` - -An image will be built with the tag `airbyte/destination-kvdb:dev`. - -**Via `docker build`:** -```bash -docker build -t airbyte/destination-kvdb:dev . -``` -#### Run -Then run any of the connector commands as follows: -``` -docker run --rm airbyte/destination-kvdb:dev spec -docker run --rm -v $(pwd)/secrets:/secrets airbyte/destination-kvdb:dev check --config /secrets/config.json -# messages.jsonl is a file containing line-separated JSON representing AirbyteMessages -cat messages.jsonl | docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/destination-kvdb:dev write --config /secrets/config.json --catalog /integration_tests/configured_catalog.json -``` -## Testing - Make sure to familiarize yourself with [pytest test discovery](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) to know how your test files and methods should be named. -First install test dependencies into your virtual environment: -``` -pip install .[tests] -``` -### Unit Tests -To run unit tests locally, from the connector directory run: -``` -python -m pytest unit_tests -``` - -### Integration Tests -There are two types of integration tests: Acceptance Tests (Airbyte's test suite for all destination connectors) and custom integration tests (which are specific to this connector). -#### Custom Integration tests -Place custom tests inside `integration_tests/` folder, then, from the connector root, run -``` -python -m pytest integration_tests -``` -#### Acceptance Tests -You can run our full test suite locally using [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md): -```bash -airbyte-ci connectors --name=destination-kvdb test -``` - - -## Dependency Management -All of your dependencies should go in `setup.py`, NOT `requirements.txt`. The requirements file is only used to connect internal Airbyte dependencies in the monorepo for local development. -We split dependencies between two groups, dependencies that are: -* required for your connector to work need to go to `MAIN_REQUIREMENTS` list. -* required for the testing need to go to `TEST_REQUIREMENTS` list - -### Publishing a new version of the connector -You've checked out the repo, implemented a million dollar feature, and you're ready to share your changes with the world. Now what? -1. Make sure your changes are passing our test suite: `airbyte-ci connectors --name=destination-kvdb test` -2. Bump the connector version in `metadata.yaml`: increment the `dockerImageTag` value. Please follow [semantic versioning for connectors](https://docs.airbyte.com/contributing-to-airbyte/resources/pull-requests-handbook/#semantic-versioning-for-connectors). -3. Make sure the `metadata.yaml` content is up to date. -4. Make the connector documentation and its changelog is up to date (`docs/integrations/destinations/kvdb.md`). -5. Create a Pull Request: use [our PR naming conventions](https://docs.airbyte.com/contributing-to-airbyte/resources/pull-requests-handbook/#pull-request-title-convention). -6. Pat yourself on the back for being an awesome contributor. -7. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master. - diff --git a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/__init__.py b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/__init__.py deleted file mode 100644 index 5f3b041035bf..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# MIT License -# -# Copyright (c) 2020 Airbyte -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - - -from .destination import DestinationKvdb - -__all__ = ["DestinationKvdb"] diff --git a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/client.py b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/client.py deleted file mode 100644 index 74d9f41176f5..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/client.py +++ /dev/null @@ -1,78 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from typing import Any, Iterable, List, Mapping, Tuple, Union - -import requests - - -class KvDbClient: - base_url = "https://kvdb.io" - PAGE_SIZE = 1000 - - def __init__(self, bucket_id: str, secret_key: str = None): - self.secret_key = secret_key - self.bucket_id = bucket_id - - def write(self, key: str, value: Mapping[str, Any]): - return self.batch_write([(key, value)]) - - def batch_write(self, keys_and_values: List[Tuple[str, Mapping[str, Any]]]): - """ - https://kvdb.io/docs/api/#execute-transaction - """ - request_body = {"txn": [{"set": key, "value": value} for key, value in keys_and_values]} - return self._request("POST", json=request_body) - - def list_keys(self, list_values: bool = False, prefix: str = None) -> Iterable[Union[str, List]]: - """ - https://kvdb.io/docs/api/#list-keys - """ - # TODO handle rate limiting - pagination_complete = False - offset = 0 - - while not pagination_complete: - response = self._request( - "GET", - params={ - "limit": self.PAGE_SIZE, - "skip": offset, - "format": "json", - "prefix": prefix or "", - "values": "true" if list_values else "false", - }, - endpoint="/", # the "list" endpoint doesn't work without adding a trailing slash to the URL - ) - - response_json = response.json() - yield from response_json - - pagination_complete = len(response_json) < self.PAGE_SIZE - offset += self.PAGE_SIZE - - def delete(self, key: Union[str, List[str]]): - """ - https://kvdb.io/docs/api/#execute-transaction - """ - key_list = key if isinstance(key, List) else [key] - request_body = {"txn": [{"delete": k} for k in key_list]} - return self._request("POST", json=request_body) - - def _get_base_url(self) -> str: - return f"{self.base_url}/{self.bucket_id}" - - def _get_auth_headers(self) -> Mapping[str, Any]: - return {"Authorization": f"Bearer {self.secret_key}"} if self.secret_key else {} - - def _request( - self, http_method: str, endpoint: str = None, params: Mapping[str, Any] = None, json: Mapping[str, Any] = None - ) -> requests.Response: - url = self._get_base_url() + (endpoint or "") - headers = {"Accept": "application/json", **self._get_auth_headers()} - - response = requests.request(method=http_method, params=params, url=url, headers=headers, json=json) - - response.raise_for_status() - return response diff --git a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/destination.py b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/destination.py deleted file mode 100644 index 33ab8565fae4..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/destination.py +++ /dev/null @@ -1,72 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - - -import time -import traceback -import uuid -from typing import Any, Iterable, Mapping - -from airbyte_cdk import AirbyteLogger -from airbyte_cdk.destinations import Destination -from airbyte_cdk.models import AirbyteConnectionStatus, AirbyteMessage, ConfiguredAirbyteCatalog, DestinationSyncMode, Status, Type -from destination_kvdb.client import KvDbClient -from destination_kvdb.writer import KvDbWriter - - -class DestinationKvdb(Destination): - def write( - self, config: Mapping[str, Any], configured_catalog: ConfiguredAirbyteCatalog, input_messages: Iterable[AirbyteMessage] - ) -> Iterable[AirbyteMessage]: - - """ - Reads the input stream of messages, config, and catalog to write data to the destination. - - This method returns an iterable (typically a generator of AirbyteMessages via yield) containing state messages received - in the input message stream. Outputting a state message means that every AirbyteRecordMessage which came before it has been - successfully persisted to the destination. This is used to ensure fault tolerance in the case that a sync fails before fully completing, - then the source is given the last state message output from this method as the starting point of the next sync. - """ - writer = KvDbWriter(KvDbClient(**config)) - - for configured_stream in configured_catalog.streams: - if configured_stream.destination_sync_mode == DestinationSyncMode.overwrite: - writer.delete_stream_entries(configured_stream.stream.name) - - for message in input_messages: - if message.type == Type.STATE: - # Emitting a state message indicates that all records which came before it have been written to the destination. So we flush - # the queue to ensure writes happen, then output the state message to indicate it's safe to checkpoint state - writer.flush() - yield message - elif message.type == Type.RECORD: - record = message.record - writer.queue_write_operation( - record.stream, record.data, time.time_ns() / 1_000_000 - ) # convert from nanoseconds to milliseconds - else: - # ignore other message types for now - continue - - # Make sure to flush any records still in the queue - writer.flush() - - def check(self, logger: AirbyteLogger, config: Mapping[str, Any]) -> AirbyteConnectionStatus: - """ - Tests if the input configuration can be used to successfully connect to the destination with the needed permissions - e.g: if a provided API token or password can be used to connect and write to the destination. - """ - try: - # Verify write access by attempting to write and then delete to a random key - client = KvDbClient(**config) - random_key = str(uuid.uuid4()) - client.write(random_key, {"value": "_airbyte_connection_check"}) - client.delete(random_key) - except Exception as e: - traceback.print_exc() - return AirbyteConnectionStatus( - status=Status.FAILED, message=f"An exception occurred: {e}. \nStacktrace: \n{traceback.format_exc()}" - ) - else: - return AirbyteConnectionStatus(status=Status.SUCCEEDED) diff --git a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/spec.json b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/spec.json deleted file mode 100644 index 0ced52c17a22..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/spec.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "documentationUrl": "https://kvdb.io/docs/api/", - "supported_destination_sync_modes": ["overwrite", "append"], - "supportsIncremental": true, - "connectionSpecification": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Destination KVdb", - "type": "object", - "required": ["bucket_id", "secret_key"], - "additionalProperties": false, - "properties": { - "bucket_id": { - "title": "Bucket ID", - "type": "string", - "description": "The ID of your KVdb bucket.", - "order": 1 - }, - "secret_key": { - "title": "Secret Key", - "type": "string", - "description": "Your bucket Secret Key.", - "order": 2 - } - } - } -} diff --git a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/writer.py b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/writer.py deleted file mode 100644 index 33acbf8a22fb..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/writer.py +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from collections import Mapping - -from destination_kvdb.client import KvDbClient - - -class KvDbWriter: - """ - Data is written to KvDB in the following format: - key: stream_name__ab__ - value: a JSON object representing the record's data - - This is because unless a data source explicitly designates a primary key, we don't know what to key the record on. - Since KvDB allows reading records with certain prefixes, we treat it more like a message queue, expecting the reader to - read messages with a particular prefix e.g: name__ab__123, where 123 is the timestamp they last read data from. - """ - - write_buffer = [] - flush_interval = 1000 - - def __init__(self, client: KvDbClient): - self.client = client - - def delete_stream_entries(self, stream_name: str): - """Deletes all the records belonging to the input stream""" - keys_to_delete = [] - for key in self.client.list_keys(prefix=f"{stream_name}__ab__"): - keys_to_delete.append(key) - if len(keys_to_delete) == self.flush_interval: - self.client.delete(keys_to_delete) - keys_to_delete.clear() - if len(keys_to_delete) > 0: - self.client.delete(keys_to_delete) - - def queue_write_operation(self, stream_name: str, record: Mapping, written_at: int): - kv_pair = (f"{stream_name}__ab__{written_at}", record) - self.write_buffer.append(kv_pair) - if len(self.write_buffer) == self.flush_interval: - self.flush() - - def flush(self): - self.client.batch_write(self.write_buffer) - self.write_buffer.clear() diff --git a/airbyte-integrations/connectors/destination-kvdb/integration_tests/integration_test.py b/airbyte-integrations/connectors/destination-kvdb/integration_tests/integration_test.py deleted file mode 100644 index 5e083acc5351..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/integration_tests/integration_test.py +++ /dev/null @@ -1,138 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import json -from typing import Any, Dict, List, Mapping - -import pytest -from airbyte_cdk import AirbyteLogger -from airbyte_cdk.models import ( - AirbyteMessage, - AirbyteRecordMessage, - AirbyteStateMessage, - AirbyteStream, - ConfiguredAirbyteCatalog, - ConfiguredAirbyteStream, - DestinationSyncMode, - Status, - SyncMode, - Type, -) -from destination_kvdb import DestinationKvdb -from destination_kvdb.client import KvDbClient - - -@pytest.fixture(name="config") -def config_fixture() -> Mapping[str, Any]: - with open("secrets/config.json", "r") as f: - return json.loads(f.read()) - - -@pytest.fixture(name="configured_catalog") -def configured_catalog_fixture() -> ConfiguredAirbyteCatalog: - stream_schema = {"type": "object", "properties": {"string_col": {"type": "str"}, "int_col": {"type": "integer"}}} - - append_stream = ConfiguredAirbyteStream( - stream=AirbyteStream(name="append_stream", json_schema=stream_schema, supported_sync_modes=[SyncMode.incremental]), - sync_mode=SyncMode.incremental, - destination_sync_mode=DestinationSyncMode.append, - ) - - overwrite_stream = ConfiguredAirbyteStream( - stream=AirbyteStream(name="overwrite_stream", json_schema=stream_schema, supported_sync_modes=[SyncMode.incremental]), - sync_mode=SyncMode.incremental, - destination_sync_mode=DestinationSyncMode.overwrite, - ) - - return ConfiguredAirbyteCatalog(streams=[append_stream, overwrite_stream]) - - -@pytest.fixture(autouse=True) -def teardown(config: Mapping): - yield - client = KvDbClient(**config) - client.delete(list(client.list_keys())) - - -@pytest.fixture(name="client") -def client_fixture(config) -> KvDbClient: - return KvDbClient(**config) - - -def test_check_valid_config(config: Mapping): - outcome = DestinationKvdb().check(AirbyteLogger(), config) - assert outcome.status == Status.SUCCEEDED - - -def test_check_invalid_config(): - outcome = DestinationKvdb().check(AirbyteLogger(), {"bucket_id": "not_a_real_id"}) - assert outcome.status == Status.FAILED - - -def _state(data: Dict[str, Any]) -> AirbyteMessage: - return AirbyteMessage(type=Type.STATE, state=AirbyteStateMessage(data=data)) - - -def _record(stream: str, str_value: str, int_value: int) -> AirbyteMessage: - return AirbyteMessage( - type=Type.RECORD, record=AirbyteRecordMessage(stream=stream, data={"str_col": str_value, "int_col": int_value}, emitted_at=0) - ) - - -def retrieve_all_records(client: KvDbClient) -> List[AirbyteRecordMessage]: - """retrieves and formats all records in kvdb as Airbyte messages""" - all_records = client.list_keys(list_values=True) - out = [] - for record in all_records: - key = record[0] - stream = key.split("__ab__")[0] - value = record[1] - out.append(_record(stream, value["str_col"], value["int_col"])) - return out - - -def test_write(config: Mapping, configured_catalog: ConfiguredAirbyteCatalog, client: KvDbClient): - """ - This test verifies that: - 1. writing a stream in "overwrite" mode overwrites any existing data for that stream - 2. writing a stream in "append" mode appends new records without deleting the old ones - 3. The correct state message is output by the connector at the end of the sync - """ - append_stream, overwrite_stream = configured_catalog.streams[0].stream.name, configured_catalog.streams[1].stream.name - first_state_message = _state({"state": "1"}) - first_record_chunk = [_record(append_stream, str(i), i) for i in range(5)] + [_record(overwrite_stream, str(i), i) for i in range(5)] - - second_state_message = _state({"state": "2"}) - second_record_chunk = [_record(append_stream, str(i), i) for i in range(5, 10)] + [ - _record(overwrite_stream, str(i), i) for i in range(5, 10) - ] - - destination = DestinationKvdb() - - expected_states = [first_state_message, second_state_message] - output_states = list( - destination.write( - config, configured_catalog, [*first_record_chunk, first_state_message, *second_record_chunk, second_state_message] - ) - ) - assert expected_states == output_states, "Checkpoint state messages were expected from the destination" - - expected_records = [_record(append_stream, str(i), i) for i in range(10)] + [_record(overwrite_stream, str(i), i) for i in range(10)] - records_in_destination = retrieve_all_records(client) - assert expected_records == records_in_destination, "Records in destination should match records expected" - - # After this sync we expect the append stream to have 15 messages and the overwrite stream to have 5 - third_state_message = _state({"state": "3"}) - third_record_chunk = [_record(append_stream, str(i), i) for i in range(10, 15)] + [ - _record(overwrite_stream, str(i), i) for i in range(10, 15) - ] - - output_states = list(destination.write(config, configured_catalog, [*third_record_chunk, third_state_message])) - assert [third_state_message] == output_states - - records_in_destination = retrieve_all_records(client) - expected_records = [_record(append_stream, str(i), i) for i in range(15)] + [ - _record(overwrite_stream, str(i), i) for i in range(10, 15) - ] - assert expected_records == records_in_destination diff --git a/airbyte-integrations/connectors/destination-kvdb/main.py b/airbyte-integrations/connectors/destination-kvdb/main.py deleted file mode 100644 index 178789589e5a..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/main.py +++ /dev/null @@ -1,11 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - - -import sys - -from destination_kvdb import DestinationKvdb - -if __name__ == "__main__": - DestinationKvdb().run(sys.argv[1:]) diff --git a/airbyte-integrations/connectors/destination-kvdb/requirements.txt b/airbyte-integrations/connectors/destination-kvdb/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/destination-kvdb/setup.py b/airbyte-integrations/connectors/destination-kvdb/setup.py deleted file mode 100644 index dab5520718ab..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/setup.py +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - - -from setuptools import find_packages, setup - -MAIN_REQUIREMENTS = [ - "airbyte-cdk", - "requests", -] - -TEST_REQUIREMENTS = ["pytest~=6.1"] - -setup( - name="destination_kvdb", - description="Destination implementation for Kvdb.", - author="Airbyte", - author_email="contact@airbyte.io", - packages=find_packages(), - install_requires=MAIN_REQUIREMENTS, - package_data={"": ["*.json"]}, - extras_require={ - "tests": TEST_REQUIREMENTS, - }, -) diff --git a/airbyte-integrations/connectors/destination-kvdb/unit_tests/unit_test.py b/airbyte-integrations/connectors/destination-kvdb/unit_tests/unit_test.py deleted file mode 100644 index 219ae0142c72..000000000000 --- a/airbyte-integrations/connectors/destination-kvdb/unit_tests/unit_test.py +++ /dev/null @@ -1,7 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - - -def test_example_method(): - assert True diff --git a/docs/integrations/destinations/kvdb.md b/docs/integrations/destinations/kvdb.md index 1d9a4341e8fc..5ca1dfa0526b 100644 --- a/docs/integrations/destinations/kvdb.md +++ b/docs/integrations/destinations/kvdb.md @@ -1,4 +1,4 @@ -# KVDB +# KVDB [ARCHIVED] The KVDB destination for Airbyte From bbb0831c8c29d014da96a3b1319f91ebfe2c05c3 Mon Sep 17 00:00:00 2001 From: Evan Tahler Date: Fri, 16 Feb 2024 13:07:50 -0800 Subject: [PATCH 15/43] Add `archived` as connector support level (#35355) --- .../connector_ops/connector_ops/utils.py | 1 + .../generated/ConnectorMetadataDefinitionV0.py | 2 +- .../ConnectorRegistryDestinationDefinition.py | 2 +- .../ConnectorRegistrySourceDefinition.py | 2 +- .../models/generated/ConnectorRegistryV0.py | 2 +- .../models/generated/SupportLevel.py | 2 +- .../metadata_service/models/src/SupportLevel.yaml | 1 + .../metadata_support_level_archived.yaml | 15 +++++++++++++++ 8 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/valid/with_optional_field/metadata_support_level_archived.yaml diff --git a/airbyte-ci/connectors/connector_ops/connector_ops/utils.py b/airbyte-ci/connectors/connector_ops/connector_ops/utils.py index 2993288283ad..2af725f8a4f2 100644 --- a/airbyte-ci/connectors/connector_ops/connector_ops/utils.py +++ b/airbyte-ci/connectors/connector_ops/connector_ops/utils.py @@ -640,3 +640,4 @@ class ConnectorTypeEnum(str, Enum): class SupportLevelEnum(str, Enum): certified = "certified" community = "community" + archived = "archived" diff --git a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorMetadataDefinitionV0.py b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorMetadataDefinitionV0.py index 40719df845f3..f1e89b2d7d07 100644 --- a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorMetadataDefinitionV0.py +++ b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorMetadataDefinitionV0.py @@ -27,7 +27,7 @@ class ReleaseStage(BaseModel): class SupportLevel(BaseModel): - __root__: Literal["community", "certified"] = Field( + __root__: Literal["community", "certified", "archived"] = Field( ..., description="enum that describes a connector's release stage", title="SupportLevel", diff --git a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistryDestinationDefinition.py b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistryDestinationDefinition.py index e1954ad41369..00c303ddd96f 100644 --- a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistryDestinationDefinition.py +++ b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistryDestinationDefinition.py @@ -20,7 +20,7 @@ class ReleaseStage(BaseModel): class SupportLevel(BaseModel): - __root__: Literal["community", "certified"] = Field( + __root__: Literal["community", "certified", "archived"] = Field( ..., description="enum that describes a connector's release stage", title="SupportLevel", diff --git a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistrySourceDefinition.py b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistrySourceDefinition.py index 60ea7a4a970c..e1a6a1258d72 100644 --- a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistrySourceDefinition.py +++ b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistrySourceDefinition.py @@ -20,7 +20,7 @@ class ReleaseStage(BaseModel): class SupportLevel(BaseModel): - __root__: Literal["community", "certified"] = Field( + __root__: Literal["community", "certified", "archived"] = Field( ..., description="enum that describes a connector's release stage", title="SupportLevel", diff --git a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistryV0.py b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistryV0.py index b1bbd935d6e6..2feb8280b290 100644 --- a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistryV0.py +++ b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/ConnectorRegistryV0.py @@ -20,7 +20,7 @@ class ReleaseStage(BaseModel): class SupportLevel(BaseModel): - __root__: Literal["community", "certified"] = Field( + __root__: Literal["community", "certified", "archived"] = Field( ..., description="enum that describes a connector's release stage", title="SupportLevel", diff --git a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/SupportLevel.py b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/SupportLevel.py index 4a0f7d77c87e..7c5e001789f3 100644 --- a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/SupportLevel.py +++ b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/generated/SupportLevel.py @@ -8,7 +8,7 @@ class SupportLevel(BaseModel): - __root__: Literal["community", "certified"] = Field( + __root__: Literal["community", "certified", "archived"] = Field( ..., description="enum that describes a connector's release stage", title="SupportLevel", diff --git a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/src/SupportLevel.yaml b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/src/SupportLevel.yaml index 1c7c46ba0ebf..752d99a27c29 100644 --- a/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/src/SupportLevel.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/metadata_service/models/src/SupportLevel.yaml @@ -7,3 +7,4 @@ type: string enum: - community - certified + - archived diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/valid/with_optional_field/metadata_support_level_archived.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/valid/with_optional_field/metadata_support_level_archived.yaml new file mode 100644 index 000000000000..99486312e56c --- /dev/null +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/valid/with_optional_field/metadata_support_level_archived.yaml @@ -0,0 +1,15 @@ +metadataSpecVersion: 1.0 +data: + name: AlloyDB for PostgreSQL + definitionId: 1fa90628-2b9e-11ed-a261-0242ac120002 + connectorType: source + dockerRepository: airbyte/image-exists-1 + githubIssueLabel: source-alloydb-strict-encrypt + dockerImageTag: 0.0.1 + documentationUrl: https://docs.airbyte.com/integrations/sources/existingsource + connectorSubtype: database + releaseStage: generally_available + supportLevel: archived + license: MIT + tags: + - language:java From 27b0490229dc3857d50670d78024ee0f2723009c Mon Sep 17 00:00:00 2001 From: Marcos Marx Date: Fri, 16 Feb 2024 18:20:43 -0300 Subject: [PATCH 16/43] Remove `octavia-cli` (#33950) --- .github/labeler.yml | 4 - .github/workflows/release-airbyte-os.yml | 23 - docs/cli-documentation.md | 715 - docusaurus/sidebars.js | 4 - octavia-cli/.coveragerc | 3 - octavia-cli/.dockerignore | 4 - octavia-cli/.gitignore | 4 - octavia-cli/.python-version | 1 - octavia-cli/CHANGELOG.md | 0 octavia-cli/Dockerfile | 18 - octavia-cli/LICENSE | 21 - octavia-cli/README.md | 725 - octavia-cli/install.sh | 121 - .../test_api_http_headers.yaml | 26842 ---------------- .../configurations/.gitignore | 2 - .../connections/poke_to_pg/configuration.yaml | 362 - .../configuration.yaml | 367 - .../destinations/postgres/configuration.yaml | 32 - .../sources/poke/configuration.yaml | 9 - octavia-cli/integration_tests/conftest.py | 155 - .../docker-compose-proxy.yaml | 19 - .../test_api_http_headers.py | 77 - .../test_apply/test_resources.py | 65 - .../test_generate/__init__.py | 3 - .../expected_with_normalization.yaml | 56 - .../expected_without_normalization.yaml | 40 - .../destination_postgres/expected.yaml | 32 - .../destination_postgres/input_spec.yaml | 177 - .../destination_s3/expected.yaml | 52 - .../destination_s3/input_spec.yaml | 330 - .../source_postgres/expected.yaml | 40 - .../source_postgres/input_spec.yaml | 238 - .../test_generate/test_definitions.py | 33 - .../octavia_project_to_migrate/.gitignore | 2 - .../poke_to_pg_to_import/configuration.yaml | 367 - .../postgres_to_import/configuration.yaml | 32 - .../sources/poke_to_import/configuration.yaml | 9 - .../test_import/test_commands.py | 159 - .../test_list/test_listings.py | 30 - octavia-cli/octavia_cli/__init__.py | 3 - octavia-cli/octavia_cli/_import/__init__.py | 3 - octavia-cli/octavia_cli/_import/commands.py | 180 - octavia-cli/octavia_cli/api_http_headers.py | 106 - octavia-cli/octavia_cli/apply/__init__.py | 3 - octavia-cli/octavia_cli/apply/commands.py | 172 - octavia-cli/octavia_cli/apply/diff_helpers.py | 75 - octavia-cli/octavia_cli/apply/resources.py | 886 - octavia-cli/octavia_cli/apply/yaml_loaders.py | 35 - octavia-cli/octavia_cli/base_commands.py | 56 - octavia-cli/octavia_cli/check_context.py | 93 - octavia-cli/octavia_cli/entrypoint.py | 187 - octavia-cli/octavia_cli/generate/__init__.py | 3 - octavia-cli/octavia_cli/generate/commands.py | 78 - .../octavia_cli/generate/definitions.py | 153 - octavia-cli/octavia_cli/generate/renderers.py | 328 - .../generate/templates/connection.yaml.j2 | 50 - .../templates/source_or_destination.yaml.j2 | 79 - .../octavia_cli/generate/yaml_dumpers.py | 23 - octavia-cli/octavia_cli/get/__init__.py | 3 - octavia-cli/octavia_cli/get/commands.py | 108 - octavia-cli/octavia_cli/get/resources.py | 193 - octavia-cli/octavia_cli/init/__init__.py | 3 - octavia-cli/octavia_cli/init/commands.py | 58 - .../init/example_files/__init__.py | 3 - .../example_api_http_headers.yaml | 4 - octavia-cli/octavia_cli/list/__init__.py | 3 - octavia-cli/octavia_cli/list/commands.py | 84 - octavia-cli/octavia_cli/list/formatting.py | 59 - octavia-cli/octavia_cli/list/listings.py | 111 - octavia-cli/octavia_cli/telemetry.py | 91 - octavia-cli/publish.sh | 14 - octavia-cli/pytest.ini | 7 - octavia-cli/setup.py | 64 - octavia-cli/unit_tests/__init__.py | 3 - octavia-cli/unit_tests/conftest.py | 15 - .../unit_tests/test__import/__init__.py | 3 - .../unit_tests/test__import/test_commands.py | 233 - .../unit_tests/test_api_http_headers.py | 203 - octavia-cli/unit_tests/test_apply/__init__.py | 3 - .../unit_tests/test_apply/test_commands.py | 300 - .../test_apply/test_diff_helpers.py | 46 - .../unit_tests/test_apply/test_resources.py | 956 - .../test_apply/test_yaml_loaders.py | 37 - octavia-cli/unit_tests/test_base_commands.py | 57 - octavia-cli/unit_tests/test_check_context.py | 85 - octavia-cli/unit_tests/test_entrypoint.py | 243 - .../unit_tests/test_generate/__init__.py | 3 - .../unit_tests/test_generate/test_commands.py | 116 - .../test_generate/test_connection.py | 5 - .../test_generate/test_definitions.py | 122 - .../test_generate/test_renderers.py | 415 - octavia-cli/unit_tests/test_get/__init__.py | 3 - .../unit_tests/test_get/test_commands.py | 102 - .../unit_tests/test_get/test_resources.py | 137 - octavia-cli/unit_tests/test_init/__init__.py | 3 - .../unit_tests/test_init/test_commands.py | 90 - octavia-cli/unit_tests/test_list/__init__.py | 3 - .../unit_tests/test_list/test_commands.py | 62 - .../unit_tests/test_list/test_formatting.py | 45 - .../unit_tests/test_list/test_listings.py | 154 - octavia-cli/unit_tests/test_telemetry.py | 124 - tools/bin/integration_tests_octavia.sh | 22 - tools/bin/release_version_octavia.sh | 24 - 103 files changed, 38105 deletions(-) delete mode 100644 docs/cli-documentation.md delete mode 100644 octavia-cli/.coveragerc delete mode 100644 octavia-cli/.dockerignore delete mode 100644 octavia-cli/.gitignore delete mode 100644 octavia-cli/.python-version delete mode 100644 octavia-cli/CHANGELOG.md delete mode 100644 octavia-cli/Dockerfile delete mode 100644 octavia-cli/LICENSE delete mode 100644 octavia-cli/README.md delete mode 100755 octavia-cli/install.sh delete mode 100644 octavia-cli/integration_tests/cassettes/test_api_http_headers/test_api_http_headers.yaml delete mode 100644 octavia-cli/integration_tests/configurations/.gitignore delete mode 100644 octavia-cli/integration_tests/configurations/connections/poke_to_pg/configuration.yaml delete mode 100644 octavia-cli/integration_tests/configurations/connections/poke_to_pg_normalization/configuration.yaml delete mode 100644 octavia-cli/integration_tests/configurations/destinations/postgres/configuration.yaml delete mode 100644 octavia-cli/integration_tests/configurations/sources/poke/configuration.yaml delete mode 100644 octavia-cli/integration_tests/conftest.py delete mode 100644 octavia-cli/integration_tests/docker-compose-proxy.yaml delete mode 100644 octavia-cli/integration_tests/test_api_http_headers.py delete mode 100644 octavia-cli/integration_tests/test_apply/test_resources.py delete mode 100644 octavia-cli/integration_tests/test_generate/__init__.py delete mode 100644 octavia-cli/integration_tests/test_generate/expected_rendered_yaml/connection/expected_with_normalization.yaml delete mode 100644 octavia-cli/integration_tests/test_generate/expected_rendered_yaml/connection/expected_without_normalization.yaml delete mode 100644 octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_postgres/expected.yaml delete mode 100644 octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_postgres/input_spec.yaml delete mode 100644 octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_s3/expected.yaml delete mode 100644 octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_s3/input_spec.yaml delete mode 100644 octavia-cli/integration_tests/test_generate/expected_rendered_yaml/source_postgres/expected.yaml delete mode 100644 octavia-cli/integration_tests/test_generate/expected_rendered_yaml/source_postgres/input_spec.yaml delete mode 100644 octavia-cli/integration_tests/test_generate/test_definitions.py delete mode 100644 octavia-cli/integration_tests/test_import/octavia_project_to_migrate/.gitignore delete mode 100644 octavia-cli/integration_tests/test_import/octavia_project_to_migrate/connections/poke_to_pg_to_import/configuration.yaml delete mode 100644 octavia-cli/integration_tests/test_import/octavia_project_to_migrate/destinations/postgres_to_import/configuration.yaml delete mode 100644 octavia-cli/integration_tests/test_import/octavia_project_to_migrate/sources/poke_to_import/configuration.yaml delete mode 100644 octavia-cli/integration_tests/test_import/test_commands.py delete mode 100644 octavia-cli/integration_tests/test_list/test_listings.py delete mode 100644 octavia-cli/octavia_cli/__init__.py delete mode 100644 octavia-cli/octavia_cli/_import/__init__.py delete mode 100644 octavia-cli/octavia_cli/_import/commands.py delete mode 100644 octavia-cli/octavia_cli/api_http_headers.py delete mode 100644 octavia-cli/octavia_cli/apply/__init__.py delete mode 100644 octavia-cli/octavia_cli/apply/commands.py delete mode 100644 octavia-cli/octavia_cli/apply/diff_helpers.py delete mode 100644 octavia-cli/octavia_cli/apply/resources.py delete mode 100644 octavia-cli/octavia_cli/apply/yaml_loaders.py delete mode 100644 octavia-cli/octavia_cli/base_commands.py delete mode 100644 octavia-cli/octavia_cli/check_context.py delete mode 100644 octavia-cli/octavia_cli/entrypoint.py delete mode 100644 octavia-cli/octavia_cli/generate/__init__.py delete mode 100644 octavia-cli/octavia_cli/generate/commands.py delete mode 100644 octavia-cli/octavia_cli/generate/definitions.py delete mode 100644 octavia-cli/octavia_cli/generate/renderers.py delete mode 100644 octavia-cli/octavia_cli/generate/templates/connection.yaml.j2 delete mode 100644 octavia-cli/octavia_cli/generate/templates/source_or_destination.yaml.j2 delete mode 100644 octavia-cli/octavia_cli/generate/yaml_dumpers.py delete mode 100644 octavia-cli/octavia_cli/get/__init__.py delete mode 100644 octavia-cli/octavia_cli/get/commands.py delete mode 100644 octavia-cli/octavia_cli/get/resources.py delete mode 100644 octavia-cli/octavia_cli/init/__init__.py delete mode 100644 octavia-cli/octavia_cli/init/commands.py delete mode 100644 octavia-cli/octavia_cli/init/example_files/__init__.py delete mode 100644 octavia-cli/octavia_cli/init/example_files/example_api_http_headers.yaml delete mode 100644 octavia-cli/octavia_cli/list/__init__.py delete mode 100644 octavia-cli/octavia_cli/list/commands.py delete mode 100644 octavia-cli/octavia_cli/list/formatting.py delete mode 100644 octavia-cli/octavia_cli/list/listings.py delete mode 100644 octavia-cli/octavia_cli/telemetry.py delete mode 100755 octavia-cli/publish.sh delete mode 100644 octavia-cli/pytest.ini delete mode 100644 octavia-cli/setup.py delete mode 100644 octavia-cli/unit_tests/__init__.py delete mode 100644 octavia-cli/unit_tests/conftest.py delete mode 100644 octavia-cli/unit_tests/test__import/__init__.py delete mode 100644 octavia-cli/unit_tests/test__import/test_commands.py delete mode 100644 octavia-cli/unit_tests/test_api_http_headers.py delete mode 100644 octavia-cli/unit_tests/test_apply/__init__.py delete mode 100644 octavia-cli/unit_tests/test_apply/test_commands.py delete mode 100644 octavia-cli/unit_tests/test_apply/test_diff_helpers.py delete mode 100644 octavia-cli/unit_tests/test_apply/test_resources.py delete mode 100644 octavia-cli/unit_tests/test_apply/test_yaml_loaders.py delete mode 100644 octavia-cli/unit_tests/test_base_commands.py delete mode 100644 octavia-cli/unit_tests/test_check_context.py delete mode 100644 octavia-cli/unit_tests/test_entrypoint.py delete mode 100644 octavia-cli/unit_tests/test_generate/__init__.py delete mode 100644 octavia-cli/unit_tests/test_generate/test_commands.py delete mode 100644 octavia-cli/unit_tests/test_generate/test_connection.py delete mode 100644 octavia-cli/unit_tests/test_generate/test_definitions.py delete mode 100644 octavia-cli/unit_tests/test_generate/test_renderers.py delete mode 100644 octavia-cli/unit_tests/test_get/__init__.py delete mode 100644 octavia-cli/unit_tests/test_get/test_commands.py delete mode 100644 octavia-cli/unit_tests/test_get/test_resources.py delete mode 100644 octavia-cli/unit_tests/test_init/__init__.py delete mode 100644 octavia-cli/unit_tests/test_init/test_commands.py delete mode 100644 octavia-cli/unit_tests/test_list/__init__.py delete mode 100644 octavia-cli/unit_tests/test_list/test_commands.py delete mode 100644 octavia-cli/unit_tests/test_list/test_formatting.py delete mode 100644 octavia-cli/unit_tests/test_list/test_listings.py delete mode 100644 octavia-cli/unit_tests/test_telemetry.py delete mode 100755 tools/bin/integration_tests_octavia.sh delete mode 100755 tools/bin/release_version_octavia.sh diff --git a/.github/labeler.yml b/.github/labeler.yml index 09aed0435b97..23e0950d448a 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -11,10 +11,6 @@ area/documentation: - docs/* - docs/**/* -area/octavia-cli: - - octavia-cli/* - - octavia-cli/**/* - CDK: - airbyte-cdk/* - airbyte-cdk/**/* diff --git a/.github/workflows/release-airbyte-os.yml b/.github/workflows/release-airbyte-os.yml index 628c3b43e057..b4fbfc9e3255 100644 --- a/.github/workflows/release-airbyte-os.yml +++ b/.github/workflows/release-airbyte-os.yml @@ -198,29 +198,6 @@ jobs: PART_TO_BUMP: ${{ github.event.inputs.partToBump }} run: ./tools/bin/release_version_octavia.sh - - name: Publish Python Package to test.pypi.org - if: github.event.inputs.skip-publish-test != 'true' - uses: mariamrf/py-package-publish-action@v1.1.0 - with: - # specify the same version as in ~/.python-version - python_version: "3.10" - pip_version: "23.2" - subdir: "octavia-cli/" - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} - TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }} - TWINE_REPOSITORY_URL: "https://test.pypi.org/legacy/" - - name: Publish Python Package - uses: mariamrf/py-package-publish-action@v1.1.0 - with: - # specify the same version as in ~/.python-version - python_version: "3.10" - pip_version: "23.2" - subdir: "octavia-cli/" - env: - TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} - TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }} - # In case of self-hosted EC2 errors, remove this block. stop-release-airbyte-runner: name: "Release Airbyte: Stop EC2 Runner" diff --git a/docs/cli-documentation.md b/docs/cli-documentation.md deleted file mode 100644 index f4d2dcd2803c..000000000000 --- a/docs/cli-documentation.md +++ /dev/null @@ -1,715 +0,0 @@ ---- -products: oss-community ---- - -# CLI documentation - -:::caution -The Octavia CLI is an alpha, unofficial CLI that won't be maintained. -::: - -:::tip Recommendation -We recommend all users leverage the official [Airbyte Terraform Provider](https://reference.airbyte.com/reference/using-the-terraform-provider), instead of this CLI. -::: - -## What is `octavia` CLI? - -Octavia CLI is a tool to manage Airbyte configurations in YAML. -It has the following features: - -- Scaffolding of a readable directory architecture that will host the YAML configs (`octavia init`). -- Auto-generation of YAML config file that matches the resources' schemas (`octavia generate`). -- Manage Airbyte resources with YAML config files. -- Safe resources update through diff display and validation (`octavia apply`). -- Simple secret management to avoid versioning credentials. - -## Why should I use `octavia` CLI? - -A CLI provides freedom to users to use the tool in whatever context and use case they have. -These are non-exhaustive use cases `octavia` can be convenient for: - -- Managing Airbyte configurations with a CLI instead of a web UI. -- Versioning Airbyte configurations in Git. -- Updating of Airbyte configurations in an automated deployment pipeline. -- Integrating the Airbyte configuration deployment in a dev ops tooling stack: Helm, Ansible etc. -- Streamlining the deployment of Airbyte configurations to multiple Airbyte instance. - -Readers can refer to our [opened GitHub issues](https://github.com/airbytehq/airbyte/issues?q=is%3Aopen+is%3Aissue+label%3Aarea%2Foctavia-cli) to check the ongoing work on this project. - -## Table of content - -- [Workflow](#workflow) -- [Secret management](#secret-management) -- [Install](#install) -- [Commands reference](#commands-reference) -- [Contributing](#contributing) -- [Telemetry](#telemetry) -- [Changelog](#changelog) - -## Workflow - -### 1. Generate local YAML files for sources or destinations - -1. Retrieve the _definition id_ of the connector you want to use using `octavia list` command. -2. Generate YAML configuration running `octavia generate source ` or `octavia generate destination `. - -### 2. Edit your local YAML configurations - -1. Edit the generated YAML configurations according to your need. -2. Use the [secret management feature](#secret-management) feature to avoid storing credentials in the YAML files. - -### 3. Create the declared sources or destinations on your Airbyte instance - -1. Run `octavia apply` to create the **sources** and **destinations** - -### 4. Generate connections - -1. Run `octavia octavia generate connection --source --destination ` to create a YAML configuration for a new connection. -2. Edit the created configuration file according to your need: change the scheduling or the replicated streams list. - -### 5. Create the declared connections - -1. Run `octavia apply` to create the newly declared connection on your Airbyte instance. - -### 6. Update your configurations - -Changes in your local configurations can be propagated to your Airbyte instance using `octavia apply`. You will be prompted for validation of changes. You can bypass the validation step using the `--force` flag. - -## Secret management - -Sources and destinations configurations have credential fields that you **do not want to store as plain text in your VCS**. -`octavia` offers secret management through environment variables expansion: - -```yaml -configuration: - password: ${MY_PASSWORD} -``` - -If you have set a `MY_PASSWORD` environment variable, `octavia apply` will load its value into the `password` field. - -## Install - -### Requirements - -We decided to package the CLI in a docker image with portability in mind. -**[Please install and run Docker if you are not](https://docs.docker.com/get-docker/)**. - -### As a command available in your bash profile - -```bash -curl -s -o- https://raw.githubusercontent.com/airbytehq/airbyte/master/octavia-cli/install.sh | bash -``` - -This script: - -1. Pulls the [octavia-cli image](https://hub.docker.com/r/airbyte/octavia-cli/tags) from our Docker registry. -2. Creates an `octavia` alias in your profile. -3. Creates a `~/.octavia` file whose values are mapped to the octavia container's environment variables. - -### Using `docker run` - -```bash -touch ~/.octavia # Create a file to store env variables that will be mapped the octavia-cli container -mkdir my_octavia_project_directory # Create your octavia project directory where YAML configurations will be stored. -docker run --name octavia-cli -i --rm -v my_octavia_project_directory:/home/octavia-project --network host --user $(id -u):$(id -g) --env-file ~/.octavia airbyte/octavia-cli:0.40.32 -``` - -### Using `docker-compose` - -Using octavia in docker-compose could be convenient for automatic `apply` on start-up. - -Add another entry in the services key of your Airbyte `docker-compose.yml` - -```yaml -services: - # . . . - octavia-cli: - image: airbyte/octavia-cli:latest - command: apply --force - env_file: - - ~/.octavia # Use a local env file to store variables that will be mapped the octavia-cli container - volumes: - - :/home/octavia-project - depends_on: - - webapp -``` - -Other commands besides `apply` can be run like so: - -```bash -docker compose run octavia-cli ` -``` - -## Commands reference - -### `octavia` command flags - -| **Flag** | **Description** | **Env Variable** | **Default** | -| ---------------------------------------- | --------------------------------------------------------------------------------- |----------------------------| ------------------------------------------------------ | -| `--airbyte-url` | Airbyte instance URL. | `AIRBYTE_URL` | `http://localhost:8000` | -| `--airbyte-username` | Airbyte instance username (basic auth). | `AIRBYTE_USERNAME` | `airbyte` | -| `--airbyte-password` | Airbyte instance password (basic auth). | `AIRBYTE_PASSWORD` | `password` | -| `--workspace-id` | Airbyte workspace id. | `AIRBYTE_WORKSPACE_ID` | The first workspace id found on your Airbyte instance. | -| `--enable-telemetry/--disable-telemetry` | Enable or disable the sending of telemetry data. | `OCTAVIA_ENABLE_TELEMETRY` | True | -| `--api-http-header` | HTTP Header value pairs passed while calling Airbyte's API | None | None | -| `--api-http-headers-file-path` | Path to the YAML file that contains custom HTTP Headers to send to Airbyte's API. | None | None | - -#### Using custom HTTP headers - -You can set custom HTTP headers to send to Airbyte's API with options: - -```bash -octavia --api-http-header Header-Name Header-Value --api-http-header Header-Name-2 Header-Value-2 list connectors sources -``` - -You can also use a custom YAML file (one is already created on init in `api_http_headers.yaml`) to declare the HTTP headers to send to the API: - -```yaml -headers: - Authorization: Bearer my-secret-token - User-Agent: octavia-cli/0.0.0 -``` - -Environment variable expansion is available in this Yaml file - -```yaml -headers: - Authorization: Bearer ${MY_API_TOKEN} -``` - -**Options based headers are overriding file based headers if a header is declared in both.** - -### `octavia` subcommands - -| **Command** | **Usage** | -| ----------------------------------------- | ------------------------------------------------------------------------------------------ | -| **`octavia init`** | Initialize required directories for the project. | -| **`octavia list connectors sources`** | List all sources connectors available on the remote Airbyte instance. | -| **`octavia list connectors destination`** | List all destinations connectors available on the remote Airbyte instance. | -| **`octavia list workspace sources`** | List existing sources in current the Airbyte workspace. | -| **`octavia list workspace destinations`** | List existing destinations in the current Airbyte workspace. | -| **`octavia list workspace connections`** | List existing connections in the current Airbyte workspace. | -| **`octavia get source`** | Get the JSON representation of an existing source in current the Airbyte workspace. | -| **`octavia get destination`** | Get the JSON representation of an existing destination in the current Airbyte workspace. | -| **`octavia get connection`** | Get the JSON representation of an existing connection in the current Airbyte workspace. | -| **`octavia import all`** | Import all existing sources, destinations and connections to manage them with octavia-cli. | -| **`octavia import source`** | Import an existing source to manage it with octavia-cli. | -| **`octavia import destination`** | Import an existing destination to manage it with octavia-cli. | -| **`octavia import connection`** | Import an existing connection to manage it with octavia-cli. | -| **`octavia generate source`** | Generate a local YAML configuration for a new source. | -| **`octavia generate destination`** | Generate a local YAML configuration for a new destination. | -| **`octavia generate connection`** | Generate a local YAML configuration for a new connection. | -| **`octavia apply`** | Create or update Airbyte remote resources according to local YAML configurations. | - -#### `octavia init` - -The `octavia init` commands scaffolds the required directory architecture for running `octavia generate` and `octavia apply` commands. - -**Example**: - -```bash -$ mkdir my_octavia_project && cd my_octavia_project -$ octavia init -🐙 - Octavia is targetting your Airbyte instance running at http://localhost:8000 on workspace e1f46f7d-5354-4200-aed6-7816015ca54b. -🐙 - Project is not yet initialized. -🔨 - Initializing the project. -✅ - Created the following directories: sources, destinations, connections. -$ ls -connections destinations sources -``` - -#### `octavia list connectors sources` - -List all the source connectors currently available on your Airbyte instance. - -**Example**: - -```bash -$ octavia list connectors sources -NAME DOCKER REPOSITORY DOCKER IMAGE TAG SOURCE DEFINITION ID -Airtable airbyte/source-airtable 0.1.1 14c6e7ea-97ed-4f5e-a7b5-25e9a80b8212 -AWS CloudTrail airbyte/source-aws-cloudtrail 0.1.4 6ff047c0-f5d5-4ce5-8c81-204a830fa7e1 -Amazon Ads airbyte/source-amazon-ads 0.1.3 c6b0a29e-1da9-4512-9002-7bfd0cba2246 -Amazon Seller Partner airbyte/source-amazon-seller-partner 0.2.16 e55879a8-0ef8-4557-abcf-ab34c53ec460 -``` - -#### `octavia list connectors destinations` - -List all the destinations connectors currently available on your Airbyte instance. - -**Example**: - -```bash -$ octavia list connectors destinations -NAME DOCKER REPOSITORY DOCKER IMAGE TAG DESTINATION DEFINITION ID -Azure Blob Storage airbyte/destination-azure-blob-storage 0.1.3 b4c5d105-31fd-4817-96b6-cb923bfc04cb -Amazon SQS airbyte/destination-amazon-sqs 0.1.0 0eeee7fb-518f-4045-bacc-9619e31c43ea -BigQuery airbyte/destination-bigquery 0.6.11 22f6c74f-5699-40ff-833c-4a879ea40133 -BigQuery (denormalized typed struct) airbyte/destination-bigquery-denormalized 0.2.10 079d5540-f236-4294-ba7c-ade8fd918496 -``` - -#### `octavia list workspace sources` - -List all the sources existing on your targeted Airbyte instance. - -**Example**: - -```bash -$ octavia list workspace sources -NAME SOURCE NAME SOURCE ID -weather OpenWeather c4aa8550-2122-4a33-9a21-adbfaa638544 -``` - -#### `octavia list workspace destinations` - -List all the destinations existing on your targeted Airbyte instance. - -**Example**: - -```bash -$ octavia list workspace destinations -NAME DESTINATION NAME DESTINATION ID -my_db Postgres c0c977c2-48e7-46fe-9f57-576285c26d42 -``` - -#### `octavia list workspace connections` - -List all the connections existing on your targeted Airbyte instance. - -**Example**: - -```bash -$ octavia list workspace connections -NAME CONNECTION ID STATUS SOURCE ID DESTINATION ID -weather_to_pg a4491317-153e-436f-b646-0b39338f9aab active c4aa8550-2122-4a33-9a21-adbfaa638544 c0c977c2-48e7-46fe-9f57-576285c26d42 -``` - -#### `octavia get source or ` - -Get an existing source in current the Airbyte workspace. You can use a source ID or name. - -| **Argument** | **Description** | -| ------------- | ---------------- | -| `SOURCE_ID` | The source id. | -| `SOURCE_NAME` | The source name. | - -**Examples**: - -```bash -$ octavia get source c0c977c2-48e7-46fe-9f57-576285c26d42 -{'connection_configuration': {'key': '**********', - 'start_date': '2010-01-01T00:00:00.000Z', - 'token': '**********'}, - 'name': 'Pokemon', - 'source_definition_id': 'b08e4776-d1de-4e80-ab5c-1e51dad934a2', - 'source_id': 'c0c977c2-48e7-46fe-9f57-576285c26d42', - 'source_name': 'My Poke', - 'workspace_id': 'c4aa8550-2122-4a33-9a21-adbfaa638544'} -``` - -```bash -$ octavia get source "My Poke" -{'connection_configuration': {'key': '**********', - 'start_date': '2010-01-01T00:00:00.000Z', - 'token': '**********'}, - 'name': 'Pokemon', - 'source_definition_id': 'b08e4776-d1de-4e80-ab5c-1e51dad934a2', - 'source_id': 'c0c977c2-48e7-46fe-9f57-576285c26d42', - 'source_name': 'My Poke', - 'workspace_id': 'c4aa8550-2122-4a33-9a21-adbfaa638544'} -``` - -#### `octavia get destination or ` - -Get an existing destination in current the Airbyte workspace. You can use a destination ID or name. - -| **Argument** | **Description** | -| ------------------ | --------------------- | -| `DESTINATION_ID` | The destination id. | -| `DESTINATION_NAME` | The destination name. | - -**Examples**: - -```bash -$ octavia get destination c0c977c2-48e7-46fe-9f57-576285c26d42 -{ - "destinationDefinitionId": "c0c977c2-48e7-46fe-9f57-576285c26d42", - "destinationId": "18102e7c-5160-4000-841b-15e8ec48c301", - "workspaceId": "18102e7c-5160-4000-883a-30bc7cd65601", - "connectionConfiguration": { - "user": "charles" - }, - "name": "pg", - "destinationName": "Postgres" -} -``` - -```bash -$ octavia get destination pg -{ - "destinationDefinitionId": "18102e7c-5160-4000-821f-4d7cfdf87201", - "destinationId": "18102e7c-5160-4000-841b-15e8ec48c301", - "workspaceId": "18102e7c-5160-4000-883a-30bc7cd65601", - "connectionConfiguration": { - "user": "charles" - }, - "name": "string", - "destinationName": "string" -} -``` - -#### `octavia get connection or ` - -Get an existing connection in current the Airbyte workspace. You can use a connection ID or name. - -| **Argument** | **Description** | -| ----------------- | -------------------- | -| `CONNECTION_ID` | The connection id. | -| `CONNECTION_NAME` | The connection name. | - -**Example**: - -```bash -$ octavia get connection c0c977c2-48e7-46fe-9f57-576285c26d42 -{ - "connectionId": "c0c977c2-48e7-46fe-9f57-576285c26d42", - "name": "Poke To PG", - "namespaceDefinition": "source", - "namespaceFormat": "${SOURCE_NAMESPACE}", - "prefix": "string", - "sourceId": "18102e7c-5340-4000-8eaa-4a86f844b101", - "destinationId": "18102e7c-5340-4000-8e58-6bed49c24b01", - "operationIds": [ - "18102e7c-5340-4000-8ef0-f35c05a49a01" - ], - "syncCatalog": { - "streams": [ - { - "stream": { - "name": "string", - "jsonSchema": {}, - "supportedSyncModes": [ - "full_refresh" - ], - "sourceDefinedCursor": false, - "defaultCursorField": [ - "string" - ], - "sourceDefinedPrimaryKey": [ - [ - "string" - ] - ], - "namespace": "string" - }, - "config": { - "syncMode": "full_refresh", - "cursorField": [ - "string" - ], - "destinationSyncMode": "append", - "primaryKey": [ - [ - "string" - ] - ], - "aliasName": "string", - "selected": false - } - } - ] - }, - "schedule": { - "units": 0, - "timeUnit": "minutes" - }, - "status": "active", - "resourceRequirements": { - "cpu_request": "string", - "cpu_limit": "string", - "memory_request": "string", - "memory_limit": "string" - }, - "sourceCatalogId": "18102e7c-5340-4000-85f3-204ab7715801" -} -``` - -```bash -$ octavia get connection "Poke To PG" -{ - "connectionId": "c0c977c2-48e7-46fe-9f57-576285c26d42", - "name": "Poke To PG", - "namespaceDefinition": "source", - "namespaceFormat": "${SOURCE_NAMESPACE}", - "prefix": "string", - "sourceId": "18102e7c-5340-4000-8eaa-4a86f844b101", - "destinationId": "18102e7c-5340-4000-8e58-6bed49c24b01", - "operationIds": [ - "18102e7c-5340-4000-8ef0-f35c05a49a01" - ], - "syncCatalog": { - "streams": [ - { - "stream": { - "name": "string", - "jsonSchema": {}, - "supportedSyncModes": [ - "full_refresh" - ], - "sourceDefinedCursor": false, - "defaultCursorField": [ - "string" - ], - "sourceDefinedPrimaryKey": [ - [ - "string" - ] - ], - "namespace": "string" - }, - "config": { - "syncMode": "full_refresh", - "cursorField": [ - "string" - ], - "destinationSyncMode": "append", - "primaryKey": [ - [ - "string" - ] - ], - "aliasName": "string", - "selected": false - } - } - ] - }, - "schedule": { - "units": 0, - "timeUnit": "minutes" - }, - "status": "active", - "resourceRequirements": { - "cpu_request": "string", - "cpu_limit": "string", - "memory_request": "string", - "memory_limit": "string" - }, - "sourceCatalogId": "18102e7c-5340-4000-85f3-204ab7715801" -} -``` - -#### `octavia import all` - -Import all existing resources (sources, destinations, connections) on your Airbyte instance to manage them with octavia-cli. - -**Examples**: - -```bash -$ octavia import all -🐙 - Octavia is targetting your Airbyte instance running at http://localhost:8000 on workspace b06c6fbb-cadd-4c5c-bdbb-710add7dedb9. -✅ - Imported source poke in sources/poke/configuration.yaml. State stored in sources/poke/state_b06c6fbb-cadd-4c5c-bdbb-710add7dedb9.yaml -⚠️ - Please update any secrets stored in sources/poke/configuration.yaml -✅ - Imported destination Postgres in destinations/postgres/configuration.yaml. State stored in destinations/postgres/state_b06c6fbb-cadd-4c5c-bdbb-710add7dedb9.yaml -⚠️ - Please update any secrets stored in destinations/postgres/configuration.yaml -✅ - Imported connection poke-to-pg in connections/poke_to_pg/configuration.yaml. State stored in connections/poke_to_pg/state_b06c6fbb-cadd-4c5c-bdbb-710add7dedb9.yaml -``` - -You know have local configuration files for all Airbyte resources that were already existing. -You need to edit any secret values that exist in these configuration files as secrets are not imported. -You can edit the configuration files and run `octavia apply` to continue managing them with octavia-cli. - -#### `octavia import destination or ` - -Import an existing destination to manage it with octavia-cli. You can use a destination ID or name. - -| **Argument** | **Description** | -| ------------------ | --------------------- | -| `DESTINATION_ID` | The destination id. | -| `DESTINATION_NAME` | The destination name. | - -#### `octavia import source or ` - -Import an existing source to manage it with octavia-cli. You can use a source ID or name. - -| **Argument** | **Description** | -| ------------- | ---------------- | -| `SOURCE_ID` | The source id. | -| `SOURCE_NAME` | The source name. | - -**Examples**: - -```bash -$ octavia import source poke -🐙 - Octavia is targetting your Airbyte instance running at http://localhost:8000 on workspace 75658e4f-e5f0-4e35-be0c-bdad33226c94. -✅ - Imported source poke in sources/poke/configuration.yaml. State stored in sources/poke/state_75658e4f-e5f0-4e35-be0c-bdad33226c94.yaml -⚠️ - Please update any secrets stored in sources/poke/configuration.yaml -``` - -You know have local configuration file for an Airbyte source that was already existing. -You need to edit any secret value that exist in this configuration as secrets are not imported. -You can edit the configuration and run `octavia apply` to continue managing it with octavia-cli. - -#### `octavia import destination or ` - -Import an existing destination to manage it with octavia-cli. You can use a destination ID or name. - -| **Argument** | **Description** | -| ------------------ | --------------------- | -| `DESTINATION_ID` | The destination id. | -| `DESTINATION_NAME` | The destination name. | - -**Examples**: - -```bash -$ octavia import destination pg -🐙 - Octavia is targetting your Airbyte instance running at http://localhost:8000 on workspace 75658e4f-e5f0-4e35-be0c-bdad33226c94. -✅ - Imported destination pg in destinations/pg/configuration.yaml. State stored in destinations/pg/state_75658e4f-e5f0-4e35-be0c-bdad33226c94.yaml -⚠️ - Please update any secrets stored in destinations/pg/configuration.yaml -``` - -You know have local configuration file for an Airbyte destination that was already existing. -You need to edit any secret value that exist in this configuration as secrets are not imported. -You can edit the configuration and run `octavia apply` to continue managing it with octavia-cli. - -#### `octavia import connection or ` - -Import an existing connection to manage it with octavia-cli. You can use a connection ID or name. - -| **Argument** | **Description** | -| ----------------- | -------------------- | -| `CONNECTION_ID` | The connection id. | -| `CONNECTION_NAME` | The connection name. | - -**Examples**: - -```bash -$ octavia import connection poke-to-pg -🐙 - Octavia is targetting your Airbyte instance running at http://localhost:8000 on workspace 75658e4f-e5f0-4e35-be0c-bdad33226c94. -✅ - Imported connection poke-to-pg in connections/poke-to-pg/configuration.yaml. State stored in connections/poke-to-pg/state_75658e4f-e5f0-4e35-be0c-bdad33226c94.yaml -⚠️ - Please update any secrets stored in connections/poke-to-pg/configuration.yaml -``` - -You know have local configuration file for an Airbyte connection that was already existing. -**N.B.: You first need to import the source and destination used by the connection.** -You can edit the configuration and run `octavia apply` to continue managing it with octavia-cli. - -#### `octavia generate source ` - -Generate a YAML configuration for a source. -The YAML file will be stored at `./sources//configuration.yaml`. - -| **Argument** | **Description** | -| --------------- | --------------------------------------------------------------------------------------------- | -| `DEFINITION_ID` | The source connector definition id. Can be retrieved using `octavia list connectors sources`. | -| `SOURCE_NAME` | The name you want to give to this source in Airbyte. | - -**Example**: - -```bash -$ octavia generate source d8540a80-6120-485d-b7d6-272bca477d9b weather -✅ - Created the source template for weather in ./sources/weather/configuration.yaml. -``` - -#### `octavia generate destination ` - -Generate a YAML configuration for a destination. -The YAML file will be stored at `./destinations//configuration.yaml`. - -| **Argument** | **Description** | -| ------------------ | ------------------------------------------------------------------------------------------------------- | -| `DEFINITION_ID` | The destination connector definition id. Can be retrieved using `octavia list connectors destinations`. | -| `DESTINATION_NAME` | The name you want to give to this destination in Airbyte. | - -**Example**: - -```bash -$ octavia generate destination 25c5221d-dce2-4163-ade9-739ef790f503 my_db -✅ - Created the destination template for my_db in ./destinations/my_db/configuration.yaml. -``` - -#### `octavia generate connection --source --destination ` - -Generate a YAML configuration for a connection. -The YAML file will be stored at `./connections//configuration.yaml`. - -| **Option** | **Required** | **Description** | -| --------------- | ------------ | ------------------------------------------------------------------------------------------ | -| `--source` | Yes | Path to the YAML configuration file of the source you want to create a connection from. | -| `--destination` | Yes | Path to the YAML configuration file of the destination you want to create a connection to. | - -| **Argument** | **Description** | -| ----------------- | -------------------------------------------------------- | -| `CONNECTION_NAME` | The name you want to give to this connection in Airbyte. | - -**Example**: - -```bash -$ octavia generate connection --source sources/weather/configuration.yaml --destination destinations/my_db/configuration.yaml weather_to_pg -✅ - Created the connection template for weather_to_pg in ./connections/weather_to_pg/configuration.yaml. -``` - -#### `octavia apply` - -Create or update the resource on your Airbyte instance according to local configurations found in your octavia project directory. -If the resource was not found on your Airbyte instance, **apply** will **create** the remote resource. -If the resource was found on your Airbyte instance, **apply** will prompt you for validation of the changes and will run an **update** of your resource. -Please note that if a secret field was updated on your configuration, **apply** will run this change without prompt. - -| **Option** | **Required** | **Description** | -| ---------- | ------------ | ------------------------------------------------------------------ | -| `--file` | No | Path to the YAML configuration files you want to create or update. | -| `--force` | No | Run update without prompting for changes validation. | - -**Example**: - -```bash -$ octavia apply -🐙 - weather exists on your Airbyte instance, let's check if we need to update it! -👀 - Here's the computed diff (🚨 remind that diff on secret fields are not displayed): - E - Value of root['lat'] changed from "46.7603" to "45.7603". -❓ - Do you want to update weather? [y/N]: y -✍️ - Running update because a diff was detected between local and remote resource. -🎉 - Successfully updated weather on your Airbyte instance! -💾 - New state for weather stored at ./sources/weather/state_.yaml. -🐙 - my_db exists on your Airbyte instance, let's check if we need to update it! -😴 - Did not update because no change detected. -🐙 - weather_to_pg exists on your Airbyte instance, let's check if we need to update it! -👀 - Here's the computed diff (🚨 remind that diff on secret fields are not displayed): - E - Value of root['schedule']['timeUnit'] changed from "days" to "hours". -❓ - Do you want to update weather_to_pg? [y/N]: y -✍️ - Running update because a diff was detected between local and remote resource. -🎉 - Successfully updated weather_to_pg on your Airbyte instance! -💾 - New state for weather_to_pg stored at ./connections/weather_to_pg/state_.yaml. -``` - -## Contributing - -1. Please sign up to [Airbyte's Slack workspace](https://slack.airbyte.io/) and join the `#octavia-cli`. We'll sync up community efforts in this channel. -2. Pick an existing [GitHub issues](https://github.com/airbytehq/airbyte/issues?q=is%3Aopen+is%3Aissue+label%3Aarea%2Foctavia-cli) or **open** a new one to explain what you'd like to implement. -3. Assign the GitHub issue to yourself. -4. Fork Airbyte's repo, code and test thoroughly. -5. Open a PR on our Airbyte repo from your fork. - -### Developing locally - -0. Build the project locally (from the root of Airbyte's repo): `SUB_BUILD=OCTAVIA_CLI ./gradlew build # from the root directory of the repo`. -1. Install Python 3.8.12. We suggest doing it through `pyenv`. -2. Create a virtualenv: `python -m venv .venv`. -3. Activate the virtualenv: `source .venv/bin/activate`. -4. Install dev dependencies: `pip install -e .\[tests\]`. -5. Install `pre-commit` hooks: `pre-commit install`. -6. Run the unittest suite: `pytest --cov=octavia_cli`. Note, a local version of airbyte needs to be running (e.g. `docker compose up` from the root directory of the project) -7. Make sure the build passes (step 0) before opening a PR. - -## Telemetry - -This CLI has some telemetry tooling to send Airbyte some data about the usage of this tool. -We will use this data to improve the CLI and measure its adoption. -The telemetry sends data about: - -- Which command was run (not the arguments or options used). -- Success or failure of the command run and the error type (not the error payload). -- The current Airbyte workspace id if the user has not set the _anonymous data collection_ on their Airbyte instance. - -You can disable telemetry by setting the `OCTAVIA_ENABLE_TELEMETRY` environment variable to `False` or using the `--disable-telemetry` flag. diff --git a/docusaurus/sidebars.js b/docusaurus/sidebars.js index 28d3a68d96f4..2be5469c7aba 100644 --- a/docusaurus/sidebars.js +++ b/docusaurus/sidebars.js @@ -564,10 +564,6 @@ module.exports = { type: "doc", id: "terraform-documentation", }, - { - type: "doc", - id: "cli-documentation", - }, understandingAirbyte, contributeToAirbyte, { diff --git a/octavia-cli/.coveragerc b/octavia-cli/.coveragerc deleted file mode 100644 index 034c0c0c28f5..000000000000 --- a/octavia-cli/.coveragerc +++ /dev/null @@ -1,3 +0,0 @@ -[report] -# show lines missing coverage -show_missing = true diff --git a/octavia-cli/.dockerignore b/octavia-cli/.dockerignore deleted file mode 100644 index 1a4780ba9ba3..000000000000 --- a/octavia-cli/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -build -!build/airbyte_api_client -.venv -octavia_cli.egg-info diff --git a/octavia-cli/.gitignore b/octavia-cli/.gitignore deleted file mode 100644 index db492e89106a..000000000000 --- a/octavia-cli/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.coverage -.venv -state_*.yaml -dist \ No newline at end of file diff --git a/octavia-cli/.python-version b/octavia-cli/.python-version deleted file mode 100644 index bd28b9c5c27e..000000000000 --- a/octavia-cli/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.9 diff --git a/octavia-cli/CHANGELOG.md b/octavia-cli/CHANGELOG.md deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/octavia-cli/Dockerfile b/octavia-cli/Dockerfile deleted file mode 100644 index 16eb123219d9..000000000000 --- a/octavia-cli/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM python:3.9-slim as base - -RUN apt-get upgrade \ - && pip install --upgrade pip - -WORKDIR /home/octavia-cli -COPY . ./ - -RUN pip install --no-cache-dir . - -RUN useradd --create-home --shell /bin/bash octavia-cli -USER octavia-cli - -WORKDIR /home/octavia-project -ENTRYPOINT ["octavia"] - -LABEL io.airbyte.version=0.50.0 -LABEL io.airbyte.name=airbyte/octavia-cli diff --git a/octavia-cli/LICENSE b/octavia-cli/LICENSE deleted file mode 100644 index ec45d182fcb9..000000000000 --- a/octavia-cli/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 Airbyte, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/octavia-cli/README.md b/octavia-cli/README.md deleted file mode 100644 index 82ae97bca50c..000000000000 --- a/octavia-cli/README.md +++ /dev/null @@ -1,725 +0,0 @@ -# 🐙 Octavia CLI - -## Disclaimer - -The project is in **alpha** version. -Readers can refer to our [opened GitHub issues](https://github.com/airbytehq/airbyte/issues?q=is%3Aopen+is%3Aissue+label%3Aarea%2Foctavia-cli) to check the ongoing work on this project. - -## What is `octavia` CLI? - -Octavia CLI is a tool to manage Airbyte configurations in YAML. -It has the following features: - -- Scaffolding of a readable directory architecture that will host the YAML configs (`octavia init`). -- Auto-generation of YAML config file that matches the resources' schemas (`octavia generate`). -- Manage Airbyte resources with YAML config files. -- Safe resources update through diff display and validation (`octavia apply`). -- Simple secret management to avoid versioning credentials. - -## Why should I use `octavia` CLI? - -A CLI provides freedom to users to use the tool in whatever context and use case they have. -These are non-exhaustive use cases `octavia` can be convenient for: - -- Managing Airbyte configurations with a CLI instead of a web UI. -- Versioning Airbyte configurations in Git. -- Updating of Airbyte configurations in an automated deployment pipeline. -- Integrating the Airbyte configuration deployment in a dev ops tooling stack: Helm, Ansible etc. -- Streamlining the deployment of Airbyte configurations to multiple Airbyte instance. - -Feel free to share your use cases with the community in [#octavia-cli](https://airbytehq.slack.com/archives/C02RRUG9CP5) or on [Airbyte Forum](https://github.com/airbytehq/airbyte/discussions). - -## Table of content - -- [Workflow](#workflow) -- [Secret management](#secret-management) -- [Install](#install) -- [Commands reference](#commands-reference) -- [Contributing](#contributing) -- [Telemetry](#telemetry) -- [Changelog](#changelog) - -## Workflow - -### 1. Generate local YAML files for sources or destinations - -1. Retrieve the _definition id_ of the connector you want to use using `octavia list` command. -2. Generate YAML configuration running `octavia generate source ` or `octavia generate destination `. - -### 2. Edit your local YAML configurations - -1. Edit the generated YAML configurations according to your need. -2. Use the [secret management feature](#secret-management) feature to avoid storing credentials in the YAML files. - -### 3. Create the declared sources or destinations on your Airbyte instance - -1. Run `octavia apply` to create the **sources** and **destinations** - -### 4. Generate connections - -1. Run `octavia octavia generate connection --source --destination ` to create a YAML configuration for a new connection. -2. Edit the created configuration file according to your need: change the scheduling or the replicated streams list. - -### 5. Create the declared connections - -1. Run `octavia apply` to create the newly declared connection on your Airbyte instance. - -### 6. Update your configurations - -Changes in your local configurations can be propagated to your Airbyte instance using `octavia apply`. You will be prompted for validation of changes. You can bypass the validation step using the `--force` flag. - -## Secret management - -Sources and destinations configurations have credential fields that you **do not want to store as plain text in your VCS**. -`octavia` offers secret management through environment variables expansion: - -```yaml -configuration: - password: ${MY_PASSWORD} -``` - -If you have set a `MY_PASSWORD` environment variable, `octavia apply` will load its value into the `password` field. - -## Install - -### Requirements - -We decided to package the CLI in a docker image with portability in mind. -**[Please install and run Docker if you are not](https://docs.docker.com/get-docker/)**. - -### As a command available in your bash profile - -```bash -curl -s -o- https://raw.githubusercontent.com/airbytehq/airbyte/master/octavia-cli/install.sh | bash -``` - -This script: - -1. Pulls the [octavia-cli image](https://hub.docker.com/r/airbyte/octavia-cli/tags) from our Docker registry. -2. Creates an `octavia` alias in your profile. -3. Creates a `~/.octavia` file whose values are mapped to the octavia container's environment variables. - -### Using `docker run` - -```bash -touch ~/.octavia # Create a file to store env variables that will be mapped the octavia-cli container -mkdir my_octavia_project_directory # Create your octavia project directory where YAML configurations will be stored. -docker run --name octavia-cli -i --rm -v my_octavia_project_directory:/home/octavia-project --network host --user $(id -u):$(id -g) --env-file ~/.octavia airbyte/octavia-cli:0.50.0 -``` - -### Using `docker-compose` - -Using octavia in docker-compose could be convenient for automatic `apply` on start-up. - -Add another entry in the services key of your Airbyte `docker-compose.yml` - -```yaml -services: - # . . . - octavia-cli: - image: airbyte/octavia-cli:latest - command: apply --force - env_file: - - ~/.octavia # Use a local env file to store variables that will be mapped the octavia-cli container - volumes: - - :/home/octavia-project - depends_on: - - webapp -``` - -Other commands besides `apply` can be run like so: - -```bash -docker compose run octavia-cli ` -``` - -## Commands reference - -### `octavia` command flags - -| **Flag** | **Description** | **Env Variable** | **Default** | -| ---------------------------------------- | --------------------------------------------------------------------------------- |----------------------------| ------------------------------------------------------ | -| `--airbyte-url` | Airbyte instance URL. | `AIRBYTE_URL` | `http://localhost:8000` | -| `--airbyte-username` | Airbyte instance username (basic auth). | `AIRBYTE_USERNAME` | `airbyte` | -| `--airbyte-password` | Airbyte instance password (basic auth). | `AIRBYTE_PASSWORD` | `password` | -| `--workspace-id` | Airbyte workspace id. | `AIRBYTE_WORKSPACE_ID` | The first workspace id found on your Airbyte instance. | -| `--enable-telemetry/--disable-telemetry` | Enable or disable the sending of telemetry data. | `OCTAVIA_ENABLE_TELEMETRY` | True | -| `--api-http-header` | HTTP Header value pairs passed while calling Airbyte's API | None | None | -| `--api-http-headers-file-path` | Path to the YAML file that contains custom HTTP Headers to send to Airbyte's API. | None | None | - -#### Using custom HTTP headers - -You can set custom HTTP headers to send to Airbyte's API with options: - -```bash -octavia --api-http-header Header-Name Header-Value --api-http-header Header-Name-2 Header-Value-2 list connectors sources -``` - -You can also use a custom YAML file (one is already created on init in `api_http_headers.yaml`) to declare the HTTP headers to send to the API: - -```yaml -headers: - Authorization: Bearer my-secret-token - User-Agent: octavia-cli/0.0.0 -``` - -Environment variable expansion is available in this Yaml file - -```yaml -headers: - Authorization: Bearer ${MY_API_TOKEN} -``` - -**Options based headers are overriding file based headers if an header is declared in both.** - -### `octavia` subcommands - -| **Command** | **Usage** | -| ----------------------------------------- | ------------------------------------------------------------------------------------------ | -| **`octavia init`** | Initialize required directories for the project. | -| **`octavia list connectors sources`** | List all sources connectors available on the remote Airbyte instance. | -| **`octavia list connectors destinations`** | List all destinations connectors available on the remote Airbyte instance. | -| **`octavia list workspace sources`** | List existing sources in current the Airbyte workspace. | -| **`octavia list workspace destinations`** | List existing destinations in the current Airbyte workspace. | -| **`octavia list workspace connections`** | List existing connections in the current Airbyte workspace. | -| **`octavia get source`** | Get the JSON representation of an existing source in current the Airbyte workspace. | -| **`octavia get destination`** | Get the JSON representation of an existing destination in the current Airbyte workspace. | -| **`octavia get connection`** | Get the JSON representation of an existing connection in the current Airbyte workspace. | -| **`octavia import all`** | Import all existing sources, destinations and connections to manage them with octavia-cli. | -| **`octavia import source`** | Import an existing source to manage it with octavia-cli. | -| **`octavia import destination`** | Import an existing destination to manage it with octavia-cli. | -| **`octavia import connection`** | Import an existing connection to manage it with octavia-cli. | -| **`octavia generate source`** | Generate a local YAML configuration for a new source. | -| **`octavia generate destination`** | Generate a local YAML configuration for a new destination. | -| **`octavia generate connection`** | Generate a local YAML configuration for a new connection. | -| **`octavia apply`** | Create or update Airbyte remote resources according to local YAML configurations. | - -#### `octavia init` - -The `octavia init` commands scaffolds the required directory architecture for running `octavia generate` and `octavia apply` commands. - -**Example**: - -```bash -$ mkdir my_octavia_project && cd my_octavia_project -$ octavia init -🐙 - Octavia is targetting your Airbyte instance running at http://localhost:8000 on workspace e1f46f7d-5354-4200-aed6-7816015ca54b. -🐙 - Project is not yet initialized. -🔨 - Initializing the project. -✅ - Created the following directories: sources, destinations, connections. -$ ls -connections destinations sources -``` - -#### `octavia list connectors sources` - -List all the source connectors currently available on your Airbyte instance. - -**Example**: - -```bash -$ octavia list connectors sources -NAME DOCKER REPOSITORY DOCKER IMAGE TAG SOURCE DEFINITION ID -Airtable airbyte/source-airtable 0.1.1 14c6e7ea-97ed-4f5e-a7b5-25e9a80b8212 -AWS CloudTrail airbyte/source-aws-cloudtrail 0.1.4 6ff047c0-f5d5-4ce5-8c81-204a830fa7e1 -Amazon Ads airbyte/source-amazon-ads 0.1.3 c6b0a29e-1da9-4512-9002-7bfd0cba2246 -Amazon Seller Partner airbyte/source-amazon-seller-partner 0.2.16 e55879a8-0ef8-4557-abcf-ab34c53ec460 -``` - -#### `octavia list connectors destinations` - -List all the destinations connectors currently available on your Airbyte instance. - -**Example**: - -```bash -$ octavia list connectors destinations -NAME DOCKER REPOSITORY DOCKER IMAGE TAG DESTINATION DEFINITION ID -Azure Blob Storage airbyte/destination-azure-blob-storage 0.1.3 b4c5d105-31fd-4817-96b6-cb923bfc04cb -Amazon SQS airbyte/destination-amazon-sqs 0.1.0 0eeee7fb-518f-4045-bacc-9619e31c43ea -BigQuery airbyte/destination-bigquery 0.6.11 22f6c74f-5699-40ff-833c-4a879ea40133 -BigQuery (denormalized typed struct) airbyte/destination-bigquery-denormalized 0.2.10 079d5540-f236-4294-ba7c-ade8fd918496 -``` - -#### `octavia list workspace sources` - -List all the sources existing on your targeted Airbyte instance. - -**Example**: - -```bash -$ octavia list workspace sources -NAME SOURCE NAME SOURCE ID -weather OpenWeather c4aa8550-2122-4a33-9a21-adbfaa638544 -``` - -#### `octavia list workspace destinations` - -List all the destinations existing on your targeted Airbyte instance. - -**Example**: - -```bash -$ octavia list workspace destinations -NAME DESTINATION NAME DESTINATION ID -my_db Postgres c0c977c2-48e7-46fe-9f57-576285c26d42 -``` - -#### `octavia list workspace connections` - -List all the connections existing on your targeted Airbyte instance. - -**Example**: - -```bash -$ octavia list workspace connections -NAME CONNECTION ID STATUS SOURCE ID DESTINATION ID -weather_to_pg a4491317-153e-436f-b646-0b39338f9aab active c4aa8550-2122-4a33-9a21-adbfaa638544 c0c977c2-48e7-46fe-9f57-576285c26d42 -``` - -#### `octavia get source or ` - -Get an existing source in current the Airbyte workspace. You can use a source ID or name. - -| **Argument** | **Description** | -| ------------- | ---------------- | -| `SOURCE_ID` | The source id. | -| `SOURCE_NAME` | The source name. | - -**Examples**: - -```bash -$ octavia get source c0c977c2-48e7-46fe-9f57-576285c26d42 -{'connection_configuration': {'key': '**********', - 'start_date': '2010-01-01T00:00:00.000Z', - 'token': '**********'}, - 'name': 'Pokemon', - 'source_definition_id': 'b08e4776-d1de-4e80-ab5c-1e51dad934a2', - 'source_id': 'c0c977c2-48e7-46fe-9f57-576285c26d42', - 'source_name': 'My Poke', - 'workspace_id': 'c4aa8550-2122-4a33-9a21-adbfaa638544'} -``` - -```bash -$ octavia get source "My Poke" -{'connection_configuration': {'key': '**********', - 'start_date': '2010-01-01T00:00:00.000Z', - 'token': '**********'}, - 'name': 'Pokemon', - 'source_definition_id': 'b08e4776-d1de-4e80-ab5c-1e51dad934a2', - 'source_id': 'c0c977c2-48e7-46fe-9f57-576285c26d42', - 'source_name': 'My Poke', - 'workspace_id': 'c4aa8550-2122-4a33-9a21-adbfaa638544'} -``` - -#### `octavia get destination or ` - -Get an existing destination in current the Airbyte workspace. You can use a destination ID or name. - -| **Argument** | **Description** | -| ------------------ | --------------------- | -| `DESTINATION_ID` | The destination id. | -| `DESTINATION_NAME` | The destination name. | - -**Examples**: - -```bash -$ octavia get destination c0c977c2-48e7-46fe-9f57-576285c26d42 -{ - "destinationDefinitionId": "c0c977c2-48e7-46fe-9f57-576285c26d42", - "destinationId": "18102e7c-5160-4000-841b-15e8ec48c301", - "workspaceId": "18102e7c-5160-4000-883a-30bc7cd65601", - "connectionConfiguration": { - "user": "charles" - }, - "name": "pg", - "destinationName": "Postgres" -} -``` - -```bash -$ octavia get destination pg -{ - "destinationDefinitionId": "18102e7c-5160-4000-821f-4d7cfdf87201", - "destinationId": "18102e7c-5160-4000-841b-15e8ec48c301", - "workspaceId": "18102e7c-5160-4000-883a-30bc7cd65601", - "connectionConfiguration": { - "user": "charles" - }, - "name": "string", - "destinationName": "string" -} -``` - -#### `octavia get connection or ` - -Get an existing connection in current the Airbyte workspace. You can use a connection ID or name. - -| **Argument** | **Description** | -| ----------------- | -------------------- | -| `CONNECTION_ID` | The connection id. | -| `CONNECTION_NAME` | The connection name. | - -**Example**: - -```bash -$ octavia get connection c0c977c2-48e7-46fe-9f57-576285c26d42 -{ - "connectionId": "c0c977c2-48e7-46fe-9f57-576285c26d42", - "name": "Poke To PG", - "namespaceDefinition": "source", - "namespaceFormat": "${SOURCE_NAMESPACE}", - "prefix": "string", - "sourceId": "18102e7c-5340-4000-8eaa-4a86f844b101", - "destinationId": "18102e7c-5340-4000-8e58-6bed49c24b01", - "operationIds": [ - "18102e7c-5340-4000-8ef0-f35c05a49a01" - ], - "syncCatalog": { - "streams": [ - { - "stream": { - "name": "string", - "jsonSchema": {}, - "supportedSyncModes": [ - "full_refresh" - ], - "sourceDefinedCursor": false, - "defaultCursorField": [ - "string" - ], - "sourceDefinedPrimaryKey": [ - [ - "string" - ] - ], - "namespace": "string" - }, - "config": { - "syncMode": "full_refresh", - "cursorField": [ - "string" - ], - "destinationSyncMode": "append", - "primaryKey": [ - [ - "string" - ] - ], - "aliasName": "string", - "selected": false - } - } - ] - }, - "schedule": { - "units": 0, - "timeUnit": "minutes" - }, - "status": "active", - "resourceRequirements": { - "cpu_request": "string", - "cpu_limit": "string", - "memory_request": "string", - "memory_limit": "string" - }, - "sourceCatalogId": "18102e7c-5340-4000-85f3-204ab7715801" -} -``` - -```bash -$ octavia get connection "Poke To PG" -{ - "connectionId": "c0c977c2-48e7-46fe-9f57-576285c26d42", - "name": "Poke To PG", - "namespaceDefinition": "source", - "namespaceFormat": "${SOURCE_NAMESPACE}", - "prefix": "string", - "sourceId": "18102e7c-5340-4000-8eaa-4a86f844b101", - "destinationId": "18102e7c-5340-4000-8e58-6bed49c24b01", - "operationIds": [ - "18102e7c-5340-4000-8ef0-f35c05a49a01" - ], - "syncCatalog": { - "streams": [ - { - "stream": { - "name": "string", - "jsonSchema": {}, - "supportedSyncModes": [ - "full_refresh" - ], - "sourceDefinedCursor": false, - "defaultCursorField": [ - "string" - ], - "sourceDefinedPrimaryKey": [ - [ - "string" - ] - ], - "namespace": "string" - }, - "config": { - "syncMode": "full_refresh", - "cursorField": [ - "string" - ], - "destinationSyncMode": "append", - "primaryKey": [ - [ - "string" - ] - ], - "aliasName": "string", - "selected": false - } - } - ] - }, - "schedule": { - "units": 0, - "timeUnit": "minutes" - }, - "status": "active", - "resourceRequirements": { - "cpu_request": "string", - "cpu_limit": "string", - "memory_request": "string", - "memory_limit": "string" - }, - "sourceCatalogId": "18102e7c-5340-4000-85f3-204ab7715801" -} -``` - -#### `octavia import all` - -Import all existing resources (sources, destinations, connections) on your Airbyte instance to manage them with octavia-cli. - -**Examples**: - -```bash -$ octavia import all -🐙 - Octavia is targetting your Airbyte instance running at http://localhost:8000 on workspace b06c6fbb-cadd-4c5c-bdbb-710add7dedb9. -✅ - Imported source poke in sources/poke/configuration.yaml. State stored in sources/poke/state_b06c6fbb-cadd-4c5c-bdbb-710add7dedb9.yaml -⚠️ - Please update any secrets stored in sources/poke/configuration.yaml -✅ - Imported destination Postgres in destinations/postgres/configuration.yaml. State stored in destinations/postgres/state_b06c6fbb-cadd-4c5c-bdbb-710add7dedb9.yaml -⚠️ - Please update any secrets stored in destinations/postgres/configuration.yaml -✅ - Imported connection poke-to-pg in connections/poke_to_pg/configuration.yaml. State stored in connections/poke_to_pg/state_b06c6fbb-cadd-4c5c-bdbb-710add7dedb9.yaml -``` - -You know have local configuration files for all Airbyte resources that were already existing. -You need to edit any secret values that exist in these configuration files as secrets are not imported. -You can edit the configuration files and run `octavia apply` to continue managing them with octavia-cli. - -#### `octavia import destination or ` - -Import an existing destination to manage it with octavia-cli. You can use a destination ID or name. - -| **Argument** | **Description** | -| ------------------ | --------------------- | -| `DESTINATION_ID` | The destination id. | -| `DESTINATION_NAME` | The destination name. | - -#### `octavia import source or ` - -Import an existing source to manage it with octavia-cli. You can use a source ID or name. - -| **Argument** | **Description** | -| ------------- | ---------------- | -| `SOURCE_ID` | The source id. | -| `SOURCE_NAME` | The source name. | - -**Examples**: - -```bash -$ octavia import source poke -🐙 - Octavia is targetting your Airbyte instance running at http://localhost:8000 on workspace 75658e4f-e5f0-4e35-be0c-bdad33226c94. -✅ - Imported source poke in sources/poke/configuration.yaml. State stored in sources/poke/state_75658e4f-e5f0-4e35-be0c-bdad33226c94.yaml -⚠️ - Please update any secrets stored in sources/poke/configuration.yaml -``` - -You know have local configuration file for an Airbyte source that was already existing. -You need to edit any secret value that exist in this configuration as secrets are not imported. -You can edit the configuration and run `octavia apply` to continue managing it with octavia-cli. - -#### `octavia import destination or ` - -Import an existing destination to manage it with octavia-cli. You can use a destination ID or name. - -| **Argument** | **Description** | -| ------------------ | --------------------- | -| `DESTINATION_ID` | The destination id. | -| `DESTINATION_NAME` | The destination name. | - -**Examples**: - -```bash -$ octavia import destination pg -🐙 - Octavia is targetting your Airbyte instance running at http://localhost:8000 on workspace 75658e4f-e5f0-4e35-be0c-bdad33226c94. -✅ - Imported destination pg in destinations/pg/configuration.yaml. State stored in destinations/pg/state_75658e4f-e5f0-4e35-be0c-bdad33226c94.yaml -⚠️ - Please update any secrets stored in destinations/pg/configuration.yaml -``` - -You know have local configuration file for an Airbyte destination that was already existing. -You need to edit any secret value that exist in this configuration as secrets are not imported. -You can edit the configuration and run `octavia apply` to continue managing it with octavia-cli. - -#### `octavia import connection or ` - -Import an existing connection to manage it with octavia-cli. You can use a connection ID or name. - -| **Argument** | **Description** | -| ----------------- | -------------------- | -| `CONNECTION_ID` | The connection id. | -| `CONNECTION_NAME` | The connection name. | - -**Examples**: - -```bash -$ octavia import connection poke-to-pg -🐙 - Octavia is targetting your Airbyte instance running at http://localhost:8000 on workspace 75658e4f-e5f0-4e35-be0c-bdad33226c94. -✅ - Imported connection poke-to-pg in connections/poke-to-pg/configuration.yaml. State stored in connections/poke-to-pg/state_75658e4f-e5f0-4e35-be0c-bdad33226c94.yaml -⚠️ - Please update any secrets stored in connections/poke-to-pg/configuration.yaml -``` - -You know have local configuration file for an Airbyte connection that was already existing. -**N.B.: You first need to import the source and destination used by the connection.** -You can edit the configuration and run `octavia apply` to continue managing it with octavia-cli. - -#### `octavia generate source ` - -Generate a YAML configuration for a source. -The YAML file will be stored at `./sources//configuration.yaml`. - -| **Argument** | **Description** | -| --------------- | --------------------------------------------------------------------------------------------- | -| `DEFINITION_ID` | The source connector definition id. Can be retrieved using `octavia list connectors sources`. | -| `SOURCE_NAME` | The name you want to give to this source in Airbyte. | - -**Example**: - -```bash -$ octavia generate source d8540a80-6120-485d-b7d6-272bca477d9b weather -✅ - Created the source template for weather in ./sources/weather/configuration.yaml. -``` - -#### `octavia generate destination ` - -Generate a YAML configuration for a destination. -The YAML file will be stored at `./destinations//configuration.yaml`. - -| **Argument** | **Description** | -| ------------------ | ------------------------------------------------------------------------------------------------------- | -| `DEFINITION_ID` | The destination connector definition id. Can be retrieved using `octavia list connectors destinations`. | -| `DESTINATION_NAME` | The name you want to give to this destination in Airbyte. | - -**Example**: - -```bash -$ octavia generate destination 25c5221d-dce2-4163-ade9-739ef790f503 my_db -✅ - Created the destination template for my_db in ./destinations/my_db/configuration.yaml. -``` - -#### `octavia generate connection --source --destination ` - -Generate a YAML configuration for a connection. -The YAML file will be stored at `./connections//configuration.yaml`. - -| **Option** | **Required** | **Description** | -| --------------- | ------------ | ------------------------------------------------------------------------------------------ | -| `--source` | Yes | Path to the YAML configuration file of the source you want to create a connection from. | -| `--destination` | Yes | Path to the YAML configuration file of the destination you want to create a connection to. | - -| **Argument** | **Description** | -| ----------------- | -------------------------------------------------------- | -| `CONNECTION_NAME` | The name you want to give to this connection in Airbyte. | - -**Example**: - -```bash -$ octavia generate connection --source sources/weather/configuration.yaml --destination destinations/my_db/configuration.yaml weather_to_pg -✅ - Created the connection template for weather_to_pg in ./connections/weather_to_pg/configuration.yaml. -``` - -#### `octavia apply` - -Create or update the resource on your Airbyte instance according to local configurations found in your octavia project directory. -If the resource was not found on your Airbyte instance, **apply** will **create** the remote resource. -If the resource was found on your Airbyte instance, **apply** will prompt you for validation of the changes and will run an **update** of your resource. -Please note that if a secret field was updated on your configuration, **apply** will run this change without prompt. - -| **Option** | **Required** | **Description** | -| ---------- | ------------ | ------------------------------------------------------------------ | -| `--file` | No | Path to the YAML configuration files you want to create or update. | -| `--force` | No | Run update without prompting for changes validation. | - -**Example**: - -```bash -$ octavia apply -🐙 - weather exists on your Airbyte instance, let's check if we need to update it! -👀 - Here's the computed diff (🚨 remind that diff on secret fields are not displayed): - E - Value of root['lat'] changed from "46.7603" to "45.7603". -❓ - Do you want to update weather? [y/N]: y -✍️ - Running update because a diff was detected between local and remote resource. -🎉 - Successfully updated weather on your Airbyte instance! -💾 - New state for weather stored at ./sources/weather/state_.yaml. -🐙 - my_db exists on your Airbyte instance, let's check if we need to update it! -😴 - Did not update because no change detected. -🐙 - weather_to_pg exists on your Airbyte instance, let's check if we need to update it! -👀 - Here's the computed diff (🚨 remind that diff on secret fields are not displayed): - E - Value of root['schedule']['timeUnit'] changed from "days" to "hours". -❓ - Do you want to update weather_to_pg? [y/N]: y -✍️ - Running update because a diff was detected between local and remote resource. -🎉 - Successfully updated weather_to_pg on your Airbyte instance! -💾 - New state for weather_to_pg stored at ./connections/weather_to_pg/state_.yaml. -``` - -## Contributing - -1. Please sign up to [Airbyte's Slack workspace](https://slack.airbyte.io/) and join the `#octavia-cli`. We'll sync up community efforts in this channel. -2. Pick an existing [GitHub issues](https://github.com/airbytehq/airbyte/issues?q=is%3Aopen+is%3Aissue+label%3Aarea%2Foctavia-cli) or **open** a new one to explain what you'd like to implement. -3. Assign the GitHub issue to yourself. -4. Fork Airbyte's repo, code and test thoroughly. -5. Open a PR on our Airbyte repo from your fork. - -### Developing locally - -0. Build the project locally (from the root of Airbyte's repo): `./gradlew :octavia-cli:build # from the root directory of the repo`. -1. Install Python 3.8.12. We suggest doing it through `pyenv`. -2. Create a virtualenv: `python -m venv .venv`. -3. Activate the virtualenv: `source .venv/bin/activate`. -4. Install dev dependencies: `pip install -e .\[tests\]`. -5. Install `pre-commit` hooks: `pre-commit install`. -6. Run the unittest suite: `pytest --cov=octavia_cli`. Note, a local version of airbyte needs to be running (e.g. `docker compose up` from the root directory of the project) -7. Make sure the build passes (step 0) before opening a PR. - -## Telemetry - -This CLI has some telemetry tooling to send Airbyte some data about the usage of this tool. -We will use this data to improve the CLI and measure its adoption. -The telemetry sends data about: - -- Which command was run (not the arguments or options used). -- Success or failure of the command run and the error type (not the error payload). -- The current Airbyte workspace id if the user has not set the _anonymous data collection_ on their Airbyte instance. - -You can disable telemetry by setting the `OCTAVIA_ENABLE_TELEMETRY` environment variable to `False` or using the `--disable-telemetry` flag. - -## Changelog - -| Version | Date | Description | PR | -|---------| ---------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------- | -| 0.41.0 | 2022-10-13 | Use Basic Authentication for making API requests | [#17982](https://github.com/airbytehq/airbyte/pull/17982) | -| 0.40.0 | 2022-08-10 | Enable cron and basic scheduling | [#15253](https://github.com/airbytehq/airbyte/pull/15253) | -| 0.39.33 | 2022-07-05 | Add `octavia import all` command | [#14374](https://github.com/airbytehq/airbyte/pull/14374) | -| 0.39.32 | 2022-06-30 | Create import command to import and manage existing Airbyte resource from octavia-cli | [#14137](https://github.com/airbytehq/airbyte/pull/14137) | -| 0.39.27 | 2022-06-24 | Create get command to retrieve resources JSON representation | [#13254](https://github.com/airbytehq/airbyte/pull/13254) | -| 0.39.19 | 2022-06-16 | Allow connection management on multiple workspaces | [#13070](https://github.com/airbytehq/airbyte/pull/12727) | -| 0.39.19 | 2022-06-15 | Allow users to set custom HTTP headers | [#12893](https://github.com/airbytehq/airbyte/pull/12893) | -| 0.39.14 | 2022-05-12 | Enable normalization on connection | [#12727](https://github.com/airbytehq/airbyte/pull/12727) | -| 0.37.0 | 2022-05-05 | Use snake case in connection fields | [#12133](https://github.com/airbytehq/airbyte/pull/12133) | -| 0.35.68 | 2022-04-15 | Improve telemetry | [#12072](https://github.com/airbytehq/airbyte/issues/11896) | -| 0.35.68 | 2022-04-12 | Add telemetry | [#11896](https://github.com/airbytehq/airbyte/issues/11896) | -| 0.35.61 | 2022-04-07 | Alpha release | [EPIC](https://github.com/airbytehq/airbyte/issues/10704) | diff --git a/octavia-cli/install.sh b/octavia-cli/install.sh deleted file mode 100755 index 610cfe4a6703..000000000000 --- a/octavia-cli/install.sh +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env bash - -# This install scripts currently only works for ZSH and Bash profiles. -# It creates an octavia alias in your profile bound to a docker run command and your current user. - -VERSION=0.44.4 -OCTAVIA_ENV_FILE=${HOME}/.octavia - -detect_profile() { - if [ "${SHELL#*bash}" != "$SHELL" ]; then - if [ -f "$HOME/.bashrc" ]; then - DETECTED_PROFILE="$HOME/.bashrc" - elif [ -f "$HOME/.bash_profile" ]; then - DETECTED_PROFILE="$HOME/.bash_profile" - fi - elif [ "${SHELL#*zsh}" != "$SHELL" ]; then - if [ -f "$HOME/.zshrc" ]; then - DETECTED_PROFILE="$HOME/.zshrc" - fi - elif [ "${SHELL#*fish}" != "$SHELL" ]; then - if [ -f "$HOME/.config/fish/config.fish" ]; then - DETECTED_PROFILE="$HOME/.config/fish/config.fish" - fi - fi - - if [ -z "${DETECTED_PROFILE}" ]; then - echo "🚨 - Cannot install! This scripts only works if you are using one of these profiles: ~/.bashrc, ~/.bash_profile or ~/.zshrc" - exit 1 - else - echo "octavia alias will be added to ${DETECTED_PROFILE}" - fi -} - -check_docker_is_running() { - if ! docker info > /dev/null 2>&1; then - echo "🚨 - This script uses docker, and it isn't running - please start docker and try again!" - exit 1 - fi -} - -delete_previous_alias() { - sed -i'' -e '/^alias octavia=/d' ${DETECTED_PROFILE} -} - - -pull_image() { - echo "🐙 - Pulling image for octavia ${VERSION}" - docker pull airbyte/octavia-cli:${VERSION} > /dev/null - echo "🐙 - 🎉 octavia ${VERSION} image was pulled" -} - -add_octavia_comment_to_profile() { - printf "\n# OCTAVIA CLI ${VERSION}\n" >> ${DETECTED_PROFILE} -} - -create_octavia_env_file() { - if [ "${SHELL#*fish}" != "$SHELL" ]; then - echo "set OCTAVIA_ENV_FILE ${OCTAVIA_ENV_FILE}" >> ${DETECTED_PROFILE} - else - echo "OCTAVIA_ENV_FILE=${OCTAVIA_ENV_FILE}" >> ${DETECTED_PROFILE} - fi - touch ${OCTAVIA_ENV_FILE} - echo "🐙 - 💾 The octavia env file was created at ${OCTAVIA_ENV_FILE}" -} - -enable_telemetry() { - if [ "${SHELL#*fish}" != "$SHELL" ]; then - echo "set -x OCTAVIA_ENABLE_TELEMETRY $1" >> ${DETECTED_PROFILE} - else - echo "export OCTAVIA_ENABLE_TELEMETRY=$1" >> ${DETECTED_PROFILE} - fi - echo "OCTAVIA_ENABLE_TELEMETRY=$1" >> ${OCTAVIA_ENV_FILE} -} - -add_alias() { - if [ "${SHELL#*fish}" != "$SHELL" ]; then - echo 'alias octavia="docker run -i --rm -v $(pwd):/home/octavia-project --network host --env-file $OCTAVIA_ENV_FILE --user $(id -u):$(id -g) airbyte/octavia-cli:'${VERSION}'"' >> ${DETECTED_PROFILE} - else - echo 'alias octavia="docker run -i --rm -v \$(pwd):/home/octavia-project --network host --env-file \${OCTAVIA_ENV_FILE} --user \$(id -u):\$(id -g) airbyte/octavia-cli:'${VERSION}'"' >> ${DETECTED_PROFILE} - fi - echo "🐙 - 🎉 octavia alias was added to ${DETECTED_PROFILE}!" - echo "🐙 - Please open a new terminal window or run source ${DETECTED_PROFILE}" -} - -install() { - pull_image - add_alias -} - -telemetry_consent() { - read -p "❓ - Allow Airbyte to collect telemetry to improve the CLI? (Y/n)" -n 1 -r \\nimage/svg+xml\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"cc88c43f-6f53-4e8a-8c4d-b284baaf9635\",\"name\":\"Delighted\",\"dockerRepository\":\"airbyte/source-delighted\",\"dockerImageTag\":\"0.1.4\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/delighted\",\"icon\":\"\\n \\n \\n - \ \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"008b2e26-11a3-11ec-82a8-0242ac130003\",\"name\":\"Commercetools\",\"dockerRepository\":\"airbyte/source-commercetools\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/commercetools\",\"icon\":\"\\n\\n\\n\\n\\n\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\n\\t\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d917a47b-8537-4d0d-8c10-36a9928d4265\",\"name\":\"Kafka\",\"dockerRepository\":\"airbyte/source-kafka\",\"dockerImageTag\":\"0.2.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/kafka\",\"icon\":\"\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"47f25999-dd5e-4636-8c39-e7cea2453331\",\"name\":\"Bing - Ads\",\"dockerRepository\":\"airbyte/source-bing-ads\",\"dockerImageTag\":\"0.1.15\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/bing-ads\",\"icon\":\"\\n\\n \\n \\n \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"eb4c9e00-db83-4d63-a386-39cfa91012a8\",\"name\":\"Google - Search Console\",\"dockerRepository\":\"airbyte/source-google-search-console\",\"dockerImageTag\":\"0.1.17\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/google-search-console\",\"icon\":\"\\n\\n \\n Artboard\\n - \ Created with Sketch.\\n \\n \\n - \ \\n \\n - \ \\n \\n - \ \\n \\n - \ \\n - \ \\n - \ \\n \\n \\n \\n \\n - \ \\n - \ \\n \\n \\n \\n \\n \\n - \ \\n \\n - \ \\n \\n \\n - \ \\n \\n \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"a5f2c853-6e44-4aed-a9b6-7d1390c8a827\",\"name\":\"E2E - Test Source\",\"dockerRepository\":\"airbyte/source-e2e-test\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://example.com\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"custom\"},{\"sourceDefinitionId\":\"9b2d3607-7222-4709-9fa2-c2abdebbdd88\",\"name\":\"Chargify\",\"dockerRepository\":\"airbyte/source-chargify\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/chargify\",\"icon\":\"\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"2a2552ca-9f78-4c1c-9eb7-4d0dc66d72df\",\"name\":\"WooCommerce\",\"dockerRepository\":\"airbyte/source-woocommerce\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/woocommerce\",\"icon\":\"\\n\\n - \\n \\n \\n image/svg+xml\\n - \ \\n - \ \\n \\n \\n \\n \\n \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"9da77001-af33-4bcd-be46-6252bf9342b9\",\"name\":\"Shopify\",\"dockerRepository\":\"airbyte/source-shopify\",\"dockerImageTag\":\"0.1.38\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/shopify\",\"icon\":\"\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"c4cfaeda-c757-489a-8aba-859fb08b6970\",\"name\":\"US - Census\",\"dockerRepository\":\"airbyte/source-us-census\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/us-census\",\"icon\":\"\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"7865dce4-2211-4f6a-88e5-9d0fe161afe7\",\"name\":\"Yandex - Metrica\",\"dockerRepository\":\"airbyte/source-yandex-metrica\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/yandex-metrica\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"fe2b4084-3386-4d3b-9ad6-308f61a6f1e6\",\"name\":\"Harvest\",\"dockerRepository\":\"airbyte/source-harvest\",\"dockerImageTag\":\"0.1.11\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/harvest\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"90916976-a132-4ce9-8bce-82a03dd58788\",\"name\":\"BambooHR\",\"dockerRepository\":\"airbyte/source-bamboo-hr\",\"dockerImageTag\":\"0.2.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/bamboo-hr\",\"icon\":\"\\n\\n \\n BambooHR\\n Created - with Sketch.\\n \\n \\n \\n - \ \\n \\n \\n \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d8313939-3782-41b0-be29-b3ca20d8dd3a\",\"name\":\"Intercom\",\"dockerRepository\":\"airbyte/source-intercom\",\"dockerImageTag\":\"0.1.27\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/intercom\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"6e00b415-b02e-4160-bf02-58176a0ae687\",\"name\":\"Notion\",\"dockerRepository\":\"airbyte/source-notion\",\"dockerImageTag\":\"0.1.10\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/notion\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"1fa90628-2b9e-11ed-a261-0242ac120002\",\"name\":\"AlloyDB - for PostgreSQL\",\"dockerRepository\":\"airbyte/source-alloydb\",\"dockerImageTag\":\"1.0.15\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/alloydb\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"137ece28-5434-455c-8f34-69dc3782f451\",\"name\":\"LinkedIn - Ads\",\"dockerRepository\":\"airbyte/source-linkedin-ads\",\"dockerImageTag\":\"0.1.11\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/linkedin-ads\",\"icon\":\"\\n\\n\\n - \ \\n \\n \\n - \ \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"9bb85338-ea95-4c93-b267-6be89125b267\",\"name\":\"Freshservice\",\"dockerRepository\":\"airbyte/source-freshservice\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/freshservice\",\"icon\":\"\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"bad83517-5e54-4a3d-9b53-63e85fbd4d7c\",\"name\":\"ClickHouse\",\"dockerRepository\":\"airbyte/source-clickhouse\",\"dockerImageTag\":\"0.1.14\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/clickhouse\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"eff3616a-f9c3-11eb-9a03-0242ac130003\",\"name\":\"Google - Analytics (Universal Analytics)\",\"dockerRepository\":\"airbyte/source-google-analytics-v4\",\"dockerImageTag\":\"0.1.30\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/google-analytics-universal-analytics\",\"icon\":\"\\n\\n\\n\\n\\t\\n\\t\\t\\n\\t\\n\\t\\n\\t\\t\\n\\t\\n\\t\\n\\t\\t\\n\\t\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"3981c999-bd7d-4afc-849b-e53dea90c948\",\"name\":\"Lever - Hiring\",\"dockerRepository\":\"airbyte/source-lever-hiring\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/lever-hiring\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"a827c52e-791c-4135-a245-e233c5255199\",\"name\":\"SFTP\",\"dockerRepository\":\"airbyte/source-sftp\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/sftp\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"file\"},{\"sourceDefinitionId\":\"1d4fdb25-64fc-4569-92da-fcdca79a8372\",\"name\":\"Okta\",\"dockerRepository\":\"airbyte/source-okta\",\"dockerImageTag\":\"0.1.13\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/okta\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"547dc08e-ab51-421d-953b-8f3745201a8c\",\"name\":\"Kyriba\",\"dockerRepository\":\"airbyte/source-kyriba\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/kyriba\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"79c1aa37-dae3-42ae-b333-d1c105477715\",\"name\":\"Zendesk - Support\",\"dockerRepository\":\"airbyte/source-zendesk-support\",\"dockerImageTag\":\"0.2.16\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/zendesk-support\",\"icon\":\"\\nimage/svg+xml\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"ef69ef6e-aa7f-4af1-a01d-ef775033524e\",\"name\":\"GitHub\",\"dockerRepository\":\"airbyte/source-github\",\"dockerImageTag\":\"0.3.6\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/github\",\"icon\":\"\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"e55879a8-0ef8-4557-abcf-ab34c53ec460\",\"name\":\"Amazon - Seller Partner\",\"dockerRepository\":\"airbyte/source-amazon-seller-partner\",\"dockerImageTag\":\"0.2.27\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/amazon-seller-partner\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"722ba4bf-06ec-45a4-8dd5-72e4a5cf3903\",\"name\":\"My - Hours\",\"dockerRepository\":\"airbyte/source-my-hours\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/my-hours\",\"icon\":\"\\n\\n - \ \\n \\n \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"2af123bf-0aaf-4e0d-9784-cb497f23741a\",\"name\":\"Appstore\",\"dockerRepository\":\"airbyte/source-appstore-singer\",\"dockerImageTag\":\"0.2.6\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/appstore\",\"icon\":\"\\n\\n - \ \\n \\n \\n \\n - \ \\n \\n\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d53f9084-fa6b-4a5a-976c-5b8392f4ad8a\",\"name\":\"E2E - Testing\",\"dockerRepository\":\"airbyte/source-e2e-test\",\"dockerImageTag\":\"2.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/e2e-test\",\"icon\":\"\\n \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"9fa5862c-da7c-11eb-8d19-0242ac130003\",\"name\":\"Cockroachdb\",\"dockerRepository\":\"airbyte/source-cockroachdb\",\"dockerImageTag\":\"0.1.18\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/cockroachdb\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"253487c0-2246-43ba-a21f-5116b20a2c50\",\"name\":\"Google - Ads\",\"dockerRepository\":\"airbyte/source-google-ads\",\"dockerImageTag\":\"0.2.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/google-ads\",\"icon\":\"\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"6ff047c0-f5d5-4ce5-8c81-204a830fa7e1\",\"name\":\"AWS - CloudTrail\",\"dockerRepository\":\"airbyte/source-aws-cloudtrail\",\"dockerImageTag\":\"0.1.4\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/aws-cloudtrail\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"68e63de2-bb83-4c7e-93fa-a8a9051e3993\",\"name\":\"Jira\",\"dockerRepository\":\"airbyte/source-jira\",\"dockerImageTag\":\"0.2.21\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/jira\",\"icon\":\"\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"36c891d9-4bd9-43ac-bad2-10e12756272c\",\"name\":\"HubSpot\",\"dockerRepository\":\"airbyte/source-hubspot\",\"dockerImageTag\":\"0.2.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/hubspot\",\"icon\":\"\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"e7eff203-90bf-43e5-a240-19ea3056c474\",\"name\":\"Typeform\",\"dockerRepository\":\"airbyte/source-typeform\",\"dockerImageTag\":\"0.1.9\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/typeform\",\"icon\":\"\\n - \ \\n \\n \\n - \ \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d19ae824-e289-4b14-995a-0632eb46d246\",\"name\":\"Google - Directory\",\"dockerRepository\":\"airbyte/source-google-directory\",\"dockerImageTag\":\"0.1.9\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/google-directory\",\"icon\":\"\\n\\n\\n\\n - \ \\n\\n\\n \\n\\n\\n - \ \\n\\n\\n\\n \\n\\n\\n - \ \\n\\n\\n - \ \\n\\n\\n\\n \\n\\n\\n - \ \\n\\n\\n - \ \\n\\n\\n\\n \\n\\n\\n - \ \\n\\n\\n \\n\\n\\n\\n \\n\\n\\n \\n\\n\\n \\n\\n\\n\\n \\n\\n\\n - \ \\n\\n\\n \\n\\n\\n\\n \\n\\n\\n - \ \\n\\n\\n \\n\\n\\n\\n \\n\\n\\n - \ \\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"010eb12f-837b-4685-892d-0a39f76a98f5\",\"name\":\"Facebook - Pages\",\"dockerRepository\":\"airbyte/source-facebook-pages\",\"dockerImageTag\":\"0.1.6\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/facebook-pages\",\"icon\":\"\\nimage/svg+xml\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"b5ea17b1-f170-46dc-bc31-cc744ca984c1\",\"name\":\"Microsoft - SQL Server (MSSQL)\",\"dockerRepository\":\"airbyte/source-mssql\",\"dockerImageTag\":\"0.4.20\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/mssql\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"badc5925-0485-42be-8caa-b34096cb71b5\",\"name\":\"SurveyMonkey\",\"dockerRepository\":\"airbyte/source-surveymonkey\",\"dockerImageTag\":\"0.1.11\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/surveymonkey\",\"icon\":\"Horizontal_Sabaeus_RGB\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"3825db3e-c94b-42ac-bd53-b5a9507ace2b\",\"name\":\"Fauna\",\"dockerRepository\":\"airbyte/source-fauna\",\"dockerImageTag\":\"dev\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/fauna\",\"icon\":\"\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"bb1a6d31-6879-4819-a2bd-3eed299ea8e2\",\"name\":\"Cart.com\",\"dockerRepository\":\"airbyte/source-cart\",\"dockerImageTag\":\"0.2.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/cart\",\"icon\":\"\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\t\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"f1e4c7f6-db5c-4035-981f-d35ab4998794\",\"name\":\"Zenloop\",\"dockerRepository\":\"airbyte/source-zenloop\",\"dockerImageTag\":\"0.1.3\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/zenloop\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"b2e713cd-cc36-4c0a-b5bd-b47cb8a0561e\",\"name\":\"MongoDb\",\"dockerRepository\":\"airbyte/source-mongodb-v2\",\"dockerImageTag\":\"0.1.19\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/mongodb-v2\",\"icon\":\"\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"f00d2cf4-3c28-499a-ba93-b50b6f26359e\",\"name\":\"TalkDesk - Explore\",\"dockerRepository\":\"airbyte/source-talkdesk-explore\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/talkdesk-explore\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"5cb7e5fe-38c2-11ec-8d3d-0242ac130003\",\"name\":\"Pinterest\",\"dockerRepository\":\"airbyte/source-pinterest\",\"dockerImageTag\":\"0.1.7\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/pinterest\",\"icon\":\"\\nimage/svg+xml\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d1aa448b-7c54-498e-ad95-263cbebcd2db\",\"name\":\"Tempo\",\"dockerRepository\":\"airbyte/source-tempo\",\"dockerImageTag\":\"0.2.6\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/tempo\",\"icon\":\"\\n\\n\\n \\n \\n \\n \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"b6604cbd-1b12-4c08-8767-e140d0fb0877\",\"name\":\"Chartmogul\",\"dockerRepository\":\"airbyte/source-chartmogul\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/chartmogul\",\"icon\":\"\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"0b5c867e-1b12-4d02-ab74-97b2184ff6d7\",\"name\":\"Dixa\",\"dockerRepository\":\"airbyte/source-dixa\",\"dockerImageTag\":\"0.1.3\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/dixa\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"bb6afd81-87d5-47e3-97c4-e2c2901b1cf8\",\"name\":\"OneSignal\",\"dockerRepository\":\"airbyte/source-onesignal\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/onesignal\",\"icon\":\"\\n\\n \\n \\n - \ \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"5b9cb09e-1003-4f9c-983d-5779d1b2cd51\",\"name\":\"Mailgun\",\"dockerRepository\":\"airbyte/source-mailgun\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/mailgun\",\"icon\":\"\\n - \ \\n \\n - \ \\n \\n \\n \\n \\n \\n - \ \\n \\n \\n \\n \\n \\n \\n - \ \\n - \ \\n \\n \\n - \ \\n - \ \\n \\n \\n \\n - \ \\n \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"b4375641-e270-41d3-9c20-4f9cecad87a8\",\"name\":\"Appfollow\",\"dockerRepository\":\"airbyte/source-appfollow\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/appfollow\",\"icon\":\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d60a46d4-709f-4092-a6b7-2457f7d455f5\",\"name\":\"Prestashop\",\"dockerRepository\":\"airbyte/source-prestashop\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/prestashop\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"8a5d48f6-03bb-4038-a942-a8d3f175cca3\",\"name\":\"Freshcaller\",\"dockerRepository\":\"airbyte/source-freshcaller\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/freshcaller\",\"protocolVersion\":\"0.2.0\"},{\"sourceDefinitionId\":\"45d2e135-2ede-49e1-939f-3e3ec357a65e\",\"name\":\"Recharge\",\"dockerRepository\":\"airbyte/source-recharge\",\"dockerImageTag\":\"0.2.4\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/recharge\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"325e0640-e7b3-4e24-b823-3361008f603f\",\"name\":\"Zendesk - Sunshine\",\"dockerRepository\":\"airbyte/source-zendesk-sunshine\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/zendesk-sunshine\",\"icon\":\"\\nimage/svg+xml\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"40d24d0f-b8f9-4fe0-9e6c-b06c0f3f45e4\",\"name\":\"Zendesk - Chat\",\"dockerRepository\":\"airbyte/source-zendesk-chat\",\"dockerImageTag\":\"0.1.10\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/zendesk-chat\",\"icon\":\"\\nimage/svg+xml\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"72d405a3-56d8-499f-a571-667c03406e43\",\"name\":\"Dockerhub\",\"dockerRepository\":\"airbyte/source-dockerhub\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/dockerhub\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"80a54ea2-9959-4040-aac1-eee42423ec9b\",\"name\":\"Monday\",\"dockerRepository\":\"airbyte/source-monday\",\"dockerImageTag\":\"0.1.4\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/monday\",\"icon\":\"\\n\\n - \ \\n \\n \\n image/svg+xml\\n - \ \\n \\n \\n \\n \\n \\n Logo / monday.com\\n \\n - \ \\n \\n \\n \\n \\n \\n \\n \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"fa9f58c6-2d03-4237-aaa4-07d75e0c1396\",\"name\":\"Amplitude\",\"dockerRepository\":\"airbyte/source-amplitude\",\"dockerImageTag\":\"0.1.16\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/amplitude\",\"icon\":\"\\n\\t\\n\\t\\n\\t\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"789f8e7a-2d28-11ec-8d3d-0242ac130003\",\"name\":\"Lemlist\",\"dockerRepository\":\"airbyte/source-lemlist\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/lemlist\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"41991d12-d4b5-439e-afd0-260a31d4c53f\",\"name\":\"SalesLoft\",\"dockerRepository\":\"airbyte/source-salesloft\",\"dockerImageTag\":\"0.1.3\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/salesloft\",\"icon\":\"\\n\\n - \ \\n \\n \\n image/svg+xml\\n - \ \\n \\n \\n \\n - \ \\n \\n \\n - \ \\n \\n \\n \\n \\n \\n \\n \\n - \ \\n \\n \\n - \ \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d8286229-c680-4063-8c59-23b9b391c700\",\"name\":\"Pipedrive\",\"dockerRepository\":\"airbyte/source-pipedrive\",\"dockerImageTag\":\"0.1.13\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/pipedrive\",\"icon\":\"\\n\\n\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"6fe89830-d04d-401b-aad6-6552ffa5c4af\",\"name\":\"Harness\",\"dockerRepository\":\"farosai/airbyte-harness-source\",\"dockerImageTag\":\"0.1.23\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/harness\",\"icon\":\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"4f2f093d-ce44-4121-8118-9d13b7bfccd0\",\"name\":\"Netsuite\",\"dockerRepository\":\"airbyte/source-netsuite\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/netsuite\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"c6b0a29e-1da9-4512-9002-7bfd0cba2246\",\"name\":\"Amazon - Ads\",\"dockerRepository\":\"airbyte/source-amazon-ads\",\"dockerImageTag\":\"0.1.22\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/amazon-ads\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"b9dc6155-672e-42ea-b10d-9f1f1fb95ab1\",\"name\":\"Twilio\",\"dockerRepository\":\"airbyte/source-twilio\",\"dockerImageTag\":\"0.1.12\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/twilio\",\"icon\":\"\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"3052c77e-8b91-47e2-97a0-a29a22794b4b\",\"name\":\"PersistIq\",\"dockerRepository\":\"airbyte/source-persistiq\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/persistiq\",\"icon\":\"\\n - \ \\n \\n \\n \\n \\n \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"200330b2-ea62-4d11-ac6d-cfe3e3f8ab2b\",\"name\":\"Snapchat - Marketing\",\"dockerRepository\":\"airbyte/source-snapchat-marketing\",\"dockerImageTag\":\"0.1.8\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/snapchat-marketing\",\"icon\":\"\\n\\n\\n\\n - \ \\n \\n \\n - \ \\n \\n image/svg+xml\\n - \ \\n \\n \\n \\n - \ \\n \\n - \ \\n - \ \\n - \ \\n \\n \\n \\n \\n \\n \\n - \ \\n\\t\\n\\t\\t\\n\\n\\t\\n\\n\\t\\n\\n\\n \\n \\n\\t.st0{fill:#FFFFFF;}\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"4bfac00d-ce15-44ff-95b9-9e3c3e8fbd35\",\"name\":\"TikTok - Marketing\",\"dockerRepository\":\"airbyte/source-tiktok-marketing\",\"dockerImageTag\":\"0.1.17\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/tiktok-marketing\",\"icon\":\"\\n\\n \\n \u7F16\u7EC4\\n - \ Created with Sketch.\\n \\n \\n - \ \\n \\n \\n - \ \\n \\n \\n - \ \\n - \ \\n \\n \\n \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d6f73702-d7a0-4e95-9758-b0fb1af0bfba\",\"name\":\"Jenkins\",\"dockerRepository\":\"farosai/airbyte-jenkins-source\",\"dockerImageTag\":\"0.1.23\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/jenkins\",\"icon\":\"\\n\\n\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\n\\t\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"8d7ef552-2c0f-11ec-8d3d-0242ac130003\",\"name\":\"SearchMetrics\",\"dockerRepository\":\"airbyte/source-search-metrics\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/search-metrics\",\"icon\":\"\\n\\n\\n\\nCreated by potrace 1.16, written by Peter Selinger - 2001-2019\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"983fd355-6bf3-4709-91b5-37afa391eeb6\",\"name\":\"Amazon - SQS\",\"dockerRepository\":\"airbyte/source-amazon-sqs\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/amazon-sqs\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"6acf6b55-4f1e-4fca-944e-1a3caef8aba8\",\"name\":\"Instagram\",\"dockerRepository\":\"airbyte/source-instagram\",\"dockerImageTag\":\"1.0.0\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/instagram\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"9e0556f4-69df-4522-a3fb-03264d36b348\",\"name\":\"Marketo\",\"dockerRepository\":\"airbyte/source-marketo\",\"dockerImageTag\":\"0.1.11\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/marketo\",\"icon\":\"\\nimage/svg+xml\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"c47d6804-8b98-449f-970a-5ddb5cb5d7aa\",\"name\":\"Customer.io\",\"dockerRepository\":\"farosai/airbyte-customer-io-source\",\"dockerImageTag\":\"0.1.23\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/customer-io\",\"icon\":\"Logo-Color-NEW\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"e2d65910-8c8b-40a1-ae7d-ee2416b2bfa2\",\"name\":\"Snowflake\",\"dockerRepository\":\"airbyte/source-snowflake\",\"dockerImageTag\":\"0.1.24\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/snowflake\",\"icon\":\"\\n\\n \\n Group\\n Created - with Sketch.\\n \\n \\n - \ \\n \\n \\n \\n - \ \\n \\n \\n - \ \\n - \ \\n - \ \\n - \ \\n \\n - \ \\n \\n \\n - \ \\n \\n \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"374ebc65-6636-4ea0-925c-7d35999a8ffc\",\"name\":\"Smartsheets\",\"dockerRepository\":\"airbyte/source-smartsheets\",\"dockerImageTag\":\"0.1.12\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/smartsheets\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"beta\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"95bcc041-1d1a-4c2e-8802-0ca5b1bfa36a\",\"name\":\"Orbit\",\"dockerRepository\":\"airbyte/source-orbit\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/orbit\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"ed9dfefa-1bbc-419d-8c5e-4d78f0ef6734\",\"name\":\"Google - Workspace Admin Reports\",\"dockerRepository\":\"airbyte/source-google-workspace-admin-reports\",\"dockerImageTag\":\"0.1.8\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/google-workspace-admin-reports\",\"icon\":\"\\n \\n \\n - \ \\n \\n - \ \\n \\n \\n - \ \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n - \ \\n \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"cf40a7f8-71f8-45ce-a7fa-fca053e4028c\",\"name\":\"Confluence\",\"dockerRepository\":\"airbyte/source-confluence\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/confluence\",\"icon\":\"\\n\\n - \ \\n \\n - \ \\n - \ \\n - \ \\n \\n - \ \\n - \ \\n - \ \\n \\n \\n\\t\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"47f17145-fe20-4ef5-a548-e29b048adf84\",\"name\":\"Apify - Dataset\",\"dockerRepository\":\"airbyte/source-apify-dataset\",\"dockerImageTag\":\"0.1.11\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/apify-dataset\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"3cc2eafd-84aa-4dca-93af-322d9dfeec1a\",\"name\":\"Google - Analytics 4 (GA4)\",\"dockerRepository\":\"airbyte/source-google-analytics-data-api\",\"dockerImageTag\":\"0.0.3\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/google-analytics-v4\",\"icon\":\"\\n\\n\\n\\n\\t\\n\\t\\t\\n\\t\\n\\t\\n\\t\\t\\n\\t\\n\\t\\n\\t\\t\\n\\t\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"3490c201-5d95-4783-b600-eaf07a4c7787\",\"name\":\"Outreach\",\"dockerRepository\":\"airbyte/source-outreach\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/outreach\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"f636c3c6-4077-45ac-b109-19fc62a283c1\",\"name\":\"Primetric\",\"dockerRepository\":\"airbyte/source-primetric\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/prestashop\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"7f0455fb-4518-4ec0-b7a3-d808bf8081cc\",\"name\":\"Orb\",\"dockerRepository\":\"airbyte/source-orb\",\"dockerImageTag\":\"0.1.4\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/orb\",\"icon\":\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"f95337f1-2ad1-4baf-922f-2ca9152de630\",\"name\":\"Flexport\",\"dockerRepository\":\"airbyte/source-flexport\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/flexport\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d60f5393-f99e-4310-8d05-b1876820f40e\",\"name\":\"Pivotal - Tracker\",\"dockerRepository\":\"airbyte/source-pivotal-tracker\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/pivotal-tracker\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"492b56d1-937c-462e-8076-21ad2031e784\",\"name\":\"Hellobaton\",\"dockerRepository\":\"airbyte/source-hellobaton\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/hellobaton\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"eca08d79-7b92-4065-b7f3-79c14836ebe7\",\"name\":\"Freshsales\",\"dockerRepository\":\"airbyte/source-freshsales\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/freshsales\",\"icon\":\"freshsales_logo_color\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"8097ceb9-383f-42f6-9f92-d3fd4bcc7689\",\"name\":\"Hubplanner\",\"dockerRepository\":\"airbyte/source-hubplanner\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/hubplanner\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"b08e4776-d1de-4e80-ab5c-1e51dad934a2\",\"name\":\"Qualaroo\",\"dockerRepository\":\"airbyte/source-qualaroo\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/qualaroo\",\"icon\":\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"decd338e-5647-4c0b-adf4-da0e75f5a750\",\"name\":\"Postgres\",\"dockerRepository\":\"airbyte/source-postgres\",\"dockerImageTag\":\"0.4.26\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/postgres\",\"icon\":\"\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\t\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"193bdcb8-1dd9-48d1-aade-91cadfd74f9b\",\"name\":\"Paystack\",\"dockerRepository\":\"airbyte/source-paystack\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/paystack\",\"icon\":\"\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"e87ffa8e-a3b5-f69c-9076-6011339de1f6\",\"name\":\"Redshift\",\"dockerRepository\":\"airbyte/source-redshift\",\"dockerImageTag\":\"0.3.14\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/redshift\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"447e0381-3780-4b46-bb62-00a4e3c8b8e2\",\"name\":\"IBM - Db2\",\"dockerRepository\":\"airbyte/source-db2\",\"dockerImageTag\":\"0.1.16\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/db2\",\"icon\":\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"ed799e2b-2158-4c66-8da4-b40fe63bc72a\",\"name\":\"Plaid\",\"dockerRepository\":\"airbyte/source-plaid\",\"dockerImageTag\":\"0.3.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/plaid\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"fbb5fbe2-16ad-4cf4-af7d-ff9d9c316c87\",\"name\":\"Sendgrid\",\"dockerRepository\":\"airbyte/source-sendgrid\",\"dockerImageTag\":\"0.2.14\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/sendgrid\",\"icon\":\"\\nimage/svg+xml\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"beta\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"29b409d9-30a5-4cc8-ad50-886eb846fea3\",\"name\":\"QuickBooks\",\"dockerRepository\":\"airbyte/source-quickbooks-singer\",\"dockerImageTag\":\"0.1.5\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/quickbooks-singer\",\"icon\":\" qb-logoCreated with Sketch. - \",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"b117307c-14b6-41aa-9422-947e34922962\",\"name\":\"Salesforce\",\"dockerRepository\":\"airbyte/source-salesforce\",\"dockerImageTag\":\"1.0.22\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/salesforce\",\"icon\":\"\\n\\n\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"b39a7370-74c3-45a6-ac3a-380d48520a83\",\"name\":\"Oracle - DB\",\"dockerRepository\":\"airbyte/source-oracle\",\"dockerImageTag\":\"0.3.21\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/oracle\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"afa734e4-3571-11ec-991a-1e0031268139\",\"name\":\"YouTube - Analytics\",\"dockerRepository\":\"airbyte/source-youtube-analytics\",\"dockerImageTag\":\"0.1.3\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/youtube-analytics\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"beta\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"71607ba1-c0ac-4799-8049-7f4b90dd50f7\",\"name\":\"Google - Sheets\",\"dockerRepository\":\"airbyte/source-google-sheets\",\"dockerImageTag\":\"0.2.20\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/google-sheets\",\"icon\":\"\\n\\n\\n\\n\\t\\n\\t\\n\\t\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"file\"},{\"sourceDefinitionId\":\"c8630570-086d-4a40-99ae-ea5b18673071\",\"name\":\"Zendesk - Talk\",\"dockerRepository\":\"airbyte/source-zendesk-talk\",\"dockerImageTag\":\"0.1.5\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/zendesk-talk\",\"icon\":\"\\nimage/svg+xml\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"ec4b9503-13cb-48ab-a4ab-6ade4be46567\",\"name\":\"Freshdesk\",\"dockerRepository\":\"airbyte/source-freshdesk\",\"dockerImageTag\":\"0.3.6\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/freshdesk\",\"icon\":\"\\nimage/svg+xml\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"dfd88b22-b603-4c3d-aad7-3701784586b1\",\"name\":\"Faker\",\"dockerRepository\":\"airbyte/source-faker\",\"dockerImageTag\":\"0.1.8\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/faker\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"00405b19-9768-4e0c-b1ae-9fc2ee2b2a8c\",\"name\":\"Looker\",\"dockerRepository\":\"airbyte/source-looker\",\"dockerImageTag\":\"0.2.7\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/looker\",\"icon\":\"\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"59c5501b-9f95-411e-9269-7143c939adbd\",\"name\":\"BigCommerce\",\"dockerRepository\":\"airbyte/source-bigcommerce\",\"dockerImageTag\":\"0.1.7\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/bigcommerce\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d0243522-dccf-4978-8ba0-37ed47a0bdbf\",\"name\":\"Asana\",\"dockerRepository\":\"airbyte/source-asana\",\"dockerImageTag\":\"0.1.4\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/asana\",\"icon\":\"\\n\\n - \ \\n \\n \\n \\n - \ \\n - \ \\n \\n \\n \\n - \ \\n \\n \\n - \ \\n - \ \\n - \ \\n - \ \\n \\n - \ \\n \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"beta\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"2fed2292-5586-480c-af92-9944e39fe12d\",\"name\":\"Short.io\",\"dockerRepository\":\"airbyte/source-shortio\",\"dockerImageTag\":\"0.1.3\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/shortio\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"8da67652-004c-11ec-9a03-0242ac130003\",\"name\":\"Trello\",\"dockerRepository\":\"airbyte/source-trello\",\"dockerImageTag\":\"0.1.6\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/trello\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d3b7fa46-111b-419a-998a-d7f046f6d66d\",\"name\":\"Adjust\",\"dockerRepository\":\"airbyte/source-adjust\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/adjust\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d913b0f2-cc51-4e55-a44c-8ba1697b9239\",\"name\":\"Paypal - Transaction\",\"dockerRepository\":\"airbyte/source-paypal-transaction\",\"dockerImageTag\":\"0.1.10\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/paypal-transaction\",\"icon\":\"\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"1356e1d9-977f-4057-ad4b-65f25329cf61\",\"name\":\"DV - 360\",\"dockerRepository\":\"airbyte/source-dv-360\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/dv-360\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"db04ecd1-42e7-4115-9cec-95812905c626\",\"name\":\"Retently\",\"dockerRepository\":\"airbyte/source-retently\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/retently\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"b03a9f3e-22a5-11eb-adc1-0242ac120002\",\"name\":\"Mailchimp\",\"dockerRepository\":\"airbyte/source-mailchimp\",\"dockerImageTag\":\"0.2.15\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/mailchimp\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"0dad1a35-ccf8-4d03-b73e-6788c00b13ae\",\"name\":\"TiDB\",\"dockerRepository\":\"airbyte/source-tidb\",\"dockerImageTag\":\"0.2.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/tidb\",\"icon\":\"\\n - \ \\n \\n - \ \\n \\n \\n \\n \\n - \ \\n \\n - \ \\n - \ \\n - \ \\n - \ \\n \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"ef580275-d9a9-48bb-af5e-db0f5855be04\",\"name\":\"Webflow\",\"dockerRepository\":\"airbyte/source-webflow\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/webflow\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"cf8ff320-6272-4faa-89e6-4402dc17e5d5\",\"name\":\"Glassfrog\",\"dockerRepository\":\"airbyte/source-glassfrog\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/glassfrog\",\"icon\":\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"e2b40e36-aa0e-4bed-b41b-bcea6fa348b1\",\"name\":\"Exchange - Rates Api\",\"dockerRepository\":\"airbyte/source-exchange-rates\",\"dockerImageTag\":\"1.2.6\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/exchangeratesapi\",\"icon\":\"\\n\\n \\n logo\\n - \ Created with Sketch.\\n \\n \\n - \ \\n \\n \\n \\n - \ \\n \\n \\n \\n \\n \\n - \ \\n \\n \\n \\n - \ \\n \\n \\n \\n - \ \\n \\n - \ \\n \\n \\n - \ \\n \\n \\n \\n - \ \\n \\n \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"cd06e646-31bf-4dc8-af48-cbc6530fcad3\",\"name\":\"Kustomer\",\"dockerRepository\":\"airbyte/source-kustomer-singer\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/kustomer\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"7e20ce3e-d820-4327-ad7a-88f3927fd97a\",\"name\":\"VictorOps\",\"dockerRepository\":\"farosai/airbyte-victorops-source\",\"dockerImageTag\":\"0.1.23\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/victorops\",\"icon\":\"\\n\\n\\t\\n\\t\\t\\n\\t\\t\\n\\t\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"445831eb-78db-4b1f-8f1f-0d96ad8739e2\",\"name\":\"Drift\",\"dockerRepository\":\"airbyte/source-drift\",\"dockerImageTag\":\"0.2.5\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/drift\",\"icon\":\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"8baba53d-2fe3-4e33-bc85-210d0eb62884\",\"name\":\"Zenefits\",\"dockerRepository\":\"airbyte/source-zenefits\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/zenefits\",\"icon\":\"\\n\\n\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"bfd1ddf8-ae8a-4620-b1d7-55597d2ba08c\",\"name\":\"BigQuery\",\"dockerRepository\":\"airbyte/source-bigquery\",\"dockerImageTag\":\"0.2.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/bigquery\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"7b86879e-26c5-4ef6-a5ce-2be5c7b46d1e\",\"name\":\"Linnworks\",\"dockerRepository\":\"airbyte/source-linnworks\",\"dockerImageTag\":\"0.1.5\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/linnworks\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"3dc3037c-5ce8-4661-adc2-f7a9e3c5ece5\",\"name\":\"Zuora\",\"dockerRepository\":\"airbyte/source-zuora\",\"dockerImageTag\":\"0.1.3\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/zuora\",\"icon\":\"\\n\\n\\nimage/svg+xml\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"686473f1-76d9-4994-9cc7-9b13da46147c\",\"name\":\"Chargebee\",\"dockerRepository\":\"airbyte/source-chargebee\",\"dockerImageTag\":\"0.1.15\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/chargebee\",\"icon\":\"\\n\\n - \ \\n \\n - \ \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"9c13f986-a13b-4988-b808-4705badf71c2\",\"name\":\"Wrike\",\"dockerRepository\":\"airbyte/source-wrike\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/wrike\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"2817b3f0-04e4-4c7a-9f32-7a5e8a83db95\",\"name\":\"PagerDuty\",\"dockerRepository\":\"farosai/airbyte-pagerduty-source\",\"dockerImageTag\":\"0.1.23\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/pagerduty\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"12928b32-bf0a-4f1e-964f-07e12e37153a\",\"name\":\"Mixpanel\",\"dockerRepository\":\"airbyte/source-mixpanel\",\"dockerImageTag\":\"0.1.28\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/mixpanel\",\"icon\":\"\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"bc617b5f-1b9e-4a2d-bebe-782fd454a771\",\"name\":\"Timely\",\"dockerRepository\":\"airbyte/source-timely\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/timely\",\"icon\":\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"af54297c-e8f8-4d63-a00d-a94695acc9d3\",\"name\":\"LinkedIn - Pages\",\"dockerRepository\":\"airbyte/source-linkedin-pages\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/linkedin-pages\",\"icon\":\"\\n\\n\\n - \ \\n \\n \\n - \ \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d8540a80-6120-485d-b7d6-272bca477d9b\",\"name\":\"OpenWeather\",\"dockerRepository\":\"airbyte/source-openweather\",\"dockerImageTag\":\"0.1.6\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/openweather\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"95e8cffd-b8c4-4039-968e-d32fb4a69bde\",\"name\":\"Klaviyo\",\"dockerRepository\":\"airbyte/source-klaviyo\",\"dockerImageTag\":\"0.1.10\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/klaviyo\",\"icon\":\"\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"7cf88806-25f5-4e1a-b422-b2fa9e1b0090\",\"name\":\"Elasticsearch\",\"dockerRepository\":\"airbyte/source-elasticsearch\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/elasticsearch\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"d78e5de0-aa44-4744-aa4f-74c818ccfe19\",\"name\":\"RKI - Covid\",\"dockerRepository\":\"airbyte/source-rki-covid\",\"dockerImageTag\":\"0.1.1\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/rki-covid\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"798ae795-5189-42b6-b64e-3cb91db93338\",\"name\":\"Azure - Table Storage\",\"dockerRepository\":\"airbyte/source-azure-table\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/azure-table\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"6f2ac653-8623-43c4-8950-19218c7caf3d\",\"name\":\"Firebolt\",\"dockerRepository\":\"airbyte/source-firebolt\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/firebolt\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"e7778cfc-e97c-4458-9ecb-b4f2bba8946c\",\"name\":\"Facebook - Marketing\",\"dockerRepository\":\"airbyte/source-facebook-marketing\",\"dockerImageTag\":\"0.2.68\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/facebook-marketing\",\"icon\":\"\\nimage/svg+xml\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"7a4327c4-315a-11ec-8d3d-0242ac130003\",\"name\":\"Strava\",\"dockerRepository\":\"airbyte/source-strava\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/strava\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"63cea06f-1c75-458d-88fe-ad48c7cb27fd\",\"name\":\"Braintree\",\"dockerRepository\":\"airbyte/source-braintree\",\"dockerImageTag\":\"0.1.3\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/braintree\",\"icon\":\"\\n\\n - \ \\n \\n - \ \\n \\n - \ \\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"2e875208-0c0b-4ee4-9e92-1cb3156ea799\",\"name\":\"Iterable\",\"dockerRepository\":\"airbyte/source-iterable\",\"dockerImageTag\":\"0.1.19\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/iterable\",\"icon\":\"\\r\\n\\r\\n\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\t\\t\\r\\n\\t\\r\\n\\t\\t\\r\\n\\r\\n\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\t\\r\\n\\r\\n\\r\\n\\r\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"dfffecb7-9a13-43e9-acdc-b92af7997ca9\",\"name\":\"Close.com\",\"dockerRepository\":\"airbyte/source-close-com\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/close-com\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"4942d392-c7b5-4271-91f9-3b4f4e51eb3e\",\"name\":\"ZohoCRM\",\"dockerRepository\":\"airbyte/source-zoho-crm\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/zoho-crm\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"e094cb9a-26de-4645-8761-65c0c425d1de\",\"name\":\"Stripe\",\"dockerRepository\":\"airbyte/source-stripe\",\"dockerImageTag\":\"0.1.39\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/stripe\",\"icon\":\"Asset - 32Stone - Hub\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"69589781-7828-43c5-9f63-8925b1c1ccc2\",\"name\":\"S3\",\"dockerRepository\":\"airbyte/source-s3\",\"dockerImageTag\":\"0.1.23\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/s3\",\"icon\":\"\\n\\n Icon-Resource/Storage/Res_Amazon-Simple-Storage_Service-Standard_48_Light\\n - \ \\n - \ \\n \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"file\"},{\"sourceDefinitionId\":\"c7cb421b-942e-4468-99ee-e369bcabaec5\",\"name\":\"Metabase\",\"dockerRepository\":\"airbyte/source-metabase\",\"dockerImageTag\":\"0.1.0\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/metabase\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"eaf50f04-21dd-4620-913b-2a83f5635227\",\"name\":\"Microsoft - teams\",\"dockerRepository\":\"airbyte/source-microsoft-teams\",\"dockerImageTag\":\"0.2.5\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/microsoft-teams\",\"icon\":\"\\n\\n\\n\\t\\n\\t\\n\\t\\n\\t\\n\\t\\n\\t\\n\\t\\n]>\\n\\n\\n\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\t\\n\\t\\n\\t\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"5e6175e5-68e1-4c17-bff9-56103bbb0d80\",\"name\":\"Gitlab\",\"dockerRepository\":\"airbyte/source-gitlab\",\"dockerImageTag\":\"0.1.6\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/gitlab\",\"icon\":\"\\n\\n\\n\\n\\n\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\n\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\t\\n\\t\\t\\n\\t\\n\\n\\n\\t\\n\\t\\n\\t\\n\\t\\n\\tH: 2.5 x\\n\\t1/2 - x\\n\\t1x\\n\\t1x\\n\\t\\n\\t1x\\n\\t\\n\\t1x\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"aea2fd0d-377d-465e-86c0-4fdc4f688e51\",\"name\":\"Zoom\",\"dockerRepository\":\"airbyte/source-zoom-singer\",\"dockerImageTag\":\"0.2.4\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/zoom\",\"icon\":\"\\n\\n \\n \\n - \ \\n image/svg+xml\\n - \ \\n \\n \\n \\n - \ \\n \\n \\n \\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"435bb9a5-7887-4809-aa58-28c27df0d7ad\",\"name\":\"MySQL\",\"dockerRepository\":\"airbyte/source-mysql\",\"dockerImageTag\":\"1.0.4\",\"documentationUrl\":\"https://docs.airbyte.com/integrations/sources/mysql\",\"icon\":\"\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"beta\",\"sourceType\":\"database\"},{\"sourceDefinitionId\":\"6371b14b-bc68-4236-bfbd-468e8df8e968\",\"name\":\"PokeAPI\",\"dockerRepository\":\"airbyte/source-pokeapi\",\"dockerImageTag\":\"0.1.5\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/pokeapi\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"cdaf146a-9b75-49fd-9dd2-9d64a0bb4781\",\"name\":\"Sentry\",\"dockerRepository\":\"airbyte/source-sentry\",\"dockerImageTag\":\"0.1.7\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/sentry\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"c2281cee-86f9-4a86-bb48-d23286b4c7bd\",\"name\":\"Slack\",\"dockerRepository\":\"airbyte/source-slack\",\"dockerImageTag\":\"0.1.18\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/slack\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"778daa7c-feaf-4db6-96f3-70fd645acc77\",\"name\":\"File\",\"dockerRepository\":\"airbyte/source-file\",\"dockerImageTag\":\"0.2.24\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/file\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"beta\",\"sourceType\":\"file\"},{\"sourceDefinitionId\":\"77225a51-cd15-4a13-af02-65816bd0ecf4\",\"name\":\"Square\",\"dockerRepository\":\"airbyte/source-square\",\"dockerImageTag\":\"0.1.4\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/square\",\"icon\":\"\\n\\n\\n\\n\\n\\n\\n\\n\\n\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"14c6e7ea-97ed-4f5e-a7b5-25e9a80b8212\",\"name\":\"Airtable\",\"dockerRepository\":\"airbyte/source-airtable\",\"dockerImageTag\":\"0.1.2\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/airtable\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"af6d50ee-dddf-4126-a8ee-7faee990774f\",\"name\":\"PostHog\",\"dockerRepository\":\"airbyte/source-posthog\",\"dockerImageTag\":\"0.1.7\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/posthog\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"alpha\",\"sourceType\":\"api\"},{\"sourceDefinitionId\":\"59f1e50a-331f-4f09-b3e8-2e8d4d355f44\",\"name\":\"Greenhouse\",\"dockerRepository\":\"airbyte/source-greenhouse\",\"dockerImageTag\":\"0.2.11\",\"documentationUrl\":\"https://docs.airbyte.io/integrations/sources/greenhouse\",\"icon\":\"\",\"protocolVersion\":\"0.2.0\",\"releaseStage\":\"generally_available\",\"sourceType\":\"api\"}]}" - headers: - Access-Control-Allow-Headers: - - Origin, Content-Type, Accept, Content-Encoding - Access-Control-Allow-Methods: - - GET, POST, PUT, DELETE, OPTIONS, HEAD - Access-Control-Allow-Origin: - - "*" - Connection: - - keep-alive - Content-Security-Policy: - - script-src * 'unsafe-inline'; worker-src self blob:; - Content-Type: - - application/json - Date: - - Fri, 14 Oct 2022 18:12:50 GMT - Server: - - nginx/1.23.1 - Transfer-Encoding: - - chunked - status: - code: 200 - message: OK -version: 1 diff --git a/octavia-cli/integration_tests/configurations/.gitignore b/octavia-cli/integration_tests/configurations/.gitignore deleted file mode 100644 index e40706226713..000000000000 --- a/octavia-cli/integration_tests/configurations/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -**/state_*.yaml -**/updated_*.yaml diff --git a/octavia-cli/integration_tests/configurations/connections/poke_to_pg/configuration.yaml b/octavia-cli/integration_tests/configurations/connections/poke_to_pg/configuration.yaml deleted file mode 100644 index 6240fadd1047..000000000000 --- a/octavia-cli/integration_tests/configurations/connections/poke_to_pg/configuration.yaml +++ /dev/null @@ -1,362 +0,0 @@ -# Configuration for connection poke_to_pg -definition_type: connection -resource_name: poke_to_pg -source_configuration_path: TO_UPDATE_FROM_TEST -destination_configuration_path: TO_UPDATE_FROM_TEST - -# EDIT THE CONFIGURATION BELOW! -configuration: - status: active # REQUIRED | string | Allowed values: active, inactive, deprecated - skip_reset: false # OPTIONAL | boolean | Flag to check if the connection should be reset after a connection update - namespace_definition: source # OPTIONAL | string | Allowed values: source, destination, customformat - namespace_format: "${SOURCE_NAMESPACE}" # OPTIONAL | string | Used when namespaceDefinition is 'customformat'. If blank then behaves like namespaceDefinition = 'destination'. If "${SOURCE_NAMESPACE}" then behaves like namespaceDefinition = 'source'. - prefix: "" # REQUIRED | Prefix that will be prepended to the name of each stream when it is written to the destination - resource_requirements: # OPTIONAL | object | Resource requirements to run workers (blank for unbounded allocations) - cpu_limit: "" # OPTIONAL - cpu_request: "" # OPTIONAL - memory_limit: "" # OPTIONAL - memory_request: "" # OPTIONAL - schedule_type: basic - schedule_data: - basic_schedule: - time_unit: hours # REQUIRED | string | Allowed values: minutes, hours, days, weeks, months - units: 1 # REQUIRED | integer - sync_catalog: # OPTIONAL | object | 🚨 ONLY edit streams.config, streams.stream should not be edited as schema cannot be changed. - streams: - - config: - alias_name: pokemon - cursor_field: [] - destination_sync_mode: append - primary_key: [] - selected: true - sync_mode: full_refresh - stream: - default_cursor_field: [] - json_schema: - $schema: http://json-schema.org/draft-07/schema# - properties: - abilities: - items: - properties: - ability: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - is_hidden: - type: - - "null" - - boolean - slot: - type: - - "null" - - integer - type: - - "null" - - object - type: - - "null" - - array - base_experience: - type: - - "null" - - integer - forms: - items: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - array - game_indices: - items: - properties: - game_index: - type: - - "null" - - integer - version: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - height: - type: - - "null" - - integer - held_items: - items: - properties: - item: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - version_details: - items: - properties: - rarity: - type: - - "null" - - integer - version: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - type: - - "null" - - object - type: - - "null" - - array - id: - type: - - "null" - - integer - "is_default ": - type: - - "null" - - boolean - location_area_encounters: - type: - - "null" - - string - moves: - items: - properties: - move: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - version_group_details: - items: - properties: - level_learned_at: - type: - - "null" - - integer - move_learn_method: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - version_group: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - type: - - "null" - - object - type: - - "null" - - array - name: - type: - - "null" - - string - order: - type: - - "null" - - integer - species: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - sprites: - properties: - back_default: - type: - - "null" - - string - back_female: - type: - - "null" - - string - back_shiny: - type: - - "null" - - string - back_shiny_female: - type: - - "null" - - string - front_default: - type: - - "null" - - string - front_female: - type: - - "null" - - string - front_shiny: - type: - - "null" - - string - front_shiny_female: - type: - - "null" - - string - type: - - "null" - - object - stats: - items: - properties: - base_stat: - type: - - "null" - - integer - effort: - type: - - "null" - - integer - stat: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - types: - items: - properties: - slot: - type: - - "null" - - integer - type: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - weight: - type: - - "null" - - integer - type: object - name: pokemon - source_defined_primary_key: [] - supported_sync_modes: - - full_refresh diff --git a/octavia-cli/integration_tests/configurations/connections/poke_to_pg_normalization/configuration.yaml b/octavia-cli/integration_tests/configurations/connections/poke_to_pg_normalization/configuration.yaml deleted file mode 100644 index a5225215f9db..000000000000 --- a/octavia-cli/integration_tests/configurations/connections/poke_to_pg_normalization/configuration.yaml +++ /dev/null @@ -1,367 +0,0 @@ -# Configuration for connection poke_to_pg -definition_type: connection -resource_name: poke_to_pg -source_configuration_path: TO_UPDATE_FROM_TEST -destination_configuration_path: TO_UPDATE_FROM_TEST - -# EDIT THE CONFIGURATION BELOW! -configuration: - status: active # REQUIRED | string | Allowed values: active, inactive, deprecated - namespace_definition: source # OPTIONAL | string | Allowed values: source, destination, customformat - namespace_format: "${SOURCE_NAMESPACE}" # OPTIONAL | string | Used when namespaceDefinition is 'customformat'. If blank then behaves like namespaceDefinition = 'destination'. If "${SOURCE_NAMESPACE}" then behaves like namespaceDefinition = 'source'. - prefix: "" # REQUIRED | Prefix that will be prepended to the name of each stream when it is written to the destination - resource_requirements: # OPTIONAL | object | Resource requirements to run workers (blank for unbounded allocations) - cpu_limit: "" # OPTIONAL - cpu_request: "" # OPTIONAL - memory_limit: "" # OPTIONAL - memory_request: "" # OPTIONAL - schedule_type: basic - schedule_data: - basic_schedule: - time_unit: hours # REQUIRED | string | Allowed values: minutes, hours, days, weeks, months - units: 1 # REQUIRED | integer - operations: - - name: "Normalization" - operator_configuration: - normalization: - option: "basic" - operator_type: "normalization" - sync_catalog: # OPTIONAL | object | 🚨 ONLY edit streams.config, streams.stream should not be edited as schema cannot be changed. - streams: - - config: - alias_name: pokemon - cursor_field: [] - destination_sync_mode: append - primary_key: [] - selected: true - sync_mode: full_refresh - stream: - default_cursor_field: [] - json_schema: - $schema: http://json-schema.org/draft-07/schema# - properties: - abilities: - items: - properties: - ability: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - is_hidden: - type: - - "null" - - boolean - slot: - type: - - "null" - - integer - type: - - "null" - - object - type: - - "null" - - array - base_experience: - type: - - "null" - - integer - forms: - items: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - array - game_indices: - items: - properties: - game_index: - type: - - "null" - - integer - version: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - height: - type: - - "null" - - integer - held_items: - items: - properties: - item: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - version_details: - items: - properties: - rarity: - type: - - "null" - - integer - version: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - type: - - "null" - - object - type: - - "null" - - array - id: - type: - - "null" - - integer - "is_default ": - type: - - "null" - - boolean - location_area_encounters: - type: - - "null" - - string - moves: - items: - properties: - move: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - version_group_details: - items: - properties: - level_learned_at: - type: - - "null" - - integer - move_learn_method: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - version_group: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - type: - - "null" - - object - type: - - "null" - - array - name: - type: - - "null" - - string - order: - type: - - "null" - - integer - species: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - sprites: - properties: - back_default: - type: - - "null" - - string - back_female: - type: - - "null" - - string - back_shiny: - type: - - "null" - - string - back_shiny_female: - type: - - "null" - - string - front_default: - type: - - "null" - - string - front_female: - type: - - "null" - - string - front_shiny: - type: - - "null" - - string - front_shiny_female: - type: - - "null" - - string - type: - - "null" - - object - stats: - items: - properties: - base_stat: - type: - - "null" - - integer - effort: - type: - - "null" - - integer - stat: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - types: - items: - properties: - slot: - type: - - "null" - - integer - type: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - weight: - type: - - "null" - - integer - type: object - name: pokemon - source_defined_primary_key: [] - supported_sync_modes: - - full_refresh diff --git a/octavia-cli/integration_tests/configurations/destinations/postgres/configuration.yaml b/octavia-cli/integration_tests/configurations/destinations/postgres/configuration.yaml deleted file mode 100644 index e4fee2704c40..000000000000 --- a/octavia-cli/integration_tests/configurations/destinations/postgres/configuration.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# Configuration for airbyte/destination-postgres -# Documentation about this connector can be found at https://docs.airbyte.io/integrations/destinations/postgres -resource_name: postgres -definition_type: destination -definition_id: 25c5221d-dce2-4163-ade9-739ef790f503 -definition_image: airbyte/destination-postgres -definition_version: 0.3.15 - -# EDIT THE CONFIGURATION BELOW! -configuration: - ssl: False # OPTIONAL | boolean | Encrypt data using SSL. - host: localhost # REQUIRED | string | Hostname of the database. - port: 5433 # REQUIRED | integer | Port of the database. | Example: 5432 - schema: "public" # REQUIRED | string | The default schema tables are written to if the source does not specify a namespace. The usual value for this field is "public". | Example: public - database: postgres # REQUIRED | string | Name of the database. - password: ${POSTGRES_PASSWORD} # SECRET (please store in environment variables) | OPTIONAL | string | Password associated with the username. - username: postgres # REQUIRED | string | Username to use to access the database. - tunnel_method: - ## -------- Pick one valid structure among the examples below: -------- - tunnel_method: "NO_TUNNEL" # REQUIRED | string | No ssh tunnel needed to connect to database - ## -------- Another valid structure for tunnel_method: -------- - # ssh_key: ${SSH_KEY} # SECRET (please store in environment variables) | REQUIRED | string | OS-level user account ssh key credentials in RSA PEM format ( created with ssh-keygen -t rsa -m PEM -f myuser_rsa ) - # tunnel_host: # REQUIRED | string | Hostname of the jump server host that allows inbound ssh tunnel. - # tunnel_port: 22 # REQUIRED | integer | Port on the proxy/jump server that accepts inbound ssh connections. | Example: 22 - # tunnel_user: # REQUIRED | string | OS-level username for logging into the jump server host. - # tunnel_method: "SSH_KEY_AUTH" # REQUIRED | string | Connect through a jump server tunnel host using username and ssh key - ## -------- Another valid structure for tunnel_method: -------- - # tunnel_host: # REQUIRED | string | Hostname of the jump server host that allows inbound ssh tunnel. - # tunnel_port: 22 # REQUIRED | integer | Port on the proxy/jump server that accepts inbound ssh connections. | Example: 22 - # tunnel_user: # REQUIRED | string | OS-level username for logging into the jump server host - # tunnel_method: "SSH_PASSWORD_AUTH" # REQUIRED | string | Connect through a jump server tunnel host using username and password authentication - # tunnel_user_password: ${TUNNEL_USER_PASSWORD} # SECRET (please store in environment variables) | REQUIRED | string | OS-level password for logging into the jump server host diff --git a/octavia-cli/integration_tests/configurations/sources/poke/configuration.yaml b/octavia-cli/integration_tests/configurations/sources/poke/configuration.yaml deleted file mode 100644 index 89982f4196bb..000000000000 --- a/octavia-cli/integration_tests/configurations/sources/poke/configuration.yaml +++ /dev/null @@ -1,9 +0,0 @@ -resource_name: poke -definition_type: source -definition_id: 6371b14b-bc68-4236-bfbd-468e8df8e968 -definition_image: airbyte/source-pokeapi -definition_version: 0.1.4 - -# EDIT THE CONFIGURATION BELOW! -configuration: - pokemon_name: ditto diff --git a/octavia-cli/integration_tests/conftest.py b/octavia-cli/integration_tests/conftest.py deleted file mode 100644 index fd1d6d5b8006..000000000000 --- a/octavia-cli/integration_tests/conftest.py +++ /dev/null @@ -1,155 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import os - -import pytest -import yaml -from airbyte_api_client.api import connection_api -from airbyte_api_client.model.connection_id_request_body import ConnectionIdRequestBody -from octavia_cli.apply.resources import Connection, Destination, Source -from octavia_cli.entrypoint import get_api_client, get_workspace_id -from octavia_cli.init.commands import DIRECTORIES_TO_CREATE as OCTAVIA_PROJECT_DIRECTORIES - - -def silent_remove(path): - try: - os.remove(path) - return True - except FileNotFoundError: - return False - - -@pytest.fixture -def octavia_tmp_project_directory(tmpdir): - for directory in OCTAVIA_PROJECT_DIRECTORIES: - tmpdir.mkdir(directory) - return tmpdir - - -@pytest.fixture(scope="session") -def octavia_test_project_directory(): - return f"{os.path.dirname(__file__)}/configurations" - - -@pytest.fixture(scope="session") -def api_client(): - return get_api_client("http://localhost:8000", "airbyte", "password", "octavia-cli/integration-tests", None) - - -@pytest.fixture(scope="session") -def workspace_id(api_client): - return get_workspace_id(api_client, None) - - -def open_yaml_configuration(path: str): - with open(path, "r") as f: - local_configuration = yaml.safe_load(f) - return local_configuration, path - - -@pytest.fixture(scope="session") -def source_configuration_and_path(octavia_test_project_directory): - path = f"{octavia_test_project_directory}/sources/poke/configuration.yaml" - return open_yaml_configuration(path) - - -@pytest.fixture(scope="session") -def source_state_path(octavia_test_project_directory, workspace_id): - state_path = f"{octavia_test_project_directory}/sources/poke/state_{workspace_id}.yaml" - silent_remove(state_path) - yield state_path - silent_remove(state_path) - - -@pytest.fixture(scope="session") -def source(api_client, workspace_id, source_configuration_and_path, source_state_path): - configuration, path = source_configuration_and_path - source = Source(api_client, workspace_id, configuration, path) - yield source - source.api_instance.delete_source(source.get_payload) - - -@pytest.fixture(scope="session") -def destination_configuration_and_path(octavia_test_project_directory): - path = f"{octavia_test_project_directory}/destinations/postgres/configuration.yaml" - return open_yaml_configuration(path) - - -@pytest.fixture(scope="session") -def destination_state_path(octavia_test_project_directory, workspace_id): - state_path = f"{octavia_test_project_directory}/destinations/postgres/state_{workspace_id}.yaml" - silent_remove(state_path) - yield state_path - silent_remove(state_path) - - -@pytest.fixture(scope="session") -def destination(api_client, workspace_id, destination_configuration_and_path, destination_state_path): - configuration, path = destination_configuration_and_path - destination = Destination(api_client, workspace_id, configuration, path) - yield destination - destination.api_instance.delete_destination(destination.get_payload) - - -@pytest.fixture(scope="session") -def connection_configuration_and_path(octavia_test_project_directory): - path = f"{octavia_test_project_directory}/connections/poke_to_pg/configuration.yaml" - with open(path, "r") as f: - local_configuration = yaml.safe_load(f) - return local_configuration, path - - -@pytest.fixture(scope="session") -def connection_state_path(octavia_test_project_directory, workspace_id): - state_path = f"{octavia_test_project_directory}/connections/poke_to_pg/state_{workspace_id}.yaml" - silent_remove(state_path) - yield state_path - silent_remove(state_path) - - -@pytest.fixture(scope="session") -def connection_with_normalization_state_path(octavia_test_project_directory, workspace_id): - state_path = f"{octavia_test_project_directory}/connections/poke_to_pg_normalization/state_{workspace_id}.yaml" - silent_remove(state_path) - yield state_path - silent_remove(state_path) - - -def updated_connection_configuration_and_path(octavia_test_project_directory, source, destination, with_normalization=False): - if with_normalization: - path = f"{octavia_test_project_directory}/connections/poke_to_pg_normalization/configuration.yaml" - edited_path = f"{octavia_test_project_directory}/connections/poke_to_pg_normalization/updated_configuration.yaml" - else: - path = f"{octavia_test_project_directory}/connections/poke_to_pg/configuration.yaml" - edited_path = f"{octavia_test_project_directory}/connections/poke_to_pg/updated_configuration.yaml" - with open(path, "r") as dumb_local_configuration_file: - local_configuration = yaml.safe_load(dumb_local_configuration_file) - local_configuration["source_configuration_path"] = source.configuration_path - local_configuration["destination_configuration_path"] = destination.configuration_path - with open(edited_path, "w") as updated_configuration_file: - yaml.dump(local_configuration, updated_configuration_file) - return local_configuration, edited_path - - -@pytest.fixture(scope="session") -def connection(api_client, workspace_id, octavia_test_project_directory, source, destination, connection_state_path): - configuration, configuration_path = updated_connection_configuration_and_path(octavia_test_project_directory, source, destination) - connection = Connection(api_client, workspace_id, configuration, configuration_path) - yield connection - connection_api.ConnectionApi(api_client).delete_connection(ConnectionIdRequestBody(connection.resource_id)) - silent_remove(configuration_path) - - -@pytest.fixture(scope="session") -def connection_with_normalization( - api_client, workspace_id, octavia_test_project_directory, source, destination, connection_with_normalization_state_path -): - configuration, configuration_path = updated_connection_configuration_and_path( - octavia_test_project_directory, source, destination, with_normalization=True - ) - connection = Connection(api_client, workspace_id, configuration, configuration_path) - yield connection - connection_api.ConnectionApi(api_client).delete_connection(ConnectionIdRequestBody(connection.resource_id)) - silent_remove(configuration_path) diff --git a/octavia-cli/integration_tests/docker-compose-proxy.yaml b/octavia-cli/integration_tests/docker-compose-proxy.yaml deleted file mode 100644 index 0647adfc502e..000000000000 --- a/octavia-cli/integration_tests/docker-compose-proxy.yaml +++ /dev/null @@ -1,19 +0,0 @@ -version: "3.7" -services: - nginx-proxy: - build: - context: ./octavia-cli/integration_tests - dockerfile: nginx_proxy/Dockerfile - ports: - - "8010:80" - depends_on: - - init - - bootloader - - db - - scheduler - - worker - - server - - webapp - - airbyte-temporal - volumes: - - "./octavia-cli/integration_tests/nginx_proxy/nginx.conf:/etc/nginx/nginx.conf" diff --git a/octavia-cli/integration_tests/test_api_http_headers.py b/octavia-cli/integration_tests/test_api_http_headers.py deleted file mode 100644 index 13ef739d3041..000000000000 --- a/octavia-cli/integration_tests/test_api_http_headers.py +++ /dev/null @@ -1,77 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import base64 -import logging - -import pytest -from click.testing import CliRunner -from octavia_cli import api_http_headers, entrypoint - -logging.basicConfig() # you need to initialize logging, otherwise you will not see anything from vcrpy -vcr_log = logging.getLogger("vcr") -vcr_log.setLevel(logging.WARN) - -AIRBYTE_URL = "http://localhost:8000" -AIRBYTE_USERNAME = "airbyte" -AIRBYTE_PASSWORD = "password" - - -@pytest.fixture(scope="module") -def vcr_config(): - return { - "record_mode": "rewrite", - "match_on": ["method", "scheme", "host", "port", "path", "query", "headers"], - } - - -@pytest.fixture -def file_based_headers(tmp_path): - yaml_document = """ - headers: - Custom-Header: Foo - """ - custom_api_http_headers_yaml_file_path = tmp_path / "custom_api_http_headers.yaml" - custom_api_http_headers_yaml_file_path.write_text(yaml_document) - expected_headers = [api_http_headers.ApiHttpHeader("Custom-Header", "Foo")] - return custom_api_http_headers_yaml_file_path, expected_headers - - -@pytest.fixture -def option_based_headers(): - return ["Another-Custom-Header", "Bar"], [api_http_headers.ApiHttpHeader("Another-Custom-Header", "Bar")] - - -@pytest.mark.vcr -def test_api_http_headers(vcr, file_based_headers, option_based_headers): - raw_option_based_headers, expected_option_based_headers = option_based_headers - custom_api_http_headers_yaml_file_path, expected_file_based_headers = file_based_headers - basic_auth_header_value = f"Basic {base64.b64encode(f'{AIRBYTE_USERNAME}:{AIRBYTE_PASSWORD}'.encode()).decode()}" - expected_headers = ( - expected_option_based_headers - + expected_file_based_headers - + [api_http_headers.ApiHttpHeader("Authorization", basic_auth_header_value)] - ) - runner = CliRunner() - command_options = ( - [ - "--airbyte-url", - AIRBYTE_URL, - "--airbyte-username", - AIRBYTE_USERNAME, - "--airbyte-password", - AIRBYTE_PASSWORD, - "--api-http-headers-file-path", - custom_api_http_headers_yaml_file_path, - "--api-http-header", - ] - + raw_option_based_headers - + ["list", "connectors", "sources"] - ) - - result = runner.invoke(entrypoint.octavia, command_options, obj={}) - for request in vcr.requests: - for expected_header in expected_headers: - assert request.headers[expected_header.name] == expected_header.value - assert result.exit_code == 0 diff --git a/octavia-cli/integration_tests/test_apply/test_resources.py b/octavia-cli/integration_tests/test_apply/test_resources.py deleted file mode 100644 index ed424d7108e8..000000000000 --- a/octavia-cli/integration_tests/test_apply/test_resources.py +++ /dev/null @@ -1,65 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - - -import pytest - -pytestmark = pytest.mark.integration - - -def test_source_lifecycle(source, workspace_id): - assert not source.was_created - source.create() - source.state = source._get_state_from_file(source.configuration_path, workspace_id) - assert source.was_created - assert not source.get_diff_with_remote_resource() - source.raw_configuration["configuration"]["pokemon_name"] = "snorlax" - source.configuration = source._deserialize_raw_configuration() - assert 'changed from "ditto" to "snorlax"' in source.get_diff_with_remote_resource() - source.update() - assert not source.get_diff_with_remote_resource() - assert source.catalog["streams"][0]["config"]["alias_name"] == "pokemon" - - -def test_destination_lifecycle(destination, workspace_id): - assert not destination.was_created - destination.create() - destination.state = destination._get_state_from_file(destination.configuration_path, workspace_id) - assert destination.was_created - assert not destination.get_diff_with_remote_resource() - destination.raw_configuration["configuration"]["host"] = "foo" - destination.configuration = destination._deserialize_raw_configuration() - assert 'changed from "localhost" to "foo"' in destination.get_diff_with_remote_resource() - destination.update() - assert not destination.get_diff_with_remote_resource() - - -def test_connection_lifecycle(source, destination, connection, workspace_id): - assert source.was_created - assert destination.was_created - assert not connection.was_created - connection.create() - connection.state = connection._get_state_from_file(connection.configuration_path, workspace_id) - assert connection.was_created - connection.raw_configuration["configuration"]["status"] = "inactive" - connection.configuration = connection._deserialize_raw_configuration() - assert 'changed from "active" to "inactive"' in connection.get_diff_with_remote_resource() - connection.update() - - -def test_connection_lifecycle_with_normalization(source, destination, connection_with_normalization, workspace_id): - assert source.was_created - assert destination.was_created - assert not connection_with_normalization.was_created - connection_with_normalization.create() - connection_with_normalization.state = connection_with_normalization._get_state_from_file( - connection_with_normalization.configuration_path, workspace_id - ) - assert connection_with_normalization.was_created - assert connection_with_normalization.remote_resource["operations"][0]["operation_id"] is not None - assert connection_with_normalization.remote_resource["operations"][0]["operator_configuration"]["normalization"]["option"] == "basic" - connection_with_normalization.raw_configuration["configuration"]["status"] = "inactive" - connection_with_normalization.configuration = connection_with_normalization._deserialize_raw_configuration() - assert 'changed from "active" to "inactive"' in connection_with_normalization.get_diff_with_remote_resource() - connection_with_normalization.update() diff --git a/octavia-cli/integration_tests/test_generate/__init__.py b/octavia-cli/integration_tests/test_generate/__init__.py deleted file mode 100644 index 46b7376756ec..000000000000 --- a/octavia-cli/integration_tests/test_generate/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/connection/expected_with_normalization.yaml b/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/connection/expected_with_normalization.yaml deleted file mode 100644 index ceeddbc1c8de..000000000000 --- a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/connection/expected_with_normalization.yaml +++ /dev/null @@ -1,56 +0,0 @@ -# Configuration for connection my_new_connection -definition_type: connection -resource_name: "my_new_connection" -source_configuration_path: source_configuration_path -destination_configuration_path: destination_configuration_path - -# EDIT THE CONFIGURATION BELOW! -configuration: - status: active # REQUIRED | string | Allowed values: active, inactive, deprecated - skip_reset: false # OPTIONAL | boolean | Flag to check if the connection should be reset after a connection update - namespace_definition: source # OPTIONAL | string | Allowed values: source, destination, customformat - namespace_format: "${SOURCE_NAMESPACE}" # OPTIONAL | string | Used when namespaceDefinition is 'customformat'. If blank then behaves like namespaceDefinition = 'destination'. If "${SOURCE_NAMESPACE}" then behaves like namespaceDefinition = 'source'. - prefix: "" # REQUIRED | Prefix that will be prepended to the name of each stream when it is written to the destination - resource_requirements: # OPTIONAL | object | Resource requirements to run workers (blank for unbounded allocations) - cpu_limit: "" # OPTIONAL - cpu_request: "" # OPTIONAL - memory_limit: "" # OPTIONAL - memory_request: "" # OPTIONAL - schedule_type: basic # OPTIONAL | string | Allowed values: basic, cron, manual - schedule_data: # OPTIONAL | object - basic_schedule: - time_unit: hours # REQUIRED | string | Allowed values: minutes, hours, days, weeks, months - units: 1 # REQUIRED | integer - # cron: - # cron_time_zone: "UTC" # REQUIRED | string - # cron_expression: "* */2 * * * ?" # REQUIRED | string - # operations: - ## -------- Uncomment and edit the block below if you want to enable Airbyte normalization -------- - # - name: "Normalization" - # operator_configuration: - # normalization: - # option: "basic" - # operator_type: "normalization" - ## -------- Uncomment and edit the block below if you want to declare a custom transformation -------- - # - name: "My dbt transformations" # REQUIRED | string - # operator_configuration: - # dbt: - # dbt_arguments: "run" # REQUIRED | string | Entrypoint arguments for dbt cli to run the project - # docker_image: "fishtownanalytics/dbt:0.19.1" # REQUIRED | string | Docker image URL with dbt installed - # git_repo_branch: "your-repo-branch-name" # OPTIONAL | string | Git branch name - # git_repo_url: "https://github.com/" # REQUIRED | string | Git repository URL of the custom transformation project - # operator_type: dbt # REQUIRED | string | Allowed values: dbt, normalization - sync_catalog: # OPTIONAL | object | 🚨 ONLY edit streams.config, streams.stream should not be edited as schema cannot be changed. - streams: - - config: - alias_name: pokemon - destination_sync_mode: append - selected: true - sync_mode: full_refresh - stream: - default_cursor_field: - - foo - json_schema: {} - name: my_stream - supported_sync_modes: - - full_refresh diff --git a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/connection/expected_without_normalization.yaml b/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/connection/expected_without_normalization.yaml deleted file mode 100644 index ebe43dbccbef..000000000000 --- a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/connection/expected_without_normalization.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# Configuration for connection my_new_connection -definition_type: connection -resource_name: "my_new_connection" -source_configuration_path: source_configuration_path -destination_configuration_path: destination_configuration_path - -# EDIT THE CONFIGURATION BELOW! -configuration: - status: active # REQUIRED | string | Allowed values: active, inactive, deprecated - skip_reset: false # OPTIONAL | boolean | Flag to check if the connection should be reset after a connection update - namespace_definition: source # OPTIONAL | string | Allowed values: source, destination, customformat - namespace_format: "${SOURCE_NAMESPACE}" # OPTIONAL | string | Used when namespaceDefinition is 'customformat'. If blank then behaves like namespaceDefinition = 'destination'. If "${SOURCE_NAMESPACE}" then behaves like namespaceDefinition = 'source'. - prefix: "" # REQUIRED | Prefix that will be prepended to the name of each stream when it is written to the destination - resource_requirements: # OPTIONAL | object | Resource requirements to run workers (blank for unbounded allocations) - cpu_limit: "" # OPTIONAL - cpu_request: "" # OPTIONAL - memory_limit: "" # OPTIONAL - memory_request: "" # OPTIONAL - schedule_type: basic # OPTIONAL | string | Allowed values: basic, cron, manual - schedule_data: # OPTIONAL | object - basic_schedule: - time_unit: hours # REQUIRED | string | Allowed values: minutes, hours, days, weeks, months - units: 1 # REQUIRED | integer - # cron: - # cron_time_zone: "UTC" # REQUIRED | string - # cron_expression: "* */2 * * * ?" # REQUIRED | string - sync_catalog: # OPTIONAL | object | 🚨 ONLY edit streams.config, streams.stream should not be edited as schema cannot be changed. - streams: - - config: - alias_name: pokemon - destination_sync_mode: append - selected: true - sync_mode: full_refresh - stream: - default_cursor_field: - - foo - json_schema: {} - name: my_stream - supported_sync_modes: - - full_refresh diff --git a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_postgres/expected.yaml b/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_postgres/expected.yaml deleted file mode 100644 index 85c986eb8f20..000000000000 --- a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_postgres/expected.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# Configuration for airbyte/destination-postgres -# Documentation about this connector can be found at https://docs.airbyte.io/integrations/destinations/postgres -resource_name: "my_postgres_destination" -definition_type: destination -definition_id: foobar -definition_image: airbyte/destination-postgres -definition_version: 0.3.13 - -# EDIT THE CONFIGURATION BELOW! -configuration: - host: # REQUIRED | string | Hostname of the database. - port: 5432 # REQUIRED | integer | Port of the database. | Example: 5432 - database: # REQUIRED | string | Name of the database. - schema: "public" # REQUIRED | string | The default schema tables are written to if the source does not specify a namespace. The usual value for this field is "public". | Example: public - username: # REQUIRED | string | Username to use to access the database. - password: ${PASSWORD} # SECRET (please store in environment variables) | OPTIONAL | string | Password associated with the username. - ssl: # OPTIONAL | boolean | Encrypt data using SSL. - tunnel_method: - ## -------- Pick one valid structure among the examples below: -------- - tunnel_method: "NO_TUNNEL" # REQUIRED | string | No ssh tunnel needed to connect to database - ## -------- Another valid structure for tunnel_method: -------- - # tunnel_method: "SSH_KEY_AUTH" # REQUIRED | string | Connect through a jump server tunnel host using username and ssh key - # tunnel_host: # REQUIRED | string | Hostname of the jump server host that allows inbound ssh tunnel. - # tunnel_port: 22 # REQUIRED | integer | Port on the proxy/jump server that accepts inbound ssh connections. | Example: 22 - # tunnel_user: # REQUIRED | string | OS-level username for logging into the jump server host. - # ssh_key: ${SSH_KEY} # SECRET (please store in environment variables) | REQUIRED | string | OS-level user account ssh key credentials in RSA PEM format ( created with ssh-keygen -t rsa -m PEM -f myuser_rsa ) - ## -------- Another valid structure for tunnel_method: -------- - # tunnel_method: "SSH_PASSWORD_AUTH" # REQUIRED | string | Connect through a jump server tunnel host using username and password authentication - # tunnel_host: # REQUIRED | string | Hostname of the jump server host that allows inbound ssh tunnel. - # tunnel_port: 22 # REQUIRED | integer | Port on the proxy/jump server that accepts inbound ssh connections. | Example: 22 - # tunnel_user: # REQUIRED | string | OS-level username for logging into the jump server host - # tunnel_user_password: ${TUNNEL_USER_PASSWORD} # SECRET (please store in environment variables) | REQUIRED | string | OS-level password for logging into the jump server host diff --git a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_postgres/input_spec.yaml b/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_postgres/input_spec.yaml deleted file mode 100644 index dcab0bdcc097..000000000000 --- a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_postgres/input_spec.yaml +++ /dev/null @@ -1,177 +0,0 @@ -dockerImage: "airbyte/destination-postgres:0.3.13" -spec: - documentationUrl: "https://docs.airbyte.io/integrations/destinations/postgres" - connectionSpecification: - $schema: "http://json-schema.org/draft-07/schema#" - title: "Postgres Destination Spec" - type: "object" - required: - - "host" - - "port" - - "username" - - "database" - - "schema" - additionalProperties: true - properties: - host: - title: "Host" - description: "Hostname of the database." - type: "string" - order: 0 - port: - title: "Port" - description: "Port of the database." - type: "integer" - minimum: 0 - maximum: 65536 - default: 5432 - examples: - - "5432" - order: 1 - database: - title: "DB Name" - description: "Name of the database." - type: "string" - order: 2 - schema: - title: "Default Schema" - description: - "The default schema tables are written to if the source does\ - \ not specify a namespace. The usual value for this field is \"public\"\ - ." - type: "string" - examples: - - "public" - default: "public" - order: 3 - username: - title: "User" - description: "Username to use to access the database." - type: "string" - order: 4 - password: - title: "Password" - description: "Password associated with the username." - type: "string" - airbyte_secret: true - order: 5 - ssl: - title: "SSL Connection" - description: "Encrypt data using SSL." - type: "boolean" - default: false - order: 6 - tunnel_method: - type: "object" - title: "SSH Tunnel Method" - description: - "Whether to initiate an SSH tunnel before connecting to the\ - \ database, and if so, which kind of authentication to use." - oneOf: - - title: "No Tunnel" - required: - - "tunnel_method" - properties: - tunnel_method: - description: "No ssh tunnel needed to connect to database" - type: "string" - const: "NO_TUNNEL" - order: 0 - - title: "SSH Key Authentication" - required: - - "tunnel_method" - - "tunnel_host" - - "tunnel_port" - - "tunnel_user" - - "ssh_key" - properties: - tunnel_method: - description: - "Connect through a jump server tunnel host using username\ - \ and ssh key" - type: "string" - const: "SSH_KEY_AUTH" - order: 0 - tunnel_host: - title: "SSH Tunnel Jump Server Host" - description: - "Hostname of the jump server host that allows inbound\ - \ ssh tunnel." - type: "string" - order: 1 - tunnel_port: - title: "SSH Connection Port" - description: - "Port on the proxy/jump server that accepts inbound ssh\ - \ connections." - type: "integer" - minimum: 0 - maximum: 65536 - default: 22 - examples: - - "22" - order: 2 - tunnel_user: - title: "SSH Login Username" - description: "OS-level username for logging into the jump server host." - type: "string" - order: 3 - ssh_key: - title: "SSH Private Key" - description: - "OS-level user account ssh key credentials in RSA PEM\ - \ format ( created with ssh-keygen -t rsa -m PEM -f myuser_rsa )" - type: "string" - airbyte_secret: true - multiline: true - order: 4 - - title: "Password Authentication" - required: - - "tunnel_method" - - "tunnel_host" - - "tunnel_port" - - "tunnel_user" - - "tunnel_user_password" - properties: - tunnel_method: - description: - "Connect through a jump server tunnel host using username\ - \ and password authentication" - type: "string" - const: "SSH_PASSWORD_AUTH" - order: 0 - tunnel_host: - title: "SSH Tunnel Jump Server Host" - description: - "Hostname of the jump server host that allows inbound\ - \ ssh tunnel." - type: "string" - order: 1 - tunnel_port: - title: "SSH Connection Port" - description: - "Port on the proxy/jump server that accepts inbound ssh\ - \ connections." - type: "integer" - minimum: 0 - maximum: 65536 - default: 22 - examples: - - "22" - order: 2 - tunnel_user: - title: "SSH Login Username" - description: "OS-level username for logging into the jump server host" - type: "string" - order: 3 - tunnel_user_password: - title: "Password" - description: "OS-level password for logging into the jump server host" - type: "string" - airbyte_secret: true - order: 4 - supportsIncremental: true - supported_destination_sync_modes: - - "overwrite" - - "append" - - "append_dedup" diff --git a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_s3/expected.yaml b/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_s3/expected.yaml deleted file mode 100644 index 13f5a5eeee43..000000000000 --- a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_s3/expected.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# Configuration for airbyte/destination-s3 -# Documentation about this connector can be found at https://docs.airbyte.io/integrations/destinations/s3 -resource_name: "my_s3_destination" -definition_type: destination -definition_id: foobar -definition_image: airbyte/destination-s3 -definition_version: 0.2.5 - -# EDIT THE CONFIGURATION BELOW! -configuration: - s3_endpoint: # OPTIONAL | string | This is your S3 endpoint url.(if you are working with AWS S3, just leave empty). | Example: http://localhost:9000 - s3_bucket_name: # REQUIRED | string | The name of the S3 bucket. | Example: airbyte_sync - s3_bucket_path: # REQUIRED | string | Directory under the S3 bucket where data will be written. | Example: data_sync/test - s3_bucket_region: # REQUIRED | string | The region of the S3 bucket. - access_key_id: ${ACCESS_KEY_ID} # SECRET (please store in environment variables) | OPTIONAL | string | The access key id to access the S3 bucket. Airbyte requires Read and Write permissions to the given bucket, if not set, Airbyte will rely on Instance Profile. | Example: A012345678910EXAMPLE - secret_access_key: ${SECRET_ACCESS_KEY} # SECRET (please store in environment variables) | OPTIONAL | string | The corresponding secret to the access key id, if S3 Key Id is set, then S3 Access Key must also be provided | Example: a012345678910ABCDEFGH/AbCdEfGhEXAMPLEKEY - format: - ## -------- Pick one valid structure among the examples below: -------- - format_type: "Avro" # REQUIRED | string} - compression_codec: - ## -------- Pick one valid structure among the examples below: -------- - codec: "no compression" # REQUIRED | string - ## -------- Another valid structure for compression_codec: -------- - # codec: "Deflate" # REQUIRED | string - # compression_level: # REQUIRED | integer | 0: no compression & fastest, 9: best compression & slowest. - ## -------- Another valid structure for compression_codec: -------- - # codec: "bzip2" # REQUIRED | string - ## -------- Another valid structure for compression_codec: -------- - # codec: "xz" # REQUIRED | string - # compression_level: 6 # REQUIRED | integer | See here for details. - ## -------- Another valid structure for compression_codec: -------- - # codec: "zstandard" # REQUIRED | string - # compression_level: 3 # REQUIRED | integer | Negative levels are 'fast' modes akin to lz4 or snappy, levels above 9 are generally for archival purposes, and levels above 18 use a lot of memory. - # include_checksum: # OPTIONAL | boolean | If true, include a checksum with each data block. - ## -------- Another valid structure for compression_codec: -------- - # codec: "snappy" # REQUIRED | string - part_size_mb: 5 # OPTIONAL | integer | This is the size of a "Part" being buffered in memory. It limits the memory usage when writing. Larger values will allow to upload a bigger files and improve the speed, but consumes more memory. Allowed values: min=5MB, max=525MB Default: 5MB. | Example: 5 - ## -------- Another valid structure for format: -------- - # format_type: "CSV" # REQUIRED | string - # flattening: "No flattening" # REQUIRED | string | Whether the input json data should be normalized (flattened) in the output CSV. Please refer to docs for details. - # part_size_mb: 5 # OPTIONAL | integer | This is the size of a "Part" being buffered in memory. It limits the memory usage when writing. Larger values will allow to upload a bigger files and improve the speed, but consumes more memory. Allowed values: min=5MB, max=525MB Default: 5MB. | Example: 5 - ## -------- Another valid structure for format: -------- - # format_type: "JSONL" # REQUIRED | string - # part_size_mb: 5 # OPTIONAL | integer | This is the size of a "Part" being buffered in memory. It limits the memory usage when writing. Larger values will allow to upload a bigger files and improve the speed, but consumes more memory. Allowed values: min=5MB, max=525MB Default: 5MB. | Example: 5 - ## -------- Another valid structure for format: -------- - # format_type: "Parquet" # REQUIRED | string - # compression_codec: "UNCOMPRESSED" # OPTIONAL | string | The compression algorithm used to compress data pages. - # block_size_mb: 128 # OPTIONAL | integer | This is the size of a row group being buffered in memory. It limits the memory usage when writing. Larger values will improve the IO when reading, but consume more memory when writing. Default: 128 MB. | Example: 128 - # max_padding_size_mb: 8 # OPTIONAL | integer | Maximum size allowed as padding to align row groups. This is also the minimum size of a row group. Default: 8 MB. | Example: 8 - # page_size_kb: 1024 # OPTIONAL | integer | The page size is for compression. A block is composed of pages. A page is the smallest unit that must be read fully to access a single record. If this value is too small, the compression will deteriorate. Default: 1024 KB. | Example: 1024 - # dictionary_page_size_kb: 1024 # OPTIONAL | integer | There is one dictionary page per column per row group when dictionary encoding is used. The dictionary page size works like the page size but for dictionary. Default: 1024 KB. | Example: 1024 - # dictionary_encoding: true # OPTIONAL | boolean | Default: true. diff --git a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_s3/input_spec.yaml b/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_s3/input_spec.yaml deleted file mode 100644 index 7e0f17ac5b30..000000000000 --- a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/destination_s3/input_spec.yaml +++ /dev/null @@ -1,330 +0,0 @@ -dockerImage: "airbyte/destination-s3:0.2.5" -spec: - documentationUrl: "https://docs.airbyte.io/integrations/destinations/s3" - connectionSpecification: - $schema: "http://json-schema.org/draft-07/schema#" - title: "S3 Destination Spec" - type: "object" - required: - - "s3_bucket_name" - - "s3_bucket_path" - - "s3_bucket_region" - - "format" - additionalProperties: false - properties: - s3_endpoint: - title: "Endpoint" - type: "string" - default: "" - description: "This is your S3 endpoint url.(if you are working with AWS\ - \ S3, just leave empty)." - examples: - - "http://localhost:9000" - s3_bucket_name: - title: "S3 Bucket Name" - type: "string" - description: "The name of the S3 bucket." - examples: - - "airbyte_sync" - s3_bucket_path: - description: "Directory under the S3 bucket where data will be written." - type: "string" - examples: - - "data_sync/test" - s3_bucket_region: - title: "S3 Bucket Region" - type: "string" - default: "" - description: "The region of the S3 bucket." - enum: - - "" - - "us-east-1" - - "us-east-2" - - "us-west-1" - - "us-west-2" - - "af-south-1" - - "ap-east-1" - - "ap-south-1" - - "ap-northeast-1" - - "ap-northeast-2" - - "ap-northeast-3" - - "ap-southeast-1" - - "ap-southeast-2" - - "ca-central-1" - - "cn-north-1" - - "cn-northwest-1" - - "eu-central-1" - - "eu-north-1" - - "eu-south-1" - - "eu-west-1" - - "eu-west-2" - - "eu-west-3" - - "sa-east-1" - - "me-south-1" - - "us-gov-east-1" - - "us-gov-west-1" - access_key_id: - type: "string" - description: - "The access key id to access the S3 bucket. Airbyte requires\ - \ Read and Write permissions to the given bucket, if not set, Airbyte\ - \ will rely on Instance Profile." - title: "S3 Key Id" - airbyte_secret: true - examples: - - "A012345678910EXAMPLE" - secret_access_key: - type: "string" - description: - "The corresponding secret to the access key id, if S3 Key Id\ - \ is set, then S3 Access Key must also be provided" - title: "S3 Access Key" - airbyte_secret: true - examples: - - "a012345678910ABCDEFGH/AbCdEfGhEXAMPLEKEY" - format: - title: "Output Format" - type: "object" - description: "Output data format" - oneOf: - - title: "Avro: Apache Avro" - required: - - "format_type" - - "compression_codec" - properties: - format_type: - type: "string" - enum: - - "Avro" - default: "Avro" - compression_codec: - title: "Compression Codec" - description: - "The compression algorithm used to compress data. Default\ - \ to no compression." - type: "object" - oneOf: - - title: "no compression" - required: - - "codec" - properties: - codec: - type: "string" - enum: - - "no compression" - default: "no compression" - - title: "Deflate" - required: - - "codec" - - "compression_level" - properties: - codec: - type: "string" - enum: - - "Deflate" - default: "Deflate" - compression_level: - title: "Deflate level" - description: - "0: no compression & fastest, 9: best compression\ - \ & slowest." - type: "integer" - default: 0 - minimum: 0 - maximum: 9 - - title: "bzip2" - required: - - "codec" - properties: - codec: - type: "string" - enum: - - "bzip2" - default: "bzip2" - - title: "xz" - required: - - "codec" - - "compression_level" - properties: - codec: - type: "string" - enum: - - "xz" - default: "xz" - compression_level: - title: "Compression level" - description: - "See here for details." - type: "integer" - default: 6 - minimum: 0 - maximum: 9 - - title: "zstandard" - required: - - "codec" - - "compression_level" - properties: - codec: - type: "string" - enum: - - "zstandard" - default: "zstandard" - compression_level: - title: "Compression level" - description: - "Negative levels are 'fast' modes akin to lz4 or\ - \ snappy, levels above 9 are generally for archival purposes,\ - \ and levels above 18 use a lot of memory." - type: "integer" - default: 3 - minimum: -5 - maximum: 22 - include_checksum: - title: "Include checksum" - description: "If true, include a checksum with each data block." - type: "boolean" - default: false - - title: "snappy" - required: - - "codec" - properties: - codec: - type: "string" - enum: - - "snappy" - default: "snappy" - part_size_mb: - title: "Block Size (MB) for Amazon S3 multipart upload" - description: - "This is the size of a \"Part\" being buffered in memory.\ - \ It limits the memory usage when writing. Larger values will allow\ - \ to upload a bigger files and improve the speed, but consumes\ - \ more memory. Allowed values: min=5MB, max=525MB Default: 5MB." - type: "integer" - default: 5 - examples: - - 5 - - title: "CSV: Comma-Separated Values" - required: - - "format_type" - - "flattening" - properties: - format_type: - type: "string" - enum: - - "CSV" - default: "CSV" - flattening: - type: "string" - title: "Normalization (Flattening)" - description: - "Whether the input json data should be normalized (flattened)\ - \ in the output CSV. Please refer to docs for details." - default: "No flattening" - enum: - - "No flattening" - - "Root level flattening" - part_size_mb: - title: "Block Size (MB) for Amazon S3 multipart upload" - description: - "This is the size of a \"Part\" being buffered in memory.\ - \ It limits the memory usage when writing. Larger values will allow\ - \ to upload a bigger files and improve the speed, but consumes\ - \ more memory. Allowed values: min=5MB, max=525MB Default: 5MB." - type: "integer" - default: 5 - examples: - - 5 - - title: "JSON Lines: newline-delimited JSON" - required: - - "format_type" - properties: - format_type: - type: "string" - enum: - - "JSONL" - default: "JSONL" - part_size_mb: - title: "Block Size (MB) for Amazon S3 multipart upload" - description: - "This is the size of a \"Part\" being buffered in memory.\ - \ It limits the memory usage when writing. Larger values will allow\ - \ to upload a bigger files and improve the speed, but consumes\ - \ more memory. Allowed values: min=5MB, max=525MB Default: 5MB." - type: "integer" - default: 5 - examples: - - 5 - - title: "Parquet: Columnar Storage" - required: - - "format_type" - properties: - format_type: - type: "string" - enum: - - "Parquet" - default: "Parquet" - compression_codec: - title: "Compression Codec" - description: "The compression algorithm used to compress data pages." - type: "string" - enum: - - "UNCOMPRESSED" - - "SNAPPY" - - "GZIP" - - "LZO" - - "BROTLI" - - "LZ4" - - "ZSTD" - default: "UNCOMPRESSED" - block_size_mb: - title: "Block Size (Row Group Size) (MB)" - description: - "This is the size of a row group being buffered in memory.\ - \ It limits the memory usage when writing. Larger values will improve\ - \ the IO when reading, but consume more memory when writing. Default:\ - \ 128 MB." - type: "integer" - default: 128 - examples: - - 128 - max_padding_size_mb: - title: "Max Padding Size (MB)" - description: - "Maximum size allowed as padding to align row groups.\ - \ This is also the minimum size of a row group. Default: 8 MB." - type: "integer" - default: 8 - examples: - - 8 - page_size_kb: - title: "Page Size (KB)" - description: - "The page size is for compression. A block is composed\ - \ of pages. A page is the smallest unit that must be read fully\ - \ to access a single record. If this value is too small, the compression\ - \ will deteriorate. Default: 1024 KB." - type: "integer" - default: 1024 - examples: - - 1024 - dictionary_page_size_kb: - title: "Dictionary Page Size (KB)" - description: - "There is one dictionary page per column per row group\ - \ when dictionary encoding is used. The dictionary page size works\ - \ like the page size but for dictionary. Default: 1024 KB." - type: "integer" - default: 1024 - examples: - - 1024 - dictionary_encoding: - title: "Dictionary Encoding" - description: "Default: true." - type: "boolean" - default: true - supportsIncremental: true - supported_destination_sync_modes: - - "overwrite" - - "append" diff --git a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/source_postgres/expected.yaml b/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/source_postgres/expected.yaml deleted file mode 100644 index 433a0a571d07..000000000000 --- a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/source_postgres/expected.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# Configuration for airbyte/source-postgres -# Documentation about this connector can be found at https://docs.airbyte.com/integrations/sources/postgres -resource_name: "my_postgres_source" -definition_type: source -definition_id: foobar -definition_image: airbyte/source-postgres -definition_version: 0.4.4 - -# EDIT THE CONFIGURATION BELOW! -configuration: - host: # REQUIRED | string | Hostname of the database. - port: 5432 # REQUIRED | integer | Port of the database. | Example: 5432 - database: # REQUIRED | string | Name of the database. - schemas: ["public"] # OPTIONAL | array | The list of schemas to sync from. Defaults to user. Case sensitive. - username: # REQUIRED | string | Username to use to access the database. - password: ${PASSWORD} # SECRET (please store in environment variables) | OPTIONAL | string | Password associated with the username. - ssl: # OPTIONAL | boolean | Encrypt client/server communications for increased security. - replication_method: - ## -------- Pick one valid structure among the examples below: -------- - method: "Standard" # REQUIRED | string - ## -------- Another valid structure for replication_method: -------- - # method: "CDC" # REQUIRED | string - # plugin: "pgoutput" # OPTIONAL | string | A logical decoding plug-in installed on the PostgreSQL server. `pgoutput` plug-in is used by default.If replication table contains a lot of big jsonb values it is recommended to use `wal2json` plug-in. For more information about `wal2json` plug-in read Postgres Source docs. - # replication_slot: # REQUIRED | string | A plug-in logical replication slot. - # publication: # REQUIRED | string | A Postgres publication used for consuming changes. - tunnel_method: - ## -------- Pick one valid structure among the examples below: -------- - tunnel_method: "NO_TUNNEL" # REQUIRED | string | No ssh tunnel needed to connect to database - ## -------- Another valid structure for tunnel_method: -------- - # tunnel_method: "SSH_KEY_AUTH" # REQUIRED | string | Connect through a jump server tunnel host using username and ssh key - # tunnel_host: # REQUIRED | string | Hostname of the jump server host that allows inbound ssh tunnel. - # tunnel_port: 22 # REQUIRED | integer | Port on the proxy/jump server that accepts inbound ssh connections. | Example: 22 - # tunnel_user: # REQUIRED | string | OS-level username for logging into the jump server host. - # ssh_key: ${SSH_KEY} # SECRET (please store in environment variables) | REQUIRED | string | OS-level user account ssh key credentials in RSA PEM format ( created with ssh-keygen -t rsa -m PEM -f myuser_rsa ) - ## -------- Another valid structure for tunnel_method: -------- - # tunnel_method: "SSH_PASSWORD_AUTH" # REQUIRED | string | Connect through a jump server tunnel host using username and password authentication - # tunnel_host: # REQUIRED | string | Hostname of the jump server host that allows inbound ssh tunnel. - # tunnel_port: 22 # REQUIRED | integer | Port on the proxy/jump server that accepts inbound ssh connections. | Example: 22 - # tunnel_user: # REQUIRED | string | OS-level username for logging into the jump server host - # tunnel_user_password: ${TUNNEL_USER_PASSWORD} # SECRET (please store in environment variables) | REQUIRED | string | OS-level password for logging into the jump server host diff --git a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/source_postgres/input_spec.yaml b/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/source_postgres/input_spec.yaml deleted file mode 100644 index bcc8a383ad76..000000000000 --- a/octavia-cli/integration_tests/test_generate/expected_rendered_yaml/source_postgres/input_spec.yaml +++ /dev/null @@ -1,238 +0,0 @@ -dockerImage: "airbyte/source-postgres:0.4.4" -spec: - documentationUrl: "https://docs.airbyte.com/integrations/sources/postgres" - connectionSpecification: - $schema: "http://json-schema.org/draft-07/schema#" - title: "Postgres Source Spec" - type: "object" - required: - - "host" - - "port" - - "database" - - "username" - additionalProperties: false - properties: - host: - title: "Host" - description: "Hostname of the database." - type: "string" - order: 0 - port: - title: "Port" - description: "Port of the database." - type: "integer" - minimum: 0 - maximum: 65536 - default: 5432 - examples: - - "5432" - order: 1 - database: - title: "DB Name" - description: "Name of the database." - type: "string" - order: 2 - schemas: - title: "Schemas" - description: "The list of schemas to sync from. Defaults to user. Case sensitive." - type: "array" - items: - type: "string" - minItems: 0 - uniqueItems: true - default: - - "public" - order: 3 - username: - title: "User" - description: "Username to use to access the database." - type: "string" - order: 4 - password: - title: "Password" - description: "Password associated with the username." - type: "string" - airbyte_secret: true - order: 5 - ssl: - title: "Connect using SSL" - description: "Encrypt client/server communications for increased security." - type: "boolean" - default: false - order: 6 - replication_method: - type: "object" - title: "Replication Method" - description: "Replication method to use for extracting data from the database." - order: 7 - oneOf: - - title: "Standard" - additionalProperties: false - description: - "Standard replication requires no setup on the DB side but\ - \ will not be able to represent deletions incrementally." - required: - - "method" - properties: - method: - type: "string" - const: "Standard" - enum: - - "Standard" - default: "Standard" - order: 0 - - title: "Logical Replication (CDC)" - additionalProperties: false - description: - "Logical replication uses the Postgres write-ahead log (WAL)\ - \ to detect inserts, updates, and deletes. This needs to be configured\ - \ on the source database itself. Only available on Postgres 10 and above.\ - \ Read the Postgres Source docs for more information." - required: - - "method" - - "replication_slot" - - "publication" - properties: - method: - type: "string" - const: "CDC" - enum: - - "CDC" - default: "CDC" - order: 0 - plugin: - type: "string" - title: "Plugin" - description: - "A logical decoding plug-in installed on the PostgreSQL\ - \ server. `pgoutput` plug-in is used by default.\nIf replication\ - \ table contains a lot of big jsonb values it is recommended to\ - \ use `wal2json` plug-in. For more information about `wal2json`\ - \ plug-in read Postgres Source docs." - enum: - - "pgoutput" - - "wal2json" - default: "pgoutput" - order: 1 - replication_slot: - type: "string" - title: "Replication Slot" - description: "A plug-in logical replication slot." - order: 2 - publication: - type: "string" - title: "Publication" - description: "A Postgres publication used for consuming changes." - order: 3 - tunnel_method: - type: "object" - title: "SSH Tunnel Method" - description: - "Whether to initiate an SSH tunnel before connecting to the\ - \ database, and if so, which kind of authentication to use." - oneOf: - - title: "No Tunnel" - required: - - "tunnel_method" - properties: - tunnel_method: - description: "No ssh tunnel needed to connect to database" - type: "string" - const: "NO_TUNNEL" - order: 0 - - title: "SSH Key Authentication" - required: - - "tunnel_method" - - "tunnel_host" - - "tunnel_port" - - "tunnel_user" - - "ssh_key" - properties: - tunnel_method: - description: - "Connect through a jump server tunnel host using username\ - \ and ssh key" - type: "string" - const: "SSH_KEY_AUTH" - order: 0 - tunnel_host: - title: "SSH Tunnel Jump Server Host" - description: - "Hostname of the jump server host that allows inbound\ - \ ssh tunnel." - type: "string" - order: 1 - tunnel_port: - title: "SSH Connection Port" - description: - "Port on the proxy/jump server that accepts inbound ssh\ - \ connections." - type: "integer" - minimum: 0 - maximum: 65536 - default: 22 - examples: - - "22" - order: 2 - tunnel_user: - title: "SSH Login Username" - description: "OS-level username for logging into the jump server host." - type: "string" - order: 3 - ssh_key: - title: "SSH Private Key" - description: - "OS-level user account ssh key credentials in RSA PEM\ - \ format ( created with ssh-keygen -t rsa -m PEM -f myuser_rsa )" - type: "string" - airbyte_secret: true - multiline: true - order: 4 - - title: "Password Authentication" - required: - - "tunnel_method" - - "tunnel_host" - - "tunnel_port" - - "tunnel_user" - - "tunnel_user_password" - properties: - tunnel_method: - description: - "Connect through a jump server tunnel host using username\ - \ and password authentication" - type: "string" - const: "SSH_PASSWORD_AUTH" - order: 0 - tunnel_host: - title: "SSH Tunnel Jump Server Host" - description: - "Hostname of the jump server host that allows inbound\ - \ ssh tunnel." - type: "string" - order: 1 - tunnel_port: - title: "SSH Connection Port" - description: - "Port on the proxy/jump server that accepts inbound ssh\ - \ connections." - type: "integer" - minimum: 0 - maximum: 65536 - default: 22 - examples: - - "22" - order: 2 - tunnel_user: - title: "SSH Login Username" - description: "OS-level username for logging into the jump server host" - type: "string" - order: 3 - tunnel_user_password: - title: "Password" - description: "OS-level password for logging into the jump server host" - type: "string" - airbyte_secret: true - order: 4 - supported_destination_sync_modes: [] diff --git a/octavia-cli/integration_tests/test_generate/test_definitions.py b/octavia-cli/integration_tests/test_generate/test_definitions.py deleted file mode 100644 index 6f02df67801c..000000000000 --- a/octavia-cli/integration_tests/test_generate/test_definitions.py +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import os - -import pytest -import yaml -from octavia_cli.generate.commands import generate_source_or_destination - -pytestmark = pytest.mark.integration - - -@pytest.mark.parametrize( - ("definition_type, definition_id, resource_name"), - [ - ("source", "6371b14b-bc68-4236-bfbd-468e8df8e968", "test_generate_source"), - ("destination", "22f6c74f-5699-40ff-833c-4a879ea40133", "test_generate_destination"), - ], -) -def test_generate_source_or_destination( - octavia_tmp_project_directory, api_client, workspace_id, definition_type, definition_id, resource_name -): - current_path = os.getcwd() - os.chdir(octavia_tmp_project_directory) - generate_source_or_destination(definition_type, api_client, workspace_id, definition_id, resource_name) - expected_output_path = f"{definition_type}s/{resource_name}/configuration.yaml" - with open(expected_output_path, "r") as f: - parsed_yaml = yaml.safe_load(f) - assert parsed_yaml["resource_name"] == resource_name - assert parsed_yaml["definition_type"] == definition_type - assert parsed_yaml["definition_id"] == definition_id - os.chdir(current_path) diff --git a/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/.gitignore b/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/.gitignore deleted file mode 100644 index e40706226713..000000000000 --- a/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -**/state_*.yaml -**/updated_*.yaml diff --git a/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/connections/poke_to_pg_to_import/configuration.yaml b/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/connections/poke_to_pg_to_import/configuration.yaml deleted file mode 100644 index 5b4bbfd91e15..000000000000 --- a/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/connections/poke_to_pg_to_import/configuration.yaml +++ /dev/null @@ -1,367 +0,0 @@ -# Configuration for connection poke_to_pg -definition_type: connection -resource_name: poke_to_pg_to_import -source_configuration_path: sources/poke_to_import/configuration.yaml -destination_configuration_path: destinations/postgres_to_import/configuration.yaml - -# EDIT THE CONFIGURATION BELOW! -configuration: - status: active # REQUIRED | string | Allowed values: active, inactive, deprecated - namespace_definition: source # OPTIONAL | string | Allowed values: source, destination, customformat - namespace_format: "${SOURCE_NAMESPACE}" # OPTIONAL | string | Used when namespaceDefinition is 'customformat'. If blank then behaves like namespaceDefinition = 'destination'. If "${SOURCE_NAMESPACE}" then behaves like namespaceDefinition = 'source'. - prefix: "" # REQUIRED | Prefix that will be prepended to the name of each stream when it is written to the destination - resource_requirements: # OPTIONAL | object | Resource requirements to run workers (blank for unbounded allocations) - cpu_limit: "" # OPTIONAL - cpu_request: "" # OPTIONAL - memory_limit: "" # OPTIONAL - memory_request: "" # OPTIONAL - schedule_type: basic - schedule_data: - basic_schedule: - time_unit: hours # REQUIRED | string | Allowed values: minutes, hours, days, weeks, months - units: 1 # REQUIRED | integer - operations: - - name: "Normalization" - operator_configuration: - normalization: - option: "basic" - operator_type: "normalization" - sync_catalog: # OPTIONAL | object | 🚨 ONLY edit streams.config, streams.stream should not be edited as schema cannot be changed. - streams: - - config: - alias_name: pokemon - cursor_field: [] - destination_sync_mode: append - primary_key: [] - selected: true - sync_mode: full_refresh - stream: - default_cursor_field: [] - json_schema: - $schema: http://json-schema.org/draft-07/schema# - properties: - abilities: - items: - properties: - ability: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - is_hidden: - type: - - "null" - - boolean - slot: - type: - - "null" - - integer - type: - - "null" - - object - type: - - "null" - - array - base_experience: - type: - - "null" - - integer - forms: - items: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - array - game_indices: - items: - properties: - game_index: - type: - - "null" - - integer - version: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - height: - type: - - "null" - - integer - held_items: - items: - properties: - item: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - version_details: - items: - properties: - rarity: - type: - - "null" - - integer - version: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - type: - - "null" - - object - type: - - "null" - - array - id: - type: - - "null" - - integer - "is_default ": - type: - - "null" - - boolean - location_area_encounters: - type: - - "null" - - string - moves: - items: - properties: - move: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - version_group_details: - items: - properties: - level_learned_at: - type: - - "null" - - integer - move_learn_method: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - version_group: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - type: - - "null" - - object - type: - - "null" - - array - name: - type: - - "null" - - string - order: - type: - - "null" - - integer - species: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - sprites: - properties: - back_default: - type: - - "null" - - string - back_female: - type: - - "null" - - string - back_shiny: - type: - - "null" - - string - back_shiny_female: - type: - - "null" - - string - front_default: - type: - - "null" - - string - front_female: - type: - - "null" - - string - front_shiny: - type: - - "null" - - string - front_shiny_female: - type: - - "null" - - string - type: - - "null" - - object - stats: - items: - properties: - base_stat: - type: - - "null" - - integer - effort: - type: - - "null" - - integer - stat: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - types: - items: - properties: - slot: - type: - - "null" - - integer - type: - properties: - name: - type: - - "null" - - string - url: - type: - - "null" - - string - type: - - "null" - - object - type: - - "null" - - object - type: - - "null" - - array - weight: - type: - - "null" - - integer - type: object - name: pokemon - source_defined_primary_key: [] - supported_sync_modes: - - full_refresh diff --git a/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/destinations/postgres_to_import/configuration.yaml b/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/destinations/postgres_to_import/configuration.yaml deleted file mode 100644 index 865822d6f31e..000000000000 --- a/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/destinations/postgres_to_import/configuration.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# Configuration for airbyte/destination-postgres -# Documentation about this connector can be found at https://docs.airbyte.io/integrations/destinations/postgres -resource_name: postgres_to_import -definition_type: destination -definition_id: 25c5221d-dce2-4163-ade9-739ef790f503 -definition_image: airbyte/destination-postgres -definition_version: 0.3.15 - -# EDIT THE CONFIGURATION BELOW! -configuration: - ssl: False # OPTIONAL | boolean | Encrypt data using SSL. - host: localhost # REQUIRED | string | Hostname of the database. - port: 5433 # REQUIRED | integer | Port of the database. | Example: 5432 - schema: "public" # REQUIRED | string | The default schema tables are written to if the source does not specify a namespace. The usual value for this field is "public". | Example: public - database: postgres # REQUIRED | string | Name of the database. - password: my_secret_password # SECRET (please store in environment variables) | OPTIONAL | string | Password associated with the username. - username: postgres # REQUIRED | string | Username to use to access the database. - tunnel_method: - ## -------- Pick one valid structure among the examples below: -------- - tunnel_method: "NO_TUNNEL" # REQUIRED | string | No ssh tunnel needed to connect to database - ## -------- Another valid structure for tunnel_method: -------- - # ssh_key: ${SSH_KEY} # SECRET (please store in environment variables) | REQUIRED | string | OS-level user account ssh key credentials in RSA PEM format ( created with ssh-keygen -t rsa -m PEM -f myuser_rsa ) - # tunnel_host: # REQUIRED | string | Hostname of the jump server host that allows inbound ssh tunnel. - # tunnel_port: 22 # REQUIRED | integer | Port on the proxy/jump server that accepts inbound ssh connections. | Example: 22 - # tunnel_user: # REQUIRED | string | OS-level username for logging into the jump server host. - # tunnel_method: "SSH_KEY_AUTH" # REQUIRED | string | Connect through a jump server tunnel host using username and ssh key - ## -------- Another valid structure for tunnel_method: -------- - # tunnel_host: # REQUIRED | string | Hostname of the jump server host that allows inbound ssh tunnel. - # tunnel_port: 22 # REQUIRED | integer | Port on the proxy/jump server that accepts inbound ssh connections. | Example: 22 - # tunnel_user: # REQUIRED | string | OS-level username for logging into the jump server host - # tunnel_method: "SSH_PASSWORD_AUTH" # REQUIRED | string | Connect through a jump server tunnel host using username and password authentication - # tunnel_user_password: ${TUNNEL_USER_PASSWORD} # SECRET (please store in environment variables) | REQUIRED | string | OS-level password for logging into the jump server host diff --git a/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/sources/poke_to_import/configuration.yaml b/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/sources/poke_to_import/configuration.yaml deleted file mode 100644 index 8eeab56aa93d..000000000000 --- a/octavia-cli/integration_tests/test_import/octavia_project_to_migrate/sources/poke_to_import/configuration.yaml +++ /dev/null @@ -1,9 +0,0 @@ -resource_name: poke_to_import -definition_type: source -definition_id: 6371b14b-bc68-4236-bfbd-468e8df8e968 -definition_image: airbyte/source-pokeapi -definition_version: 0.1.4 - -# EDIT THE CONFIGURATION BELOW! -configuration: - pokemon_name: ditto diff --git a/octavia-cli/integration_tests/test_import/test_commands.py b/octavia-cli/integration_tests/test_import/test_commands.py deleted file mode 100644 index 8b831819bdde..000000000000 --- a/octavia-cli/integration_tests/test_import/test_commands.py +++ /dev/null @@ -1,159 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - - -import glob -import os -import shutil -from distutils.dir_util import copy_tree -from pathlib import Path -from unittest import mock - -import pytest -from airbyte_api_client.api import connection_api -from airbyte_api_client.model.connection_id_request_body import ConnectionIdRequestBody -from click.testing import CliRunner -from octavia_cli._import.commands import all as octavia_import_all -from octavia_cli._import.commands import connection as octavia_import_connection -from octavia_cli._import.commands import destination as octavia_import_destination -from octavia_cli._import.commands import source as octavia_import_source -from octavia_cli.apply.commands import apply as octavia_apply -from octavia_cli.apply.resources import ResourceState -from octavia_cli.apply.resources import factory as resource_factory - -pytestmark = pytest.mark.integration -click_runner = CliRunner() - - -@pytest.fixture(scope="module") -def context_object(api_client, workspace_id): - return {"TELEMETRY_CLIENT": mock.MagicMock(), "PROJECT_IS_INITIALIZED": True, "API_CLIENT": api_client, "WORKSPACE_ID": workspace_id} - - -@pytest.fixture(scope="module") -def initialized_project_directory(context_object): - """This fixture initializes a temporary local directory with configuration.yaml files copied from ./octavia_project_to_migrate - It runs octavia apply on these configurations and then removes the local yaml files. - At the end of the run of this function we have remote resources an our Airbyte instance but they are not managed by octavia due to the file deletion. - The fixture returns source, destination and connection previously instantiated resources to make sure the import command ran in the following tests imports configuration at the right location. - """ - cwd = os.getcwd() - dir_path = f"{os.path.dirname(__file__)}/octavia_test_project" - copy_tree(f"{os.path.dirname(__file__)}/octavia_project_to_migrate", dir_path) - os.chdir(dir_path) - - result = click_runner.invoke(octavia_apply, obj=context_object) - assert result.exit_code == 0 - for configuration_file in glob.glob("./**/configuration.yaml", recursive=True): - resource = resource_factory(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], configuration_file) - if resource.resource_type == "source": - source_id, source_expected_configuration_path, source_expected_state_path = ( - resource.resource_id, - resource.configuration_path, - resource.state.path, - ) - if resource.resource_type == "destination": - destination_id, destination_expected_configuration_path, destination_expected_state_path = ( - resource.resource_id, - resource.configuration_path, - ResourceState._get_path_from_configuration_and_workspace_id(resource.configuration_path, context_object["WORKSPACE_ID"]), - ) - if resource.resource_type == "connection": - connection_id, connection_configuration_path, connection_expected_state_path = ( - resource.resource_id, - resource.configuration_path, - ResourceState._get_path_from_configuration_and_workspace_id(resource.configuration_path, context_object["WORKSPACE_ID"]), - ) - os.remove(configuration_file) - os.remove(resource.state.path) - yield (source_id, source_expected_configuration_path, source_expected_state_path), ( - destination_id, - destination_expected_configuration_path, - destination_expected_state_path, - ), (connection_id, connection_configuration_path, connection_expected_state_path) - os.chdir(cwd) - shutil.rmtree(dir_path) - - -@pytest.fixture(scope="module") -def expected_source(initialized_project_directory): - yield initialized_project_directory[0] - - -@pytest.fixture(scope="module") -def expected_destination(initialized_project_directory): - yield initialized_project_directory[1] - - -@pytest.fixture(scope="module") -def expected_connection(initialized_project_directory, context_object, expected_source, expected_destination): - connection_id, connection_configuration_path, connection_expected_state_path = initialized_project_directory[2] - yield connection_id, connection_configuration_path, connection_expected_state_path - # To delete the connection we have to create a ConnectionApi instance because WebBackendApi instance does not have delete endpoint - connection = resource_factory(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], connection_configuration_path) - connection_api_instance = connection_api.ConnectionApi(context_object["API_CLIENT"]) - connection_api_instance.delete_connection( - ConnectionIdRequestBody( - connection_id=connection.resource_id, - ) - ) - # Delete source and destination after connection to not make the connection deprecated - source = resource_factory(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], expected_source[1]) - source.api_instance.delete_source(source.get_payload) - destination = resource_factory(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], expected_destination[1]) - destination.api_instance.delete_destination(destination.get_payload) - - -def test_import_source(expected_source, context_object): - source_id, expected_configuration_path, expected_state_path = expected_source - result = click_runner.invoke(octavia_import_source, source_id, obj=context_object) - assert result.exit_code == 0 - assert Path(expected_configuration_path).is_file() and Path(expected_state_path).is_file() - source = resource_factory(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], expected_configuration_path) - assert source.was_created # Check if the remote resource is considered as managed by octavia and exists remotely - assert source.get_diff_with_remote_resource() == "" - assert source.state.path in str(expected_state_path) - - -def test_import_destination(expected_destination, context_object): - destination_id, expected_configuration_path, expected_state_path = expected_destination - result = click_runner.invoke(octavia_import_destination, destination_id, obj=context_object) - assert result.exit_code == 0 - assert Path(expected_configuration_path).is_file() and Path(expected_state_path).is_file() - destination = resource_factory(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], expected_configuration_path) - assert destination.was_created # Check if the remote resource is considered as managed by octavia and exists remotely - assert destination.get_diff_with_remote_resource() == "" - assert destination.state.path in str(expected_state_path) - assert destination.configuration["password"] == "**********" - - -def test_import_connection(expected_connection, context_object): - connection_id, expected_configuration_path, expected_state_path = expected_connection - result = click_runner.invoke(octavia_import_connection, connection_id, obj=context_object) - assert result.exit_code == 0 - assert Path(expected_configuration_path).is_file() and Path(expected_state_path).is_file() - connection = resource_factory(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], expected_configuration_path) - assert connection.was_created # Check if the remote resource is considered as managed by octavia and exists remotely - assert connection.get_diff_with_remote_resource() == "" - assert connection.state.path in str(expected_state_path) - - -def test_import_all(expected_source, expected_destination, expected_connection, context_object): - _, source_expected_configuration_path, source_expected_state_path = expected_source - _, destination_expected_configuration_path, destination_expected_state_path = expected_destination - _, connection_expected_configuration_path, connection_expected_state_path = expected_connection - paths_to_first_delete_and_then_check_existence = [ - source_expected_configuration_path, - source_expected_state_path, - destination_expected_configuration_path, - destination_expected_state_path, - connection_expected_configuration_path, - connection_expected_state_path, - ] - for path in paths_to_first_delete_and_then_check_existence: - os.remove(path) - result = click_runner.invoke(octavia_import_all, obj=context_object) - assert result.exit_code == 0 - for path in paths_to_first_delete_and_then_check_existence: - assert os.path.exists(path) diff --git a/octavia-cli/integration_tests/test_list/test_listings.py b/octavia-cli/integration_tests/test_list/test_listings.py deleted file mode 100644 index 5775e8255118..000000000000 --- a/octavia-cli/integration_tests/test_list/test_listings.py +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - - -import pytest -from octavia_cli.list.listings import Connections, DestinationConnectorsDefinitions, Destinations, SourceConnectorsDefinitions, Sources - -pytestmark = pytest.mark.integration - - -@pytest.mark.parametrize("ConnectorsDefinitionListing", [SourceConnectorsDefinitions, DestinationConnectorsDefinitions]) -def test_list_connectors(api_client, ConnectorsDefinitionListing): - connector_definitions = ConnectorsDefinitionListing(api_client) - listing = connector_definitions.get_listing() - assert len(listing) > 0 - assert len(listing[0]) == len(ConnectorsDefinitionListing.fields_to_display) - assert str(listing) - - -@pytest.mark.parametrize("WorkspaceListing", [Sources, Destinations, Connections]) -def test_list_workspace_resource(api_client, source, destination, connection, workspace_id, WorkspaceListing): - assert source.was_created - assert destination.was_created - assert connection.was_created - connector_definitions = WorkspaceListing(api_client, workspace_id) - listing = connector_definitions.get_listing() - assert len(listing) >= 1 - assert len(listing[0]) == len(WorkspaceListing.fields_to_display) - assert str(listing) diff --git a/octavia-cli/octavia_cli/__init__.py b/octavia-cli/octavia_cli/__init__.py deleted file mode 100644 index 46b7376756ec..000000000000 --- a/octavia-cli/octavia_cli/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/octavia_cli/_import/__init__.py b/octavia-cli/octavia_cli/_import/__init__.py deleted file mode 100644 index c941b3045795..000000000000 --- a/octavia-cli/octavia_cli/_import/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/octavia_cli/_import/commands.py b/octavia-cli/octavia_cli/_import/commands.py deleted file mode 100644 index b34f8b5a04fb..000000000000 --- a/octavia-cli/octavia_cli/_import/commands.py +++ /dev/null @@ -1,180 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import json -from typing import List, Type, Union - -import airbyte_api_client -import click -from octavia_cli.apply import resources -from octavia_cli.base_commands import OctaviaCommand -from octavia_cli.check_context import requires_init -from octavia_cli.generate import definitions, renderers -from octavia_cli.get.commands import get_json_representation -from octavia_cli.get.resources import Connection as UnmanagedConnection -from octavia_cli.get.resources import Destination as UnmanagedDestination -from octavia_cli.get.resources import Source as UnmanagedSource -from octavia_cli.list.listings import Connections as UnmanagedConnections -from octavia_cli.list.listings import Destinations as UnmanagedDestinations -from octavia_cli.list.listings import Sources as UnmanagedSources - - -class MissingResourceDependencyError(click.UsageError): - pass - - -def build_help_message(resource_type: str) -> str: - """Helper function to build help message consistently for all the commands in this module. - Args: - resource_type (str): source, destination or connection - Returns: - str: The generated help message. - """ - return f"Import an existing {resource_type} to manage it with octavia-cli." - - -def import_source_or_destination( - api_client: airbyte_api_client.ApiClient, - workspace_id: str, - ResourceClass: Type[Union[UnmanagedSource, UnmanagedDestination]], - resource_to_get: str, -) -> str: - """Helper function to import sources & destinations. - - Args: - api_client (airbyte_api_client.ApiClient): the Airbyte API client. - workspace_id (str): current Airbyte workspace id. - ResourceClass (Union[UnmanagedSource, UnmanagedDestination]): the Airbyte Resource Class. - resource_to_get (str): the name or ID of the resource in the current Airbyte workspace id. - - Returns: - str: The generated import message. - """ - remote_configuration = json.loads(get_json_representation(api_client, workspace_id, ResourceClass, resource_to_get)) - - resource_type = ResourceClass.__name__.lower() - - definition = definitions.factory(resource_type, api_client, workspace_id, remote_configuration[f"{resource_type}_definition_id"]) - - renderer = renderers.ConnectorSpecificationRenderer(remote_configuration["name"], definition) - - new_configuration_path = renderer.import_configuration(project_path=".", configuration=remote_configuration["connection_configuration"]) - managed_resource, state = resources.factory(api_client, workspace_id, new_configuration_path).manage( - remote_configuration[f"{resource_type}_id"] - ) - message = f"✅ - Imported {resource_type} {managed_resource.name} in {new_configuration_path}. State stored in {state.path}" - click.echo(click.style(message, fg="green")) - message = f"⚠️ - Please update any secrets stored in {new_configuration_path}" - click.echo(click.style(message, fg="yellow")) - - -def import_connection( - api_client: airbyte_api_client.ApiClient, - workspace_id: str, - resource_to_get: str, -) -> str: - """Helper function to import connection. - - Args: - api_client (airbyte_api_client.ApiClient): the Airbyte API client. - workspace_id (str): current Airbyte workspace id. - resource_to_get (str): the name or ID of the resource in the current Airbyte workspace id. - - Returns: - str: The generated import message. - """ - remote_configuration = json.loads(get_json_representation(api_client, workspace_id, UnmanagedConnection, resource_to_get)) - # Since #15253 "schedule" is deprecated - remote_configuration.pop("schedule", None) - source_name, destination_name = remote_configuration["source"]["name"], remote_configuration["destination"]["name"] - source_configuration_path = renderers.ConnectorSpecificationRenderer.get_output_path( - project_path=".", definition_type="source", resource_name=source_name - ) - - destination_configuration_path = renderers.ConnectorSpecificationRenderer.get_output_path( - project_path=".", definition_type="destination", resource_name=destination_name - ) - if not source_configuration_path.is_file(): - raise MissingResourceDependencyError( - f"The source {source_name} is not managed by octavia-cli, please import and apply it before importing your connection." - ) - elif not destination_configuration_path.is_file(): - raise MissingResourceDependencyError( - f"The destination {destination_name} is not managed by octavia-cli, please import and apply it before importing your connection." - ) - else: - source = resources.factory(api_client, workspace_id, source_configuration_path) - destination = resources.factory(api_client, workspace_id, destination_configuration_path) - if not source.was_created: - raise resources.NonExistingResourceError( - f"The source defined at {source_configuration_path} does not exists. Please run octavia apply before creating this connection." - ) - if not destination.was_created: - raise resources.NonExistingResourceError( - f"The destination defined at {destination_configuration_path} does not exists. Please run octavia apply before creating this connection." - ) - - connection_name, connection_id = remote_configuration["name"], remote_configuration["connection_id"] - connection_renderer = renderers.ConnectionRenderer(connection_name, source, destination) - new_configuration_path = connection_renderer.import_configuration(".", remote_configuration) - managed_resource, state = resources.factory(api_client, workspace_id, new_configuration_path).manage(connection_id) - message = f"✅ - Imported connection {managed_resource.name} in {new_configuration_path}. State stored in {state.path}" - click.echo(click.style(message, fg="green")) - - -@click.group( - "import", - help=f'{build_help_message("source, destination or connection")}. ID or name can be used as argument. Example: \'octavia import source "My Pokemon source"\' or \'octavia import source cb5413b2-4159-46a2-910a-dc282a439d2d\'', -) -@click.pass_context -def _import(ctx: click.Context): # pragma: no cover - pass - - -@_import.command(cls=OctaviaCommand, name="source", help=build_help_message("source")) -@click.argument("resource", type=click.STRING) -@click.pass_context -@requires_init -def source(ctx: click.Context, resource: str): - click.echo(import_source_or_destination(ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"], UnmanagedSource, resource)) - - -@_import.command(cls=OctaviaCommand, name="destination", help=build_help_message("destination")) -@click.argument("resource", type=click.STRING) -@click.pass_context -@requires_init -def destination(ctx: click.Context, resource: str): - click.echo(import_source_or_destination(ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"], UnmanagedDestination, resource)) - - -@_import.command(cls=OctaviaCommand, name="connection", help=build_help_message("connection")) -@click.argument("resource", type=click.STRING) -@click.pass_context -@requires_init -def connection(ctx: click.Context, resource: str): - click.echo(import_connection(ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"], resource)) - - -@_import.command(cls=OctaviaCommand, name="all", help=build_help_message("all")) -@click.pass_context -@requires_init -def all(ctx: click.Context): - api_client, workspace_id = ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"] - for _, _, resource_id in UnmanagedSources(api_client, workspace_id).get_listing(): - import_source_or_destination(api_client, workspace_id, UnmanagedSource, resource_id) - for _, _, resource_id in UnmanagedDestinations(api_client, workspace_id).get_listing(): - import_source_or_destination(api_client, workspace_id, UnmanagedDestination, resource_id) - for _, resource_id, _, _, _ in UnmanagedConnections(api_client, workspace_id).get_listing(): - import_connection(api_client, workspace_id, resource_id) - - -AVAILABLE_COMMANDS: List[click.Command] = [source, destination, connection] - - -def add_commands_to_list(): - for command in AVAILABLE_COMMANDS: - _import.add_command(command) - - -add_commands_to_list() diff --git a/octavia-cli/octavia_cli/api_http_headers.py b/octavia-cli/octavia_cli/api_http_headers.py deleted file mode 100644 index 95fd7117e0ee..000000000000 --- a/octavia-cli/octavia_cli/api_http_headers.py +++ /dev/null @@ -1,106 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from dataclasses import dataclass -from typing import List, Optional, Tuple - -import airbyte_api_client -import click -import yaml - -from .apply.yaml_loaders import EnvVarLoader -from .init.commands import API_HTTP_HEADERS_TARGET_PATH - - -class InvalidApiHttpHeadersFileError(click.exceptions.ClickException): - pass - - -@dataclass -class ApiHttpHeader: - name: str - value: str - - def __post_init__(self): - try: - assert isinstance(self.name, str) and self.name - assert isinstance(self.value, str) and self.value - except AssertionError: - raise AttributeError("Header name and value must be non empty string.") - self.name = self.name.strip() - self.value = self.value.strip() - - -def deserialize_file_based_headers(header_configuration_path: str) -> List[ApiHttpHeader]: - """Parse API HTTP headers declared in a YAML file to a list of ApiHttpHeaders - - Args: - header_configuration_path (str): Path to the YAML file where API HTTP headers are declared. - - Raises: - InvalidApiHttpHeadersFileError: Raised if the YAML structure is not valid. - - Returns: - List[ApiHttpHeader]: List of HTTP headers parsed from the YAML file. - """ - with open(header_configuration_path) as file: - try: - content = yaml.load(file, EnvVarLoader) - headers = content["headers"] - except (TypeError, KeyError, yaml.scanner.ScannerError): - raise InvalidApiHttpHeadersFileError( - f"Please provide valid yaml file to declare API HTTP headers. Please check the {API_HTTP_HEADERS_TARGET_PATH} file." - ) - - return [ApiHttpHeader(name, value) for name, value in headers.items()] - - -def deserialize_option_based_headers(api_http_headers: List[Tuple[str, str]]) -> List[ApiHttpHeader]: - """Parse API HTTP headers declared in CLI options to a list of ApiHttpHeaders - - Args: - api_http_headers (List[Tuple[str, str]]): Raw list of api headers tuples retrieved from CLI options. - - Returns: - List[ApiHttpHeader]: List of HTTP headers parsed from the CLI options. - """ - return list({header_name: ApiHttpHeader(header_name, header_value) for header_name, header_value in api_http_headers}.values()) - - -def merge_api_headers( - option_based_api_http_headers: Optional[List[Tuple[str, str]]], api_http_headers_file_path: Optional[str] -) -> List[ApiHttpHeader]: - """Deserialize headers from options and files into ApiHttpHeader and merge options based headers with file based headers. - - Args: - option_based_api_http_headers (Optional[List[Tuple[str, str]]]): Option based headers. - api_http_headers_file_path (Optional[str]): Path to the YAML file with http headers. - - Returns: - List[ApiHttpHeader]: Lit of unique ApiHttpHeaders - """ - if option_based_api_http_headers and api_http_headers_file_path: - click.echo( - "ℹ️ - You passed API HTTP headers in a file and in options at the same time. Option based headers will override file based headers." - ) - option_based_headers = ( - deserialize_option_based_headers(option_based_api_http_headers) if option_based_api_http_headers is not None else [] - ) - file_based_headers = deserialize_file_based_headers(api_http_headers_file_path) if api_http_headers_file_path else [] - - merged_headers = {header.name: header for header in file_based_headers} - for header in option_based_headers: - merged_headers[header.name] = header - return list(merged_headers.values()) - - -def set_api_headers_on_api_client(api_client: airbyte_api_client.ApiClient, api_headers: List[ApiHttpHeader]) -> None: - """Set the API headers on the API client - - Args: - api_client (airbyte_api_client.ApiClient): The API client on which headers will be set. - api_headers (List[ApiHttpHeader]): Headers to set on the API client. - """ - for api_header in api_headers: - api_client.set_default_header(api_header.name, api_header.value) diff --git a/octavia-cli/octavia_cli/apply/__init__.py b/octavia-cli/octavia_cli/apply/__init__.py deleted file mode 100644 index 46b7376756ec..000000000000 --- a/octavia-cli/octavia_cli/apply/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/octavia_cli/apply/commands.py b/octavia-cli/octavia_cli/apply/commands.py deleted file mode 100644 index 4a1a6d5fdd7d..000000000000 --- a/octavia-cli/octavia_cli/apply/commands.py +++ /dev/null @@ -1,172 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from glob import glob -from typing import List, Optional, Tuple - -import airbyte_api_client -import click -from octavia_cli.base_commands import OctaviaCommand -from octavia_cli.check_context import REQUIRED_PROJECT_DIRECTORIES, requires_init - -from .diff_helpers import display_diff_line -from .resources import BaseResource -from .resources import factory as resource_factory - - -@click.command(cls=OctaviaCommand, name="apply", help="Create or update Airbyte remote resources according local YAML configurations.") -@click.option("--file", "-f", "configurations_files", type=click.Path(), multiple=True) -@click.option("--force", is_flag=True, default=False, help="Does not display the diff and updates without user prompt.") -@click.pass_context -@requires_init -def apply(ctx: click.Context, configurations_files: List[click.Path], force: bool): - if not configurations_files: - configurations_files = find_local_configuration_files() - - resources = get_resources_to_apply(configurations_files, ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"]) - for resource in resources: - apply_single_resource(resource, force) - - -def get_resources_to_apply( - configuration_files: List[str], api_client: airbyte_api_client.ApiClient, workspace_id: str -) -> List[BaseResource]: - """Create resource objects with factory and sort according to apply priority. - - Args: - configuration_files (List[str]): List of YAML configuration files. - api_client (airbyte_api_client.ApiClient): the Airbyte API client. - workspace_id (str): current Airbyte workspace id. - - Returns: - List[BaseResource]: Resources sorted according to their apply priority. - """ - all_resources = [resource_factory(api_client, workspace_id, path) for path in configuration_files] - return sorted(all_resources, key=lambda resource: resource.APPLY_PRIORITY) - - -def apply_single_resource(resource: BaseResource, force: bool) -> None: - """Runs resource creation if it was not created, update it otherwise. - - Args: - resource (BaseResource): The resource to apply. - force (bool): Whether force mode is on. - """ - if resource.was_created: - click.echo( - click.style( - f"🐙 - {resource.resource_name} exists on your Airbyte instance according to your state file, let's check if we need to update it!", - fg="yellow", - ) - ) - messages = update_resource(resource, force) - else: - click.echo(click.style(f"🐙 - {resource.resource_name} does not exists on your Airbyte instance, let's create it!", fg="green")) - messages = create_resource(resource) - click.echo("\n".join(messages)) - - -def should_update_resource(force: bool, user_validation: Optional[bool], local_file_changed: bool) -> Tuple[bool, str]: - """Function to decide if the resource needs an update or not. - - Args: - force (bool): Whether force mode is on. - user_validation (bool): User validated the existing changes. - local_file_changed (bool): Whether the local file describing the resource was modified. - - Returns: - Tuple[bool, str]: Boolean to know if resource should be updated and string describing the update reason. - """ - if force: - should_update, update_reason = True, "🚨 - Running update because the force mode is activated." - elif user_validation is True: - should_update, update_reason = True, "🟢 - Running update because you validated the changes." - elif user_validation is False: - should_update, update_reason = False, "🔴 - Did not update because you refused the changes." - elif user_validation is None and local_file_changed: - should_update, update_reason = ( - True, - "🟡 - Running update because a local file change was detected and a secret field might have been edited.", - ) - else: - should_update, update_reason = False, "😴 - Did not update because no change detected." - return should_update, click.style(update_reason, fg="green") - - -def prompt_for_diff_validation(resource_name: str, diff: str) -> bool: - """Display the diff to user and prompt them from validation. - - Args: - resource_name (str): Name of the resource the diff was computed for. - diff (str): The diff. - - Returns: - bool: Whether user validated the diff. - """ - if diff: - click.echo( - click.style("👀 - Here's the computed diff (🚨 remind that diff on secret fields are not displayed):", fg="magenta", bold=True) - ) - for line in diff.split("\n"): - display_diff_line(line) - return click.confirm(click.style(f"❓ - Do you want to update {resource_name}?", bold=True)) - else: - return False - - -def create_resource(resource: BaseResource) -> List[str]: - """Run a resource creation. - - Args: - resource (BaseResource): The resource to create. - - Returns: - List[str]: Post create messages to display to standard output. - """ - created_resource, state = resource.create() - return [ - click.style(f"🎉 - Successfully created {created_resource.name} on your Airbyte instance!", fg="green", bold=True), - click.style(f"💾 - New state for {created_resource.name} saved at {state.path}", fg="yellow"), - ] - - -def update_resource(resource: BaseResource, force: bool) -> List[str]: - """Run a resource update. Check if update is required and prompt for user diff validation if needed. - - Args: - resource (BaseResource): Resource to update - force (bool): Whether force mode is on. - - Returns: - List[str]: Post update messages to display to standard output. - """ - output_messages = [] - diff = resource.get_diff_with_remote_resource() - user_validation = None - if not force and diff: - user_validation = prompt_for_diff_validation(resource.resource_name, diff) - should_update, update_reason = should_update_resource(force, user_validation, resource.local_file_changed) - click.echo(update_reason) - - if should_update: - updated_resource, state = resource.update() - output_messages.append( - click.style(f"🎉 - Successfully updated {updated_resource.name} on your Airbyte instance!", fg="green", bold=True) - ) - output_messages.append(click.style(f"💾 - New state for {updated_resource.name} stored at {state.path}.", fg="yellow")) - return output_messages - - -def find_local_configuration_files() -> List[str]: - """Discover local configuration files. - - Returns: - List[str]: Paths to YAML configuration files. - """ - configuration_files = [] - for resource_directory in REQUIRED_PROJECT_DIRECTORIES: - configuration_files += glob(f"./{resource_directory}/**/configuration.yaml") - if not configuration_files: - click.echo(click.style("😒 - No YAML file found to run apply.", fg="red")) - return configuration_files diff --git a/octavia-cli/octavia_cli/apply/diff_helpers.py b/octavia-cli/octavia_cli/apply/diff_helpers.py deleted file mode 100644 index 7d4d7c06d18d..000000000000 --- a/octavia-cli/octavia_cli/apply/diff_helpers.py +++ /dev/null @@ -1,75 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import hashlib -import json -from typing import Any - -import click -from deepdiff import DeepDiff - -SECRET_MASK = "**********" - - -def hash_config(configuration: dict) -> str: - """Computes a SHA256 hash from a dictionnary. - - Args: - configuration (dict): The configuration to hash - - Returns: - str: _description_ - """ - stringified = json.dumps(configuration, sort_keys=True) - return hashlib.sha256(stringified.encode("utf-8")).hexdigest() - - -def exclude_secrets_from_diff(obj: Any, path: str) -> bool: - """Callback function used with DeepDiff to ignore secret values from the diff. - - Args: - obj (Any): Object for which a diff will be computed. - path (str): unused. - - Returns: - bool: Whether to ignore the object from the diff. - """ - if isinstance(obj, str): - return True if SECRET_MASK in obj else False - else: - return False - - -def compute_diff(a: Any, b: Any) -> DeepDiff: - """Wrapper around the DeepDiff computation. - - Args: - a (Any): Object to compare with b. - b (Any): Object to compare with a. - - Returns: - DeepDiff: the computed diff object. - """ - return DeepDiff(a, b, view="tree", exclude_obj_callback=exclude_secrets_from_diff) - - -def display_diff_line(diff_line: str) -> None: - """Prettify a diff line and print it to standard output. - - Args: - diff_line (str): The diff line to display. - """ - if "changed from" in diff_line: - color = "yellow" - prefix = "E" - elif "added" in diff_line: - color = "green" - prefix = "+" - elif "removed" in diff_line: - color = "red" - prefix = "-" - else: - prefix = "" - color = None - click.echo(click.style(f"\t{prefix} - {diff_line}", fg=color)) diff --git a/octavia-cli/octavia_cli/apply/resources.py b/octavia-cli/octavia_cli/apply/resources.py deleted file mode 100644 index 0356abd4732d..000000000000 --- a/octavia-cli/octavia_cli/apply/resources.py +++ /dev/null @@ -1,886 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import abc -import os -import time -from copy import deepcopy -from pathlib import Path -from typing import Callable, List, Optional, Set, Tuple, Type, Union - -import airbyte_api_client -import click -import yaml -from airbyte_api_client.api import ( - destination_api, - destination_definition_api, - destination_definition_specification_api, - source_api, - source_definition_api, - source_definition_specification_api, - web_backend_api, -) -from airbyte_api_client.model.airbyte_catalog import AirbyteCatalog -from airbyte_api_client.model.airbyte_stream import AirbyteStream -from airbyte_api_client.model.airbyte_stream_and_configuration import AirbyteStreamAndConfiguration -from airbyte_api_client.model.airbyte_stream_configuration import AirbyteStreamConfiguration -from airbyte_api_client.model.connection_read import ConnectionRead -from airbyte_api_client.model.connection_schedule_data import ConnectionScheduleData -from airbyte_api_client.model.connection_schedule_data_basic_schedule import ConnectionScheduleDataBasicSchedule -from airbyte_api_client.model.connection_schedule_data_cron import ConnectionScheduleDataCron -from airbyte_api_client.model.connection_schedule_type import ConnectionScheduleType -from airbyte_api_client.model.connection_status import ConnectionStatus -from airbyte_api_client.model.destination_create import DestinationCreate -from airbyte_api_client.model.destination_definition_id_request_body import DestinationDefinitionIdRequestBody -from airbyte_api_client.model.destination_definition_id_with_workspace_id import DestinationDefinitionIdWithWorkspaceId -from airbyte_api_client.model.destination_definition_read import DestinationDefinitionRead -from airbyte_api_client.model.destination_definition_specification_read import DestinationDefinitionSpecificationRead -from airbyte_api_client.model.destination_id_request_body import DestinationIdRequestBody -from airbyte_api_client.model.destination_read import DestinationRead -from airbyte_api_client.model.destination_sync_mode import DestinationSyncMode -from airbyte_api_client.model.destination_update import DestinationUpdate -from airbyte_api_client.model.geography import Geography -from airbyte_api_client.model.namespace_definition_type import NamespaceDefinitionType -from airbyte_api_client.model.non_breaking_changes_preference import NonBreakingChangesPreference -from airbyte_api_client.model.operation_create import OperationCreate -from airbyte_api_client.model.operator_configuration import OperatorConfiguration -from airbyte_api_client.model.operator_dbt import OperatorDbt -from airbyte_api_client.model.operator_normalization import OperatorNormalization -from airbyte_api_client.model.operator_type import OperatorType -from airbyte_api_client.model.resource_requirements import ResourceRequirements -from airbyte_api_client.model.selected_field_info import SelectedFieldInfo -from airbyte_api_client.model.source_create import SourceCreate -from airbyte_api_client.model.source_definition_id_request_body import SourceDefinitionIdRequestBody -from airbyte_api_client.model.source_definition_id_with_workspace_id import SourceDefinitionIdWithWorkspaceId -from airbyte_api_client.model.source_definition_read import SourceDefinitionRead -from airbyte_api_client.model.source_definition_specification_read import SourceDefinitionSpecificationRead -from airbyte_api_client.model.source_discover_schema_request_body import SourceDiscoverSchemaRequestBody -from airbyte_api_client.model.source_id_request_body import SourceIdRequestBody -from airbyte_api_client.model.source_read import SourceRead -from airbyte_api_client.model.source_update import SourceUpdate -from airbyte_api_client.model.sync_mode import SyncMode -from airbyte_api_client.model.web_backend_connection_create import WebBackendConnectionCreate -from airbyte_api_client.model.web_backend_connection_request_body import WebBackendConnectionRequestBody -from airbyte_api_client.model.web_backend_connection_update import WebBackendConnectionUpdate -from airbyte_api_client.model.web_backend_operation_create_or_update import WebBackendOperationCreateOrUpdate - -from .diff_helpers import compute_diff, hash_config -from .yaml_loaders import EnvVarLoader - - -class NonExistingResourceError(click.ClickException): - pass - - -class InvalidConfigurationError(click.ClickException): - pass - - -class InvalidStateError(click.ClickException): - pass - - -class MissingStateError(click.ClickException): - pass - - -class ResourceState: - def __init__( - self, - configuration_path: Union[str, Path], - workspace_id: Optional[str], - resource_id: str, - generation_timestamp: int, - configuration_hash: str, - ): - """This constructor is meant to be private. Construction shall be made with create or from_file class methods. - Args: - configuration_path (str): Path to the configuration this state relates to. - workspace_id Optional(str): Id of the workspace the state relates to. #TODO mark this a not optional after the user base has upgraded to >= 0.39.18 - resource_id (str): Id of the resource the state relates to. - generation_timestamp (int): State generation timestamp. - configuration_hash (str): Hash of the loaded configuration file. - """ - self.configuration_path = str(configuration_path) - self.resource_id = resource_id - self.generation_timestamp = generation_timestamp - self.configuration_hash = configuration_hash - self.workspace_id = workspace_id - self.path = self._get_path_from_configuration_and_workspace_id(configuration_path, workspace_id) - - def as_dict(self): - return { - "resource_id": self.resource_id, - "workspace_id": self.workspace_id, - "generation_timestamp": self.generation_timestamp, - "configuration_path": self.configuration_path, - "configuration_hash": self.configuration_hash, - } - - def _save(self) -> None: - """Save the state as a YAML file.""" - with open(self.path, "w") as state_file: - yaml.dump(self.as_dict(), state_file) - - @classmethod - def create(cls, configuration_path: str, configuration_hash: str, workspace_id: str, resource_id: str) -> "ResourceState": - """Create a state for a resource configuration. - Args: - configuration_path (str): Path to the YAML file defining the resource. - configuration_hash (str): Hash of the loaded configuration fie. - resource_id (str): UUID of the resource. - Returns: - ResourceState: state representing the resource. - """ - generation_timestamp = int(time.time()) - state = ResourceState(configuration_path, workspace_id, resource_id, generation_timestamp, configuration_hash) - state._save() - return state - - def delete(self) -> None: - """Delete the state file""" - os.remove(self.path) - - @classmethod - def from_file(cls, file_path: str) -> "ResourceState": - """Deserialize a state from a YAML path. - Args: - file_path (str): Path to the YAML state. - Returns: - ResourceState: state deserialized from YAML. - """ - with open(file_path, "r") as f: - raw_state = yaml.safe_load(f) - return ResourceState( - raw_state["configuration_path"], - # TODO: workspace id should not be nullable after the user base has upgraded to >= 0.39.18 - raw_state.get("workspace_id"), - raw_state["resource_id"], - raw_state["generation_timestamp"], - raw_state["configuration_hash"], - ) - - @classmethod - def _get_path_from_configuration_and_workspace_id(cls, configuration_path, workspace_id): - return os.path.join(os.path.dirname(configuration_path), f"state_{workspace_id}.yaml") - - @classmethod - def from_configuration_path_and_workspace(cls, configuration_path, workspace_id): - state_path = cls._get_path_from_configuration_and_workspace_id(configuration_path, workspace_id) - state = cls.from_file(state_path) - return state - - @classmethod - def migrate(self, state_to_migrate_path: str, workspace_id: str) -> "ResourceState": - """Create a per workspace state from a legacy state file and remove the legacy state file. - Args: - state_to_migrate_path (str): Path to the legacy state file to migrate. - workspace_id (str): Workspace id for which the new state will be stored. - Returns: - ResourceState: The new state after migration. - """ - state_to_migrate = ResourceState.from_file(state_to_migrate_path) - new_state = ResourceState.create( - state_to_migrate.configuration_path, state_to_migrate.configuration_hash, workspace_id, state_to_migrate.resource_id - ) - state_to_migrate.delete() - return new_state - - -class BaseResource(abc.ABC): - # Priority of the resource during the apply. 0 means the resource is top priority. - APPLY_PRIORITY = 0 - - @property - @abc.abstractmethod - def api( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def create_function_name( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def create_payload( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def update_payload( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def update_function_name( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def get_function_name( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def get_payload( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def resource_id_field( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def resource_type( - self, - ): # pragma: no cover - pass - - def __init__( - self, api_client: airbyte_api_client.ApiClient, workspace_id: str, raw_configuration: dict, configuration_path: str - ) -> None: - """Create a BaseResource object. - Args: - api_client (airbyte_api_client.ApiClient): the Airbyte API client. - workspace_id (str): the workspace id. - raw_configuration (dict): The local configuration describing the resource. - configuration_path (str): The path to the local configuration describing the resource with YAML. - """ - self._create_fn = getattr(self.api, self.create_function_name) - self._update_fn = getattr(self.api, self.update_function_name) - self._get_fn = getattr(self.api, self.get_function_name) - - self.workspace_id = workspace_id - self.configuration_path = configuration_path - self.state = self._get_state_from_file(configuration_path, workspace_id) - self.configuration_hash = hash_config( - raw_configuration - ) # Hash as early as possible to limit risks of raw_configuration downstream mutations. - - self.local_file_changed = True if self.state is None else self.configuration_hash != self.state.configuration_hash - - self.raw_configuration = raw_configuration - self.configuration = self._deserialize_raw_configuration() - self.api_client = api_client - self.api_instance = self.api(api_client) - self.resource_name = raw_configuration["resource_name"] - - def _deserialize_raw_configuration(self): - """Deserialize a raw configuration into another object and perform extra validation if needed. - The base implementation does nothing except extracting the configuration field and returning a copy of it. - Returns: - dict: Deserialized configuration - """ - return deepcopy(self.raw_configuration["configuration"]) - - @staticmethod - def _check_for_invalid_configuration_keys(dict_to_check: dict, invalid_keys: Set[str], error_message: str): - """Utils function to check if a configuration dictionnary has legacy keys that were removed/renamed after an octavia update. - Args: - dict_to_check (dict): The dictionnary for which keys should be checked - invalid_keys (Set[str]): The set of invalid keys we want to check the existence - error_message (str): The error message to display to the user - Raises: - InvalidConfigurationError: Raised if an invalid key was found in the dict_to_check - """ - invalid_keys = list(set(dict_to_check.keys()) & invalid_keys) - if invalid_keys: - raise InvalidConfigurationError(f"Invalid configuration keys: {', '.join(invalid_keys)}. {error_message}. ") - - @property - def remote_resource(self): - return self._get_remote_resource() if self.state else None - - def _get_local_comparable_configuration(self) -> dict: - return self.raw_configuration["configuration"] - - @abc.abstractmethod - def _get_remote_comparable_configuration( - self, - ) -> dict: # pragma: no cover - raise NotImplementedError - - @property - def was_created(self): - return True if self.remote_resource else False - - def _get_remote_resource(self) -> Union[SourceRead, DestinationRead, ConnectionRead]: - """Retrieve a resources on the remote Airbyte instance. - Returns: - Union[SourceReadList, DestinationReadList, ConnectionReadList]: Search results - """ - return self._get_fn(self.api_instance, self.get_payload) - - @staticmethod - def _get_state_from_file(configuration_file: str, workspace_id: str) -> Optional[ResourceState]: - """Retrieve a state object from a local YAML file if it exists. - Returns: - Optional[ResourceState]: the deserialized resource state if YAML file found. - """ - expected_state_path = Path(os.path.join(os.path.dirname(configuration_file), f"state_{workspace_id}.yaml")) - legacy_state_path = Path(os.path.join(os.path.dirname(configuration_file), "state.yaml")) - if expected_state_path.is_file(): - return ResourceState.from_file(expected_state_path) - elif legacy_state_path.is_file(): # TODO: remove condition after user base has upgraded to >= 0.39.18 - if click.confirm( - click.style( - f"⚠️ - State files are now saved on a workspace basis. Do you want octavia to rename and update {legacy_state_path}? ", - fg="red", - ) - ): - return ResourceState.migrate(legacy_state_path, workspace_id) - else: - raise InvalidStateError( - f"Octavia expects the state file to be located at {expected_state_path} with a workspace_id key. Please update {legacy_state_path}." - ) - else: - return None - - def get_diff_with_remote_resource(self) -> str: - """Compute the diff between current resource and the remote resource. - Raises: - NonExistingResourceError: Raised if the remote resource does not exist. - Returns: - str: The prettyfied diff. - """ - if not self.was_created: - raise NonExistingResourceError("Cannot compute diff with a non existing remote resource.") - local_config = self._get_local_comparable_configuration() - remote_config = self._get_remote_comparable_configuration() - diff = compute_diff(remote_config, local_config) - return diff.pretty() - - def _create_or_update( - self, - operation_fn: Callable, - payload: Union[ - SourceCreate, SourceUpdate, DestinationCreate, DestinationUpdate, WebBackendConnectionCreate, WebBackendConnectionUpdate - ], - ) -> Union[SourceRead, DestinationRead]: - """Wrapper to trigger create or update of remote resource. - Args: - operation_fn (Callable): The API function to run. - payload (Union[SourceCreate, SourceUpdate, DestinationCreate, DestinationUpdate]): The payload to send to create or update the resource. - . - Raises: - InvalidConfigurationError: Raised if the create or update payload is invalid. - ApiException: Raised in case of other API errors. - Returns: - Union[SourceRead, DestinationRead, ConnectionRead]: The created or updated resource. - """ - try: - result = operation_fn(self.api_instance, payload) - new_state = ResourceState.create( - self.configuration_path, self.configuration_hash, self.workspace_id, result[self.resource_id_field] - ) - return result, new_state - except airbyte_api_client.ApiException as api_error: - if api_error.status == 422: - # This API response error is really verbose, but it embodies all the details about why the config is not valid. - # TODO alafanechere: try to parse it and display it in a more readable way. - raise InvalidConfigurationError(api_error.body) - else: - raise api_error - - def manage( - self, resource_id: str - ) -> Union[Tuple[SourceRead, ResourceState], Tuple[DestinationRead, ResourceState], Tuple[ConnectionRead, ResourceState]]: - """Declare a remote resource as locally managed by creating a local state - - Args: - resource_id (str): Remote resource ID. - - Returns: - Union[Tuple[SourceRead, ResourceState], Tuple[DestinationRead, ResourceState], Tuple[ConnectionRead, ResourceState]]: The remote resource model instance and its local state. - """ - self.state = ResourceState.create(self.configuration_path, self.configuration_hash, self.workspace_id, resource_id) - - return self.remote_resource, self.state - - def create(self) -> Union[SourceRead, DestinationRead, ConnectionRead]: - """Public function to create the resource on the remote Airbyte instance. - Returns: - Union[SourceRead, DestinationRead, ConnectionRead]: The created resource. - """ - return self._create_or_update(self._create_fn, self.create_payload) - - def update(self) -> Union[SourceRead, DestinationRead, ConnectionRead]: - """Public function to update the resource on the remote Airbyte instance. - Returns: - Union[SourceRead, DestinationRead, ConnectionRead]: The updated resource. - """ - return self._create_or_update(self._update_fn, self.update_payload) - - @property - def resource_id(self) -> Optional[str]: - """Exposes the resource UUID of the remote resource - Returns: - str: Remote resource's UUID - """ - return self.state.resource_id if self.state is not None else None - - -class SourceAndDestination(BaseResource): - @property - @abc.abstractmethod - def definition( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def definition_specification( - self, - ): # pragma: no cover - pass - - @property - def definition_id(self): - return self.raw_configuration["definition_id"] - - @property - def definition_image(self): - return self.raw_configuration["definition_image"] - - @property - def definition_version(self): - return self.raw_configuration["definition_version"] - - def _get_remote_comparable_configuration(self) -> dict: - return self.remote_resource.connection_configuration - - -class Source(SourceAndDestination): - - api = source_api.SourceApi - create_function_name = "create_source" - resource_id_field = "source_id" - get_function_name = "get_source" - update_function_name = "update_source" - resource_type = "source" - - @property - def create_payload(self): - return SourceCreate(self.definition_id, self.configuration, self.workspace_id, self.resource_name) - - @property - def get_payload(self) -> Optional[SourceIdRequestBody]: - """Defines the payload to retrieve the remote source if a state exists. - Returns: - SourceIdRequestBody: The SourceIdRequestBody payload. - """ - if self.state is not None: - return SourceIdRequestBody(self.state.resource_id) - - @property - def update_payload(self): - return SourceUpdate( - source_id=self.resource_id, - connection_configuration=self.configuration, - name=self.resource_name, - ) - - @property - def source_discover_schema_request_body(self) -> SourceDiscoverSchemaRequestBody: - """Creates SourceDiscoverSchemaRequestBody from resource id. - Raises: - NonExistingResourceError: raised if the resource id is None. - Returns: - SourceDiscoverSchemaRequestBody: The SourceDiscoverSchemaRequestBody model instance. - """ - if self.resource_id is None: - raise NonExistingResourceError("The resource id could not be retrieved, the remote resource is not existing.") - return SourceDiscoverSchemaRequestBody(self.resource_id) - - @property - def catalog(self) -> AirbyteCatalog: - """Retrieves the source's Airbyte catalog. - Returns: - AirbyteCatalog: The catalog issued by schema discovery. - """ - schema = self.api_instance.discover_schema_for_source(self.source_discover_schema_request_body) - if schema.job_info.succeeded: - return schema.catalog - raise Exception("Could not discover schema for source", self.source_discover_schema_request_body, schema.job_info.logs) - - @property - def definition(self) -> SourceDefinitionRead: - api_instance = source_definition_api.SourceDefinitionApi(self.api_client) - payload = SourceDefinitionIdRequestBody(source_definition_id=self.definition_id) - return api_instance.get_source_definition(payload) - - @property - def definition_specification(self) -> SourceDefinitionSpecificationRead: - api_instance = source_definition_specification_api.SourceDefinitionSpecificationApi(self.api_client) - payload = SourceDefinitionIdWithWorkspaceId(source_definition_id=self.definition_id, workspace_id=self.workspace_id) - return api_instance.get_source_definition_specification(payload) - - -class Destination(SourceAndDestination): - api = destination_api.DestinationApi - create_function_name = "create_destination" - resource_id_field = "destination_id" - get_function_name = "get_destination" - update_function_name = "update_destination" - resource_type = "destination" - - @property - def create_payload(self) -> DestinationCreate: - """Defines the payload to create the remote resource. - Returns: - DestinationCreate: The DestinationCreate model instance - """ - return DestinationCreate(self.workspace_id, self.resource_name, self.definition_id, self.configuration) - - @property - def get_payload(self) -> Optional[DestinationRead]: - """Defines the payload to retrieve the remote destination if a state exists. - Returns: - DestinationRead: The DestinationRead model instance - """ - if self.state is not None: - return DestinationIdRequestBody(self.state.resource_id) - - @property - def update_payload(self) -> DestinationUpdate: - """Defines the payload to update a remote resource. - Returns: - DestinationUpdate: The DestinationUpdate model instance. - """ - return DestinationUpdate( - destination_id=self.resource_id, - connection_configuration=self.configuration, - name=self.resource_name, - ) - - @property - def definition(self) -> DestinationDefinitionRead: - api_instance = destination_definition_api.DestinationDefinitionApi(self.api_client) - payload = DestinationDefinitionIdRequestBody(destination_definition_id=self.definition_id) - return api_instance.get_destination_definition(payload) - - @property - def definition_specification(self) -> DestinationDefinitionSpecificationRead: - api_instance = destination_definition_specification_api.DestinationDefinitionSpecificationApi(self.api_client) - payload = DestinationDefinitionIdWithWorkspaceId(destination_definition_id=self.definition_id, workspace_id=self.workspace_id) - return api_instance.get_destination_definition_specification(payload) - - -class Connection(BaseResource): - # Set to 1 to create connection after source or destination. - APPLY_PRIORITY = 1 - api = web_backend_api.WebBackendApi - create_function_name = "web_backend_create_connection" - update_function_name = "web_backend_update_connection" - get_function_name = "web_backend_get_connection" - resource_id_field = "connection_id" - - resource_type = "connection" - - local_root_level_keys_to_remove_during_create = ["skip_reset"] # Remove these keys when sending a create request - - local_root_level_keys_to_filter_out_for_comparison = ["skip_reset"] # Remote do not have these keys - - remote_root_level_keys_to_filter_out_for_comparison = [ - "name", - "source", - "destination", - "source_id", - "destination_id", - "connection_id", - "operation_ids", - "source_catalog_id", - "catalog_id", - "is_syncing", - "latest_sync_job_status", - "latest_sync_job_created_at", - "schedule", - ] # We do not allow local editing of these keys - - # We do not allow local editing of these keys - remote_operation_level_keys_to_filter_out = ["workspace_id", "operation_id"] - - def _deserialize_raw_configuration(self): - """Deserialize a raw configuration into another dict and perform serialization if needed. - In this implementation we cast raw types to Airbyte API client models types for validation. - Args: - raw_configuration (dict): The raw configuration - Returns: - dict: Deserialized connection configuration - """ - self._check_for_legacy_raw_configuration_keys(self.raw_configuration) - configuration = super()._deserialize_raw_configuration() - self._check_for_legacy_connection_configuration_keys(configuration) - configuration["sync_catalog"] = self._create_configured_catalog(configuration["sync_catalog"]) - configuration["namespace_definition"] = NamespaceDefinitionType(configuration["namespace_definition"]) - if "non_breaking_changes_preference" in configuration: - configuration["non_breaking_changes_preference"] = NonBreakingChangesPreference( - configuration["non_breaking_changes_preference"] - ) - else: - configuration["non_breaking_changes_preference"] = NonBreakingChangesPreference("ignore") - if "geography" in configuration: - configuration["geography"] = Geography(configuration["geography"]) - else: - configuration["geography"] = Geography("auto") - - if "schedule_type" in configuration: - # If schedule type is manual we do not expect a schedule_data field to be set - # TODO: sending a WebConnectionCreate payload without schedule_data (for manual) fails. - is_manual = configuration["schedule_type"] == "manual" - configuration["schedule_type"] = ConnectionScheduleType(configuration["schedule_type"]) - if not is_manual: - if "basic_schedule" in configuration["schedule_data"]: - basic_schedule = ConnectionScheduleDataBasicSchedule(**configuration["schedule_data"]["basic_schedule"]) - configuration["schedule_data"]["basic_schedule"] = basic_schedule - if "cron" in configuration["schedule_data"]: - cron = ConnectionScheduleDataCron(**configuration["schedule_data"]["cron"]) - configuration["schedule_data"]["cron"] = cron - configuration["schedule_data"] = ConnectionScheduleData(**configuration["schedule_data"]) - if "resource_requirements" in configuration: - configuration["resource_requirements"] = ResourceRequirements(**configuration["resource_requirements"]) - configuration["status"] = ConnectionStatus(configuration["status"]) - return configuration - - @property - def source_id(self): - """Retrieve the source id from the source state file of the current workspace. - Raises: - MissingStateError: Raised if the state file of the current workspace is not found. - Returns: - str: source id - """ - try: - source_state = ResourceState.from_configuration_path_and_workspace( - self.raw_configuration["source_configuration_path"], self.workspace_id - ) - except FileNotFoundError: - raise MissingStateError( - f"Could not find the source state file for configuration {self.raw_configuration['source_configuration_path']}." - ) - return source_state.resource_id - - @property - def destination_id(self): - """Retrieve the destination id from the destination state file of the current workspace. - Raises: - MissingStateError: Raised if the state file of the current workspace is not found. - Returns: - str: destination id - """ - try: - destination_state = ResourceState.from_configuration_path_and_workspace( - self.raw_configuration["destination_configuration_path"], self.workspace_id - ) - except FileNotFoundError: - raise MissingStateError( - f"Could not find the destination state file for configuration {self.raw_configuration['destination_configuration_path']}." - ) - return destination_state.resource_id - - @property - def create_payload(self) -> WebBackendConnectionCreate: - """Defines the payload to create the remote connection. - Returns: - WebBackendConnectionCreate: The WebBackendConnectionCreate model instance - """ - - if self.raw_configuration["configuration"].get("operations") is not None: - self.configuration["operations"] = self._deserialize_operations( - self.raw_configuration["configuration"]["operations"], OperationCreate - ) - for k in self.local_root_level_keys_to_remove_during_create: - self.configuration.pop(k, None) - return WebBackendConnectionCreate( - name=self.resource_name, source_id=self.source_id, destination_id=self.destination_id, **self.configuration - ) - - @property - def get_payload(self) -> Optional[WebBackendConnectionRequestBody]: - """Defines the payload to retrieve the remote connection if a state exists. - Returns: - ConnectionIdRequestBody: The ConnectionIdRequestBody payload. - """ - if self.state is not None: - return WebBackendConnectionRequestBody(connection_id=self.state.resource_id, with_refreshed_catalog=False) - - @property - def update_payload(self) -> WebBackendConnectionUpdate: - """Defines the payload to update a remote connection. - Returns: - WebBackendConnectionUpdate: The DestinationUpdate model instance. - """ - if self.raw_configuration["configuration"].get("operations") is not None: - self.configuration["operations"] = self._deserialize_operations( - self.raw_configuration["configuration"]["operations"], WebBackendOperationCreateOrUpdate - ) - return WebBackendConnectionUpdate(connection_id=self.resource_id, **self.configuration) - - def create(self) -> dict: - return self._create_or_update(self._create_fn, self.create_payload) - - def update(self) -> dict: - return self._create_or_update(self._update_fn, self.update_payload) - - @staticmethod - def _create_configured_catalog(sync_catalog: dict) -> AirbyteCatalog: - """Deserialize a sync_catalog represented as dict to an AirbyteCatalog. - Args: - sync_catalog (dict): The sync catalog represented as a dict. - Returns: - AirbyteCatalog: The configured catalog. - """ - streams_and_configurations = [] - for stream in sync_catalog["streams"]: - stream["stream"]["supported_sync_modes"] = [SyncMode(sm) for sm in stream["stream"]["supported_sync_modes"]] - stream["config"]["sync_mode"] = SyncMode(stream["config"]["sync_mode"]) - stream["config"]["destination_sync_mode"] = DestinationSyncMode(stream["config"]["destination_sync_mode"]) - if "selected_fields" in stream["config"]: - stream["config"]["selected_fields"] = [ - SelectedFieldInfo(field_path=selected_field["field_path"]) for selected_field in stream["config"]["selected_fields"] - ] - streams_and_configurations.append( - AirbyteStreamAndConfiguration( - stream=AirbyteStream(**stream["stream"]), config=AirbyteStreamConfiguration(**stream["config"]) - ) - ) - return AirbyteCatalog(streams_and_configurations) - - def _deserialize_operations( - self, operations: List[dict], outputModelClass: Union[Type[OperationCreate], Type[WebBackendOperationCreateOrUpdate]] - ) -> List[Union[OperationCreate, WebBackendOperationCreateOrUpdate]]: - """Deserialize operations to OperationCreate (to create connection) or WebBackendOperationCreateOrUpdate (to update connection) models. - Args: - operations (List[dict]): List of operations to deserialize - outputModelClass (Union[Type[OperationCreate], Type[WebBackendOperationCreateOrUpdate]]): The model to which the operation dict will be deserialized - Raises: - ValueError: Raised if the operator type declared in the configuration is not supported - Returns: - List[Union[OperationCreate, WebBackendOperationCreateOrUpdate]]: Deserialized operations - """ - deserialized_operations = [] - for operation in operations: - if operation["operator_configuration"]["operator_type"] == "normalization": - operation = outputModelClass( - workspace_id=self.workspace_id, - name=operation["name"], - operator_configuration=OperatorConfiguration( - operator_type=OperatorType(operation["operator_configuration"]["operator_type"]), - normalization=OperatorNormalization(**operation["operator_configuration"]["normalization"]), - ), - ) - elif operation["operator_configuration"]["operator_type"] == "dbt": - operation = outputModelClass( - workspace_id=self.workspace_id, - name=operation["name"], - operator_configuration=OperatorConfiguration( - operator_type=OperatorType(operation["operator_configuration"]["operator_type"]), - dbt=OperatorDbt(**operation["operator_configuration"]["dbt"]), - ), - ) - else: - raise ValueError(f"Operation type {operation['operator_configuration']['operator_type']} is not supported") - deserialized_operations.append(operation) - return deserialized_operations - - def _check_for_legacy_connection_configuration_keys(self, configuration_to_check): - self._check_for_wrong_casing_in_connection_configurations_keys(configuration_to_check) - self._check_for_schedule_in_connection_configurations_keys(configuration_to_check) - - # TODO this check can be removed when all our active user are on >= 0.37.0 - def _check_for_schedule_in_connection_configurations_keys(self, configuration_to_check): - error_message = "The schedule key is deprecated since 0.40.0, please use a combination of schedule_type and schedule_data" - self._check_for_invalid_configuration_keys(configuration_to_check, {"schedule"}, error_message) - - def _check_for_wrong_casing_in_connection_configurations_keys(self, configuration_to_check): - """We changed connection configuration keys from camelCase to snake_case in 0.37.0. - This function check if the connection configuration has some camelCase keys and display a meaningful error message. - Args: - configuration_to_check (dict): Configuration to validate - """ - error_message = "These keys should be in snake_case since version 0.37.0, please edit or regenerate your connection configuration" - self._check_for_invalid_configuration_keys( - configuration_to_check, {"syncCatalog", "namespaceDefinition", "namespaceFormat", "resourceRequirements"}, error_message - ) - self._check_for_invalid_configuration_keys(configuration_to_check.get("schedule", {}), {"timeUnit"}, error_message) - for stream in configuration_to_check["sync_catalog"]["streams"]: - self._check_for_invalid_configuration_keys( - stream["stream"], - {"defaultCursorField", "jsonSchema", "sourceDefinedCursor", "sourceDefinedPrimaryKey", "supportedSyncModes"}, - error_message, - ) - self._check_for_invalid_configuration_keys( - stream["config"], {"aliasName", "cursorField", "destinationSyncMode", "primaryKey", "syncMode"}, error_message - ) - - # TODO this check can be removed when all our active user are on > 0.39.18 - def _check_for_legacy_raw_configuration_keys(self, raw_configuration): - self._check_for_invalid_configuration_keys( - raw_configuration, - {"source_id", "destination_id"}, - "These keys changed to source_configuration_path and destination_configuration_path in version > 0.39.18, please update your connection configuration to give path to source and destination configuration files or regenerate the connection", - ) - - def _get_local_comparable_configuration(self) -> dict: - comparable = { - k: v - for k, v in self.raw_configuration["configuration"].items() - if k not in self.local_root_level_keys_to_filter_out_for_comparison - } - return comparable - - def _get_remote_comparable_configuration(self) -> dict: - - comparable = { - k: v for k, v in self.remote_resource.to_dict().items() if k not in self.remote_root_level_keys_to_filter_out_for_comparison - } - if "operations" in comparable: - for operation in comparable["operations"]: - for k in self.remote_operation_level_keys_to_filter_out: - operation.pop(k) - if "operations" in comparable and len(comparable["operations"]) == 0: - comparable.pop("operations") - return comparable - - -def factory(api_client: airbyte_api_client.ApiClient, workspace_id: str, configuration_path: str) -> Union[Source, Destination, Connection]: - """Create resource object according to the definition type field in their YAML configuration. - Args: - api_client (airbyte_api_client.ApiClient): The Airbyte API client. - workspace_id (str): The current workspace id. - configuration_path (str): Path to the YAML file with the configuration. - Raises: - NotImplementedError: Raised if the definition type found in the YAML is not a supported resource. - Returns: - Union[Source, Destination, Connection]: The resource object created from the YAML config. - """ - with open(configuration_path, "r") as f: - raw_configuration = yaml.load(f, EnvVarLoader) - if raw_configuration["definition_type"] == "source": - return Source(api_client, workspace_id, raw_configuration, configuration_path) - if raw_configuration["definition_type"] == "destination": - return Destination(api_client, workspace_id, raw_configuration, configuration_path) - if raw_configuration["definition_type"] == "connection": - return Connection(api_client, workspace_id, raw_configuration, configuration_path) - else: - raise NotImplementedError(f"Resource {raw_configuration['definition_type']} was not yet implemented") diff --git a/octavia-cli/octavia_cli/apply/yaml_loaders.py b/octavia-cli/octavia_cli/apply/yaml_loaders.py deleted file mode 100644 index 1b42054e1945..000000000000 --- a/octavia-cli/octavia_cli/apply/yaml_loaders.py +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import os -import re -from typing import Any - -import yaml - -ENV_VAR_MATCHER_PATTERN = re.compile(r".*\$\{([^}^{]+)\}.*") - - -def env_var_replacer(loader: yaml.Loader, node: yaml.Node) -> Any: - """Convert a YAML node to a Python object, expanding variable. - - Args: - loader (yaml.Loader): Not used - node (yaml.Node): Yaml node to convert to python object - - Returns: - Any: Python object with expanded vars. - """ - return os.path.expandvars(node.value) - - -class EnvVarLoader(yaml.SafeLoader): - pass - - -# All yaml nodes matching the regex will be tagged as !environment_variable. -EnvVarLoader.add_implicit_resolver("!environment_variable", ENV_VAR_MATCHER_PATTERN, None) - -# All yaml nodes tagged as !environment_variable will be constructed with the env_var_replacer callback. -EnvVarLoader.add_constructor("!environment_variable", env_var_replacer) diff --git a/octavia-cli/octavia_cli/base_commands.py b/octavia-cli/octavia_cli/base_commands.py deleted file mode 100644 index 150e5a8940cd..000000000000 --- a/octavia-cli/octavia_cli/base_commands.py +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import typing as t - -import click - - -class OctaviaCommand(click.Command): - def make_context( - self, info_name: t.Optional[str], args: t.List[str], parent: t.Optional[click.Context] = None, **extra: t.Any - ) -> click.Context: - """Wrap parent make context with telemetry sending in case of failure. - - Args: - info_name (t.Optional[str]): The info name for this invocation. - args (t.List[str]): The arguments to parse as list of strings. - parent (t.Optional[click.Context], optional): The parent context if available.. Defaults to None. - - Raises: - e: Raise whatever exception that was caught. - - Returns: - click.Context: The built context. - """ - try: - return super().make_context(info_name, args, parent, **extra) - except Exception as e: - telemetry_client = parent.obj["TELEMETRY_CLIENT"] - if isinstance(e, click.exceptions.Exit) and e.exit_code == 0: # Click raises Exit(0) errors when running --help commands - telemetry_client.send_command_telemetry(parent, extra_info_name=info_name, is_help=True) - else: - telemetry_client.send_command_telemetry(parent, error=e, extra_info_name=info_name) - raise e - - def invoke(self, ctx: click.Context) -> t.Any: - """Wrap parent invoke by sending telemetry in case of success or failure. - - Args: - ctx (click.Context): The invocation context. - - Raises: - e: Raise whatever exception that was caught. - - Returns: - t.Any: The invocation return value. - """ - telemetry_client = ctx.obj["TELEMETRY_CLIENT"] - try: - result = super().invoke(ctx) - except Exception as e: - telemetry_client.send_command_telemetry(ctx, error=e) - raise e - telemetry_client.send_command_telemetry(ctx) - return result diff --git a/octavia-cli/octavia_cli/check_context.py b/octavia-cli/octavia_cli/check_context.py deleted file mode 100644 index c1bedf1bb02e..000000000000 --- a/octavia-cli/octavia_cli/check_context.py +++ /dev/null @@ -1,93 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import os - -import airbyte_api_client -import click -from airbyte_api_client.api import health_api, workspace_api -from airbyte_api_client.model.workspace_id_request_body import WorkspaceIdRequestBody -from urllib3.exceptions import MaxRetryError - -from .init.commands import DIRECTORIES_TO_CREATE as REQUIRED_PROJECT_DIRECTORIES - - -class UnhealthyApiError(click.ClickException): - pass - - -class UnreachableAirbyteInstanceError(click.ClickException): - pass - - -class WorkspaceIdError(click.ClickException): - pass - - -class ProjectNotInitializedError(click.ClickException): - pass - - -def check_api_health(api_client: airbyte_api_client.ApiClient) -> None: - """Check if the Airbyte API is network reachable and healthy. - - Args: - api_client (airbyte_api_client.ApiClient): Airbyte API client. - - Raises: - click.ClickException: Raised if the Airbyte api server is unavailable according to the API response. - click.ClickException: Raised if the Airbyte URL is not reachable. - """ - api_instance = health_api.HealthApi(api_client) - try: - api_response = api_instance.get_health_check() - if not api_response.available: - raise UnhealthyApiError( - "Your Airbyte instance is not ready to receive requests: the health endpoint returned 'available: False.'" - ) - except (airbyte_api_client.ApiException, MaxRetryError) as e: - raise UnreachableAirbyteInstanceError( - f"Could not reach your Airbyte instance, make sure the instance is up and running and network reachable: {e}" - ) - - -def check_workspace_exists(api_client: airbyte_api_client.ApiClient, workspace_id: str) -> None: - """Check if the provided workspace id corresponds to an existing workspace on the Airbyte instance. - - Args: - api_client (airbyte_api_client.ApiClient): Airbyte API client. - workspace_id (str): Id of the workspace whose existence we are trying to verify. - - Raises: - click.ClickException: Raised if the workspace does not exist on the Airbyte instance. - """ - api_instance = workspace_api.WorkspaceApi(api_client) - try: - api_instance.get_workspace(WorkspaceIdRequestBody(workspace_id=workspace_id), _check_return_type=False) - except airbyte_api_client.ApiException: - raise WorkspaceIdError("The workspace you are trying to use does not exist in your Airbyte instance") - - -def check_is_initialized(project_directory: str = ".") -> bool: - """Check if required project directories exist to consider the project as initialized. - - Args: - project_directory (str, optional): Where the project should be initialized. Defaults to ".". - - Returns: - bool: [description] - """ - sub_directories = [f.name for f in os.scandir(project_directory) if f.is_dir()] - return set(REQUIRED_PROJECT_DIRECTORIES).issubset(sub_directories) - - -def requires_init(f): - def wrapper(ctx, **kwargs): - if not ctx.obj["PROJECT_IS_INITIALIZED"]: - raise ProjectNotInitializedError( - "Your octavia project is not initialized, please run 'octavia init' before running this command." - ) - f(ctx, **kwargs) - - return wrapper diff --git a/octavia-cli/octavia_cli/entrypoint.py b/octavia-cli/octavia_cli/entrypoint.py deleted file mode 100644 index 7a7d4665e921..000000000000 --- a/octavia-cli/octavia_cli/entrypoint.py +++ /dev/null @@ -1,187 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from typing import List, Optional, Tuple - -import airbyte_api_client -import click -import pkg_resources -from airbyte_api_client.api import workspace_api -from airbyte_api_client.model.workspace_id_request_body import WorkspaceIdRequestBody - -from ._import import commands as import_commands -from .api_http_headers import ApiHttpHeader, merge_api_headers, set_api_headers_on_api_client -from .apply import commands as apply_commands -from .check_context import check_api_health, check_is_initialized, check_workspace_exists -from .generate import commands as generate_commands -from .get import commands as get_commands -from .init import commands as init_commands -from .list import commands as list_commands -from .telemetry import TelemetryClient, build_user_agent - -AVAILABLE_COMMANDS: List[click.Command] = [ - list_commands._list, - get_commands.get, - import_commands._import, - init_commands.init, - generate_commands.generate, - apply_commands.apply, -] - - -def set_context_object( - ctx: click.Context, - airbyte_url: str, - airbyte_username: str, - airbyte_password: str, - workspace_id: str, - enable_telemetry: bool, - option_based_api_http_headers: Optional[List[Tuple[str, str]]], - api_http_headers_file_path: Optional[str], -) -> click.Context: - """Fill the context object with resources that will be reused by other commands. - Performs check and telemetry sending in case of error. - - Args: - ctx (click.Context): Current command context. - airbyte_url (str): The airbyte instance url. - airbyte_username (str): The OSS airbyte instance username. - airbyte_password (str): The OSS airbyte instance password. - workspace_id (str): The user_defined workspace id. - enable_telemetry (bool): Whether the telemetry should send data. - option_based_api_http_headers (Optional[List[Tuple[str, str]]]): Option based headers. - api_http_headers_file_path (Optional[str]): Path to the YAML file with http headers. - - Raises: - e: Raise whatever error that might happen during the execution. - - Returns: - click.Context: The context with it's updated object. - """ - telemetry_client = TelemetryClient(enable_telemetry) - - try: - ctx.ensure_object(dict) - ctx.obj["OCTAVIA_VERSION"] = pkg_resources.require("octavia-cli")[0].version - ctx.obj["TELEMETRY_CLIENT"] = telemetry_client - user_agent = build_user_agent(ctx.obj["OCTAVIA_VERSION"]) - api_http_headers = merge_api_headers(option_based_api_http_headers, api_http_headers_file_path) - api_client = get_api_client(airbyte_url, airbyte_username, airbyte_password, user_agent, api_http_headers) - ctx.obj["WORKSPACE_ID"] = get_workspace_id(api_client, workspace_id) - ctx.obj["ANONYMOUS_DATA_COLLECTION"] = get_anonymous_data_collection(api_client, ctx.obj["WORKSPACE_ID"]) - ctx.obj["API_CLIENT"] = api_client - ctx.obj["PROJECT_IS_INITIALIZED"] = check_is_initialized() - except Exception as e: - telemetry_client.send_command_telemetry(ctx, error=e) - raise e - return ctx - - -@click.group() -@click.option("--airbyte-url", envvar="AIRBYTE_URL", default="http://localhost:8000", help="The URL of your Airbyte instance.") -@click.option("--airbyte-username", envvar="AIRBYTE_USERNAME", default="airbyte", help="The username for your Airbyte OSS instance.") -@click.option("--airbyte-password", envvar="AIRBYTE_PASSWORD", default="password", help="The password for your Airbyte OSS instance.") -@click.option( - "--workspace-id", - envvar="AIRBYTE_WORKSPACE_ID", - default=None, - help="The id of the workspace on which you want octavia-cli to work. Defaults to the first one found on your Airbyte instance.", -) -@click.option( - "--enable-telemetry/--disable-telemetry", - envvar="OCTAVIA_ENABLE_TELEMETRY", - default=True, - help="Enable or disable telemetry for product improvement.", - type=bool, -) -@click.option( - "--api-http-header", - "-ah", - "option_based_api_http_headers", - help='Additional HTTP header name and header value pairs to pass to use when calling Airbyte\'s API ex. --api-http-header "Authorization" "Basic dXNlcjpwYXNzd29yZA=="', - multiple=True, - nargs=2, - type=click.Tuple([str, str]), -) -@click.option( - "--api-http-headers-file-path", - help=f"Path to the Yaml file with API HTTP headers. Please check the {init_commands.API_HTTP_HEADERS_TARGET_PATH} file.", - type=click.Path(exists=True, readable=True), -) -@click.pass_context -def octavia( - ctx: click.Context, - airbyte_url: str, - airbyte_username: str, - airbyte_password: str, - workspace_id: str, - enable_telemetry: bool, - option_based_api_http_headers: Optional[List[Tuple[str, str]]] = None, - api_http_headers_file_path: Optional[str] = None, -) -> None: - - ctx = set_context_object( - ctx, - airbyte_url, - airbyte_username, - airbyte_password, - workspace_id, - enable_telemetry, - option_based_api_http_headers, - api_http_headers_file_path, - ) - - click.echo( - click.style( - f"🐙 - Octavia is targetting your Airbyte instance running at {airbyte_url} on workspace {ctx.obj['WORKSPACE_ID']}.", fg="green" - ) - ) - if not ctx.obj["PROJECT_IS_INITIALIZED"]: - click.echo(click.style("🐙 - Project is not yet initialized.", fg="red", bold=True)) - - -def get_api_client( - airbyte_url: str, airbyte_username: str, airbyte_password: str, user_agent: str, api_http_headers: Optional[List[ApiHttpHeader]] -): - client_configuration = airbyte_api_client.Configuration(host=f"{airbyte_url}/api", username=airbyte_username, password=airbyte_password) - api_client = airbyte_api_client.ApiClient(client_configuration) - api_client.user_agent = user_agent - api_http_headers = api_http_headers if api_http_headers else [] - has_existing_authorization_headers = bool([header for header in api_http_headers if header.name.lower() == "authorization"]) - if not has_existing_authorization_headers: - basic_auth_token = client_configuration.get_basic_auth_token() - api_http_headers.append(ApiHttpHeader("Authorization", basic_auth_token)) - api_http_headers.append(ApiHttpHeader("X-Airbyte-Analytic-Source", "octavia-cli")) - set_api_headers_on_api_client(api_client, api_http_headers) - check_api_health(api_client) - return api_client - - -def get_workspace_id(api_client, user_defined_workspace_id): - if user_defined_workspace_id: - check_workspace_exists(api_client, user_defined_workspace_id) - return user_defined_workspace_id - else: - api_instance = workspace_api.WorkspaceApi(api_client) - api_response = api_instance.list_workspaces(_check_return_type=False) - return api_response.workspaces[0]["workspaceId"] - - -def get_anonymous_data_collection(api_client, workspace_id): - api_instance = workspace_api.WorkspaceApi(api_client) - api_response = api_instance.get_workspace(WorkspaceIdRequestBody(workspace_id), _check_return_type=False) - return api_response.get("anonymous_data_collection", True) - - -def add_commands_to_octavia(): - for command in AVAILABLE_COMMANDS: - octavia.add_command(command) - - -@octavia.command(help="[NOT IMPLEMENTED] Delete resources") -def delete() -> None: - raise click.ClickException("The delete command is not yet implemented.") - - -add_commands_to_octavia() diff --git a/octavia-cli/octavia_cli/generate/__init__.py b/octavia-cli/octavia_cli/generate/__init__.py deleted file mode 100644 index 46b7376756ec..000000000000 --- a/octavia-cli/octavia_cli/generate/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/octavia_cli/generate/commands.py b/octavia-cli/octavia_cli/generate/commands.py deleted file mode 100644 index c692ece85846..000000000000 --- a/octavia-cli/octavia_cli/generate/commands.py +++ /dev/null @@ -1,78 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import click -import octavia_cli.generate.definitions as definitions -from octavia_cli.apply import resources -from octavia_cli.base_commands import OctaviaCommand -from octavia_cli.check_context import requires_init - -from .renderers import ConnectionRenderer, ConnectorSpecificationRenderer - - -@click.group("generate", help="Generate a YAML template for a source, destination or a connection.") -@click.pass_context -@requires_init -def generate(ctx: click.Context): - pass - - -def generate_source_or_destination(definition_type, api_client, workspace_id, definition_id, resource_name): - definition = definitions.factory(definition_type, api_client, workspace_id, definition_id) - renderer = ConnectorSpecificationRenderer(resource_name, definition) - output_path = renderer.write_yaml(project_path=".") - message = f"✅ - Created the {definition_type} template for {resource_name} in {output_path}." - click.echo(click.style(message, fg="green")) - - -@generate.command(cls=OctaviaCommand, name="source", help="Create YAML for a source") -@click.argument("definition_id", type=click.STRING) -@click.argument("resource_name", type=click.STRING) -@click.pass_context -def source(ctx: click.Context, definition_id: str, resource_name: str): - generate_source_or_destination("source", ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"], definition_id, resource_name) - - -@generate.command(cls=OctaviaCommand, name="destination", help="Create YAML for a destination") -@click.argument("definition_id", type=click.STRING) -@click.argument("resource_name", type=click.STRING) -@click.pass_context -def destination(ctx: click.Context, definition_id: str, resource_name: str): - generate_source_or_destination("destination", ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"], definition_id, resource_name) - - -@generate.command(cls=OctaviaCommand, name="connection", help="Generate a YAML template for a connection.") -@click.argument("connection_name", type=click.STRING) -@click.option( - "--source", - "source_path", - type=click.Path(exists=True, readable=True), - required=True, - help="Path to the YAML file defining your source configuration.", -) -@click.option( - "--destination", - "destination_path", - type=click.Path(exists=True, readable=True), - required=True, - help="Path to the YAML file defining your destination configuration.", -) -@click.pass_context -def connection(ctx: click.Context, connection_name: str, source_path: str, destination_path: str): - source = resources.factory(ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"], source_path) - if not source.was_created: - raise resources.NonExistingResourceError( - f"The source defined at {source_path} does not exists. Please run octavia apply before creating this connection." - ) - - destination = resources.factory(ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"], destination_path) - if not destination.was_created: - raise resources.NonExistingResourceError( - f"The destination defined at {destination_path} does not exists. Please run octavia apply before creating this connection." - ) - - connection_renderer = ConnectionRenderer(connection_name, source, destination) - output_path = connection_renderer.write_yaml(project_path=".") - message = f"✅ - Created the connection template for {connection_name} in {output_path}." - click.echo(click.style(message, fg="green")) diff --git a/octavia-cli/octavia_cli/generate/definitions.py b/octavia-cli/octavia_cli/generate/definitions.py deleted file mode 100644 index b0b5e59f7d19..000000000000 --- a/octavia-cli/octavia_cli/generate/definitions.py +++ /dev/null @@ -1,153 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import abc -from typing import Any, Callable, Union - -import airbyte_api_client -import click -from airbyte_api_client.api import ( - destination_definition_api, - destination_definition_specification_api, - source_definition_api, - source_definition_specification_api, -) -from airbyte_api_client.exceptions import ApiException -from airbyte_api_client.model.destination_definition_id_request_body import DestinationDefinitionIdRequestBody -from airbyte_api_client.model.destination_definition_id_with_workspace_id import DestinationDefinitionIdWithWorkspaceId -from airbyte_api_client.model.source_definition_id_request_body import SourceDefinitionIdRequestBody -from airbyte_api_client.model.source_definition_id_with_workspace_id import SourceDefinitionIdWithWorkspaceId - - -class DefinitionNotFoundError(click.ClickException): - pass - - -class BaseDefinition(abc.ABC): - COMMON_GET_FUNCTION_KWARGS = {"_check_return_type": False} - - specification = None - - @property - @abc.abstractmethod - def api( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def type( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def get_function_name( - self, - ): # pragma: no cover - pass - - @property - def _get_fn(self) -> Callable: - return getattr(self.api, self.get_function_name) - - @property - def _get_fn_kwargs(self) -> dict: - return {} - - def __init__(self, api_client: airbyte_api_client.ApiClient, id: str) -> None: - self.id = id - self.api_instance = self.api(api_client) - self._api_data = self._read() - - def _read(self) -> dict: - try: - return self._get_fn(self.api_instance, **self._get_fn_kwargs, **self.COMMON_GET_FUNCTION_KWARGS) - except ApiException as e: - if e.status in [422, 404]: - raise DefinitionNotFoundError(f"Definition {self.id} does not exists on your Airbyte instance.") - raise e - - def __getattr__(self, name: str) -> Any: - """Map attribute of the API response to the BaseDefinition object. - - Args: - name (str): Attribute name - - Raises: - AttributeError: Raised if the attributed was not found in the API response payload. - - Returns: - [Any]: Attribute value - """ - if name in self._api_data: - return self._api_data.get(name) - raise AttributeError(f"{self.__class__.__name__}.{name} is invalid.") - - -class ConnectionDefinition(BaseDefinition): - type = "connection" - - -class SourceDefinition(BaseDefinition): - api = source_definition_api.SourceDefinitionApi - type = "source" - get_function_name = "get_source_definition" - - @property - def _get_fn_kwargs(self) -> dict: - return {"source_definition_id_request_body": SourceDefinitionIdRequestBody(self.id)} - - -class DestinationDefinition(BaseDefinition): - api = destination_definition_api.DestinationDefinitionApi - type = "destination" - get_function_name = "get_destination_definition" - - @property - def _get_fn_kwargs(self) -> dict: - return {"destination_definition_id_request_body": DestinationDefinitionIdRequestBody(self.id)} - - -class DefinitionSpecification(BaseDefinition): - def __init__(self, api_client: airbyte_api_client.ApiClient, workspace_id: str, id: str) -> None: - self.workspace_id = workspace_id - super().__init__(api_client, id) - - -class SourceDefinitionSpecification(DefinitionSpecification): - api = source_definition_specification_api.SourceDefinitionSpecificationApi - type = "source" - get_function_name = "get_source_definition_specification" - - @property - def _get_fn_kwargs(self) -> dict: - return {"source_definition_id_with_workspace_id": SourceDefinitionIdWithWorkspaceId(self.id, self.workspace_id)} - - -class DestinationDefinitionSpecification(DefinitionSpecification): - api = destination_definition_specification_api.DestinationDefinitionSpecificationApi - type = "destination" - get_function_name = "get_destination_definition_specification" - - @property - def _get_fn_kwargs(self) -> dict: - return {"destination_definition_id_with_workspace_id": DestinationDefinitionIdWithWorkspaceId(self.id, self.workspace_id)} - - -def factory( - definition_type: str, api_client: airbyte_api_client.ApiClient, workspace_id: str, definition_id: str -) -> Union[SourceDefinition, DestinationDefinition]: - if definition_type == "source": - definition = SourceDefinition(api_client, definition_id) - specification = SourceDefinitionSpecification(api_client, workspace_id, definition_id) - elif definition_type == "destination": - definition = DestinationDefinition(api_client, definition_id) - specification = DestinationDefinitionSpecification(api_client, workspace_id, definition_id) - else: - raise ValueError(f"{definition_type} does not exist") - definition.specification = specification - return definition diff --git a/octavia-cli/octavia_cli/generate/renderers.py b/octavia-cli/octavia_cli/generate/renderers.py deleted file mode 100644 index 190297312095..000000000000 --- a/octavia-cli/octavia_cli/generate/renderers.py +++ /dev/null @@ -1,328 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import abc -import os -from pathlib import Path -from typing import Any, Callable, List - -import click -import yaml -from airbyte_api_client.model.airbyte_catalog import AirbyteCatalog -from jinja2 import Environment, PackageLoader, Template, select_autoescape -from octavia_cli.apply import resources -from slugify import slugify - -from .definitions import BaseDefinition, ConnectionDefinition -from .yaml_dumpers import CatalogDumper - -JINJA_ENV = Environment(loader=PackageLoader(__package__), autoescape=select_autoescape(), trim_blocks=False, lstrip_blocks=True) - - -class FieldToRender: - def __init__(self, name: str, required: bool, field_metadata: dict) -> None: - """Initialize a FieldToRender instance - Args: - name (str): name of the field - required (bool): whether it's a required field or not - field_metadata (dict): metadata associated with the field - """ - self.name = name - self.required = required - self.field_metadata = field_metadata - self.one_of_values = self._get_one_of_values() - self.object_properties = get_object_fields(field_metadata) - self.array_items = self._get_array_items() - self.comment = self._build_comment( - [ - self._get_secret_comment, - self._get_required_comment, - self._get_type_comment, - self._get_description_comment, - self._get_example_comment, - ] - ) - self.default = self._get_default() - - def __getattr__(self, name: str) -> Any: - """Map field_metadata keys to attributes of Field. - Args: - name (str): attribute name - Returns: - [Any]: attribute value - """ - if name in self.field_metadata: - return self.field_metadata.get(name) - - @property - def is_array_of_objects(self) -> bool: - if self.type == "array" and self.items: - if self.items.get("type") == "object": - return True - return False - - def _get_one_of_values(self) -> List[List["FieldToRender"]]: - """An object field can have multiple kind of values if it's a oneOf. - This functions returns all the possible one of values the field can take. - Returns: - [list]: List of oneof values. - """ - if not self.oneOf: - return [] - one_of_values = [] - for one_of_value in self.oneOf: - properties = get_object_fields(one_of_value) - one_of_values.append(properties) - return one_of_values - - def _get_array_items(self) -> List["FieldToRender"]: - """If the field is an array of objects, retrieve fields of these objects. - Returns: - [list]: List of fields - """ - if self.is_array_of_objects: - required_fields = self.items.get("required", []) - return parse_fields(required_fields, self.items["properties"]) - return [] - - def _get_required_comment(self) -> str: - return "REQUIRED" if self.required else "OPTIONAL" - - def _get_type_comment(self) -> str: - if isinstance(self.type, list): - return ", ".join(self.type) - return self.type if self.type else None - - def _get_secret_comment(self) -> str: - return "SECRET (please store in environment variables)" if self.airbyte_secret else None - - def _get_description_comment(self) -> str: - return self.description if self.description else None - - def _get_example_comment(self) -> str: - example_comment = None - if self.examples: - if isinstance(self.examples, list): - if len(self.examples) > 1: - example_comment = f"Examples: {', '.join([str(example) for example in self.examples])}" - else: - example_comment = f"Example: {self.examples[0]}" - else: - example_comment = f"Example: {self.examples}" - return example_comment - - def _get_default(self) -> str: - if self.const: - return self.const - if self.airbyte_secret: - return f"${{{self.name.upper()}}}" - return self.default - - @staticmethod - def _build_comment(comment_functions: Callable) -> str: - return " | ".join(filter(None, [comment_fn() for comment_fn in comment_functions])).replace("\n", "") - - -def parse_fields(required_fields: List[str], fields: dict) -> List["FieldToRender"]: - return [FieldToRender(f_name, f_name in required_fields, f_metadata) for f_name, f_metadata in fields.items()] - - -def get_object_fields(field_metadata: dict) -> List["FieldToRender"]: - if field_metadata.get("properties"): - required_fields = field_metadata.get("required", []) - return parse_fields(required_fields, field_metadata["properties"]) - return [] - - -class BaseRenderer(abc.ABC): - @property - @abc.abstractmethod - def TEMPLATE( - self, - ) -> Template: # pragma: no cover - pass - - def __init__(self, resource_name: str) -> None: - self.resource_name = resource_name - - @classmethod - def get_output_path(cls, project_path: str, definition_type: str, resource_name: str) -> Path: - """Get rendered file output path - Args: - project_path (str): Current project path. - definition_type (str): Current definition_type. - resource_name (str): Current resource_name. - Returns: - Path: Full path to the output path. - """ - directory = os.path.join(project_path, f"{definition_type}s", slugify(resource_name, separator="_")) - if not os.path.exists(directory): - os.makedirs(directory) - return Path(os.path.join(directory, "configuration.yaml")) - - @staticmethod - def _confirm_overwrite(output_path): - """User input to determine if the configuration paqth should be overwritten. - Args: - output_path (str): Path of the configuration file to overwrite - Returns: - bool: Boolean representing if the configuration file is to be overwritten - """ - overwrite = True - if output_path.is_file(): - overwrite = click.confirm( - f"The configuration octavia-cli is about to create already exists, do you want to replace it? ({output_path})" - ) - return overwrite - - @abc.abstractmethod - def _render(self): # pragma: no cover - """Runs the template rendering. - Raises: - NotImplementedError: Must be implemented on subclasses. - """ - raise NotImplementedError - - def write_yaml(self, project_path: Path) -> str: - """Write rendered specification to a YAML file in local project path. - Args: - project_path (str): Path to directory hosting the octavia project. - Returns: - str: Path to the rendered specification. - """ - output_path = self.get_output_path(project_path, self.definition.type, self.resource_name) - if self._confirm_overwrite(output_path): - with open(output_path, "w") as f: - rendered_yaml = self._render() - f.write(rendered_yaml) - return output_path - - def import_configuration(self, project_path: str, configuration: dict) -> Path: - """Import the resource configuration. Save the yaml file to disk and return its path. - Args: - project_path (str): Current project path. - configuration (dict): The configuration of the resource. - Returns: - Path: Path to the resource configuration. - """ - rendered = self._render() - data = yaml.safe_load(rendered) - data["configuration"] = configuration - output_path = self.get_output_path(project_path, self.definition.type, self.resource_name) - if self._confirm_overwrite(output_path): - with open(output_path, "wb") as f: - yaml.safe_dump(data, f, default_flow_style=False, sort_keys=False, allow_unicode=True, encoding="utf-8") - return output_path - - -class ConnectorSpecificationRenderer(BaseRenderer): - TEMPLATE = JINJA_ENV.get_template("source_or_destination.yaml.j2") - - def __init__(self, resource_name: str, definition: BaseDefinition) -> None: - """Connector specification renderer constructor. - Args: - resource_name (str): Name of the source or destination. - definition (BaseDefinition): The definition related to a source or a destination. - """ - super().__init__(resource_name) - self.definition = definition - - def _parse_connection_specification(self, schema: dict) -> List[List["FieldToRender"]]: - """Create a renderable structure from the specification schema - Returns: - List[List["FieldToRender"]]: List of list of fields to render. - """ - if schema.get("oneOf"): - roots = [] - for one_of_value in schema.get("oneOf"): - required_fields = one_of_value.get("required", []) - roots.append(parse_fields(required_fields, one_of_value["properties"])) - return roots - else: - required_fields = schema.get("required", []) - return [parse_fields(required_fields, schema["properties"])] - - def _render(self) -> str: - parsed_schema = self._parse_connection_specification(self.definition.specification.connection_specification) - return self.TEMPLATE.render( - {"resource_name": self.resource_name, "definition": self.definition, "configuration_fields": parsed_schema} - ) - - -class ConnectionRenderer(BaseRenderer): - - TEMPLATE = JINJA_ENV.get_template("connection.yaml.j2") - definition = ConnectionDefinition - KEYS_TO_REMOVE_FROM_REMOTE_CONFIGURATION = [ - "connection_id", - "name", - "source_id", - "destination_id", - "latest_sync_job_created_at", - "latest_sync_job_status", - "source", - "destination", - "is_syncing", - "operation_ids", - "catalog_id", - "catalog_diff", - ] - - def __init__(self, connection_name: str, source: resources.Source, destination: resources.Destination) -> None: - """Connection renderer constructor. - Args: - connection_name (str): Name of the connection to render. - source (resources.Source): Connection's source. - destination (resources.Destination): Connections's destination. - """ - super().__init__(connection_name) - self.source = source - self.destination = destination - - @staticmethod - def catalog_to_yaml(catalog: AirbyteCatalog) -> str: - """Convert the source catalog to a YAML string. - Args: - catalog (AirbyteCatalog): Source's catalog. - Returns: - str: Catalog rendered as yaml. - """ - return yaml.dump(catalog.to_dict(), Dumper=CatalogDumper, default_flow_style=False) - - def _render(self) -> str: - yaml_catalog = self.catalog_to_yaml(self.source.catalog) - return self.TEMPLATE.render( - { - "connection_name": self.resource_name, - "source_configuration_path": self.source.configuration_path, - "destination_configuration_path": self.destination.configuration_path, - "catalog": yaml_catalog, - "supports_normalization": self.destination.definition.normalization_config.supported, - "supports_dbt": self.destination.definition.supports_dbt, - } - ) - - def import_configuration(self, project_path: Path, configuration: dict) -> Path: - """Import the connection configuration. Save the yaml file to disk and return its path. - Args: - project_path (str): Current project path. - configuration (dict): The configuration of the connection. - Returns: - Path: Path to the connection configuration. - """ - rendered = self._render() - data = yaml.safe_load(rendered) - data["configuration"] = {k: v for k, v in configuration.items() if k not in self.KEYS_TO_REMOVE_FROM_REMOTE_CONFIGURATION} - if "operations" in data["configuration"] and len(data["configuration"]["operations"]) == 0: - data["configuration"].pop("operations") - [ - operation.pop(field_to_remove, "") - for field_to_remove in ["workspace_id", "operation_id"] - for operation in data["configuration"].get("operations", {}) - ] - output_path = self.get_output_path(project_path, self.definition.type, self.resource_name) - if self._confirm_overwrite(output_path): - with open(output_path, "wb") as f: - yaml.safe_dump(data, f, default_flow_style=False, sort_keys=False, allow_unicode=True, encoding="utf-8") - return output_path diff --git a/octavia-cli/octavia_cli/generate/templates/connection.yaml.j2 b/octavia-cli/octavia_cli/generate/templates/connection.yaml.j2 deleted file mode 100644 index 510083944e91..000000000000 --- a/octavia-cli/octavia_cli/generate/templates/connection.yaml.j2 +++ /dev/null @@ -1,50 +0,0 @@ -# Configuration for connection {{ connection_name }} -definition_type: connection -resource_name: "{{ connection_name }}" -source_configuration_path: {{ source_configuration_path }} -destination_configuration_path: {{ destination_configuration_path }} - -# EDIT THE CONFIGURATION BELOW! -configuration: - status: active # REQUIRED | string | Allowed values: active, inactive, deprecated - skip_reset: false # OPTIONAL | boolean | Flag to check if the connection should be reset after a connection update - namespace_definition: source # OPTIONAL | string | Allowed values: source, destination, customformat - namespace_format: "${SOURCE_NAMESPACE}" # OPTIONAL | string | Used when namespaceDefinition is 'customformat'. If blank then behaves like namespaceDefinition = 'destination'. If "${SOURCE_NAMESPACE}" then behaves like namespaceDefinition = 'source'. - prefix: "" # REQUIRED | Prefix that will be prepended to the name of each stream when it is written to the destination - resource_requirements: # OPTIONAL | object | Resource requirements to run workers (blank for unbounded allocations) - cpu_limit: "" # OPTIONAL - cpu_request: "" # OPTIONAL - memory_limit: "" # OPTIONAL - memory_request: "" # OPTIONAL - schedule_type: basic # OPTIONAL | string | Allowed values: basic, cron, manual - schedule_data: # OPTIONAL | object - basic_schedule: - time_unit: hours # REQUIRED | string | Allowed values: minutes, hours, days, weeks, months - units: 1 # REQUIRED | integer - # cron: - # cron_time_zone: "UTC" # REQUIRED | string - # cron_expression: "* */2 * * * ?" # REQUIRED | string - {%- if supports_normalization or supports_dbt%} - # operations: - {%- endif %} - {%- if supports_normalization %} - ## -------- Uncomment and edit the block below if you want to enable Airbyte normalization -------- - # - name: "Normalization" - # operator_configuration: - # normalization: - # option: "basic" - # operator_type: "normalization" - {%- endif %} - {%- if supports_dbt %} - ## -------- Uncomment and edit the block below if you want to declare a custom transformation -------- - # - name: "My dbt transformations" # REQUIRED | string - # operator_configuration: - # dbt: - # dbt_arguments: "run" # REQUIRED | string | Entrypoint arguments for dbt cli to run the project - # docker_image: "fishtownanalytics/dbt:0.19.1" # REQUIRED | string | Docker image URL with dbt installed - # git_repo_branch: "your-repo-branch-name" # OPTIONAL | string | Git branch name - # git_repo_url: "https://github.com/" # REQUIRED | string | Git repository URL of the custom transformation project - # operator_type: dbt # REQUIRED | string | Allowed values: dbt, normalization - {%- endif %} - sync_catalog: # OPTIONAL | object | 🚨 ONLY edit streams.config, streams.stream should not be edited as schema cannot be changed. - {{ catalog | indent(4)}} diff --git a/octavia-cli/octavia_cli/generate/templates/source_or_destination.yaml.j2 b/octavia-cli/octavia_cli/generate/templates/source_or_destination.yaml.j2 deleted file mode 100644 index c8a33f708577..000000000000 --- a/octavia-cli/octavia_cli/generate/templates/source_or_destination.yaml.j2 +++ /dev/null @@ -1,79 +0,0 @@ -# Configuration for {{ definition.docker_repository }} -# Documentation about this connector can be found at {{ definition.documentation_url }} -resource_name: "{{ resource_name}}" -definition_type: {{ definition.type}} -definition_id: {{ definition.id }} -definition_image: {{ definition.docker_repository }} -definition_version: {{ definition.docker_image_tag }} - -{%- macro render_field(field, is_commented) %} -{%- if is_commented %}# {% endif %}{{ field.name }}:{% if field.default %} {% if field.airbyte_secret %}{{ field.default }}{% else %}{{ field.default | tojson() }}{% endif %}{% endif %} # {{ field.comment }} -{%- endmacro %} - -{%- macro render_sub_fields(sub_fields, is_commented) %} -{%- for f in sub_fields %} -{%- if f.type == "object" and not f.oneOf %} -{{- render_object_field(f)|indent(2, False) }} -{%- elif f.oneOf %}} -{{- render_one_of(f) }} -{%- elif f.is_array_of_objects %}} -{{- render_array_of_objects(f) }} -{%- else %} -{{ render_field(f, is_commented) }} -{%- endif %} -{%- endfor %} -{%- endmacro %} - -{%- macro render_array_sub_fields(sub_fields, is_commented) %} -{%- for f in sub_fields %} -{% if loop.first %}- {% else %} {% endif %}{{ render_field(f, is_commented) }} -{%- endfor %} -{%- endmacro %} - - -{%- macro render_one_of(field) %} -{{ field.name }}: -{%- for one_of_value in field.one_of_values %} - {%- if loop.first %} - ## -------- Pick one valid structure among the examples below: -------- - {{- render_sub_fields(one_of_value, False)|indent(2, False) }} - {%- else %} - ## -------- Another valid structure for {{ field.name }}: -------- - {{- render_sub_fields(one_of_value, True)|indent(2, False) }} - {%- endif %} -{%- endfor %} -{%- endmacro %} - -{%- macro render_object_field(field) %} -{{ field.name }}: - {{- render_sub_fields(field.object_properties, is_commented=False)|indent(2, False)}} -{%- endmacro %} - -{%- macro render_array_of_objects(field) %} -{{ field.name }}: - {{- render_array_sub_fields(field.array_items, is_commented=False)|indent(2, False)}} -{%- endmacro %} - -{%- macro render_root(root, is_commented) %} -{%- for f in root %} - {%- if f.type == "object" and not f.oneOf %} - {{- render_object_field(f)|indent(2, False) }} - {%- elif f.oneOf %} - {{- render_one_of(f)|indent(2, False) }} - {%- elif f.is_array_of_objects %} - {{- render_array_of_objects(f)|indent(2, False) }} - {%- else %} - {{ render_field(f, is_commented=is_commented) }} - {%- endif %} -{%- endfor %} -{%- endmacro %} - -# EDIT THE CONFIGURATION BELOW! -configuration: -{%- for root in configuration_fields %} -{%- if loop.first %} -{{- render_root(root, is_commented=False)}} -{%- else %} -{{- render_root(root, is_commented=True)}} -{%- endif %} -{% endfor %} diff --git a/octavia-cli/octavia_cli/generate/yaml_dumpers.py b/octavia-cli/octavia_cli/generate/yaml_dumpers.py deleted file mode 100644 index 9bd107def0fa..000000000000 --- a/octavia-cli/octavia_cli/generate/yaml_dumpers.py +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import yaml - - -# This custom Dumper allows the list indentation expected by our prettier formatter: -# Normal dumper behavior -# my_list: -# - bar: test2 -# foo: test -# - bar: test4 -# foo: test3 -# Custom behavior to match prettier's rules: -# my_list: -# - bar: test2 -# foo: test -# - bar: test4 -# foo: test3 -class CatalogDumper(yaml.Dumper): - def increase_indent(self, flow=False, indentless=False): - return super(CatalogDumper, self).increase_indent(flow, False) diff --git a/octavia-cli/octavia_cli/get/__init__.py b/octavia-cli/octavia_cli/get/__init__.py deleted file mode 100644 index c941b3045795..000000000000 --- a/octavia-cli/octavia_cli/get/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/octavia_cli/get/commands.py b/octavia-cli/octavia_cli/get/commands.py deleted file mode 100644 index 52c55d799614..000000000000 --- a/octavia-cli/octavia_cli/get/commands.py +++ /dev/null @@ -1,108 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import uuid -from typing import List, Optional, Tuple, Type, Union - -import airbyte_api_client -import click -from octavia_cli.base_commands import OctaviaCommand - -from .resources import Connection, Destination, Source - -COMMON_HELP_MESSAGE_PREFIX = "Get a JSON representation of a remote" - - -def build_help_message(resource_type: str) -> str: - """Helper function to build help message consistently for all the commands in this module. - - Args: - resource_type (str): source, destination or connection - - Returns: - str: The generated help message. - """ - return f"Get a JSON representation of a remote {resource_type}." - - -def get_resource_id_or_name(resource: str) -> Tuple[Optional[str], Optional[str]]: - """Helper function to detect if the resource argument passed to the CLI is a resource ID or name. - - Args: - resource (str): the resource ID or name passed as an argument to the CLI. - - Returns: - Tuple[Optional[str], Optional[str]]: the resource_id and resource_name, the not detected kind is set to None. - """ - resource_id, resource_name = None, None - try: - uuid.UUID(resource) - resource_id = resource - except ValueError: - resource_name = resource - return resource_id, resource_name - - -def get_json_representation( - api_client: airbyte_api_client.ApiClient, - workspace_id: str, - ResourceClass: Type[Union[Source, Destination, Connection]], - resource_to_get: str, -) -> str: - """Helper function to retrieve a resource json representation and avoid repeating the same logic for Source/Destination and connection. - - - Args: - api_client (airbyte_api_client.ApiClient): The Airbyte API client. - workspace_id (str): Current workspace id. - ResourceClass (Type[Union[Source, Destination, Connection]]): Resource class to use - resource_to_get (str): resource name or id to get JSON representation for. - - Returns: - str: The resource's JSON representation. - """ - resource_id, resource_name = get_resource_id_or_name(resource_to_get) - resource = ResourceClass(api_client, workspace_id, resource_id=resource_id, resource_name=resource_name) - return resource.to_json() - - -@click.group( - "get", - help=f'{build_help_message("source, destination or connection")} ID or name can be used as argument. Example: \'octavia get source "My Pokemon source"\' or \'octavia get source cb5413b2-4159-46a2-910a-dc282a439d2d\'', -) -@click.pass_context -def get(ctx: click.Context): # pragma: no cover - pass - - -@get.command(cls=OctaviaCommand, name="source", help=build_help_message("source")) -@click.argument("resource", type=click.STRING) -@click.pass_context -def source(ctx: click.Context, resource: str): - click.echo(get_json_representation(ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"], Source, resource)) - - -@get.command(cls=OctaviaCommand, name="destination", help=build_help_message("destination")) -@click.argument("resource", type=click.STRING) -@click.pass_context -def destination(ctx: click.Context, resource: str): - click.echo(get_json_representation(ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"], Destination, resource)) - - -@get.command(cls=OctaviaCommand, name="connection", help=build_help_message("connection")) -@click.argument("resource", type=click.STRING) -@click.pass_context -def connection(ctx: click.Context, resource: str): - click.echo(get_json_representation(ctx.obj["API_CLIENT"], ctx.obj["WORKSPACE_ID"], Connection, resource)) - - -AVAILABLE_COMMANDS: List[click.Command] = [source, destination, connection] - - -def add_commands_to_list(): - for command in AVAILABLE_COMMANDS: - get.add_command(command) - - -add_commands_to_list() diff --git a/octavia-cli/octavia_cli/get/resources.py b/octavia-cli/octavia_cli/get/resources.py deleted file mode 100644 index d20fbe5cf8b6..000000000000 --- a/octavia-cli/octavia_cli/get/resources.py +++ /dev/null @@ -1,193 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import abc -import json -from typing import Optional, Union - -import airbyte_api_client -import click -from airbyte_api_client.api import destination_api, source_api, web_backend_api -from airbyte_api_client.model.destination_id_request_body import DestinationIdRequestBody -from airbyte_api_client.model.destination_read import DestinationRead -from airbyte_api_client.model.source_id_request_body import SourceIdRequestBody -from airbyte_api_client.model.source_read import SourceRead -from airbyte_api_client.model.web_backend_connection_read import WebBackendConnectionRead -from airbyte_api_client.model.web_backend_connection_request_body import WebBackendConnectionRequestBody -from airbyte_api_client.model.workspace_id_request_body import WorkspaceIdRequestBody - - -class DuplicateResourceError(click.ClickException): - pass - - -class ResourceNotFoundError(click.ClickException): - pass - - -class BaseResource(abc.ABC): - @property - @abc.abstractmethod - def api( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def name( - self, - ) -> str: # pragma: no cover - pass - - @property - @abc.abstractmethod - def get_function_name( - self, - ) -> str: # pragma: no cover - pass - - @property - def _get_fn(self): - return getattr(self.api, self.get_function_name) - - @property - @abc.abstractmethod - def get_payload( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def list_for_workspace_function_name( - self, - ) -> str: # pragma: no cover - pass - - @property - def _list_for_workspace_fn(self): - return getattr(self.api, self.list_for_workspace_function_name) - - @property - def list_for_workspace_payload( - self, - ): - return WorkspaceIdRequestBody(workspace_id=self.workspace_id) - - def __init__( - self, - api_client: airbyte_api_client.ApiClient, - workspace_id: str, - resource_id: Optional[str] = None, - resource_name: Optional[str] = None, - ): - if resource_id is None and resource_name is None: - raise ValueError("resource_id and resource_name keyword arguments can't be both None.") - if resource_id is not None and resource_name is not None: - raise ValueError("resource_id and resource_name keyword arguments can't be both set.") - self.resource_id = resource_id - self.resource_name = resource_name - self.api_instance = self.api(api_client) - self.workspace_id = workspace_id - - def _find_by_resource_name( - self, - ) -> Union[WebBackendConnectionRead, SourceRead, DestinationRead]: - """Retrieve a remote resource from its name by listing the available resources on the Airbyte instance. - - Raises: - ResourceNotFoundError: Raised if no resource was found with the current resource_name. - DuplicateResourceError: Raised if multiple resources were found with the current resource_name. - - Returns: - Union[WebBackendConnectionRead, SourceRead, DestinationRead]: The remote resource model instance. - """ - - api_response = self._list_for_workspace_fn(self.api_instance, self.list_for_workspace_payload) - matching_resources = [] - for resource in getattr(api_response, f"{self.name}s"): - if resource.name == self.resource_name: - matching_resources.append(resource) - if not matching_resources: - raise ResourceNotFoundError(f"The {self.name} {self.resource_name} was not found in your current Airbyte workspace.") - if len(matching_resources) > 1: - raise DuplicateResourceError( - f"{len(matching_resources)} {self.name}s with the name {self.resource_name} were found in your current Airbyte workspace." - ) - return matching_resources[0] - - def _find_by_resource_id( - self, - ) -> Union[WebBackendConnectionRead, SourceRead, DestinationRead]: - """Retrieve a remote resource from its id by calling the get endpoint of the resource type. - - Returns: - Union[WebBackendConnectionRead, SourceRead, DestinationRead]: The remote resource model instance. - """ - return self._get_fn(self.api_instance, self.get_payload) - - def get_remote_resource(self) -> Union[WebBackendConnectionRead, SourceRead, DestinationRead]: - """Retrieve a remote resource with a resource_name or a resource_id - - Returns: - Union[WebBackendConnectionRead, SourceRead, DestinationRead]: The remote resource model instance. - """ - if self.resource_id is not None: - return self._find_by_resource_id() - else: - return self._find_by_resource_name() - - def to_json(self) -> str: - """Get the JSON representation of the remote resource model instance. - - Returns: - str: The JSON representation of the remote resource model instance. - """ - return json.dumps(self.get_remote_resource().to_dict()) - - -class Source(BaseResource): - name = "source" - api = source_api.SourceApi - get_function_name = "get_source" - list_for_workspace_function_name = "list_sources_for_workspace" - - @property - def get_payload(self) -> Optional[SourceIdRequestBody]: - """Defines the payload to retrieve the remote source according to its resource_id. - Returns: - SourceIdRequestBody: The SourceIdRequestBody payload. - """ - return SourceIdRequestBody(self.resource_id) - - -class Destination(BaseResource): - name = "destination" - api = destination_api.DestinationApi - get_function_name = "get_destination" - list_for_workspace_function_name = "list_destinations_for_workspace" - - @property - def get_payload(self) -> Optional[DestinationIdRequestBody]: - """Defines the payload to retrieve the remote destination according to its resource_id. - Returns: - DestinationIdRequestBody: The DestinationIdRequestBody payload. - """ - return DestinationIdRequestBody(self.resource_id) - - -class Connection(BaseResource): - name = "connection" - api = web_backend_api.WebBackendApi - get_function_name = "web_backend_get_connection" - list_for_workspace_function_name = "web_backend_list_connections_for_workspace" - - @property - def get_payload(self) -> Optional[WebBackendConnectionRequestBody]: - """Defines the payload to retrieve the remote connection according to its resource_id. - Returns: - WebBackendConnectionRequestBody: The WebBackendConnectionRequestBody payload. - """ - return WebBackendConnectionRequestBody(with_refreshed_catalog=False, connection_id=self.resource_id) diff --git a/octavia-cli/octavia_cli/init/__init__.py b/octavia-cli/octavia_cli/init/__init__.py deleted file mode 100644 index 46b7376756ec..000000000000 --- a/octavia-cli/octavia_cli/init/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/octavia_cli/init/commands.py b/octavia-cli/octavia_cli/init/commands.py deleted file mode 100644 index 83c683e11aa3..000000000000 --- a/octavia-cli/octavia_cli/init/commands.py +++ /dev/null @@ -1,58 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import importlib.resources as pkg_resources -import os -from pathlib import Path -from typing import Iterable, Tuple - -import click -from octavia_cli.base_commands import OctaviaCommand - -from . import example_files - -DIRECTORIES_TO_CREATE = {"connections", "destinations", "sources"} -DEFAULT_API_HEADERS_FILE_CONTENT = pkg_resources.read_text(example_files, "example_api_http_headers.yaml") -API_HTTP_HEADERS_TARGET_PATH = Path("api_http_headers.yaml") - - -def create_api_headers_configuration_file() -> bool: - if not API_HTTP_HEADERS_TARGET_PATH.is_file(): - with open(API_HTTP_HEADERS_TARGET_PATH, "w") as file: - file.write(DEFAULT_API_HEADERS_FILE_CONTENT) - return True - return False - - -def create_directories(directories_to_create: Iterable[str]) -> Tuple[Iterable[str], Iterable[str]]: - created_directories = [] - not_created_directories = [] - for directory in directories_to_create: - try: - os.mkdir(directory) - created_directories.append(directory) - except FileExistsError: - not_created_directories.append(directory) - return created_directories, not_created_directories - - -@click.command(cls=OctaviaCommand, help="Initialize required directories for the project.") -@click.pass_context -def init(ctx: click.Context): - click.echo("🔨 - Initializing the project.") - created_directories, not_created_directories = create_directories(DIRECTORIES_TO_CREATE) - if created_directories: - message = f"✅ - Created the following directories: {', '.join(created_directories)}." - click.echo(click.style(message, fg="green")) - if not_created_directories: - message = f"❓ - Already existing directories: {', '.join(not_created_directories) }." - click.echo(click.style(message, fg="yellow", bold=True)) - - created_api_http_headers_file = create_api_headers_configuration_file() - if created_api_http_headers_file: - message = f"✅ - Created API HTTP headers file in {API_HTTP_HEADERS_TARGET_PATH}" - click.echo(click.style(message, fg="green", bold=True)) - else: - message = "❓ - API HTTP headers file already exists, skipping." - click.echo(click.style(message, fg="yellow", bold=True)) diff --git a/octavia-cli/octavia_cli/init/example_files/__init__.py b/octavia-cli/octavia_cli/init/example_files/__init__.py deleted file mode 100644 index c941b3045795..000000000000 --- a/octavia-cli/octavia_cli/init/example_files/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/octavia_cli/init/example_files/example_api_http_headers.yaml b/octavia-cli/octavia_cli/init/example_files/example_api_http_headers.yaml deleted file mode 100644 index 73a639e3b460..000000000000 --- a/octavia-cli/octavia_cli/init/example_files/example_api_http_headers.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# This file is an example file with API HTTP headers used to pass to the octavia CLI API client. -# It can be helpful to reach out to secured airbyte instances (ex. proxy auth server) -headers: - Content-Type: application/json diff --git a/octavia-cli/octavia_cli/list/__init__.py b/octavia-cli/octavia_cli/list/__init__.py deleted file mode 100644 index 46b7376756ec..000000000000 --- a/octavia-cli/octavia_cli/list/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/octavia_cli/list/commands.py b/octavia-cli/octavia_cli/list/commands.py deleted file mode 100644 index 8680ee919c11..000000000000 --- a/octavia-cli/octavia_cli/list/commands.py +++ /dev/null @@ -1,84 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from typing import List - -import click -from octavia_cli.base_commands import OctaviaCommand - -from .listings import Connections, DestinationConnectorsDefinitions, Destinations, SourceConnectorsDefinitions, Sources - - -@click.group("list", help="List existing Airbyte resources.") -@click.pass_context -def _list(ctx: click.Context): # pragma: no cover - pass - - -@click.group("connectors", help="List sources and destinations connectors available on your Airbyte instance.") -@click.pass_context -def connectors(ctx: click.Context): # pragma: no cover - pass - - -@click.group("workspace", help="Latest information on workspace's sources and destinations.") -@click.pass_context -def workspace(ctx: click.Context): # pragma: no cover - pass - - -@connectors.command(cls=OctaviaCommand, name="sources", help="List all the source connectors currently available on your Airbyte instance.") -@click.pass_context -def sources_connectors(ctx: click.Context): - api_client = ctx.obj["API_CLIENT"] - definitions = SourceConnectorsDefinitions(api_client) - click.echo(definitions) - - -@connectors.command( - cls=OctaviaCommand, name="destinations", help="List all the destination connectors currently available on your Airbyte instance" -) -@click.pass_context -def destinations_connectors(ctx: click.Context): - api_client = ctx.obj["API_CLIENT"] - definitions = DestinationConnectorsDefinitions(api_client) - click.echo(definitions) - - -@workspace.command(cls=OctaviaCommand, help="List existing sources in a workspace.") -@click.pass_context -def sources(ctx: click.Context): - api_client = ctx.obj["API_CLIENT"] - workspace_id = ctx.obj["WORKSPACE_ID"] - sources = Sources(api_client, workspace_id) - click.echo(sources) - - -@workspace.command(cls=OctaviaCommand, help="List existing destinations in a workspace.") -@click.pass_context -def destinations(ctx: click.Context): - api_client = ctx.obj["API_CLIENT"] - workspace_id = ctx.obj["WORKSPACE_ID"] - destinations = Destinations(api_client, workspace_id) - click.echo(destinations) - - -@workspace.command(cls=OctaviaCommand, help="List existing connections in a workspace.") -@click.pass_context -def connections(ctx: click.Context): - api_client = ctx.obj["API_CLIENT"] - workspace_id = ctx.obj["WORKSPACE_ID"] - connections = Connections(api_client, workspace_id) - click.echo(connections) - - -AVAILABLE_COMMANDS: List[click.Command] = [connectors, workspace] - - -def add_commands_to_list(): - for command in AVAILABLE_COMMANDS: - _list.add_command(command) - - -add_commands_to_list() diff --git a/octavia-cli/octavia_cli/list/formatting.py b/octavia-cli/octavia_cli/list/formatting.py deleted file mode 100644 index 09aaae23e37d..000000000000 --- a/octavia-cli/octavia_cli/list/formatting.py +++ /dev/null @@ -1,59 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from typing import List - - -def compute_columns_width(data: List[List[str]], padding: int = 2) -> List[int]: - """Compute columns width for display purposes: - Find size for each columns in the data and add padding. - Args: - data (List[List[str]]): Tabular data containing rows and columns. - padding (int): Number of character to adds to create space between columns. - Returns: - columns_width (List[int]): The computed columns widths for each column according to input data. - """ - columns_width = [0 for _ in data[0]] - for row in data: - for i, col in enumerate(row): - current_col_width = len(col) + padding - if current_col_width > columns_width[i]: - columns_width[i] = current_col_width - return columns_width - - -def camelcased_to_uppercased_spaced(camelcased: str) -> str: - """Util function to transform a camelCase string to a UPPERCASED SPACED string - e.g: dockerImageName -> DOCKER IMAGE NAME - Args: - camelcased (str): The camel cased string to convert. - - Returns: - (str): The converted UPPERCASED SPACED string - """ - return "".join(map(lambda x: x if x.islower() else " " + x, camelcased)).upper() - - -def display_as_table(data: List[List[str]]) -> str: - """Formats tabular input data into a displayable table with columns. - Args: - data (List[List[str]]): Tabular data containing rows and columns. - Returns: - table (str): String representation of input tabular data. - """ - columns_width = compute_columns_width(data) - table = "\n".join(["".join(col.ljust(columns_width[i]) for i, col in enumerate(row)) for row in data]) - return table - - -def format_column_names(camelcased_column_names: List[str]) -> List[str]: - """Format camel cased column names to uppercased spaced column names - - Args: - camelcased_column_names (List[str]): Column names in camel case. - - Returns: - (List[str]): Column names in uppercase with spaces. - """ - return [camelcased_to_uppercased_spaced(column_name) for column_name in camelcased_column_names] diff --git a/octavia-cli/octavia_cli/list/listings.py b/octavia-cli/octavia_cli/list/listings.py deleted file mode 100644 index 8f7f49c64c17..000000000000 --- a/octavia-cli/octavia_cli/list/listings.py +++ /dev/null @@ -1,111 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import abc -from typing import List - -import airbyte_api_client -import octavia_cli.list.formatting as formatting -from airbyte_api_client.api import connection_api, destination_api, destination_definition_api, source_api, source_definition_api -from airbyte_api_client.model.workspace_id_request_body import WorkspaceIdRequestBody - - -class BaseListing(abc.ABC): - COMMON_LIST_FUNCTION_KWARGS = {"_check_return_type": False} - - @property - @abc.abstractmethod - def api( - self, - ): # pragma: no cover - pass - - @property - @abc.abstractmethod - def fields_to_display( - self, - ) -> List[str]: # pragma: no cover - pass - - @property - @abc.abstractmethod - def list_field_in_response( - self, - ) -> str: # pragma: no cover - pass - - @property - @abc.abstractmethod - def list_function_name( - self, - ) -> str: # pragma: no cover - pass - - @property - def _list_fn(self): - return getattr(self.api, self.list_function_name) - - @property - def list_function_kwargs(self) -> dict: - return {} - - def __init__(self, api_client: airbyte_api_client.ApiClient): - self.api_instance = self.api(api_client) - - def _parse_response(self, api_response) -> List[List[str]]: - items = [[item[field] for field in self.fields_to_display] for item in api_response[self.list_field_in_response]] - return items - - def get_listing(self) -> List[List[str]]: - api_response = self._list_fn(self.api_instance, **self.list_function_kwargs, **self.COMMON_LIST_FUNCTION_KWARGS) - return self._parse_response(api_response) - - def __repr__(self): - items = [formatting.format_column_names(self.fields_to_display)] + self.get_listing() - return formatting.display_as_table(items) - - -class SourceConnectorsDefinitions(BaseListing): - api = source_definition_api.SourceDefinitionApi - fields_to_display = ["name", "dockerRepository", "dockerImageTag", "sourceDefinitionId"] - list_field_in_response = "source_definitions" - list_function_name = "list_source_definitions" - - -class DestinationConnectorsDefinitions(BaseListing): - api = destination_definition_api.DestinationDefinitionApi - fields_to_display = ["name", "dockerRepository", "dockerImageTag", "destinationDefinitionId"] - list_field_in_response = "destination_definitions" - list_function_name = "list_destination_definitions" - - -class WorkspaceListing(BaseListing, abc.ABC): - def __init__(self, api_client: airbyte_api_client.ApiClient, workspace_id: str): - self.workspace_id = workspace_id - super().__init__(api_client) - - @property - def list_function_kwargs(self) -> dict: - return {"workspace_id_request_body": WorkspaceIdRequestBody(workspace_id=self.workspace_id)} - - -class Sources(WorkspaceListing): - api = source_api.SourceApi - fields_to_display = ["name", "sourceName", "sourceId"] - list_field_in_response = "sources" - list_function_name = "list_sources_for_workspace" - - -class Destinations(WorkspaceListing): - api = destination_api.DestinationApi - fields_to_display = ["name", "destinationName", "destinationId"] - list_field_in_response = "destinations" - list_function_name = "list_destinations_for_workspace" - - -class Connections(WorkspaceListing): - api = connection_api.ConnectionApi - fields_to_display = ["name", "connectionId", "status", "sourceId", "destinationId"] - list_field_in_response = "connections" - list_function_name = "list_connections_for_workspace" diff --git a/octavia-cli/octavia_cli/telemetry.py b/octavia-cli/octavia_cli/telemetry.py deleted file mode 100644 index 5c474b9693e4..000000000000 --- a/octavia-cli/octavia_cli/telemetry.py +++ /dev/null @@ -1,91 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import os -from typing import Optional - -import analytics -import click - - -def build_user_agent(octavia_version: str) -> str: - """Build user-agent for the API client according to octavia version. - - Args: - octavia_version (str): Current octavia version. - - Returns: - str: the user-agent string. - """ - return f"octavia-cli/{octavia_version}" - - -class TelemetryClient: - - WRITE_KEY = "ER8EjdRVFut7n05XPaaTKrSEnjLscyKr" - - def __init__(self, send_data: bool = False) -> None: - """Create a TelemetryClient instance. - - Args: - send_data (bool, optional): Whether the telemetry should be sent. Defaults to False. - """ - self.segment_client = analytics.Client(self.write_key, send=send_data) - - @property - def write_key(self) -> str: - """Retrieve the write key according to environment. - Developer can set the OCTAVIA_TELEMETRY_WRITE_KEY env var to send telemetry to another Segment source. - - Returns: - str: The write key to use with the analytics client. - """ - return os.getenv("OCTAVIA_TELEMETRY_WRITE_KEY", TelemetryClient.WRITE_KEY) - - def _create_command_name(self, ctx: click.Context, command_names: Optional[list] = None, extra_info_name: Optional[str] = None) -> str: - """Build the full command name by concatenating info names the context and its parents. - - Args: - ctx (click.Context): The click context from which we want to build the command name. - command_names (Optional[list], optional): Previously builds commands name (used for recursion). Defaults to None. - extra_info_name (Optional[str], optional): Extra info name if the context was not built yet. Defaults to None. - - Returns: - str: The full command name. - """ - if command_names is None: - command_names = [ctx.info_name] - else: - command_names.insert(0, ctx.info_name) - if ctx.parent is not None: - self._create_command_name(ctx.parent, command_names) - return " ".join(command_names) if not extra_info_name else " ".join(command_names + [extra_info_name]) - - def send_command_telemetry( - self, ctx: click.Context, error: Optional[Exception] = None, extra_info_name: Optional[str] = None, is_help: bool = False - ): - """Send telemetry with the analytics client. - The event name is the command name. - The context has the octavia version. - The properties hold success or failure of command run, error type if exists and other metadata. - - Args: - ctx (click.Context): Context from which the telemetry is built. - error (Optional[Exception], optional): The error that was raised. Defaults to None. - extra_info_name (Optional[str], optional): Extra info name if the context was not built yet. Defaults to None. - """ - user_id = ctx.obj.get("WORKSPACE_ID") if ctx.obj.get("ANONYMOUS_DATA_COLLECTION", True) is False else None - anonymous_id = None if user_id else "anonymous" - segment_context = {"app": {"name": "octavia-cli", "version": ctx.obj.get("OCTAVIA_VERSION")}} - segment_properties = { - "success": error is None, - "is_help": is_help, - "error_type": error.__class__.__name__ if error is not None else None, - "project_is_initialized": ctx.obj.get("PROJECT_IS_INITIALIZED"), - "airbyter": os.getenv("AIRBYTE_ROLE") == "airbyter", - } - command_name = self._create_command_name(ctx, extra_info_name=extra_info_name) - self.segment_client.track( - user_id=user_id, anonymous_id=anonymous_id, event=command_name, properties=segment_properties, context=segment_context - ) diff --git a/octavia-cli/publish.sh b/octavia-cli/publish.sh deleted file mode 100755 index 5a09728ddbed..000000000000 --- a/octavia-cli/publish.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -set -uxe -VERSION=$1 -GIT_REVISION=$2 -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) - -docker run --privileged --rm tonistiigi/binfmt --install all # This installs the emulator to build multi-arch images -set +e # Disable exit if the next command fails if the builder already exist. -docker buildx create --name octavia_builder > /dev/null 2>&1 -set -e # The previous command can fail safely if -docker buildx use octavia_builder -docker buildx inspect --bootstrap -docker buildx build --push --tag airbyte/octavia-cli:${VERSION} --platform=linux/arm64,linux/amd64 --label "io.airbyte.git-revision=${GIT_REVISION}" ${SCRIPT_DIR} diff --git a/octavia-cli/pytest.ini b/octavia-cli/pytest.ini deleted file mode 100644 index 58f2d9ae315e..000000000000 --- a/octavia-cli/pytest.ini +++ /dev/null @@ -1,7 +0,0 @@ -[pytest] -log_cli = 1 -log_cli_level = INFO -log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s) -log_cli_date_format=%Y-%m-%d %H:%M:%S -markers = - integration: marks tests as integration test (deselect with '-m "not integration"') \ No newline at end of file diff --git a/octavia-cli/setup.py b/octavia-cli/setup.py deleted file mode 100644 index 628defaeac7c..000000000000 --- a/octavia-cli/setup.py +++ /dev/null @@ -1,64 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import os -import pathlib - -from setuptools import find_packages, setup - -# The directory containing this file -HERE = pathlib.Path(__file__).parent - -# The text of the README file -README = (HERE / "README.md").read_text() - -setup( - name="octavia-cli", - version="0.50.0", - description="A command line interface to manage Airbyte configurations", - long_description=README, - author="Airbyte", - author_email="contact@airbyte.io", - license="MIT", - url="https://github.com/airbytehq/airbyte", - classifiers=[ - # This information is used when browsing on PyPi. - # Dev Status - "Development Status :: 3 - Alpha", - # Project Audience - "Intended Audience :: Developers", - "Topic :: Scientific/Engineering", - "Topic :: Software Development :: Libraries :: Python Modules", - "License :: OSI Approved :: MIT License", - # Python Version Support - "Programming Language :: Python :: 3.8", - ], - keywords="airbyte cli command-line-interface configuration", - project_urls={ - "Documentation": "https://docs.airbyte.io/", - "Source": "https://github.com/airbytehq/airbyte", - "Tracker": "https://github.com/airbytehq/airbyte/issues", - }, - packages=find_packages(exclude=("unit_tests", "integration_tests", "docs")), - package_data={"octavia_cli.generate": ["templates/*.j2"], "octavia_cli.init.example_files": ["example_api_http_headers.yaml"]}, - install_requires=[ - "click~=8.0.3", - f"airbyte_api_client @ file://{os.getcwd()}/build/airbyte_api_client", - "jinja2~=3.0.3", - "deepdiff~=5.7.0", - "pyyaml~=6.0", - "analytics-python~=1.4.0", - "python-slugify~=6.1.2", - "urllib3<2", - ], - python_requires=">=3.9.11", - extras_require={ - "tests": ["MyPy~=0.812", "pytest~=6.2.5", "pytest-cov", "pytest-mock", "pytest-recording", "requests-mock", "pre-commit"], - "sphinx-docs": [ - "Sphinx~=4.2", - "sphinx-rtd-theme~=1.0", - ], - }, - entry_points={"console_scripts": ["octavia=octavia_cli.entrypoint:octavia"]}, -) diff --git a/octavia-cli/unit_tests/__init__.py b/octavia-cli/unit_tests/__init__.py deleted file mode 100644 index 46b7376756ec..000000000000 --- a/octavia-cli/unit_tests/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/unit_tests/conftest.py b/octavia-cli/unit_tests/conftest.py deleted file mode 100644 index 2cf1853b5d60..000000000000 --- a/octavia-cli/unit_tests/conftest.py +++ /dev/null @@ -1,15 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import pytest - - -@pytest.fixture -def mock_api_client(mocker): - return mocker.Mock() - - -@pytest.fixture -def mock_telemetry_client(mocker): - return mocker.Mock() diff --git a/octavia-cli/unit_tests/test__import/__init__.py b/octavia-cli/unit_tests/test__import/__init__.py deleted file mode 100644 index c941b3045795..000000000000 --- a/octavia-cli/unit_tests/test__import/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/unit_tests/test__import/test_commands.py b/octavia-cli/unit_tests/test__import/test_commands.py deleted file mode 100644 index 5ddf0fee3242..000000000000 --- a/octavia-cli/unit_tests/test__import/test_commands.py +++ /dev/null @@ -1,233 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import pytest -from click.testing import CliRunner -from octavia_cli._import import commands - - -@pytest.fixture -def patch_click(mocker): - mocker.patch.object(commands, "click") - - -@pytest.fixture -def context_object(mock_api_client, mock_telemetry_client): - return { - "PROJECT_IS_INITIALIZED": True, - "API_CLIENT": mock_api_client, - "WORKSPACE_ID": "workspace_id", - "TELEMETRY_CLIENT": mock_telemetry_client, - } - - -def test_build_help_message(): - assert commands.build_help_message("source") == "Import an existing source to manage it with octavia-cli." - - -@pytest.mark.parametrize("ResourceClass", [commands.UnmanagedSource, commands.UnmanagedDestination]) -def test_import_source_or_destination(mocker, context_object, ResourceClass): - resource_type = ResourceClass.__name__.lower() - mocker.patch.object(commands.click, "style") - mocker.patch.object(commands.click, "echo") - mocker.patch.object(commands, "get_json_representation") - mocker.patch.object( - commands.json, - "loads", - mocker.Mock( - return_value={ - "name": "foo", - "connection_configuration": "bar", - f"{resource_type}_definition_id": f"{resource_type}_definition_id", - f"{resource_type}_id": f"my_{resource_type}_id", - } - ), - ) - mocker.patch.object(commands.definitions, "factory") - mocker.patch.object(commands.renderers, "ConnectorSpecificationRenderer") - expected_managed_resource, expected_state = (mocker.Mock(), mocker.Mock()) - mocker.patch.object( - commands.resources, - "factory", - mocker.Mock(return_value=mocker.Mock(manage=mocker.Mock(return_value=(expected_managed_resource, expected_state)))), - ) - commands.import_source_or_destination(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], ResourceClass, "resource_to_get") - commands.get_json_representation.assert_called_with( - context_object["API_CLIENT"], context_object["WORKSPACE_ID"], ResourceClass, "resource_to_get" - ) - commands.json.loads.assert_called_with(commands.get_json_representation.return_value) - remote_configuration = commands.json.loads.return_value - commands.definitions.factory.assert_called_with( - resource_type, context_object["API_CLIENT"], context_object["WORKSPACE_ID"], f"{resource_type}_definition_id" - ) - commands.renderers.ConnectorSpecificationRenderer.assert_called_with("foo", commands.definitions.factory.return_value) - renderer = commands.renderers.ConnectorSpecificationRenderer.return_value - renderer.import_configuration.assert_called_with(project_path=".", configuration=remote_configuration["connection_configuration"]) - commands.resources.factory.assert_called_with( - context_object["API_CLIENT"], context_object["WORKSPACE_ID"], renderer.import_configuration.return_value - ) - commands.resources.factory.return_value.manage.assert_called_with(remote_configuration[f"{resource_type}_id"]) - commands.click.style.assert_has_calls( - [ - mocker.call( - f"✅ - Imported {resource_type} {expected_managed_resource.name} in {renderer.import_configuration.return_value}. State stored in {expected_state.path}", - fg="green", - ), - mocker.call(f"⚠️ - Please update any secrets stored in {renderer.import_configuration.return_value}", fg="yellow"), - ] - ) - assert commands.click.echo.call_count == 2 - - -@pytest.mark.parametrize( - "source_exists, source_was_created, destination_exists, destination_was_created", - [ - (True, True, True, True), - (False, False, False, False), - (True, False, True, False), - (True, True, False, False), - (True, True, True, False), - ], -) -def test_import_connection(mocker, context_object, source_exists, source_was_created, destination_exists, destination_was_created): - mocker.patch.object(commands.click, "style") - mocker.patch.object(commands.click, "echo") - mocker.patch.object(commands, "get_json_representation") - mocker.patch.object( - commands.json, - "loads", - mocker.Mock( - return_value={ - "source": {"name": "my_source"}, - "destination": {"name": "my_destination"}, - "name": "my_connection", - "connection_id": "my_connection_id", - } - ), - ) - remote_configuration = commands.json.loads.return_value - mocker.patch.object(commands.definitions, "factory") - mock_source_configuration_path = mocker.Mock(is_file=mocker.Mock(return_value=source_exists)) - mock_destination_configuration_path = mocker.Mock(is_file=mocker.Mock(return_value=destination_exists)) - - mocker.patch.object( - commands.renderers.ConnectorSpecificationRenderer, - "get_output_path", - mocker.Mock(side_effect=[mock_source_configuration_path, mock_destination_configuration_path]), - ) - mocker.patch.object(commands.renderers, "ConnectionRenderer") - mock_managed_source = mocker.Mock(was_created=source_was_created) - mock_managed_destination = mocker.Mock(was_created=destination_was_created) - mock_remote_connection, mock_connection_state = mocker.Mock(), mocker.Mock() - mock_managed_connection = mocker.Mock(manage=mocker.Mock(return_value=(mock_remote_connection, mock_connection_state))) - - mocker.patch.object( - commands.resources, "factory", mocker.Mock(side_effect=[mock_managed_source, mock_managed_destination, mock_managed_connection]) - ) - if all([source_exists, destination_exists, source_was_created, destination_was_created]): - - commands.import_connection(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], "resource_to_get") - commands.get_json_representation.assert_called_with( - context_object["API_CLIENT"], context_object["WORKSPACE_ID"], commands.UnmanagedConnection, "resource_to_get" - ) - commands.renderers.ConnectorSpecificationRenderer.get_output_path.assert_has_calls( - [ - mocker.call(project_path=".", definition_type="source", resource_name="my_source"), - mocker.call(project_path=".", definition_type="destination", resource_name="my_destination"), - ] - ) - commands.resources.factory.assert_has_calls( - [ - mocker.call(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], mock_source_configuration_path), - mocker.call(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], mock_destination_configuration_path), - mocker.call( - context_object["API_CLIENT"], - context_object["WORKSPACE_ID"], - commands.renderers.ConnectionRenderer.return_value.import_configuration.return_value, - ), - ] - ) - commands.renderers.ConnectionRenderer.assert_called_with( - remote_configuration["name"], mock_managed_source, mock_managed_destination - ) - commands.renderers.ConnectionRenderer.return_value.import_configuration.assert_called_with(".", remote_configuration) - new_configuration_path = commands.renderers.ConnectionRenderer.return_value.import_configuration.return_value - commands.click.style.assert_called_with( - f"✅ - Imported connection {mock_remote_connection.name} in {new_configuration_path}. State stored in {mock_connection_state.path}", - fg="green", - ) - commands.click.echo.assert_called_with(commands.click.style.return_value) - if not source_exists or not destination_exists: - with pytest.raises( - commands.MissingResourceDependencyError, - match="is not managed by octavia-cli, please import and apply it before importing your connection.", - ): - commands.import_connection(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], "resource_to_get") - if source_exists and destination_exists and (not source_was_created or not destination_was_created): - with pytest.raises(commands.resources.NonExistingResourceError, match="Please run octavia apply before creating this connection."): - commands.import_connection(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], "resource_to_get") - - -@pytest.mark.parametrize("command", [commands.source, commands.destination, commands.connection, commands.all]) -def test_import_not_initialized(command): - runner = CliRunner() - result = runner.invoke(command, obj={"PROJECT_IS_INITIALIZED": False}) - assert result.exit_code == 1 - - -@pytest.mark.parametrize( - "command, ResourceClass, import_function", - [ - (commands.source, commands.UnmanagedSource, "import_source_or_destination"), - (commands.destination, commands.UnmanagedDestination, "import_source_or_destination"), - (commands.connection, None, "import_connection"), - ], -) -def test_import_commands(mocker, context_object, ResourceClass, command, import_function): - runner = CliRunner() - mock_import_function = mocker.Mock() - mocker.patch.object(commands, import_function, mock_import_function) - result = runner.invoke(command, ["resource_to_import"], obj=context_object) - if import_function == "import_source_or_destination": - mock_import_function.assert_called_with( - context_object["API_CLIENT"], context_object["WORKSPACE_ID"], ResourceClass, "resource_to_import" - ) - else: - mock_import_function.assert_called_with(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], "resource_to_import") - assert result.exit_code == 0 - - -def test_import_all(mocker, context_object): - runner = CliRunner() - mock_manager = mocker.Mock() - mocker.patch.object(commands, "import_source_or_destination", mock_manager.import_source_or_destination) - mocker.patch.object(commands, "import_connection", mock_manager.import_connection) - mocker.patch.object( - commands, "UnmanagedSources", return_value=mocker.Mock(get_listing=mocker.Mock(return_value=[("_", "_", "source_resource_id")])) - ) - mocker.patch.object( - commands, - "UnmanagedDestinations", - return_value=mocker.Mock(get_listing=mocker.Mock(return_value=[("_", "_", "destination_resource_id")])), - ) - mocker.patch.object( - commands, - "UnmanagedConnections", - return_value=mocker.Mock(get_listing=mocker.Mock(return_value=[("_", "connection_resource_id", "_", "_", "_")])), - ) - result = runner.invoke(commands.all, obj=context_object) - - commands.UnmanagedSources.return_value.get_listing.assert_called_once() - commands.UnmanagedDestinations.return_value.get_listing.assert_called_once() - commands.UnmanagedConnections.return_value.get_listing.assert_called_once() - assert result.exit_code == 0 - assert mock_manager.mock_calls[0] == mocker.call.import_source_or_destination( - context_object["API_CLIENT"], "workspace_id", commands.UnmanagedSource, "source_resource_id" - ) - assert mock_manager.mock_calls[1] == mocker.call.import_source_or_destination( - context_object["API_CLIENT"], "workspace_id", commands.UnmanagedDestination, "destination_resource_id" - ) - assert mock_manager.mock_calls[2] == mocker.call.import_connection( - context_object["API_CLIENT"], "workspace_id", "connection_resource_id" - ) diff --git a/octavia-cli/unit_tests/test_api_http_headers.py b/octavia-cli/unit_tests/test_api_http_headers.py deleted file mode 100644 index a48fecf3b512..000000000000 --- a/octavia-cli/unit_tests/test_api_http_headers.py +++ /dev/null @@ -1,203 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import os - -import pytest -from octavia_cli import api_http_headers - - -class TestApiHttpHeader: - @pytest.mark.parametrize( - "header_name, header_value, expected_error, expected_name, expected_value", - [ - ("foo", "bar", None, "foo", "bar"), - (" foo ", " bar ", None, "foo", "bar"), - ("", "bar", AttributeError, None, None), - ("foo", "", AttributeError, None, None), - ], - ) - def test_init(self, header_name, header_value, expected_error, expected_name, expected_value): - if expected_error is None: - api_http_header = api_http_headers.ApiHttpHeader(header_name, header_value) - assert api_http_header.name == expected_name and api_http_header.value == expected_value - else: - with pytest.raises(expected_error): - api_http_headers.ApiHttpHeader(header_name, header_value) - - -@pytest.fixture -def api_http_header_env_var(): - os.environ["API_HTTP_HEADER_IN_ENV_VAR"] = "bar" - yield "bar" - del os.environ["API_HTTP_HEADER_IN_ENV_VAR"] - - -@pytest.mark.parametrize( - "yaml_document, expected_api_http_headers, expected_error", - [ - ( - """ - headers: - Content-Type: ${API_HTTP_HEADER_IN_ENV_VAR} - """, - [api_http_headers.ApiHttpHeader("Content-Type", "bar")], - None, - ), - ( - """ - headers: - Content-Type: application/json - """, - [api_http_headers.ApiHttpHeader("Content-Type", "application/json")], - None, - ), - ( - """ - headers: - Content-Type: application/csv - Content-Type: application/json - """, - [api_http_headers.ApiHttpHeader("Content-Type", "application/json")], - None, - ), - ( - """ - headers: - Content-Type: application/json - Authorization: Bearer XXX - """, - [ - api_http_headers.ApiHttpHeader("Content-Type", "application/json"), - api_http_headers.ApiHttpHeader("Authorization", "Bearer XXX"), - ], - None, - ), - ("no_headers: foo", None, api_http_headers.InvalidApiHttpHeadersFileError), - ("", None, api_http_headers.InvalidApiHttpHeadersFileError), - ( - """ - some random words - - some dashes: - - and_next - """.strip(), - None, - api_http_headers.InvalidApiHttpHeadersFileError, - ), - ], -) -def test_deserialize_file_based_headers(api_http_header_env_var, tmp_path, yaml_document, expected_api_http_headers, expected_error): - yaml_file_path = tmp_path / "api_http_headers.yaml" - yaml_file_path.write_text(yaml_document) - if expected_error is None: - file_based_headers = api_http_headers.deserialize_file_based_headers(yaml_file_path) - assert file_based_headers == expected_api_http_headers - else: - with pytest.raises(expected_error): - api_http_headers.deserialize_file_based_headers(yaml_file_path) - - -@pytest.mark.parametrize( - "option_based_headers, expected_option_based_headers", - [ - ([("Content-Type", "application/json")], [api_http_headers.ApiHttpHeader("Content-Type", "application/json")]), - ( - [("Content-Type", "application/yaml"), ("Content-Type", "application/json")], - [api_http_headers.ApiHttpHeader("Content-Type", "application/json")], - ), - ( - [("Content-Type", "application/json"), ("Authorization", "Bearer XXX")], - [ - api_http_headers.ApiHttpHeader("Content-Type", "application/json"), - api_http_headers.ApiHttpHeader("Authorization", "Bearer XXX"), - ], - ), - ([], []), - ], -) -def test_deserialize_option_based_headers(option_based_headers, expected_option_based_headers): - assert api_http_headers.deserialize_option_based_headers(option_based_headers) == expected_option_based_headers - - -@pytest.mark.parametrize( - "yaml_document, option_based_raw_headers, expected_merged_headers", - [ - ( - """ - headers: - Content-Type: application/csv - """, - [("Content-Type", "application/json")], - [api_http_headers.ApiHttpHeader("Content-Type", "application/json")], - ), - ( - None, - [("Content-Type", "application/json")], - [api_http_headers.ApiHttpHeader("Content-Type", "application/json")], - ), - ( - """ - headers: - Content-Type: application/json - """, - [], - [api_http_headers.ApiHttpHeader("Content-Type", "application/json")], - ), - ( - """ - headers: - Content-Type: application/json - """, - None, - [api_http_headers.ApiHttpHeader("Content-Type", "application/json")], - ), - ( - """ - headers: - Content-Type: application/json - """, - [("Authorization", "Bearer XXX")], - [ - api_http_headers.ApiHttpHeader("Content-Type", "application/json"), - api_http_headers.ApiHttpHeader("Authorization", "Bearer XXX"), - ], - ), - ( - """ - headers: - Content-Type: application/json - Foo: Bar - """, - [("Authorization", "Bearer XXX")], - [ - api_http_headers.ApiHttpHeader("Content-Type", "application/json"), - api_http_headers.ApiHttpHeader("Foo", "Bar"), - api_http_headers.ApiHttpHeader("Authorization", "Bearer XXX"), - ], - ), - ], -) -def test_merge_api_headers(tmp_path, mocker, yaml_document, option_based_raw_headers, expected_merged_headers): - mocker.patch.object(api_http_headers.click, "echo") - if yaml_document is not None: - yaml_file_path = tmp_path / "api_http_headers.yaml" - yaml_file_path.write_text(yaml_document) - else: - yaml_file_path = None - assert api_http_headers.merge_api_headers(option_based_raw_headers, yaml_file_path) == expected_merged_headers - if option_based_raw_headers and yaml_file_path: - api_http_headers.click.echo.assert_called_with( - "ℹ️ - You passed API HTTP headers in a file and in options at the same time. Option based headers will override file based headers." - ) - - -def test_set_api_headers_on_api_client(mocker, mock_api_client): - headers = [api_http_headers.ApiHttpHeader("foo", "bar"), api_http_headers.ApiHttpHeader("bar", "foo")] - api_http_headers.set_api_headers_on_api_client(mock_api_client, headers) - mock_api_client.set_default_header.assert_has_calls( - [ - mocker.call(headers[0].name, headers[0].value), - mocker.call(headers[1].name, headers[1].value), - ] - ) diff --git a/octavia-cli/unit_tests/test_apply/__init__.py b/octavia-cli/unit_tests/test_apply/__init__.py deleted file mode 100644 index 46b7376756ec..000000000000 --- a/octavia-cli/unit_tests/test_apply/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/unit_tests/test_apply/test_commands.py b/octavia-cli/unit_tests/test_apply/test_commands.py deleted file mode 100644 index 2666ae86d64a..000000000000 --- a/octavia-cli/unit_tests/test_apply/test_commands.py +++ /dev/null @@ -1,300 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import pytest -from click.testing import CliRunner -from octavia_cli.apply import commands - - -@pytest.fixture -def patch_click(mocker): - mocker.patch.object(commands, "click") - - -@pytest.fixture -def context_object(mock_api_client, mock_telemetry_client): - return { - "PROJECT_IS_INITIALIZED": True, - "API_CLIENT": mock_api_client, - "WORKSPACE_ID": "workspace_id", - "TELEMETRY_CLIENT": mock_telemetry_client, - } - - -def test_apply_not_initialized(): - runner = CliRunner() - result = runner.invoke(commands.apply, obj={"PROJECT_IS_INITIALIZED": False}) - assert result.exit_code == 1 - - -def test_apply_without_custom_configuration_file(mocker, context_object): - runner = CliRunner() - local_files = ["foo", "bar"] - mocker.patch.object(commands, "find_local_configuration_files", mocker.Mock(return_value=local_files)) - mock_resources_to_apply = [mocker.Mock(), mocker.Mock()] - mocker.patch.object(commands, "get_resources_to_apply", mocker.Mock(return_value=mock_resources_to_apply)) - mocker.patch.object(commands, "apply_single_resource") - result = runner.invoke(commands.apply, obj=context_object) - assert result.exit_code == 0 - commands.find_local_configuration_files.assert_called_once() - commands.get_resources_to_apply.assert_called_once_with(local_files, context_object["API_CLIENT"], context_object["WORKSPACE_ID"]) - commands.apply_single_resource([mocker.call(r, False) for r in commands.get_resources_to_apply.return_value]) - - -def test_apply_with_custom_configuration_file(mocker, context_object): - runner = CliRunner() - mocker.patch.object(commands, "find_local_configuration_files") - mocker.patch.object(commands, "get_resources_to_apply") - mocker.patch.object(commands, "apply_single_resource") - result = runner.invoke(commands.apply, ["--file", "foo", "--file", "bar"], obj=context_object) - assert result.exit_code == 0 - commands.find_local_configuration_files.assert_not_called() - commands.get_resources_to_apply.assert_called_with(("foo", "bar"), context_object["API_CLIENT"], context_object["WORKSPACE_ID"]) - - -def test_apply_with_custom_configuration_file_force(mocker, context_object): - runner = CliRunner() - mocker.patch.object(commands, "find_local_configuration_files") - mocker.patch.object(commands, "get_resources_to_apply", mocker.Mock(return_value=[mocker.Mock()])) - mocker.patch.object(commands, "apply_single_resource") - result = runner.invoke(commands.apply, ["--file", "foo", "--file", "bar", "--force"], obj=context_object) - assert result.exit_code == 0 - commands.apply_single_resource.assert_called_with(commands.get_resources_to_apply.return_value[0], True) - - -def test_get_resource_to_apply(mocker, mock_api_client): - local_files_priorities = [("foo", 2), ("bar", 1)] - mock_resource_factory = mocker.Mock() - mock_resource_factory.side_effect = [mocker.Mock(APPLY_PRIORITY=priority) for _, priority in local_files_priorities] - mocker.patch.object(commands, "resource_factory", mock_resource_factory) - - resources_to_apply = commands.get_resources_to_apply([f[0] for f in local_files_priorities], mock_api_client, "workspace_id") - assert resources_to_apply == sorted(resources_to_apply, key=lambda r: r.APPLY_PRIORITY) - assert commands.resource_factory.call_count == len(local_files_priorities) - commands.resource_factory.assert_has_calls([mocker.call(mock_api_client, "workspace_id", path) for path, _ in local_files_priorities]) - - -@pytest.mark.parametrize("resource_was_created", [True, False]) -def test_apply_single_resource(patch_click, mocker, resource_was_created): - mocker.patch.object(commands, "update_resource", mocker.Mock(return_value=["updated"])) - mocker.patch.object(commands, "create_resource", mocker.Mock(return_value=["created"])) - resource = mocker.Mock(was_created=resource_was_created, resource_name="my_resource_name") - force = mocker.Mock() - commands.apply_single_resource(resource, force) - if resource_was_created: - commands.update_resource.assert_called_once_with(resource, force) - commands.create_resource.assert_not_called() - expected_message = ( - "🐙 - my_resource_name exists on your Airbyte instance according to your state file, let's check if we need to update it!" - ) - expected_message_color = "yellow" - expected_echo_calls = [mocker.call(commands.click.style.return_value), mocker.call("\n".join(["updated"]))] - else: - commands.update_resource.assert_not_called() - commands.create_resource.assert_called_once_with(resource) - expected_message = "🐙 - my_resource_name does not exists on your Airbyte instance, let's create it!" - expected_message_color = "green" - expected_echo_calls = [mocker.call(commands.click.style.return_value), mocker.call("\n".join(["created"]))] - commands.click.style.assert_called_with(expected_message, fg=expected_message_color) - commands.click.echo.assert_has_calls(expected_echo_calls) - - -@pytest.mark.parametrize( - "force,user_validation,local_file_changed,expect_update,expected_reason", - [ - pytest.param( - True, True, True, True, "🚨 - Running update because the force mode is activated.", id="1 - Check if force has the top priority." - ), - pytest.param( - True, - False, - True, - True, - "🚨 - Running update because the force mode is activated.", - id="2 - Check if force has the top priority.", - ), - pytest.param( - True, - False, - False, - True, - "🚨 - Running update because the force mode is activated.", - id="3 - Check if force has the top priority.", - ), - pytest.param( - True, - True, - False, - True, - "🚨 - Running update because the force mode is activated.", - id="4 - Check if force has the top priority.", - ), - pytest.param( - False, - True, - True, - True, - "🟢 - Running update because you validated the changes.", - id="Check if user validation has priority over local file change.", - ), - pytest.param( - False, - False, - True, - False, - "🔴 - Did not update because you refused the changes.", - id="Check if user validation has priority over local file change.", - ), - pytest.param( - False, - None, - True, - True, - "🟡 - Running update because a local file change was detected and a secret field might have been edited.", - id="Check if local_file_changed runs even if user validation is None.", - ), - pytest.param( - False, - None, - False, - False, - "😴 - Did not update because no change detected.", - id="Check no update if no local change and user validation is None.", - ), - ], -) -def test_should_update_resource(patch_click, mocker, force, user_validation, local_file_changed, expect_update, expected_reason): - should_update, update_reason = commands.should_update_resource(force, user_validation, local_file_changed) - assert should_update == expect_update - assert update_reason == commands.click.style.return_value - commands.click.style.assert_called_with(expected_reason, fg="green") - - -@pytest.mark.parametrize( - "diff,expected_number_calls_to_display_diff_line", - [("", 0), ("First diff line", 1), ("First diff line\nSecond diff line", 2), ("First diff line\nSecond diff line\nThird diff line", 3)], -) -def test_prompt_for_diff_validation(patch_click, mocker, diff, expected_number_calls_to_display_diff_line): - mocker.patch.object(commands, "display_diff_line") - output = commands.prompt_for_diff_validation("my_resource", diff) - assert commands.display_diff_line.call_count == expected_number_calls_to_display_diff_line - if diff and expected_number_calls_to_display_diff_line > 0: - commands.display_diff_line.assert_has_calls([mocker.call(line) for line in diff.split("\n")]) - commands.click.style.assert_has_calls( - [ - mocker.call( - "👀 - Here's the computed diff (🚨 remind that diff on secret fields are not displayed):", fg="magenta", bold=True - ), - mocker.call("❓ - Do you want to update my_resource?", bold=True), - ] - ) - commands.click.echo.assert_called_with(commands.click.style.return_value) - assert output == commands.click.confirm.return_value - else: - assert output is False - - -def test_create_resource(patch_click, mocker): - mock_created_resource = mocker.Mock() - mock_state = mocker.Mock() - mock_resource = mocker.Mock(create=mocker.Mock(return_value=(mock_created_resource, mock_state))) - output_messages = commands.create_resource(mock_resource) - mock_resource.create.assert_called_once() - assert output_messages == [commands.click.style.return_value, commands.click.style.return_value] - commands.click.style.assert_has_calls( - [ - mocker.call(f"🎉 - Successfully created {mock_created_resource.name} on your Airbyte instance!", fg="green", bold=True), - mocker.call(f"💾 - New state for {mock_created_resource.name} saved at {mock_state.path}", fg="yellow"), - ] - ) - - -@pytest.mark.parametrize( - "force,diff,local_file_changed,expect_prompt,user_validation,expect_update", - [ - pytest.param(True, True, True, False, False, True, id="Force, diff, local file change -> no prompt, no validation, expect update."), - pytest.param( - True, True, False, False, False, True, id="Force, diff, no local file change -> no prompt, no validation, expect update." - ), - pytest.param( - True, False, False, False, False, True, id="Force, no diff, no local file change -> no prompt, no validation, expect update." - ), - pytest.param( - True, False, True, False, False, True, id="Force, no diff, local file change -> no prompt, no validation, expect update." - ), - pytest.param( - False, True, True, True, True, True, id="No force, diff, local file change -> expect prompt, validation, expect update." - ), - pytest.param( - False, True, True, True, False, False, id="No force, diff, local file change -> expect prompt, no validation, no update." - ), - pytest.param( - False, True, False, True, True, True, id="No force, diff, no local file change -> expect prompt, validation, expect update." - ), - pytest.param( - False, True, False, True, False, False, id="No force, diff, no local file change -> expect prompt, no validation, no update." - ), - pytest.param( - False, False, True, False, False, True, id="No force, no diff, local file change -> no prompt, no validation, expect update." - ), - pytest.param( - False, False, False, False, False, False, id="No force, no diff, no local file change -> no prompt, no validation, no update." - ), - ], -) -def test_update_resource(patch_click, mocker, force, diff, local_file_changed, expect_prompt, user_validation, expect_update): - mock_updated_resource = mocker.Mock() - mock_state = mocker.Mock() - mock_resource = mocker.Mock( - get_diff_with_remote_resource=mocker.Mock(return_value=diff), - resource_name="my_resource", - local_file_changed=local_file_changed, - update=mocker.Mock(return_value=(mock_updated_resource, mock_state)), - ) - mocker.patch.object(commands, "prompt_for_diff_validation", mocker.Mock(return_value=user_validation)) - - output_messages = commands.update_resource(mock_resource, force) - commands.click.echo.assert_called_once() - - if expect_prompt: - commands.prompt_for_diff_validation.assert_called_once_with("my_resource", diff) - else: - commands.prompt_for_diff_validation.assert_not_called() - if expect_update: - mock_resource.update.assert_called_once() - else: - mock_resource.update.assert_not_called() - - if expect_update: - assert output_messages == [ - commands.click.style.return_value, - commands.click.style.return_value, - ] - commands.click.style.assert_has_calls( - [ - mocker.call(f"🎉 - Successfully updated {mock_updated_resource.name} on your Airbyte instance!", fg="green", bold=True), - mocker.call(f"💾 - New state for {mock_updated_resource.name} stored at {mock_state.path}.", fg="yellow"), - ] - ) - else: - assert output_messages == [] - - -def test_find_local_configuration_files(mocker): - project_directories = ["sources", "connections", "destinations"] - mocker.patch.object(commands, "REQUIRED_PROJECT_DIRECTORIES", project_directories) - mocker.patch.object(commands, "glob", mocker.Mock(return_value=["foo.yaml"])) - configuration_files = commands.find_local_configuration_files() - assert isinstance(configuration_files, list) - commands.glob.assert_has_calls([mocker.call(f"./{directory}/**/configuration.yaml") for directory in project_directories]) - assert configuration_files == ["foo.yaml" for _ in range(len(project_directories))] - - -def test_find_local_configuration_files_no_file_found(patch_click, mocker): - project_directories = ["sources", "connections", "destinations"] - mocker.patch.object(commands, "REQUIRED_PROJECT_DIRECTORIES", project_directories) - mocker.patch.object(commands, "glob", mocker.Mock(return_value=[])) - configuration_files = commands.find_local_configuration_files() - assert not configuration_files - commands.click.style.assert_called_once_with("😒 - No YAML file found to run apply.", fg="red") diff --git a/octavia-cli/unit_tests/test_apply/test_diff_helpers.py b/octavia-cli/unit_tests/test_apply/test_diff_helpers.py deleted file mode 100644 index 96816d299e68..000000000000 --- a/octavia-cli/unit_tests/test_apply/test_diff_helpers.py +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import pytest -from octavia_cli.apply import diff_helpers - - -def test_hash_config(): - data_to_hash = {"example": "foo"} - assert diff_helpers.hash_config(data_to_hash) == "8d621bd700ff9a864bc603f56b4ec73536110b37d814dd4629767e898da70bef" - - -@pytest.mark.parametrize( - "obj, expected_output", - [ - (diff_helpers.SECRET_MASK, True), - ("not secret", False), - ({}, False), - ], -) -def test_exclude_secrets_from_diff(obj, expected_output): - assert diff_helpers.exclude_secrets_from_diff(obj, "foo") == expected_output - - -def test_compute_diff(mocker): - mocker.patch.object(diff_helpers, "DeepDiff") - diff = diff_helpers.compute_diff("foo", "bar") - assert diff == diff_helpers.DeepDiff.return_value - diff_helpers.DeepDiff.assert_called_with("foo", "bar", view="tree", exclude_obj_callback=diff_helpers.exclude_secrets_from_diff) - - -@pytest.mark.parametrize( - "diff_line,expected_message,expected_color", - [ - ("resource changed from", "E - resource changed from", "yellow"), - ("resource added", "+ - resource added", "green"), - ("resource removed", "- - resource removed", "red"), - ("whatever", " - whatever", None), - ], -) -def test_display_diff_line(mocker, diff_line, expected_message, expected_color): - mocker.patch.object(diff_helpers, "click") - diff_helpers.display_diff_line(diff_line) - diff_helpers.click.style.assert_called_with(f"\t{expected_message}", fg=expected_color) - diff_helpers.click.echo.assert_called_with(diff_helpers.click.style.return_value) diff --git a/octavia-cli/unit_tests/test_apply/test_resources.py b/octavia-cli/unit_tests/test_apply/test_resources.py deleted file mode 100644 index f13cb932cdfd..000000000000 --- a/octavia-cli/unit_tests/test_apply/test_resources.py +++ /dev/null @@ -1,956 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from copy import deepcopy -from unittest.mock import mock_open, patch - -import pytest -from airbyte_api_client import ApiException -from airbyte_api_client.model.airbyte_catalog import AirbyteCatalog -from airbyte_api_client.model.connection_schedule_data_basic_schedule import ConnectionScheduleDataBasicSchedule -from airbyte_api_client.model.connection_schedule_type import ConnectionScheduleType -from airbyte_api_client.model.connection_status import ConnectionStatus -from airbyte_api_client.model.destination_definition_id_request_body import DestinationDefinitionIdRequestBody -from airbyte_api_client.model.destination_definition_id_with_workspace_id import DestinationDefinitionIdWithWorkspaceId -from airbyte_api_client.model.namespace_definition_type import NamespaceDefinitionType -from airbyte_api_client.model.operation_create import OperationCreate -from airbyte_api_client.model.operator_type import OperatorType -from airbyte_api_client.model.resource_requirements import ResourceRequirements -from airbyte_api_client.model.source_definition_id_request_body import SourceDefinitionIdRequestBody -from airbyte_api_client.model.source_definition_id_with_workspace_id import SourceDefinitionIdWithWorkspaceId -from airbyte_api_client.model.web_backend_operation_create_or_update import WebBackendOperationCreateOrUpdate -from octavia_cli.apply import resources, yaml_loaders - - -class TestResourceState: - def test_init(self, mocker): - mocker.patch.object(resources, "os") - state = resources.ResourceState("config_path", "workspace_id", "resource_id", 123, "config_hash") - assert state.configuration_path == "config_path" - assert state.workspace_id == "workspace_id" - assert state.resource_id == "resource_id" - assert state.generation_timestamp == 123 - assert state.configuration_hash == "config_hash" - assert state.path == resources.os.path.join.return_value - resources.os.path.dirname.assert_called_with("config_path") - resources.os.path.join.assert_called_with(resources.os.path.dirname.return_value, "state_workspace_id.yaml") - - @pytest.fixture - def state(self): - return resources.ResourceState("config_path", "workspace_id", "resource_id", 123, "config_hash") - - def test_as_dict(self, state): - assert state.as_dict() == { - "configuration_path": state.configuration_path, - "resource_id": state.resource_id, - "generation_timestamp": state.generation_timestamp, - "configuration_hash": state.configuration_hash, - "workspace_id": state.workspace_id, - } - - def test_save(self, mocker, state): - mocker.patch.object(resources, "yaml") - mocker.patch.object(state, "as_dict") - - expected_content = state.as_dict.return_value - with patch("builtins.open", mock_open()) as mock_file: - state._save() - mock_file.assert_called_with(state.path, "w") - resources.yaml.dump.assert_called_with(expected_content, mock_file.return_value) - - def test_create(self, mocker): - mocker.patch.object(resources.time, "time", mocker.Mock(return_value=0)) - mocker.patch.object(resources.ResourceState, "_save") - state = resources.ResourceState.create("config_path", "my_hash", "workspace_id", "resource_id") - assert isinstance(state, resources.ResourceState) - resources.ResourceState._save.assert_called_once() - assert state.configuration_path == "config_path" - assert state.resource_id == "resource_id" - assert state.generation_timestamp == 0 - assert state.configuration_hash == "my_hash" - - def test_delete(self, mocker, state): - mocker.patch.object(resources.os, "remove") - state.delete() - resources.os.remove.assert_called_with(state.path) - - def test_from_file(self, mocker): - mocker.patch.object(resources, "yaml") - resources.yaml.safe_load.return_value = { - "configuration_path": "config_path", - "resource_id": "resource_id", - "generation_timestamp": 0, - "configuration_hash": "my_hash", - "workspace_id": "workspace_id", - } - with patch("builtins.open", mock_open(read_data="data")) as mock_file: - state = resources.ResourceState.from_file("state_workspace_id.yaml") - resources.yaml.safe_load.assert_called_with(mock_file.return_value) - assert isinstance(state, resources.ResourceState) - assert state.configuration_path == "config_path" - assert state.resource_id == "resource_id" - assert state.generation_timestamp == 0 - assert state.configuration_hash == "my_hash" - - def test__get_path_from_configuration_and_workspace_id(self, mocker): - mocker.patch.object(resources.os.path, "dirname", mocker.Mock(return_value="my_dir")) - state_path = resources.ResourceState._get_path_from_configuration_and_workspace_id("config_path", "workspace_id") - assert state_path == "my_dir/state_workspace_id.yaml" - resources.os.path.dirname.assert_called_with("config_path") - - def test_from_configuration_path_and_workspace(self, mocker): - mocker.patch.object(resources.ResourceState, "_get_path_from_configuration_and_workspace_id") - mocker.patch.object(resources.ResourceState, "from_file") - state = resources.ResourceState.from_configuration_path_and_workspace("config_path", "workspace_id") - assert state == resources.ResourceState.from_file.return_value - resources.ResourceState.from_file.assert_called_with( - resources.ResourceState._get_path_from_configuration_and_workspace_id.return_value - ) - resources.ResourceState._get_path_from_configuration_and_workspace_id.assert_called_with("config_path", "workspace_id") - - def test_migrate(self, mocker): - mocker.patch.object(resources.ResourceState, "from_file") - mocker.patch.object(resources.ResourceState, "create") - new_state = resources.ResourceState.migrate("old_state_path", "workspace_id") - resources.ResourceState.from_file.assert_called_with("old_state_path") - old_state = resources.ResourceState.from_file.return_value - resources.ResourceState.create.assert_called_with( - old_state.configuration_path, old_state.configuration_hash, "workspace_id", old_state.resource_id - ) - old_state.delete.assert_called_once() - assert new_state == resources.ResourceState.create.return_value - - -@pytest.fixture -def local_configuration(): - return { - "exotic_attribute": "foo", - "configuration": {"foo": "bar"}, - "resource_name": "bar", - "definition_id": "bar", - "definition_image": "fooo", - "definition_version": "barrr", - } - - -class TestBaseResource: - @pytest.fixture - def patch_base_class(self, mocker): - # Mock abstract methods to enable instantiating abstract class - mocker.patch.object(resources.BaseResource, "__abstractmethods__", set()) - mocker.patch.object(resources.BaseResource, "create_function_name", "create_resource") - mocker.patch.object(resources.BaseResource, "resource_id_field", "resource_id") - mocker.patch.object(resources.BaseResource, "update_function_name", "update_resource") - mocker.patch.object(resources.BaseResource, "get_function_name", "get_resource") - mocker.patch.object(resources.BaseResource, "resource_type", "universal_resource") - mocker.patch.object(resources.BaseResource, "api") - - def test_init_no_remote_resource(self, mocker, patch_base_class, mock_api_client, local_configuration): - mocker.patch.object(resources.BaseResource, "_get_state_from_file", mocker.Mock(return_value=None)) - mocker.patch.object(resources, "hash_config") - resource = resources.BaseResource(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - assert resource.APPLY_PRIORITY == 0 - assert resource.workspace_id == "workspace_id" - assert resource.raw_configuration == local_configuration - assert resource.configuration_path == "bar.yaml" - assert resource.api_instance == resource.api.return_value - resource.api.assert_called_with(mock_api_client) - assert resource.state == resource._get_state_from_file.return_value - assert resource.remote_resource is None - assert resource.was_created is False - assert resource.local_file_changed is True - assert resource.resource_id is None - - def test_init_with_remote_resource_not_changed(self, mocker, patch_base_class, mock_api_client, local_configuration): - mocker.patch.object( - resources.BaseResource, "_get_state_from_file", mocker.Mock(return_value=mocker.Mock(configuration_hash="my_hash")) - ) - mocker.patch.object(resources.BaseResource, "_get_remote_resource", mocker.Mock(return_value={"resource_id": "my_resource_id"})) - - mocker.patch.object(resources, "hash_config", mocker.Mock(return_value="my_hash")) - resource = resources.BaseResource(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - assert resource.was_created is True - assert resource.local_file_changed is False - assert resource.resource_id == resource.state.resource_id - - def test_init_with_remote_resource_changed(self, mocker, patch_base_class, mock_api_client, local_configuration): - mocker.patch.object( - resources.BaseResource, - "_get_state_from_file", - mocker.Mock(return_value=mocker.Mock(configuration_hash="my_state_hash")), - ) - mocker.patch.object(resources.BaseResource, "_get_remote_resource", mocker.Mock(return_value={"resource_id": "my_resource_id"})) - mocker.patch.object(resources, "hash_config", mocker.Mock(return_value="my_new_hash")) - resource = resources.BaseResource(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - assert resource.was_created is True - assert resource.local_file_changed is True - assert resource.resource_id == resource.state.resource_id - - @pytest.fixture - def resource(self, patch_base_class, mock_api_client, local_configuration): - return resources.BaseResource(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - - def test_get_remote_resource(self, resource, mocker): - mocker.patch.object(resource, "_get_fn") - remote_resource = resource._get_remote_resource() - assert remote_resource == resource._get_fn.return_value - resource._get_fn.assert_called_with(resource.api_instance, resource.get_payload) - - @pytest.mark.parametrize( - "state_path_is_file, legacy_state_path_is_file, confirm_migration", - [(True, False, False), (False, True, True), (False, True, False), (False, False, False)], - ) - def test_get_state_from_file(self, mocker, resource, state_path_is_file, legacy_state_path_is_file, confirm_migration): - mocker.patch.object(resources, "os") - mocker.patch.object(resources.click, "confirm", mocker.Mock(return_value=confirm_migration)) - mock_expected_state_path = mocker.Mock(is_file=mocker.Mock(return_value=state_path_is_file)) - mock_expected_legacy_state_path = mocker.Mock(is_file=mocker.Mock(return_value=legacy_state_path_is_file)) - mocker.patch.object(resources, "Path", mocker.Mock(side_effect=[mock_expected_state_path, mock_expected_legacy_state_path])) - mocker.patch.object(resources, "ResourceState") - - if legacy_state_path_is_file and not confirm_migration: - with pytest.raises(resources.InvalidStateError): - state = resource._get_state_from_file(resource.configuration_path, resource.workspace_id) - else: - state = resource._get_state_from_file(resource.configuration_path, resource.workspace_id) - - resources.os.path.dirname.assert_called_with(resource.configuration_path) - resources.os.path.join.assert_has_calls( - [ - mocker.call(resources.os.path.dirname.return_value, f"state_{resource.workspace_id}.yaml"), - mocker.call(resources.os.path.dirname.return_value, "state.yaml"), - ] - ) - resources.Path.assert_called_with(resources.os.path.join.return_value) - mock_expected_state_path.is_file.assert_called_once() - if state_path_is_file: - resources.ResourceState.from_file.assert_called_with(mock_expected_state_path) - assert state == resources.ResourceState.from_file.return_value - mock_expected_legacy_state_path.is_file.assert_not_called() - elif legacy_state_path_is_file: - if confirm_migration: - mock_expected_legacy_state_path.is_file.assert_called_once() - resources.ResourceState.migrate.assert_called_with(mock_expected_legacy_state_path, resource.workspace_id) - assert state == resources.ResourceState.migrate.return_value - else: - assert state is None - - @pytest.mark.parametrize( - "was_created", - [True, False], - ) - def test_get_diff_with_remote_resource(self, patch_base_class, mocker, mock_api_client, local_configuration, was_created): - mocker.patch.object(resources.BaseResource, "_get_remote_comparable_configuration") - mocker.patch.object(resources.BaseResource, "was_created", was_created) - resource = resources.BaseResource(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - mocker.patch.object(resources, "compute_diff") - if was_created: - diff = resource.get_diff_with_remote_resource() - resources.compute_diff.assert_called_with(resource._get_remote_comparable_configuration.return_value, resource.configuration) - assert diff == resources.compute_diff.return_value.pretty.return_value - else: - with pytest.raises(resources.NonExistingResourceError): - resource.get_diff_with_remote_resource() - - def test_create_or_update(self, mocker, resource): - expected_results = {resource.resource_id_field: "resource_id"} - operation_fn = mocker.Mock(return_value=expected_results) - mocker.patch.object(resources, "ResourceState") - payload = "foo" - result, state = resource._create_or_update(operation_fn, payload) - assert result == expected_results - assert state == resources.ResourceState.create.return_value - resources.ResourceState.create.assert_called_with( - resource.configuration_path, resource.configuration_hash, resource.workspace_id, "resource_id" - ) - - @pytest.mark.parametrize( - "response_status,expected_error", - [(404, ApiException), (422, resources.InvalidConfigurationError)], - ) - def test_create_or_update_error(self, mocker, resource, response_status, expected_error): - operation_fn = mocker.Mock(side_effect=ApiException(status=response_status)) - mocker.patch.object(resources, "ResourceState") - with pytest.raises(expected_error): - resource._create_or_update(operation_fn, "foo") - - def test_create(self, mocker, resource): - mocker.patch.object(resource, "_create_or_update") - assert resource.create() == resource._create_or_update.return_value - resource._create_or_update.assert_called_with(resource._create_fn, resource.create_payload) - - def test_update(self, mocker, resource): - mocker.patch.object(resource, "_create_or_update") - assert resource.update() == resource._create_or_update.return_value - resource._create_or_update.assert_called_with(resource._update_fn, resource.update_payload) - - def test_manage(self, mocker, resource): - mocker.patch.object(resources, "ResourceState") - remote_resource, new_state = resource.manage("resource_id") - resources.ResourceState.create.assert_called_with( - resource.configuration_path, resource.configuration_hash, resource.workspace_id, "resource_id" - ) - assert new_state == resources.ResourceState.create.return_value - assert remote_resource == resource.remote_resource - - @pytest.mark.parametrize( - "configuration, invalid_keys, expect_error", - [ - ({"valid_key": "foo", "invalidKey": "bar"}, {"invalidKey"}, True), - ({"valid_key": "foo", "invalidKey": "bar", "secondInvalidKey": "bar"}, {"invalidKey", "secondInvalidKey"}, True), - ({"valid_key": "foo", "validKey": "bar"}, {"invalidKey"}, False), - ], - ) - def test__check_for_invalid_configuration_keys(self, configuration, invalid_keys, expect_error): - if not expect_error: - result = resources.BaseResource._check_for_invalid_configuration_keys(configuration, invalid_keys, "Invalid configuration keys") - assert result is None - else: - with pytest.raises(resources.InvalidConfigurationError, match="Invalid configuration keys") as error_info: - resources.BaseResource._check_for_invalid_configuration_keys(configuration, invalid_keys, "Invalid configuration keys") - assert all([invalid_key in str(error_info) for invalid_key in invalid_keys]) - - -class TestSourceAndDestination: - @pytest.fixture - def patch_source_and_destination(self, mocker): - mocker.patch.object(resources.SourceAndDestination, "__abstractmethods__", set()) - mocker.patch.object(resources.SourceAndDestination, "api") - mocker.patch.object(resources.SourceAndDestination, "create_function_name", "create") - mocker.patch.object(resources.SourceAndDestination, "update_function_name", "update") - mocker.patch.object(resources.SourceAndDestination, "get_function_name", "get") - mocker.patch.object(resources.SourceAndDestination, "_get_state_from_file", mocker.Mock(return_value=None)) - mocker.patch.object(resources, "hash_config") - - def test_init(self, patch_source_and_destination, mocker, mock_api_client, local_configuration): - assert resources.SourceAndDestination.__base__ == resources.BaseResource - resource = resources.SourceAndDestination(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - assert resource.definition_id == local_configuration["definition_id"] - assert resource.definition_image == local_configuration["definition_image"] - assert resource.definition_version == local_configuration["definition_version"] - - def test_get_remote_comparable_configuration(self, patch_source_and_destination, mocker, mock_api_client, local_configuration): - mocker.patch.object(resources.Source, "remote_resource") - resource = resources.Source(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - assert resource._get_remote_comparable_configuration() == resource.remote_resource.connection_configuration - - -class TestSource: - @pytest.mark.parametrize( - "state", - [None, resources.ResourceState("config_path", "workspace_id", "resource_id", 123, "abc")], - ) - def test_init(self, mocker, mock_api_client, local_configuration, state): - assert resources.Source.__base__ == resources.SourceAndDestination - mocker.patch.object(resources.Source, "resource_id", "foo") - source = resources.Source(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - mocker.patch.object(source, "state", state) - assert source.api == resources.source_api.SourceApi - assert source.create_function_name == "create_source" - assert source.resource_id_field == "source_id" - assert source.update_function_name == "update_source" - assert source.resource_type == "source" - assert source.APPLY_PRIORITY == 0 - assert source.create_payload == resources.SourceCreate( - source.definition_id, source.configuration, source.workspace_id, source.resource_name - ) - assert source.update_payload == resources.SourceUpdate( - source_id=source.resource_id, connection_configuration=source.configuration, name=source.resource_name - ) - if state is None: - assert source.get_payload is None - else: - assert source.get_payload == resources.SourceIdRequestBody(state.resource_id) - - @pytest.mark.parametrize( - "resource_id", - [None, "foo"], - ) - def test_source_discover_schema_request_body(self, mocker, mock_api_client, resource_id, local_configuration): - mocker.patch.object(resources, "SourceDiscoverSchemaRequestBody") - mocker.patch.object(resources.Source, "resource_id", resource_id) - source = resources.Source(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - if resource_id is None: - with pytest.raises(resources.NonExistingResourceError): - source.source_discover_schema_request_body - resources.SourceDiscoverSchemaRequestBody.assert_not_called() - else: - assert source.source_discover_schema_request_body == resources.SourceDiscoverSchemaRequestBody.return_value - resources.SourceDiscoverSchemaRequestBody.assert_called_with(source.resource_id) - - def test_catalog(self, mocker, mock_api_client, local_configuration): - mocker.patch.object(resources.Source, "source_discover_schema_request_body") - source = resources.Source(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - source.api_instance = mocker.Mock() - catalog = source.catalog - assert catalog == source.api_instance.discover_schema_for_source.return_value.catalog - source.api_instance.discover_schema_for_source.assert_called_with(source.source_discover_schema_request_body) - - def test_definition(self, mocker, mock_api_client, local_configuration): - mocker.patch.object(resources.source_definition_api, "SourceDefinitionApi") - mock_api_instance = resources.source_definition_api.SourceDefinitionApi.return_value - source = resources.Source(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - assert source.definition == mock_api_instance.get_source_definition.return_value - resources.source_definition_api.SourceDefinitionApi.assert_called_with(mock_api_client) - expected_payload = SourceDefinitionIdRequestBody(source_definition_id=source.definition_id) - mock_api_instance.get_source_definition.assert_called_with(expected_payload) - - def test_definition_specification(self, mocker, mock_api_client, local_configuration): - mocker.patch.object(resources.source_definition_specification_api, "SourceDefinitionSpecificationApi") - mock_api_instance = resources.source_definition_specification_api.SourceDefinitionSpecificationApi.return_value - source = resources.Source(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - assert source.definition_specification == mock_api_instance.get_source_definition_specification.return_value - resources.source_definition_specification_api.SourceDefinitionSpecificationApi.assert_called_with(mock_api_client) - expected_payload = SourceDefinitionIdWithWorkspaceId(source_definition_id=source.definition_id, workspace_id=source.workspace_id) - mock_api_instance.get_source_definition_specification.assert_called_with(expected_payload) - - -class TestDestination: - @pytest.mark.parametrize( - "state", - [None, resources.ResourceState("config_path", "workspace_id", "resource_id", 123, "abc")], - ) - def test_init(self, mocker, mock_api_client, local_configuration, state): - assert resources.Destination.__base__ == resources.SourceAndDestination - mocker.patch.object(resources.Destination, "resource_id", "foo") - destination = resources.Destination(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - mocker.patch.object(destination, "state", state) - assert destination.api == resources.destination_api.DestinationApi - assert destination.create_function_name == "create_destination" - assert destination.resource_id_field == "destination_id" - assert destination.update_function_name == "update_destination" - assert destination.resource_type == "destination" - assert destination.APPLY_PRIORITY == 0 - assert destination.create_payload == resources.DestinationCreate( - destination.workspace_id, destination.resource_name, destination.definition_id, destination.configuration - ) - assert destination.update_payload == resources.DestinationUpdate( - destination_id=destination.resource_id, connection_configuration=destination.configuration, name=destination.resource_name - ) - if state is None: - assert destination.get_payload is None - else: - assert destination.get_payload == resources.DestinationIdRequestBody(state.resource_id) - - def test_definition(self, mocker, mock_api_client, local_configuration): - mocker.patch.object(resources.destination_definition_api, "DestinationDefinitionApi") - mock_api_instance = resources.destination_definition_api.DestinationDefinitionApi.return_value - destination = resources.Destination(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - assert destination.definition == mock_api_instance.get_destination_definition.return_value - resources.destination_definition_api.DestinationDefinitionApi.assert_called_with(mock_api_client) - expected_payload = DestinationDefinitionIdRequestBody(destination_definition_id=destination.definition_id) - mock_api_instance.get_destination_definition.assert_called_with(expected_payload) - - def test_definition_specification(self, mocker, mock_api_client, local_configuration): - mocker.patch.object(resources.destination_definition_specification_api, "DestinationDefinitionSpecificationApi") - mock_api_instance = resources.destination_definition_specification_api.DestinationDefinitionSpecificationApi.return_value - destination = resources.Destination(mock_api_client, "workspace_id", local_configuration, "bar.yaml") - assert destination.definition_specification == mock_api_instance.get_destination_definition_specification.return_value - resources.destination_definition_specification_api.DestinationDefinitionSpecificationApi.assert_called_with(mock_api_client) - expected_payload = DestinationDefinitionIdWithWorkspaceId( - destination_definition_id=destination.definition_id, workspace_id=destination.workspace_id - ) - mock_api_instance.get_destination_definition_specification.assert_called_with(expected_payload) - - -class TestConnection: - @pytest.fixture - def connection_configuration(self): - return { - "definition_type": "connection", - "resource_name": "my_connection", - "source_configuration_path": "my_source_configuration_path", - "destination_configuration_path": "my_destination_configuration_path", - "configuration": { - "namespace_definition": "customformat", - "namespace_format": "foo", - "prefix": "foo", - "sync_catalog": { - "streams": [ - { - "stream": { - "name": "name_example", - "json_schema": {}, - "supported_sync_modes": ["incremental"], - "source_defined_cursor": True, - "default_cursor_field": ["default_cursor_field"], - "source_defined_primary_key": [["string_example"]], - "namespace": "namespace_example", - }, - "config": { - "sync_mode": "incremental", - "cursor_field": ["cursor_field_example"], - "destination_sync_mode": "append_dedup", - "primary_key": [["string_example"]], - "alias_name": "alias_name_example", - "selected": True, - }, - } - ] - }, - "schedule_type": "basic", - "schedule_data": {"units": 1, "time_unit": "days"}, - "status": "active", - "resource_requirements": {"cpu_request": "foo", "cpu_limit": "foo", "memory_request": "foo", "memory_limit": "foo"}, - }, - } - - @pytest.fixture - def connection_configuration_with_manual_schedule(self, connection_configuration): - connection_configuration_with_manual_schedule = deepcopy(connection_configuration) - connection_configuration_with_manual_schedule["configuration"]["schedule_type"] = "manual" - connection_configuration_with_manual_schedule["configuration"]["schedule_data"] = None - return connection_configuration_with_manual_schedule - - @pytest.fixture - def connection_configuration_with_normalization(self, connection_configuration): - connection_configuration_with_normalization = deepcopy(connection_configuration) - connection_configuration_with_normalization["configuration"]["operations"] = [ - {"name": "Normalization", "operator_configuration": {"normalization": {"option": "basic"}, "operator_type": "normalization"}} - ] - return connection_configuration_with_normalization - - @pytest.fixture - def legacy_connection_configurations(self): - return [ - { - "definition_type": "connection", - "resource_name": "my_connection", - "source_id": "my_source", - "destination_id": "my_destination", - "configuration": { - "namespaceDefinition": "customformat", - "namespaceFormat": "foo", - "prefix": "foo", - "syncCatalog": { - "streams": [ - { - "stream": { - "name": "name_example", - "json_schema": {}, - "supported_sync_modes": ["incremental"], - "source_defined_cursor": True, - "default_cursor_field": ["default_cursor_field"], - "source_defined_primary_key": [["string_example"]], - "namespace": "namespace_example", - }, - "config": { - "sync_mode": "incremental", - "cursor_field": ["cursor_field_example"], - "destination_sync_mode": "append_dedup", - "primary_key": [["string_example"]], - "alias_name": "alias_name_example", - "selected": True, - }, - } - ] - }, - "schedule": {"units": 1, "time_unit": "days"}, - "status": "active", - "resourceRequirements": {"cpu_request": "foo", "cpu_limit": "foo", "memory_request": "foo", "memory_limit": "foo"}, - }, - }, - { - "definition_type": "connection", - "resource_name": "my_connection", - "source_id": "my_source", - "destination_id": "my_destination", - "configuration": { - "namespace_definition": "customformat", - "namespace_format": "foo", - "prefix": "foo", - "sync_catalog": { - "streams": [ - { - "stream": { - "name": "name_example", - "jsonSchema": {}, - "supportedSyncModes": ["incremental"], - "sourceDefinedCursor": True, - "defaultCursorField": ["default_cursor_field"], - "sourceDefinedPrimary_key": [["string_example"]], - "namespace": "namespace_example", - }, - "config": { - "syncMode": "incremental", - "cursorField": ["cursor_field_example"], - "destinationSyncMode": "append_dedup", - "primaryKey": [["string_example"]], - "aliasName": "alias_name_example", - "selected": True, - }, - } - ] - }, - "schedule": {"units": 1, "time_unit": "days"}, - "status": "active", - "resource_requirements": {"cpu_request": "foo", "cpu_limit": "foo", "memory_request": "foo", "memory_limit": "foo"}, - }, - }, - { - "definition_type": "connection", - "resource_name": "my_connection", - "source_id": "my_source", - "destination_id": "my_destination", - "configuration": { - "namespace_definition": "customformat", - "namespace_format": "foo", - "prefix": "foo", - "sync_catalog": { - "streams": [ - { - "stream": {}, - "config": {}, - } - ] - }, - "schedule": {"units": 1, "time_unit": "days"}, - "status": "active", - "resource_requirements": {"cpu_request": "foo", "cpu_limit": "foo", "memory_request": "foo", "memory_limit": "foo"}, - }, - }, - ] - - @pytest.mark.parametrize( - "state", - [None, resources.ResourceState("config_path", "workspace_id", "resource_id", 123, "abc")], - ) - def test_init(self, mocker, mock_api_client, state, connection_configuration): - assert resources.Connection.__base__ == resources.BaseResource - mocker.patch.object(resources.Connection, "resource_id", "foo") - connection = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - mocker.patch.object(connection, "state", state) - assert connection.api == resources.web_backend_api.WebBackendApi - assert connection.create_function_name == "web_backend_create_connection" - assert connection.update_function_name == "web_backend_update_connection" - assert connection.resource_id_field == "connection_id" - assert connection.resource_type == "connection" - assert connection.APPLY_PRIORITY == 1 - - assert connection.update_payload == resources.WebBackendConnectionUpdate( - connection_id=connection.resource_id, **connection.configuration - ) - if state is None: - assert connection.get_payload is None - else: - assert connection.get_payload == resources.WebBackendConnectionRequestBody( - connection_id=state.resource_id, with_refreshed_catalog=False - ) - - @pytest.mark.parametrize("file_not_found_error", [False, True]) - def test_source_id(self, mocker, mock_api_client, connection_configuration, file_not_found_error): - assert resources.Connection.__base__ == resources.BaseResource - mocker.patch.object(resources.Connection, "resource_id", "foo") - if file_not_found_error: - mocker.patch.object( - resources.ResourceState, "from_configuration_path_and_workspace", mocker.Mock(side_effect=FileNotFoundError()) - ) - else: - mocker.patch.object( - resources.ResourceState, - "from_configuration_path_and_workspace", - mocker.Mock(return_value=mocker.Mock(resource_id="expected_source_id")), - ) - - connection = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - if file_not_found_error: - with pytest.raises(resources.MissingStateError): - connection.source_id - else: - source_id = connection.source_id - assert source_id == "expected_source_id" - resources.ResourceState.from_configuration_path_and_workspace.assert_called_with( - connection_configuration["source_configuration_path"], connection.workspace_id - ) - - @pytest.mark.parametrize("file_not_found_error", [False, True]) - def test_destination_id(self, mocker, mock_api_client, connection_configuration, file_not_found_error): - assert resources.Connection.__base__ == resources.BaseResource - mocker.patch.object(resources.Connection, "resource_id", "foo") - if file_not_found_error: - mocker.patch.object( - resources.ResourceState, "from_configuration_path_and_workspace", mocker.Mock(side_effect=FileNotFoundError()) - ) - else: - mocker.patch.object( - resources.ResourceState, - "from_configuration_path_and_workspace", - mocker.Mock(return_value=mocker.Mock(resource_id="expected_destination_id")), - ) - - connection = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - if file_not_found_error: - with pytest.raises(resources.MissingStateError): - connection.destination_id - else: - destination_id = connection.destination_id - assert destination_id == "expected_destination_id" - resources.ResourceState.from_configuration_path_and_workspace.assert_called_with( - connection_configuration["destination_configuration_path"], connection.workspace_id - ) - - def test_create_payload_no_normalization(self, mocker, mock_api_client, connection_configuration): - assert resources.Connection.__base__ == resources.BaseResource - mocker.patch.object(resources.Connection, "resource_id", "foo") - mocker.patch.object(resources.Connection, "source_id", "source_id") - mocker.patch.object(resources.Connection, "destination_id", "destination_id") - connection = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - assert connection.create_payload == resources.WebBackendConnectionCreate( - name=connection.resource_name, - source_id=connection.source_id, - destination_id=connection.destination_id, - **connection.configuration, - ) - assert "operations" not in connection.create_payload - - def test_create_payload_with_normalization(self, mocker, mock_api_client, connection_configuration_with_normalization): - assert resources.Connection.__base__ == resources.BaseResource - mocker.patch.object(resources.Connection, "resource_id", "foo") - mocker.patch.object(resources.Connection, "source_id", "source_id") - mocker.patch.object(resources.Connection, "destination_id", "destination_id") - connection = resources.Connection(mock_api_client, "workspace_id", connection_configuration_with_normalization, "bar.yaml") - assert connection.create_payload == resources.WebBackendConnectionCreate( - name=connection.resource_name, - source_id=connection.source_id, - destination_id=connection.destination_id, - **connection.configuration, - ) - assert isinstance(connection.create_payload["operations"][0], OperationCreate) - - def test_update_payload_no_normalization(self, mocker, mock_api_client, connection_configuration): - assert resources.Connection.__base__ == resources.BaseResource - mocker.patch.object(resources.Connection, "resource_id", "foo") - mocker.patch.object(resources.Connection, "source_id", "source_id") - mocker.patch.object(resources.Connection, "destination_id", "destination_id") - connection = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - assert connection.update_payload == resources.WebBackendConnectionUpdate( - connection_id=connection.resource_id, - **connection.configuration, - ) - assert "operations" not in connection.update_payload - - def test_update_payload_with_normalization(self, mocker, mock_api_client, connection_configuration_with_normalization): - assert resources.Connection.__base__ == resources.BaseResource - mocker.patch.object(resources.Connection, "resource_id", "foo") - mocker.patch.object(resources.Connection, "source_id", "source_id") - mocker.patch.object(resources.Connection, "destination_id", "destination_id") - connection = resources.Connection(mock_api_client, "workspace_id", connection_configuration_with_normalization, "bar.yaml") - assert connection.update_payload == resources.WebBackendConnectionUpdate( - connection_id=connection.resource_id, - **connection.configuration, - ) - assert isinstance(connection.update_payload["operations"][0], WebBackendOperationCreateOrUpdate) - - @pytest.mark.parametrize( - "remote_resource", - [ - { - "name": "foo", - "source_id": "bar", - "destination_id": "fooo", - "connection_id": "baar", - "operation_ids": "foooo", - "foo": "bar", - }, - { - "name": "foo", - "source_id": "bar", - "destination_id": "fooo", - "connection_id": "baar", - "operation_ids": "foooo", - "foo": "bar", - "operations": [], - }, - { - "name": "foo", - "source_id": "bar", - "destination_id": "fooo", - "connection_id": "baar", - "operation_ids": "foooo", - "foo": "bar", - "operations": [{"workspace_id": "foo", "operation_id": "foo", "operator_configuration": {"normalization": "foo"}}], - }, - { - "name": "foo", - "source_id": "bar", - "destination_id": "fooo", - "connection_id": "baar", - "operation_ids": "foooo", - "foo": "bar", - "operations": [{"workspace_id": "foo", "operation_id": "foo", "operator_configuration": {"dbt": "foo"}}], - }, - ], - ) - def test_get_remote_comparable_configuration(self, mocker, mock_api_client, connection_configuration, remote_resource): - mocker.patch.object( - resources.Connection, - "remote_resource", - mocker.Mock(to_dict=mocker.Mock(return_value=remote_resource)), - ) - resource = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - comparable = resource._get_remote_comparable_configuration() - resource.remote_resource.to_dict.assert_called_once() - - assert isinstance(comparable, dict) - assert all([k not in comparable for k in resource.remote_root_level_keys_to_filter_out_for_comparison]) - if "operations" in remote_resource and "operations" in comparable: - assert all([k not in comparable["operations"][0] for k in resource.remote_operation_level_keys_to_filter_out]) - if remote_resource["operations"][0]["operator_configuration"].get("normalization") is not None: - assert "dbt" not in remote_resource["operations"][0]["operator_configuration"] - if remote_resource["operations"][0]["operator_configuration"].get("dbt") is not None: - assert "normalization" not in remote_resource["operations"][0]["operator_configuration"] - if "operations" in remote_resource and len(remote_resource["operations"]) == 0: - assert "operations" not in comparable - - def test_create(self, mocker, mock_api_client, connection_configuration): - mocker.patch.object(resources.Connection, "_create_or_update") - mocker.patch.object(resources.Connection, "source_id", "source_id") - mocker.patch.object(resources.Connection, "destination_id", "destination_id") - resource = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - create_result = resource.create() - assert create_result == resource._create_or_update.return_value - resource._create_or_update.assert_called_with(resource._create_fn, resource.create_payload) - - def test_update(self, mocker, mock_api_client, connection_configuration): - mocker.patch.object(resources.Connection, "_create_or_update") - resource = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - resource.state = mocker.Mock(resource_id="foo") - update_result = resource.update() - assert update_result == resource._create_or_update.return_value - resource._create_or_update.assert_called_with(resource._update_fn, resource.update_payload) - - def test__deserialize_raw_configuration(self, mock_api_client, connection_configuration, connection_configuration_with_manual_schedule): - resource = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - configuration = resource._deserialize_raw_configuration() - assert isinstance(configuration["sync_catalog"], AirbyteCatalog) - assert configuration["namespace_definition"] == NamespaceDefinitionType( - connection_configuration["configuration"]["namespace_definition"] - ) - assert configuration["schedule_type"] == ConnectionScheduleType(connection_configuration["configuration"]["schedule_type"]) - assert ( - configuration["schedule_data"].to_dict() - == ConnectionScheduleDataBasicSchedule(**connection_configuration["configuration"]["schedule_data"]).to_dict() - ) - assert configuration["resource_requirements"] == ResourceRequirements( - **connection_configuration["configuration"]["resource_requirements"] - ) - assert configuration["status"] == ConnectionStatus(connection_configuration["configuration"]["status"]) - assert list(configuration.keys()) == [ - "namespace_definition", - "namespace_format", - "prefix", - "sync_catalog", - "schedule_type", - "schedule_data", - "status", - "resource_requirements", - "non_breaking_changes_preference", - "geography", - ] - - resource = resources.Connection(mock_api_client, "workspace_id", connection_configuration_with_manual_schedule, "bar.yaml") - configuration = resource._deserialize_raw_configuration() - assert configuration["schedule_type"] == ConnectionScheduleType( - connection_configuration_with_manual_schedule["configuration"]["schedule_type"] - ) - assert configuration["schedule_data"] is None - - def test__deserialize_operations(self, mock_api_client, connection_configuration): - resource = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - operations = [ - { - "operator_configuration": {"operator_type": "normalization", "normalization": {"option": "basic"}}, - "name": "operation-with-normalization", - }, - { - "operator_configuration": { - "operator_type": "dbt", - "dbt": { - "dbt_arguments": "run", - "docker_image": "fishtownanalytics/dbt:0.19.1", - "git_repo_branch": "my-branch-name", - "git_repo_url": "https://github.com/airbytehq/airbyte", - }, - }, - "name": "operation-with-custom_dbt", - }, - ] - deserialized_operations = resource._deserialize_operations(operations, OperationCreate) - assert len(deserialized_operations) == 2 - assert all([isinstance(o, OperationCreate) for o in deserialized_operations]) - assert "normalization" in deserialized_operations[0]["operator_configuration"] and deserialized_operations[0][ - "operator_configuration" - ]["operator_type"] == OperatorType("normalization") - assert "dbt" in deserialized_operations[1]["operator_configuration"] - assert deserialized_operations[1]["operator_configuration"]["operator_type"] == OperatorType("dbt") - - with pytest.raises(ValueError): - resource._deserialize_operations( - [ - { - "operator_configuration": {"operator_type": "not-supported", "normalization": {"option": "basic"}}, - "name": "operation-not-supported", - }, - ], - OperationCreate, - ) - - def test__create_configured_catalog(self, mock_api_client, connection_configuration): - resource = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - created_catalog = resource._create_configured_catalog(connection_configuration["configuration"]["sync_catalog"]) - stream, config = ( - connection_configuration["configuration"]["sync_catalog"]["streams"][0]["stream"], - connection_configuration["configuration"]["sync_catalog"]["streams"][0]["config"], - ) - - assert len(created_catalog.streams) == len(connection_configuration["configuration"]["sync_catalog"]["streams"]) - assert created_catalog.streams[0].stream.name == stream["name"] - assert created_catalog.streams[0].stream.json_schema == stream["json_schema"] - assert created_catalog.streams[0].stream.supported_sync_modes == stream["supported_sync_modes"] - assert created_catalog.streams[0].stream.source_defined_cursor == stream["source_defined_cursor"] - assert created_catalog.streams[0].stream.namespace == stream["namespace"] - assert created_catalog.streams[0].stream.source_defined_primary_key == stream["source_defined_primary_key"] - assert created_catalog.streams[0].stream.default_cursor_field == stream["default_cursor_field"] - - assert created_catalog.streams[0].config.sync_mode == config["sync_mode"] - assert created_catalog.streams[0].config.cursor_field == config["cursor_field"] - assert created_catalog.streams[0].config.destination_sync_mode == config["destination_sync_mode"] - assert created_catalog.streams[0].config.primary_key == config["primary_key"] - assert created_catalog.streams[0].config.alias_name == config["alias_name"] - assert created_catalog.streams[0].config.selected == config["selected"] - - def test__check_for_legacy_connection_configuration_keys( - self, mock_api_client, connection_configuration, legacy_connection_configurations - ): - resource = resources.Connection(mock_api_client, "workspace_id", connection_configuration, "bar.yaml") - assert resource._check_for_legacy_connection_configuration_keys(connection_configuration["configuration"]) is None - for legacy_configuration in legacy_connection_configurations: - with pytest.raises(resources.InvalidConfigurationError): - resource._check_for_legacy_connection_configuration_keys(legacy_configuration["configuration"]) - - -@pytest.mark.parametrize( - "local_configuration,resource_to_mock,expected_error", - [ - ({"definition_type": "source"}, "Source", None), - ({"definition_type": "destination"}, "Destination", None), - ({"definition_type": "connection"}, "Connection", None), - ({"definition_type": "not_existing"}, None, NotImplementedError), - ], -) -def test_factory(mocker, mock_api_client, local_configuration, resource_to_mock, expected_error): - mocker.patch.object(resources, "yaml") - if resource_to_mock is not None: - mocker.patch.object(resources, resource_to_mock) - resources.yaml.load.return_value = local_configuration - with patch("builtins.open", mock_open(read_data="data")) as mock_file: - if not expected_error: - resource = resources.factory(mock_api_client, "workspace_id", "my_config.yaml") - resources.yaml.load.assert_called_with(mock_file.return_value, yaml_loaders.EnvVarLoader) - resource == getattr(resources, resource_to_mock).return_value - mock_file.assert_called_with("my_config.yaml", "r") - else: - with pytest.raises(expected_error): - resources.factory(mock_api_client, "workspace_id", "my_config.yaml") - mock_file.assert_called_with("my_config.yaml", "r") diff --git a/octavia-cli/unit_tests/test_apply/test_yaml_loaders.py b/octavia-cli/unit_tests/test_apply/test_yaml_loaders.py deleted file mode 100644 index ebf338860aa1..000000000000 --- a/octavia-cli/unit_tests/test_apply/test_yaml_loaders.py +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import os - -import pytest -import yaml -from octavia_cli.apply import yaml_loaders - - -def test_env_var_replacer(mocker): - mocker.patch.object(yaml_loaders, "os") - mock_node = mocker.Mock() - assert yaml_loaders.env_var_replacer(mocker.Mock(), mock_node) == yaml_loaders.os.path.expandvars.return_value - yaml_loaders.os.path.expandvars.assert_called_with(mock_node.value) - - -@pytest.fixture -def test_env_vars(): - old_environ = dict(os.environ) - secret_env_vars = {"MY_SECRET_PASSWORD": "🤫", "ANOTHER_SECRET_VALUE": "🔒"} - os.environ.update(secret_env_vars) - yield secret_env_vars - os.environ.clear() - os.environ.update(old_environ) - - -def test_env_var_loader(test_env_vars): - assert yaml_loaders.EnvVarLoader.yaml_implicit_resolvers[None] == [("!environment_variable", yaml_loaders.ENV_VAR_MATCHER_PATTERN)] - assert yaml_loaders.EnvVarLoader.yaml_constructors["!environment_variable"] == yaml_loaders.env_var_replacer - test_yaml = "my_secret_password: ${MY_SECRET_PASSWORD}\nanother_secret_value: ${ANOTHER_SECRET_VALUE}" - deserialized = yaml.load(test_yaml, yaml_loaders.EnvVarLoader) - assert deserialized == { - "my_secret_password": test_env_vars["MY_SECRET_PASSWORD"], - "another_secret_value": test_env_vars["ANOTHER_SECRET_VALUE"], - } diff --git a/octavia-cli/unit_tests/test_base_commands.py b/octavia-cli/unit_tests/test_base_commands.py deleted file mode 100644 index f68580682ec0..000000000000 --- a/octavia-cli/unit_tests/test_base_commands.py +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import click -import pytest -from octavia_cli import base_commands - - -class TestOctaviaCommand: - @pytest.fixture - def octavia_command(self): - octavia_command = base_commands.OctaviaCommand("test_command") - assert isinstance(octavia_command, click.Command) - return octavia_command - - def test_make_context(self, mocker, octavia_command): - mock_parent_ctx = mocker.Mock() - parent_make_context = mocker.Mock() - mocker.patch.object(click.Command, "make_context", parent_make_context) - made_context = octavia_command.make_context("my_info_name", ["arg1", "arg2"], parent=mock_parent_ctx, foo="foo", bar="bar") - parent_make_context.assert_called_with("my_info_name", ["arg1", "arg2"], mock_parent_ctx, foo="foo", bar="bar") - assert made_context == parent_make_context.return_value - - @pytest.mark.parametrize("error", [Exception(), click.exceptions.Exit(0), click.exceptions.Exit(1)]) - def test_make_context_error(self, mocker, octavia_command, mock_telemetry_client, error): - mock_parent_ctx = mocker.Mock(obj={"TELEMETRY_CLIENT": mock_telemetry_client}) - parent_make_context = mocker.Mock(side_effect=error) - mocker.patch.object(click.Command, "make_context", parent_make_context) - with pytest.raises(type(error)): - octavia_command.make_context("my_info_name", ["arg1", "arg2"], parent=mock_parent_ctx, foo="foo", bar="bar") - if isinstance(error, click.exceptions.Exit) and error.exit_code == 0: - mock_telemetry_client.send_command_telemetry.assert_called_with( - mock_parent_ctx, extra_info_name="my_info_name", is_help=True - ) - else: - mock_telemetry_client.send_command_telemetry.assert_called_with( - mock_parent_ctx, error=error, extra_info_name="my_info_name" - ) - - def test_invoke(self, mocker, octavia_command, mock_telemetry_client): - mock_ctx = mocker.Mock(obj={"TELEMETRY_CLIENT": mock_telemetry_client}) - parent_invoke = mocker.Mock() - mocker.patch.object(click.Command, "invoke", parent_invoke) - result = octavia_command.invoke(mock_ctx) - parent_invoke.assert_called_with(mock_ctx) - mock_telemetry_client.send_command_telemetry.assert_called_with(mock_ctx) - assert result == parent_invoke.return_value - - def test_invoke_error(self, mocker, octavia_command, mock_telemetry_client): - mock_ctx = mocker.Mock(obj={"TELEMETRY_CLIENT": mock_telemetry_client}) - error = Exception() - parent_invoke = mocker.Mock(side_effect=error) - mocker.patch.object(click.Command, "invoke", parent_invoke) - with pytest.raises(Exception): - octavia_command.invoke(mock_ctx) - mock_telemetry_client.send_command_telemetry.assert_called_with(mock_ctx, error=error) diff --git a/octavia-cli/unit_tests/test_check_context.py b/octavia-cli/unit_tests/test_check_context.py deleted file mode 100644 index 6af7384925ec..000000000000 --- a/octavia-cli/unit_tests/test_check_context.py +++ /dev/null @@ -1,85 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import os -import shutil -import tempfile -from pathlib import Path - -import airbyte_api_client -import pytest -from airbyte_api_client.model.workspace_id_request_body import WorkspaceIdRequestBody -from octavia_cli import check_context -from urllib3.exceptions import MaxRetryError - - -@pytest.fixture -def mock_api_client(mocker): - return mocker.Mock() - - -def test_api_check_health_available(mock_api_client, mocker): - mocker.patch.object(check_context, "health_api") - mock_api_response = mocker.Mock(available=True) - check_context.health_api.HealthApi.return_value.get_health_check.return_value = mock_api_response - - assert check_context.check_api_health(mock_api_client) is None - check_context.health_api.HealthApi.assert_called_with(mock_api_client) - api_instance = check_context.health_api.HealthApi.return_value - api_instance.get_health_check.assert_called() - - -def test_api_check_health_unavailable(mock_api_client, mocker): - mocker.patch.object(check_context, "health_api") - mock_api_response = mocker.Mock(available=False) - check_context.health_api.HealthApi.return_value.get_health_check.return_value = mock_api_response - with pytest.raises(check_context.UnhealthyApiError): - check_context.check_api_health(mock_api_client) - - -def test_api_check_health_unreachable_api_exception(mock_api_client, mocker): - mocker.patch.object(check_context, "health_api") - check_context.health_api.HealthApi.return_value.get_health_check.side_effect = airbyte_api_client.ApiException() - with pytest.raises(check_context.UnreachableAirbyteInstanceError): - check_context.check_api_health(mock_api_client) - - -def test_api_check_health_unreachable_max_retry_error(mock_api_client, mocker): - mocker.patch.object(check_context, "health_api") - check_context.health_api.HealthApi.return_value.get_health_check.side_effect = MaxRetryError("foo", "bar") - with pytest.raises(check_context.UnreachableAirbyteInstanceError): - check_context.check_api_health(mock_api_client) - - -def test_check_workspace_exists(mock_api_client, mocker): - mocker.patch.object(check_context, "workspace_api") - mock_api_instance = mocker.Mock() - check_context.workspace_api.WorkspaceApi.return_value = mock_api_instance - assert check_context.check_workspace_exists(mock_api_client, "foo") is None - check_context.workspace_api.WorkspaceApi.assert_called_with(mock_api_client) - mock_api_instance.get_workspace.assert_called_with(WorkspaceIdRequestBody("foo"), _check_return_type=False) - - -def test_check_workspace_exists_error(mock_api_client, mocker): - mocker.patch.object(check_context, "workspace_api") - check_context.workspace_api.WorkspaceApi.return_value.get_workspace.side_effect = airbyte_api_client.ApiException() - with pytest.raises(check_context.WorkspaceIdError): - check_context.check_workspace_exists(mock_api_client, "foo") - - -@pytest.fixture -def project_directories(): - dirpath = tempfile.mkdtemp() - yield str(Path(dirpath).parent.absolute()), [os.path.basename(dirpath)] - shutil.rmtree(dirpath) - - -def test_check_is_initialized(mocker, project_directories): - project_directory, sub_directories = project_directories - mocker.patch.object(check_context, "REQUIRED_PROJECT_DIRECTORIES", sub_directories) - assert check_context.check_is_initialized(project_directory) - - -def test_check_not_initialized(): - assert not check_context.check_is_initialized(".") diff --git a/octavia-cli/unit_tests/test_entrypoint.py b/octavia-cli/unit_tests/test_entrypoint.py deleted file mode 100644 index 8159f3a67bd1..000000000000 --- a/octavia-cli/unit_tests/test_entrypoint.py +++ /dev/null @@ -1,243 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from typing import List, Optional - -import click -import pkg_resources -import pytest -from airbyte_api_client.model.workspace_id_request_body import WorkspaceIdRequestBody -from click.testing import CliRunner -from octavia_cli import entrypoint -from octavia_cli.api_http_headers import ApiHttpHeader - - -@click.command() -@click.pass_context -def dumb(ctx): - pass - - -@pytest.mark.parametrize( - "option_based_api_http_headers, api_http_headers_file_path", - [ - ([("foo", "bar")], "api_http_headers_file_path"), - ([], None), - (None, None), - ], -) -def test_set_context_object(mocker, option_based_api_http_headers, api_http_headers_file_path): - mocker.patch.object(entrypoint, "TelemetryClient") - mocker.patch.object(entrypoint, "build_user_agent") - mocker.patch.object(entrypoint, "merge_api_headers") - mocker.patch.object(entrypoint, "get_api_client") - mocker.patch.object(entrypoint, "get_workspace_id") - mocker.patch.object(entrypoint, "check_is_initialized") - mocker.patch.object(entrypoint, "get_anonymous_data_collection") - mock_ctx = mocker.Mock(obj={}) - built_context = entrypoint.set_context_object( - mock_ctx, - "my_airbyte_url", - "my_airbyte_username", - "my_airbyte_password", - "my_workspace_id", - "enable_telemetry", - option_based_api_http_headers, - api_http_headers_file_path, - ) - entrypoint.TelemetryClient.assert_called_with("enable_telemetry") - mock_ctx.ensure_object.assert_called_with(dict) - assert built_context.obj == { - "OCTAVIA_VERSION": pkg_resources.require("octavia-cli")[0].version, - "TELEMETRY_CLIENT": entrypoint.TelemetryClient.return_value, - "WORKSPACE_ID": entrypoint.get_workspace_id.return_value, - "API_CLIENT": entrypoint.get_api_client.return_value, - "PROJECT_IS_INITIALIZED": entrypoint.check_is_initialized.return_value, - "ANONYMOUS_DATA_COLLECTION": entrypoint.get_anonymous_data_collection.return_value, - } - entrypoint.build_user_agent.assert_called_with(built_context.obj["OCTAVIA_VERSION"]) - entrypoint.merge_api_headers.assert_called_with(option_based_api_http_headers, api_http_headers_file_path) - entrypoint.get_api_client.assert_called_with( - "my_airbyte_url", - "my_airbyte_username", - "my_airbyte_password", - entrypoint.build_user_agent.return_value, - entrypoint.merge_api_headers.return_value, - ) - - -def test_set_context_object_error(mocker): - mocker.patch.object(entrypoint, "TelemetryClient") - mock_ctx = mocker.Mock(obj={}) - mock_ctx.ensure_object.side_effect = NotImplementedError() - with pytest.raises(NotImplementedError): - entrypoint.set_context_object( - mock_ctx, - "my_airbyte_url", - "my_airbyte_username", - "my_airbyte_password", - "my_workspace_id", - "enable_telemetry", - [("foo", "bar")], - "api_http_headers_file_path", - ) - entrypoint.TelemetryClient.return_value.send_command_telemetry.assert_called_with( - mock_ctx, error=mock_ctx.ensure_object.side_effect - ) - - -@pytest.mark.parametrize( - "options, expected_exit_code", - [ - (["--airbyte-url", "test-airbyte-url"], 0), - (["--airbyte-url", "test-airbyte-url", "--enable-telemetry"], 0), - (["--airbyte-url", "test-airbyte-url", "--enable-telemetry foo"], 2), - (["--airbyte-url", "test-airbyte-url", "--disable-telemetry"], 0), - (["--airbyte-url", "test-airbyte-url", "--api-http-headers-file-path", "path-does-not-exist"], 2), - (["--airbyte-url", "test-airbyte-url", "--api-http-headers-file-path", "path-exists"], 0), - (["--airbyte-url", "test-airbyte-url", "--api-http-header", "Content-Type", "application/json"], 0), - ( - [ - "--airbyte-url", - "test-airbyte-url", - "--api-http-header", - "Content-Type", - "application/json", - "--api-http-header", - "Authorization", - "'Bearer XXX'", - ], - 0, - ), - ( - [ - "--airbyte-url", - "test-airbyte-url", - "--api-http-header", - "Content-Type", - "--api-http-header", - "Authorization", - "'Bearer XXX'", - ], - 2, - ), - ], -) -def test_octavia(tmp_path, mocker, options, expected_exit_code): - if "path-exists" in options: - tmp_file = tmp_path / "path_exists.yaml" - tmp_file.write_text("foobar") - options[options.index("path-exists")] = tmp_file - - mocker.patch.object(entrypoint, "click") - mocker.patch.object( - entrypoint, - "set_context_object", - mocker.Mock(return_value=mocker.Mock(obj={"WORKSPACE_ID": "api-defined-workspace-id", "PROJECT_IS_INITIALIZED": True})), - ) - entrypoint.octavia.add_command(dumb) - runner = CliRunner() - result = runner.invoke(entrypoint.octavia, options + ["dumb"], obj={}) - expected_message = "🐙 - Octavia is targetting your Airbyte instance running at test-airbyte-url on workspace api-defined-workspace-id." - assert result.exit_code == expected_exit_code - if expected_exit_code == 0: - entrypoint.click.style.assert_called_with(expected_message, fg="green") - entrypoint.click.echo.assert_called_with(entrypoint.click.style.return_value) - - -def test_octavia_not_initialized(mocker): - mocker.patch.object(entrypoint, "click") - mocker.patch.object( - entrypoint, - "set_context_object", - mocker.Mock(return_value=mocker.Mock(obj={"WORKSPACE_ID": "api-defined-workspace-id", "PROJECT_IS_INITIALIZED": False})), - ) - entrypoint.octavia.add_command(dumb) - runner = CliRunner() - result = runner.invoke(entrypoint.octavia, ["--airbyte-url", "test-airbyte-url", "dumb"], obj={}) - entrypoint.click.style.assert_called_with("🐙 - Project is not yet initialized.", fg="red", bold=True) - entrypoint.click.echo.assert_called_with(entrypoint.click.style.return_value) - assert result.exit_code == 0 - - -@pytest.mark.parametrize( - "api_http_headers", - [ - None, - [], - [ApiHttpHeader(name="Authorization", value="Basic dXNlcjE6cGFzc3dvcmQ=")], - [ApiHttpHeader(name="Authorization", value="Basic dXNlcjE6cGFzc3dvcmQ="), ApiHttpHeader(name="Header", value="header_value")], - ], -) -def test_get_api_client(mocker, api_http_headers: Optional[List[str]]): - mocker.patch.object(entrypoint, "airbyte_api_client") - entrypoint.airbyte_api_client.Configuration.return_value.get_basic_auth_token.return_value = "my_basic_auth_token" - mocker.patch.object(entrypoint, "check_api_health") - mocker.patch.object(entrypoint, "set_api_headers_on_api_client") - api_client = entrypoint.get_api_client("test-url", "test-username", "test-password", "test-user-agent", api_http_headers) - entrypoint.airbyte_api_client.Configuration.assert_called_with(host="test-url/api", username="test-username", password="test-password") - entrypoint.airbyte_api_client.ApiClient.assert_called_with(entrypoint.airbyte_api_client.Configuration.return_value) - assert entrypoint.airbyte_api_client.ApiClient.return_value.user_agent == "test-user-agent" - if api_http_headers: - entrypoint.set_api_headers_on_api_client.assert_called_with(entrypoint.airbyte_api_client.ApiClient.return_value, api_http_headers) - entrypoint.check_api_health.assert_called_with(entrypoint.airbyte_api_client.ApiClient.return_value) - assert api_client == entrypoint.airbyte_api_client.ApiClient.return_value - - -def test_get_workspace_id_user_defined(mocker): - mock_api_client = mocker.Mock() - mocker.patch.object(entrypoint, "check_workspace_exists") - mocker.patch.object(entrypoint, "workspace_api") - assert entrypoint.get_workspace_id(mock_api_client, "user-defined-workspace-id") == "user-defined-workspace-id" - entrypoint.check_workspace_exists.assert_called_with(mock_api_client, "user-defined-workspace-id") - - -def test_get_workspace_id_api_defined(mocker): - mock_api_client = mocker.Mock() - mocker.patch.object(entrypoint, "check_workspace_exists") - mocker.patch.object(entrypoint, "workspace_api") - mock_api_instance = entrypoint.workspace_api.WorkspaceApi.return_value - mock_api_instance.list_workspaces.return_value = mocker.Mock(workspaces=[{"workspaceId": "api-defined-workspace-id"}]) - assert entrypoint.get_workspace_id(mock_api_client, None) == "api-defined-workspace-id" - entrypoint.workspace_api.WorkspaceApi.assert_called_with(mock_api_client) - mock_api_instance.list_workspaces.assert_called_with(_check_return_type=False) - - -def test_get_anonymous_data_collection(mocker, mock_api_client): - mocker.patch.object(entrypoint, "workspace_api") - mock_api_instance = entrypoint.workspace_api.WorkspaceApi.return_value - assert ( - entrypoint.get_anonymous_data_collection(mock_api_client, "my_workspace_id") - == mock_api_instance.get_workspace.return_value.get.return_value - ) - entrypoint.workspace_api.WorkspaceApi.assert_called_with(mock_api_client) - mock_api_instance.get_workspace.assert_called_with(WorkspaceIdRequestBody("my_workspace_id"), _check_return_type=False) - - -def test_commands_in_octavia_group(): - octavia_commands = entrypoint.octavia.commands.values() - for command in entrypoint.AVAILABLE_COMMANDS: - assert command in octavia_commands - - -@pytest.mark.parametrize( - "command", - [entrypoint.delete], -) -def test_not_implemented_commands(command): - runner = CliRunner() - result = runner.invoke(command) - assert result.exit_code == 1 - assert result.output.endswith("not yet implemented.\n") - - -def test_available_commands(): - assert entrypoint.AVAILABLE_COMMANDS == [ - entrypoint.list_commands._list, - entrypoint.get_commands.get, - entrypoint.import_commands._import, - entrypoint.init_commands.init, - entrypoint.generate_commands.generate, - entrypoint.apply_commands.apply, - ] diff --git a/octavia-cli/unit_tests/test_generate/__init__.py b/octavia-cli/unit_tests/test_generate/__init__.py deleted file mode 100644 index 46b7376756ec..000000000000 --- a/octavia-cli/unit_tests/test_generate/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/unit_tests/test_generate/test_commands.py b/octavia-cli/unit_tests/test_generate/test_commands.py deleted file mode 100644 index d4b50516fca8..000000000000 --- a/octavia-cli/unit_tests/test_generate/test_commands.py +++ /dev/null @@ -1,116 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import pytest -from click.testing import CliRunner -from octavia_cli.apply.resources import NonExistingResourceError -from octavia_cli.generate import commands - - -@pytest.fixture -def context_object(mock_api_client, mock_telemetry_client): - return {"PROJECT_IS_INITIALIZED": True, "API_CLIENT": mock_api_client, "WORKSPACE_ID": "foo", "TELEMETRY_CLIENT": mock_telemetry_client} - - -def test_generate_initialized(mocker, context_object): - runner = CliRunner() - mocker.patch.object(commands, "definitions") - mocker.patch.object(commands, "ConnectorSpecificationRenderer", mocker.Mock()) - mock_renderer = commands.ConnectorSpecificationRenderer.return_value - mock_renderer.write_yaml.return_value = "expected_output_path" - result = runner.invoke(commands.generate, ["source", "uuid", "my_source"], obj=context_object) - assert result.exit_code == 0 - - -def test_generate_not_initialized(context_object): - runner = CliRunner() - context_object["PROJECT_IS_INITIALIZED"] = False - result = runner.invoke(commands.generate, ["source", "uuid", "my_source"], obj=context_object) - assert result.exit_code == 1 - - assert result.output == "Error: Your octavia project is not initialized, please run 'octavia init' before running this command.\n" - - -def test_invalid_definition_type(context_object): - runner = CliRunner() - result = runner.invoke(commands.generate, ["random_definition", "uuid", "my_source"], obj=context_object) - assert result.exit_code == 2 - - -@pytest.mark.parametrize( - "command,resource_name,definition_type", - [ - (commands.source, "my_source", "source"), - (commands.destination, "my_destination", "destination"), - ], -) -def test_generate_source_or_destination(mocker, context_object, command, resource_name, definition_type): - runner = CliRunner() - mocker.patch.object(commands, "definitions") - mocker.patch.object(commands, "ConnectorSpecificationRenderer", mocker.Mock()) - mock_renderer = commands.ConnectorSpecificationRenderer.return_value - mock_renderer.write_yaml.return_value = "expected_output_path" - result = runner.invoke(command, ["uuid", resource_name], obj=context_object) - assert result.exit_code == 0 - assert result.output == f"✅ - Created the {definition_type} template for {resource_name} in expected_output_path.\n" - commands.definitions.factory.assert_called_with(definition_type, context_object["API_CLIENT"], context_object["WORKSPACE_ID"], "uuid") - commands.ConnectorSpecificationRenderer.assert_called_with(resource_name, commands.definitions.factory.return_value) - mock_renderer.write_yaml.assert_called_with(project_path=".") - - -@pytest.fixture -def tmp_source_path(tmp_path): - source_path = tmp_path / "my_source.yaml" - source_path.write_text("foo") - return source_path - - -@pytest.fixture -def tmp_destination_path(tmp_path): - destination_path = tmp_path / "my_destination.yaml" - destination_path.write_text("foo") - return destination_path - - -@pytest.mark.parametrize( - "source_created,destination_created", - [(True, True), (False, True), (True, False), (False, False)], -) -def test_generate_connection(mocker, context_object, tmp_source_path, tmp_destination_path, source_created, destination_created): - runner = CliRunner() - mock_source = mocker.Mock(was_created=source_created) - mock_destination = mocker.Mock(was_created=destination_created) - - mock_resource_factory = mocker.Mock(side_effect=[mock_source, mock_destination]) - mocker.patch.object( - commands, "resources", mocker.Mock(factory=mock_resource_factory, NonExistingResourceError=NonExistingResourceError) - ) - mocker.patch.object(commands, "ConnectionRenderer", mocker.Mock()) - mock_renderer = commands.ConnectionRenderer.return_value - mock_renderer.write_yaml.return_value = "expected_output_path" - cli_input = ["my_new_connection", "--source", tmp_source_path, "--destination", tmp_destination_path] - result = runner.invoke(commands.connection, cli_input, obj=context_object) - if source_created and destination_created: - assert result.exit_code == 0 - assert result.output == "✅ - Created the connection template for my_new_connection in expected_output_path.\n" - commands.resources.factory.assert_has_calls( - [ - mocker.call(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], tmp_source_path), - mocker.call(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], tmp_destination_path), - ] - ) - commands.ConnectionRenderer.assert_called_with("my_new_connection", mock_source, mock_destination) - mock_renderer.write_yaml.assert_called_with(project_path=".") - elif not source_created: - assert ( - result.output - == f"Error: The source defined at {tmp_source_path} does not exists. Please run octavia apply before creating this connection.\n" - ) - assert result.exit_code == 1 - elif not destination_created: - assert ( - result.output - == f"Error: The destination defined at {tmp_destination_path} does not exists. Please run octavia apply before creating this connection.\n" - ) - assert result.exit_code == 1 diff --git a/octavia-cli/unit_tests/test_generate/test_connection.py b/octavia-cli/unit_tests/test_generate/test_connection.py deleted file mode 100644 index db48914fdeb7..000000000000 --- a/octavia-cli/unit_tests/test_generate/test_connection.py +++ /dev/null @@ -1,5 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -# diff --git a/octavia-cli/unit_tests/test_generate/test_definitions.py b/octavia-cli/unit_tests/test_generate/test_definitions.py deleted file mode 100644 index 977fc931ed54..000000000000 --- a/octavia-cli/unit_tests/test_generate/test_definitions.py +++ /dev/null @@ -1,122 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import pytest -from airbyte_api_client.api import ( - destination_definition_api, - destination_definition_specification_api, - source_definition_api, - source_definition_specification_api, -) -from airbyte_api_client.exceptions import ApiException -from airbyte_api_client.model.destination_definition_id_request_body import DestinationDefinitionIdRequestBody -from airbyte_api_client.model.source_definition_id_request_body import SourceDefinitionIdRequestBody -from octavia_cli.generate.definitions import ( - BaseDefinition, - DefinitionNotFoundError, - DefinitionSpecification, - DestinationDefinition, - DestinationDefinitionSpecification, - SourceDefinition, - SourceDefinitionSpecification, - factory, -) - - -class TestBaseDefinition: - @pytest.fixture - def patch_base_class(self, mocker): - # Mock abstract methods to enable instantiating abstract class - mocker.patch.object(BaseDefinition, "__abstractmethods__", set()) - mocker.patch.object(BaseDefinition, "api", mocker.Mock()) - mocker.patch.object(BaseDefinition, "get_function_name", "foo") - - def test_init(self, patch_base_class, mock_api_client, mocker): - mocker.patch.object(BaseDefinition, "_read", mocker.Mock()) - base_definition = BaseDefinition(mock_api_client, "my_definition_id") - assert base_definition.specification is None - assert base_definition.id == "my_definition_id" - assert base_definition.api_instance == base_definition.api.return_value - assert base_definition._api_data == base_definition._read.return_value - base_definition.api.assert_called_with(mock_api_client) - assert base_definition._get_fn_kwargs == {} - assert base_definition._get_fn == getattr(base_definition.api, base_definition.get_function_name) - - def test_get_attr(self, patch_base_class, mock_api_client): - base_definition = BaseDefinition(mock_api_client, "my_definition_id") - base_definition._api_data = {"foo": "bar"} - assert base_definition.foo == "bar" - with pytest.raises(AttributeError): - base_definition.not_existing - - def test_read_success(self, patch_base_class, mock_api_client, mocker): - mocker.patch.object(BaseDefinition, "_get_fn", mocker.Mock()) - base_definition = BaseDefinition(mock_api_client, "my_definition_id") - read_output = base_definition._read() - assert read_output == base_definition._get_fn.return_value - base_definition._get_fn.assert_called_with(base_definition.api_instance, **base_definition._get_fn_kwargs, _check_return_type=False) - - @pytest.mark.parametrize("status_code", [404, 422]) - def test_read_error_not_found(self, status_code, patch_base_class, mock_api_client, mocker): - mocker.patch.object(BaseDefinition, "_get_fn", mocker.Mock(side_effect=ApiException(status=status_code))) - with pytest.raises(DefinitionNotFoundError): - BaseDefinition(mock_api_client, "my_definition_id") - - def test_read_error_other(self, patch_base_class, mock_api_client, mocker): - expected_error = ApiException(status=42) - mocker.patch.object(BaseDefinition, "_get_fn", mocker.Mock(side_effect=expected_error)) - with pytest.raises(ApiException) as e: - BaseDefinition(mock_api_client, "my_definition_id") - assert e == expected_error - - -class TestSourceDefinition: - def test_init(self, mock_api_client): - assert SourceDefinition.__base__ == BaseDefinition - source_definition = SourceDefinition(mock_api_client, "source_id") - assert source_definition.api == source_definition_api.SourceDefinitionApi - assert source_definition.type == "source" - assert source_definition.get_function_name == "get_source_definition" - assert source_definition._get_fn_kwargs == {"source_definition_id_request_body": SourceDefinitionIdRequestBody("source_id")} - - -class TestDestinationDefinition: - def test_init(self, mock_api_client): - assert DestinationDefinition.__base__ == BaseDefinition - destination_definition = DestinationDefinition(mock_api_client, "source_id") - assert destination_definition.api == destination_definition_api.DestinationDefinitionApi - assert destination_definition.type == "destination" - assert destination_definition.get_function_name == "get_destination_definition" - assert destination_definition._get_fn_kwargs == { - "destination_definition_id_request_body": DestinationDefinitionIdRequestBody("source_id") - } - - -class TestSourceDefinitionSpecification: - def test_init(self, mock_api_client): - assert SourceDefinitionSpecification.__base__ == DefinitionSpecification - source_specification = SourceDefinitionSpecification(mock_api_client, "workspace_id", "source_id") - assert source_specification.api == source_definition_specification_api.SourceDefinitionSpecificationApi - assert source_specification.get_function_name == "get_source_definition_specification" - - -class TestDestinationDefinitionSpecification: - def test_init(self, mock_api_client): - assert DestinationDefinitionSpecification.__base__ == DefinitionSpecification - destination_specification = DestinationDefinitionSpecification(mock_api_client, "workspace_id", "source_id") - assert destination_specification.api == destination_definition_specification_api.DestinationDefinitionSpecificationApi - assert destination_specification.get_function_name == "get_destination_definition_specification" - - -def test_factory(mock_api_client): - source_definition = factory("source", mock_api_client, "workspace_id", "source_definition_id") - assert isinstance(source_definition, SourceDefinition) - assert isinstance(source_definition.specification, SourceDefinitionSpecification) - - destination_definition = factory("destination", mock_api_client, "workspace_id", "destination_definition_id") - assert isinstance(destination_definition, DestinationDefinition) - assert isinstance(destination_definition.specification, DestinationDefinitionSpecification) - - with pytest.raises(ValueError): - factory("random", mock_api_client, "workspace_id", "random_definition_id") diff --git a/octavia-cli/unit_tests/test_generate/test_renderers.py b/octavia-cli/unit_tests/test_generate/test_renderers.py deleted file mode 100644 index 2e33d2905975..000000000000 --- a/octavia-cli/unit_tests/test_generate/test_renderers.py +++ /dev/null @@ -1,415 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from pathlib import Path -from unittest.mock import mock_open, patch - -import pytest -import yaml -from airbyte_api_client.model.airbyte_catalog import AirbyteCatalog -from airbyte_api_client.model.airbyte_stream import AirbyteStream -from airbyte_api_client.model.airbyte_stream_and_configuration import AirbyteStreamAndConfiguration -from airbyte_api_client.model.airbyte_stream_configuration import AirbyteStreamConfiguration -from airbyte_api_client.model.destination_sync_mode import DestinationSyncMode -from airbyte_api_client.model.sync_mode import SyncMode -from octavia_cli.generate import renderers, yaml_dumpers - - -class TestFieldToRender: - def test_init(self, mocker): - mocker.patch.object(renderers.FieldToRender, "_get_one_of_values") - mocker.patch.object(renderers, "get_object_fields") - mocker.patch.object(renderers.FieldToRender, "_get_array_items") - mocker.patch.object(renderers.FieldToRender, "_build_comment") - mocker.patch.object(renderers.FieldToRender, "_get_default") - - field_metadata = mocker.Mock() - field_to_render = renderers.FieldToRender("field_name", True, field_metadata) - assert field_to_render.name == "field_name" - assert field_to_render.required - assert field_to_render.field_metadata == field_metadata - assert field_to_render.one_of_values == field_to_render._get_one_of_values.return_value - assert field_to_render.object_properties == renderers.get_object_fields.return_value - assert field_to_render.array_items == field_to_render._get_array_items.return_value - assert field_to_render.comment == field_to_render._build_comment.return_value - assert field_to_render.default == field_to_render._get_default.return_value - field_to_render._build_comment.assert_called_with( - [ - field_to_render._get_secret_comment, - field_to_render._get_required_comment, - field_to_render._get_type_comment, - field_to_render._get_description_comment, - field_to_render._get_example_comment, - ] - ) - - def test_get_attr(self): - field_to_render = renderers.FieldToRender("field_name", True, {"foo": "bar"}) - assert field_to_render.foo == "bar" - assert field_to_render.not_existing is None - - def test_is_array_of_objects(self): - field_to_render = renderers.FieldToRender("field_name", True, {"foo": "bar"}) - field_to_render.type = "array" - field_to_render.items = {"type": "object"} - assert field_to_render.is_array_of_objects - field_to_render.type = "array" - field_to_render.items = {"type": "int"} - assert not field_to_render.is_array_of_objects - - def test__get_one_of_values(self, mocker): - field_to_render = renderers.FieldToRender("field_name", True, {"foo": "bar"}) - field_to_render.oneOf = False - assert field_to_render._get_one_of_values() == [] - - mocker.patch.object(renderers, "get_object_fields") - one_of_value = mocker.Mock() - field_to_render.oneOf = [one_of_value] - one_of_values = field_to_render._get_one_of_values() - renderers.get_object_fields.assert_called_once_with(one_of_value) - assert one_of_values == [renderers.get_object_fields.return_value] - - def test__get_array_items(self, mocker): - mocker.patch.object(renderers, "parse_fields") - mocker.patch.object(renderers.FieldToRender, "is_array_of_objects", False) - - field_to_render = renderers.FieldToRender("field_name", True, {"foo": "bar"}) - assert field_to_render._get_array_items() == [] - field_to_render.items = {"required": [], "properties": []} - mocker.patch.object(renderers.FieldToRender, "is_array_of_objects", True) - assert field_to_render._get_array_items() == renderers.parse_fields.return_value - renderers.parse_fields.assert_called_with([], []) - - def test__get_required_comment(self): - field_to_render = renderers.FieldToRender("field_name", True, {"foo": "bar"}) - field_to_render.required = True - assert field_to_render._get_required_comment() == "REQUIRED" - field_to_render.required = False - assert field_to_render._get_required_comment() == "OPTIONAL" - - @pytest.mark.parametrize( - "_type,expected_comment", - [("string", "string"), (["string", "null"], "string, null"), (None, None)], - ) - def test__get_type_comment(self, _type, expected_comment): - field_to_render = renderers.FieldToRender("field_name", True, {"foo": "bar"}) - field_to_render.type = _type - assert field_to_render._get_type_comment() == expected_comment - - def test__get_secret_comment(self): - field_to_render = renderers.FieldToRender("field_name", True, {"foo": "bar"}) - field_to_render.airbyte_secret = True - assert field_to_render._get_secret_comment() == "SECRET (please store in environment variables)" - field_to_render.airbyte_secret = False - assert field_to_render._get_secret_comment() is None - - def test__get_description_comment(self): - field_to_render = renderers.FieldToRender("field_name", True, {"foo": "bar"}) - field_to_render.description = "foo" - assert field_to_render._get_description_comment() == "foo" - field_to_render.description = None - assert field_to_render._get_description_comment() is None - - @pytest.mark.parametrize( - "examples_value,expected_output", - [ - (["foo", "bar"], "Examples: foo, bar"), - (["foo"], "Example: foo"), - ("foo", "Example: foo"), - ([5432], "Example: 5432"), - (None, None), - ], - ) - def test__get_example_comment(self, examples_value, expected_output): - field_to_render = renderers.FieldToRender("field_name", True, {"foo": "bar"}) - field_to_render.examples = examples_value - assert field_to_render._get_example_comment() == expected_output - - @pytest.mark.parametrize( - "field_metadata,expected_default", - [ - ({"const": "foo", "default": "bar"}, "foo"), - ({"default": "bar"}, "bar"), - ({"airbyte_secret": True}, "${FIELD_NAME}"), - ({}, None), - ], - ) - def test__get_default(self, field_metadata, expected_default): - field_to_render = renderers.FieldToRender("field_name", True, field_metadata) - assert field_to_render.default == expected_default - - def test__build_comment(self, mocker): - comment_functions = [mocker.Mock(return_value="foo"), mocker.Mock(return_value=None), mocker.Mock(return_value="bar")] - comment = renderers.FieldToRender._build_comment(comment_functions) - assert comment == "foo | bar" - - -def test_parse_fields(): - required_fields = ["foo"] - properties = {"foo": {}, "bar": {}} - fields_to_render = renderers.parse_fields(required_fields, properties) - assert fields_to_render[0].name == "foo" - assert fields_to_render[0].required - assert fields_to_render[1].name == "bar" - assert not fields_to_render[1].required - - -def test_get_object_fields(mocker): - mocker.patch.object(renderers, "parse_fields") - field_metadata = {"properties": {"foo": {}, "bar": {}}, "required": ["foo"]} - object_properties = renderers.get_object_fields(field_metadata) - assert object_properties == renderers.parse_fields.return_value - renderers.parse_fields.assert_called_with(["foo"], field_metadata["properties"]) - field_metadata = {} - assert renderers.get_object_fields(field_metadata) == [] - - -class TestBaseRenderer: - @pytest.fixture - def patch_base_class(self, mocker): - # Mock abstract methods to enable instantiating abstract class - mocker.patch.object(renderers.BaseRenderer, "__abstractmethods__", set()) - - def test_init(self, patch_base_class): - base = renderers.BaseRenderer("resource_name") - assert base.resource_name == "resource_name" - - def test_get_output_path(self, patch_base_class, mocker): - mocker.patch.object(renderers, "os") - mocker.patch.object(renderers, "slugify") - renderers.os.path.exists.return_value = False - spec_renderer = renderers.BaseRenderer("my_resource_name") - renderers.os.path.join.side_effect = [ - "./my_definition_types/my_resource_name", - "./my_definition_types/my_resource_name/configuration.yaml", - ] - output_path = spec_renderer.get_output_path(".", "my_definition_type", "my_resource_name") - renderers.os.makedirs.assert_called_once() - renderers.slugify.assert_called_with("my_resource_name", separator="_") - renderers.os.path.join.assert_has_calls( - [ - mocker.call(".", "my_definition_types", renderers.slugify.return_value), - mocker.call("./my_definition_types/my_resource_name", "configuration.yaml"), - ] - ) - assert output_path == Path("./my_definition_types/my_resource_name/configuration.yaml") - - @pytest.mark.parametrize("file_exists, confirmed_overwrite", [(True, True), (False, None), (True, False)]) - def test__confirm_overwrite(self, mocker, file_exists, confirmed_overwrite): - mock_output_path = mocker.Mock(is_file=mocker.Mock(return_value=file_exists)) - mocker.patch.object(renderers.click, "confirm", mocker.Mock(return_value=confirmed_overwrite)) - overwrite = renderers.BaseRenderer._confirm_overwrite(mock_output_path) - if file_exists: - assert overwrite == confirmed_overwrite - else: - assert overwrite is True - - @pytest.mark.parametrize("confirmed_overwrite", [True, False]) - def test_import_configuration(self, mocker, patch_base_class, confirmed_overwrite): - configuration = {"foo": "bar"} - mocker.patch.object(renderers.BaseRenderer, "_render") - mocker.patch.object(renderers.BaseRenderer, "get_output_path") - mocker.patch.object(renderers.yaml, "safe_load", mocker.Mock(return_value={})) - mocker.patch.object(renderers.yaml, "safe_dump") - mocker.patch.object(renderers.BaseRenderer, "_confirm_overwrite", mocker.Mock(return_value=confirmed_overwrite)) - spec_renderer = renderers.BaseRenderer("my_resource_name") - spec_renderer.definition = mocker.Mock(type="my_definition") - expected_output_path = renderers.BaseRenderer.get_output_path.return_value - with patch("builtins.open", mock_open()) as mock_file: - output_path = spec_renderer.import_configuration(project_path=".", configuration=configuration) - spec_renderer._render.assert_called_once() - renderers.yaml.safe_load.assert_called_with(spec_renderer._render.return_value) - assert renderers.yaml.safe_load.return_value["configuration"] == configuration - spec_renderer.get_output_path.assert_called_with(".", spec_renderer.definition.type, spec_renderer.resource_name) - spec_renderer._confirm_overwrite.assert_called_with(expected_output_path) - if confirmed_overwrite: - mock_file.assert_called_with(expected_output_path, "wb") - renderers.yaml.safe_dump.assert_called_with( - renderers.yaml.safe_load.return_value, - mock_file.return_value, - default_flow_style=False, - sort_keys=False, - allow_unicode=True, - encoding="utf-8", - ) - assert output_path == renderers.BaseRenderer.get_output_path.return_value - - -class TestConnectorSpecificationRenderer: - def test_init(self, mocker): - assert renderers.ConnectorSpecificationRenderer.TEMPLATE == renderers.JINJA_ENV.get_template("source_or_destination.yaml.j2") - definition = mocker.Mock() - spec_renderer = renderers.ConnectorSpecificationRenderer("my_resource_name", definition) - assert spec_renderer.resource_name == "my_resource_name" - assert spec_renderer.definition == definition - - def test__parse_connection_specification(self, mocker): - mocker.patch.object(renderers, "parse_fields") - schema = {"required": ["foo"], "properties": {"foo": "bar"}} - definition = mocker.Mock() - spec_renderer = renderers.ConnectorSpecificationRenderer("my_resource_name", definition) - parsed_schema = spec_renderer._parse_connection_specification(schema) - assert renderers.parse_fields.call_count == 1 - assert parsed_schema[0], renderers.parse_fields.return_value - renderers.parse_fields.assert_called_with(["foo"], {"foo": "bar"}) - - def test__parse_connection_specification_one_of(self, mocker): - mocker.patch.object(renderers, "parse_fields") - schema = {"oneOf": [{"required": ["foo"], "properties": {"foo": "bar"}}, {"required": ["free"], "properties": {"free": "beer"}}]} - spec_renderer = renderers.ConnectorSpecificationRenderer("my_resource_name", mocker.Mock()) - parsed_schema = spec_renderer._parse_connection_specification(schema) - assert renderers.parse_fields.call_count == 2 - assert parsed_schema[0], renderers.parse_fields.return_value - assert parsed_schema[1], renderers.parse_fields.return_value - assert len(parsed_schema) == len(schema["oneOf"]) - renderers.parse_fields.assert_called_with(["free"], {"free": "beer"}) - - @pytest.mark.parametrize("overwrite", [True, False]) - def test_write_yaml(self, mocker, overwrite): - - mocker.patch.object(renderers.ConnectorSpecificationRenderer, "get_output_path") - mocker.patch.object(renderers.ConnectorSpecificationRenderer, "_parse_connection_specification") - mocker.patch.object( - renderers.ConnectorSpecificationRenderer, "TEMPLATE", mocker.Mock(render=mocker.Mock(return_value="rendered_string")) - ) - mocker.patch.object(renderers.ConnectorSpecificationRenderer, "_confirm_overwrite", mocker.Mock(return_value=overwrite)) - - spec_renderer = renderers.ConnectorSpecificationRenderer("my_resource_name", mocker.Mock(type="source")) - if overwrite: - with patch("builtins.open", mock_open()) as mock_file: - output_path = spec_renderer.write_yaml(".") - spec_renderer.TEMPLATE.render.assert_called_with( - { - "resource_name": "my_resource_name", - "definition": spec_renderer.definition, - "configuration_fields": spec_renderer._parse_connection_specification.return_value, - } - ) - mock_file.assert_called_with(output_path, "w") - else: - output_path = spec_renderer.write_yaml(".") - assert output_path == spec_renderer.get_output_path.return_value - - def test__render(self, mocker): - mocker.patch.object(renderers.ConnectorSpecificationRenderer, "_parse_connection_specification") - mocker.patch.object(renderers.ConnectorSpecificationRenderer, "TEMPLATE") - spec_renderer = renderers.ConnectorSpecificationRenderer("my_resource_name", mocker.Mock()) - rendered = spec_renderer._render() - spec_renderer._parse_connection_specification.assert_called_with(spec_renderer.definition.specification.connection_specification) - spec_renderer.TEMPLATE.render.assert_called_with( - { - "resource_name": spec_renderer.resource_name, - "definition": spec_renderer.definition, - "configuration_fields": spec_renderer._parse_connection_specification.return_value, - } - ) - assert rendered == spec_renderer.TEMPLATE.render.return_value - - -class TestConnectionRenderer: - @pytest.fixture - def mock_source(self, mocker): - return mocker.Mock() - - @pytest.fixture - def mock_destination(self, mocker): - return mocker.Mock() - - def test_init(self, mock_source, mock_destination): - assert renderers.ConnectionRenderer.TEMPLATE == renderers.JINJA_ENV.get_template("connection.yaml.j2") - connection_renderer = renderers.ConnectionRenderer("my_resource_name", mock_source, mock_destination) - assert connection_renderer.resource_name == "my_resource_name" - assert connection_renderer.source == mock_source - assert connection_renderer.destination == mock_destination - - def test_catalog_to_yaml(self, mocker): - stream = AirbyteStream( - default_cursor_field=["foo"], json_schema={}, name="my_stream", supported_sync_modes=[SyncMode("full_refresh")] - ) - config = AirbyteStreamConfiguration( - alias_name="pokemon", selected=True, destination_sync_mode=DestinationSyncMode("append"), sync_mode=SyncMode("full_refresh") - ) - catalog = AirbyteCatalog([AirbyteStreamAndConfiguration(stream=stream, config=config)]) - yaml_catalog = renderers.ConnectionRenderer.catalog_to_yaml(catalog) - assert yaml_catalog == yaml.dump(catalog.to_dict(), Dumper=yaml_dumpers.CatalogDumper, default_flow_style=False) - - @pytest.mark.parametrize("overwrite", [True, False]) - def test_write_yaml(self, mocker, mock_source, mock_destination, overwrite): - mocker.patch.object(renderers.ConnectionRenderer, "get_output_path") - mocker.patch.object(renderers.ConnectionRenderer, "catalog_to_yaml") - mocker.patch.object(renderers.ConnectionRenderer, "TEMPLATE") - mocker.patch.object(renderers.ConnectionRenderer, "_confirm_overwrite", mocker.Mock(return_value=overwrite)) - - connection_renderer = renderers.ConnectionRenderer("my_resource_name", mock_source, mock_destination) - if overwrite: - with patch("builtins.open", mock_open()) as mock_file: - output_path = connection_renderer.write_yaml(".") - connection_renderer.get_output_path.assert_called_with(".", renderers.ConnectionDefinition.type, "my_resource_name") - connection_renderer.catalog_to_yaml.assert_called_with(mock_source.catalog) - mock_file.assert_called_with(output_path, "w") - mock_file.return_value.write.assert_called_with(connection_renderer.TEMPLATE.render.return_value) - connection_renderer.TEMPLATE.render.assert_called_with( - { - "connection_name": connection_renderer.resource_name, - "source_configuration_path": mock_source.configuration_path, - "destination_configuration_path": mock_destination.configuration_path, - "catalog": connection_renderer.catalog_to_yaml.return_value, - "supports_normalization": connection_renderer.destination.definition.normalization_config.supported, - "supports_dbt": connection_renderer.destination.definition.supports_dbt, - } - ) - else: - output_path = connection_renderer.write_yaml(".") - assert output_path == connection_renderer.get_output_path.return_value - - def test__render(self, mocker): - mocker.patch.object(renderers.ConnectionRenderer, "catalog_to_yaml") - mocker.patch.object(renderers.ConnectionRenderer, "TEMPLATE") - connection_renderer = renderers.ConnectionRenderer("my_connection_name", mocker.Mock(), mocker.Mock()) - rendered = connection_renderer._render() - connection_renderer.catalog_to_yaml.assert_called_with(connection_renderer.source.catalog) - connection_renderer.TEMPLATE.render.assert_called_with( - { - "connection_name": connection_renderer.resource_name, - "source_configuration_path": connection_renderer.source.configuration_path, - "destination_configuration_path": connection_renderer.destination.configuration_path, - "catalog": connection_renderer.catalog_to_yaml.return_value, - "supports_normalization": connection_renderer.destination.definition.normalization_config.supported, - "supports_dbt": connection_renderer.destination.definition.supports_dbt, - } - ) - assert rendered == connection_renderer.TEMPLATE.render.return_value - - @pytest.mark.parametrize("confirmed_overwrite, operations", [(True, []), (False, []), (True, [{}]), (False, [{}])]) - def test_import_configuration(self, mocker, confirmed_overwrite, operations): - configuration = {"foo": "bar", "bar": "foo", "operations": operations} - mocker.patch.object(renderers.ConnectionRenderer, "KEYS_TO_REMOVE_FROM_REMOTE_CONFIGURATION", ["bar"]) - mocker.patch.object(renderers.ConnectionRenderer, "_render") - mocker.patch.object(renderers.ConnectionRenderer, "get_output_path") - mocker.patch.object(renderers.yaml, "safe_load", mocker.Mock(return_value={})) - mocker.patch.object(renderers.yaml, "safe_dump") - mocker.patch.object(renderers.ConnectionRenderer, "_confirm_overwrite", mocker.Mock(return_value=confirmed_overwrite)) - spec_renderer = renderers.ConnectionRenderer("my_resource_name", mocker.Mock(), mocker.Mock()) - expected_output_path = renderers.ConnectionRenderer.get_output_path.return_value - with patch("builtins.open", mock_open()) as mock_file: - output_path = spec_renderer.import_configuration(project_path=".", configuration=configuration) - spec_renderer._render.assert_called_once() - renderers.yaml.safe_load.assert_called_with(spec_renderer._render.return_value) - if operations: - assert renderers.yaml.safe_load.return_value["configuration"] == {"foo": "bar", "operations": operations} - else: - assert renderers.yaml.safe_load.return_value["configuration"] == {"foo": "bar"} - spec_renderer.get_output_path.assert_called_with(".", spec_renderer.definition.type, spec_renderer.resource_name) - spec_renderer._confirm_overwrite.assert_called_with(expected_output_path) - if confirmed_overwrite: - mock_file.assert_called_with(expected_output_path, "wb") - renderers.yaml.safe_dump.assert_called_with( - renderers.yaml.safe_load.return_value, - mock_file.return_value, - default_flow_style=False, - sort_keys=False, - allow_unicode=True, - encoding="utf-8", - ) - assert output_path == renderers.ConnectionRenderer.get_output_path.return_value diff --git a/octavia-cli/unit_tests/test_get/__init__.py b/octavia-cli/unit_tests/test_get/__init__.py deleted file mode 100644 index c941b3045795..000000000000 --- a/octavia-cli/unit_tests/test_get/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/unit_tests/test_get/test_commands.py b/octavia-cli/unit_tests/test_get/test_commands.py deleted file mode 100644 index 42243d5272e0..000000000000 --- a/octavia-cli/unit_tests/test_get/test_commands.py +++ /dev/null @@ -1,102 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import pytest -from click.testing import CliRunner -from octavia_cli.get import commands - - -def test_commands_in_get_group(): - get_commands = commands.get.commands.values() - for command in commands.AVAILABLE_COMMANDS: - assert command in get_commands - - -@pytest.fixture -def context_object(mock_api_client, mock_telemetry_client): - return { - "API_CLIENT": mock_api_client, - "WORKSPACE_ID": "my_workspace_id", - "resource_id": "my_resource_id", - "TELEMETRY_CLIENT": mock_telemetry_client, - } - - -def test_available_commands(): - assert commands.AVAILABLE_COMMANDS == [commands.source, commands.destination, commands.connection] - - -def test_build_help_message(): - assert commands.build_help_message("fake_resource_type") == "Get a JSON representation of a remote fake_resource_type." - - -def test_get_resource_id_or_name(): - resource_id, resource_name = commands.get_resource_id_or_name("resource_name") - assert resource_id is None and resource_name == "resource_name" - resource_id, resource_name = commands.get_resource_id_or_name("8c2e8369-3b81-471a-9945-32a3c67c31b7") - assert resource_id == "8c2e8369-3b81-471a-9945-32a3c67c31b7" and resource_name is None - - -def test_get_json_representation(mocker, context_object): - mock_cls = mocker.Mock() - mocker.patch.object(commands.click, "echo") - mock_resource_id = mocker.Mock() - mock_resource_name = mocker.Mock() - mocker.patch.object(commands, "get_resource_id_or_name", mocker.Mock(return_value=(mock_resource_id, mock_resource_name))) - json_repr = commands.get_json_representation(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], mock_cls, "resource_to_get") - commands.get_resource_id_or_name.assert_called_with("resource_to_get") - mock_cls.assert_called_with( - context_object["API_CLIENT"], context_object["WORKSPACE_ID"], resource_id=mock_resource_id, resource_name=mock_resource_name - ) - assert json_repr == mock_cls.return_value.to_json.return_value - - -@pytest.mark.parametrize( - "command, resource_cls, resource", - [ - (commands.source, commands.Source, "my_resource_id"), - (commands.destination, commands.Destination, "my_resource_id"), - (commands.connection, commands.Connection, "my_resource_id"), - ], -) -def test_commands(context_object, mocker, command, resource_cls, resource): - mocker.patch.object(commands, "get_json_representation", mocker.Mock(return_value='{"foo": "bar"}')) - runner = CliRunner() - result = runner.invoke(command, [resource], obj=context_object) - commands.get_json_representation.assert_called_once_with( - context_object["API_CLIENT"], context_object["WORKSPACE_ID"], resource_cls, resource - ) - assert result.exit_code == 0 - - -# @pytest.mark.parametrize( -# "command,resource_id", -# [ -# (commands.destination, "my_resource_id"), -# ], -# ) -# def test_destination(mocker, context_object, command, resource_id): -# runner = CliRunner() -# mocker.patch.object(commands, "Destination", mocker.Mock()) -# mock_renderer = commands.Destination.return_value -# mock_renderer.get_remote_resource.return_value = '{"hello": "world"}' -# result = runner.invoke(command, [resource_id], obj=context_object) -# assert result.exit_code == 0 -# commands.Destination.assert_called_with(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], resource_id) - - -# @pytest.mark.parametrize( -# "command,resource_id", -# [ -# (commands.connection, "my_resource_id"), -# ], -# ) -# def test_connection(mocker, context_object, command, resource_id): -# runner = CliRunner() -# mocker.patch.object(commands, "Connection", mocker.Mock()) -# mock_renderer = commands.Connection.return_value -# mock_renderer.get_remote_resource.return_value = '{"hello": "world"}' -# result = runner.invoke(command, [resource_id], obj=context_object) -# assert result.exit_code == 0 -# commands.Connection.assert_called_with(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], resource_id) diff --git a/octavia-cli/unit_tests/test_get/test_resources.py b/octavia-cli/unit_tests/test_get/test_resources.py deleted file mode 100644 index c376ea8534af..000000000000 --- a/octavia-cli/unit_tests/test_get/test_resources.py +++ /dev/null @@ -1,137 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import pytest -from airbyte_api_client.api import destination_api, source_api, web_backend_api -from airbyte_api_client.model.destination_id_request_body import DestinationIdRequestBody -from airbyte_api_client.model.source_id_request_body import SourceIdRequestBody -from airbyte_api_client.model.web_backend_connection_request_body import WebBackendConnectionRequestBody -from octavia_cli.get.resources import BaseResource, Connection, Destination, DuplicateResourceError, ResourceNotFoundError, Source - - -class TestBaseResource: - @pytest.fixture - def patch_base_class(self, mocker): - # Mock abstract methods to enable instantiating abstract class - mocker.patch.object(BaseResource, "__abstractmethods__", set()) - mocker.patch.object(BaseResource, "api", mocker.Mock()) - mocker.patch.object(BaseResource, "get_function_name", "get_function_name") - mocker.patch.object(BaseResource, "get_payload", "get_payload") - mocker.patch.object(BaseResource, "list_for_workspace_function_name", "list_for_workspace_function_name") - mocker.patch.object(BaseResource, "name", "fake_resource") - - @pytest.mark.parametrize( - "resource_id, resource_name, expected_error, expected_error_message", - [ - ("my_resource_id", None, None, None), - (None, "my_resource_name", None, None), - (None, None, ValueError, "resource_id and resource_name keyword arguments can't be both None."), - ("my_resource_id", "my_resource_name", ValueError, "resource_id and resource_name keyword arguments can't be both set."), - ], - ) - def test_init(self, patch_base_class, mock_api_client, resource_id, resource_name, expected_error, expected_error_message): - if expected_error: - with pytest.raises(expected_error, match=expected_error_message): - base_resource = BaseResource(mock_api_client, "workspace_id", resource_id=resource_id, resource_name=resource_name) - else: - base_resource = BaseResource(mock_api_client, "workspace_id", resource_id=resource_id, resource_name=resource_name) - base_resource.api.assert_called_with(mock_api_client) - assert base_resource.api_instance == base_resource.api.return_value - assert base_resource.workspace_id == "workspace_id" - assert base_resource._get_fn == getattr(base_resource.api, base_resource.get_function_name) - assert base_resource._list_for_workspace_fn == getattr(base_resource.api, base_resource.list_for_workspace_function_name) - assert base_resource.resource_id == resource_id - assert base_resource.resource_name == resource_name - - @pytest.mark.parametrize( - "resource_name, api_response_resources_names, expected_error, expected_error_message", - [ - ("foo", ["foo", "bar"], None, None), - ("foo", ["bar", "fooo"], ResourceNotFoundError, "The fake_resource foo was not found in your current Airbyte workspace."), - ( - "foo", - ["foo", "foo"], - DuplicateResourceError, - "2 fake_resources with the name foo were found in your current Airbyte workspace.", - ), - ], - ) - def test__find_by_resource_name( - self, mocker, patch_base_class, mock_api_client, resource_name, api_response_resources_names, expected_error, expected_error_message - ): - mock_api_response_records = [] - for fake_resource_name in api_response_resources_names: - mock_api_response_record = mocker.Mock() # We can't set the mock name on creation as it's a reserved attribute - mock_api_response_record.name = fake_resource_name - mock_api_response_records.append(mock_api_response_record) - - mocker.patch.object( - BaseResource, "_list_for_workspace_fn", mocker.Mock(return_value=mocker.Mock(fake_resources=mock_api_response_records)) - ) - base_resource = BaseResource(mock_api_client, "workspace_id", resource_id=None, resource_name=resource_name) - if not expected_error: - found_resource = base_resource._find_by_resource_name() - assert found_resource.name == resource_name - if expected_error: - with pytest.raises(expected_error, match=expected_error_message): - base_resource._find_by_resource_name() - - def test__find_by_id(self, mocker, patch_base_class, mock_api_client): - mocker.patch.object(BaseResource, "_get_fn") - base_resource = BaseResource(mock_api_client, "workspace_id", resource_id="my_resource_id") - base_resource._find_by_resource_id() - base_resource._get_fn.assert_called_with(base_resource.api_instance, base_resource.get_payload) - - @pytest.mark.parametrize("resource_id, resource_name", [("my_resource_id", None), (None, "my_resource_name")]) - def test_get_remote_resource(self, mocker, patch_base_class, mock_api_client, resource_id, resource_name): - mocker.patch.object(BaseResource, "_find_by_resource_id") - mocker.patch.object(BaseResource, "_find_by_resource_name") - base_resource = BaseResource(mock_api_client, "workspace_id", resource_id=resource_id, resource_name=resource_name) - remote_resource = base_resource.get_remote_resource() - if resource_id is not None: - base_resource._find_by_resource_id.assert_called_once() - base_resource._find_by_resource_name.assert_not_called() - assert remote_resource == base_resource._find_by_resource_id.return_value - if resource_name is not None: - base_resource._find_by_resource_id.assert_not_called() - base_resource._find_by_resource_name.assert_called_once() - assert remote_resource == base_resource._find_by_resource_name.return_value - - def test_to_json(self, mocker, patch_base_class, mock_api_client): - mocker.patch.object( - BaseResource, "get_remote_resource", mocker.Mock(return_value=mocker.Mock(to_dict=mocker.Mock(return_value={"foo": "bar"}))) - ) - base_resource = BaseResource(mock_api_client, "workspace_id", resource_id="my_resource_id") - json_repr = base_resource.to_json() - assert json_repr == '{"foo": "bar"}' - - -class TestSource: - def test_init(self, mock_api_client): - assert Source.__base__ == BaseResource - source = Source(mock_api_client, "workspace_id", "resource_id") - assert source.api == source_api.SourceApi - assert source.get_function_name == "get_source" - assert source.list_for_workspace_function_name == "list_sources_for_workspace" - assert source.get_payload == SourceIdRequestBody("resource_id") - - -class TestDestination: - def test_init(self, mock_api_client): - assert Destination.__base__ == BaseResource - destination = Destination(mock_api_client, "workspace_id", "resource_id") - assert destination.api == destination_api.DestinationApi - assert destination.get_function_name == "get_destination" - assert destination.list_for_workspace_function_name == "list_destinations_for_workspace" - assert destination.get_payload == DestinationIdRequestBody("resource_id") - - -class TestConnection: - def test_init(self, mock_api_client): - assert Connection.__base__ == BaseResource - connection = Connection(mock_api_client, "workspace_id", "resource_id") - assert connection.api == web_backend_api.WebBackendApi - assert connection.get_function_name == "web_backend_get_connection" - assert connection.list_for_workspace_function_name == "web_backend_list_connections_for_workspace" - assert connection.get_payload == WebBackendConnectionRequestBody(with_refreshed_catalog=False, connection_id=connection.resource_id) diff --git a/octavia-cli/unit_tests/test_init/__init__.py b/octavia-cli/unit_tests/test_init/__init__.py deleted file mode 100644 index 46b7376756ec..000000000000 --- a/octavia-cli/unit_tests/test_init/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/unit_tests/test_init/test_commands.py b/octavia-cli/unit_tests/test_init/test_commands.py deleted file mode 100644 index 9d766ff0a830..000000000000 --- a/octavia-cli/unit_tests/test_init/test_commands.py +++ /dev/null @@ -1,90 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from unittest.mock import mock_open, patch - -import pytest -from click.testing import CliRunner -from octavia_cli.init import commands -from octavia_cli.init.commands import create_api_headers_configuration_file - - -def test_directories_to_create(): - assert commands.DIRECTORIES_TO_CREATE == {"connections", "destinations", "sources"} - - -@pytest.fixture -def context_object(mock_telemetry_client): - return {"TELEMETRY_CLIENT": mock_telemetry_client} - - -@pytest.mark.parametrize( - "directories_to_create,mkdir_side_effects,expected_created_directories,expected_not_created_directories", - [ - (["dir_a", "dir_b"], None, ["dir_a", "dir_b"], []), - (["dir_a", "dir_b"], FileExistsError(), [], ["dir_a", "dir_b"]), - (["dir_a", "dir_b"], [None, FileExistsError()], ["dir_a"], ["dir_b"]), - ], -) -def test_create_directories( - mocker, directories_to_create, mkdir_side_effects, expected_created_directories, expected_not_created_directories -): - mocker.patch.object(commands, "os", mocker.Mock(mkdir=mocker.Mock(side_effect=mkdir_side_effects))) - created_directories, not_created_directories = commands.create_directories(directories_to_create) - assert created_directories == expected_created_directories - assert not_created_directories == expected_not_created_directories - commands.os.mkdir.assert_has_calls([mocker.call(d) for d in directories_to_create]) - - -def test_init(mocker, context_object): - runner = CliRunner() - mocker.patch.object(commands, "create_directories", mocker.Mock(return_value=(["dir_a", "dir_b"], []))) - mocker.patch.object(commands, "create_api_headers_configuration_file", mocker.Mock(return_value=True)) - result = runner.invoke(commands.init, obj=context_object) - assert result.exit_code == 0 - assert ( - result.output - == "🔨 - Initializing the project.\n✅ - Created the following directories: dir_a, dir_b.\n" - + f"✅ - Created API HTTP headers file in {commands.API_HTTP_HEADERS_TARGET_PATH}\n" - ) - - -def test_init_some_existing_directories(mocker, context_object): - runner = CliRunner() - mocker.patch.object(commands, "create_directories", mocker.Mock(return_value=(["dir_a"], ["dir_b"]))) - mocker.patch.object(commands, "create_api_headers_configuration_file", mocker.Mock(return_value=False)) - result = runner.invoke(commands.init, obj=context_object) - assert result.exit_code == 0 - assert "Already existing directories: dir_b.\n" in result.output - - -def test_init_all_existing_directories(mocker, context_object): - runner = CliRunner() - mocker.patch.object(commands, "create_directories", mocker.Mock(return_value=([], ["dir_a", "dir_b"]))) - mocker.patch.object(commands, "create_api_headers_configuration_file", mocker.Mock(return_value=False)) - result = runner.invoke(commands.init, obj=context_object) - assert result.exit_code == 0 - assert "Already existing directories: dir_a, dir_b.\n" in result.output - - -def test_init_when_api_headers_configuration_file_exists(mocker, context_object): - runner = CliRunner() - mocker.patch.object(commands, "create_directories", mocker.Mock(return_value=([], ["dir_a", "dir_b"]))) - mocker.patch.object(commands, "create_api_headers_configuration_file", mocker.Mock(return_value=False)) - result = runner.invoke(commands.init, obj=context_object) - assert result.exit_code == 0 - assert "API HTTP headers file already exists, skipping." in result.output - - -@pytest.mark.parametrize("api_http_headers_file_exist", [False, True]) -def test_create_init_configuration(mocker, api_http_headers_file_exist): - mock_path = mocker.Mock(is_file=mocker.Mock(return_value=api_http_headers_file_exist)) - mocker.patch.object(commands, "API_HTTP_HEADERS_TARGET_PATH", mock_path) - if not api_http_headers_file_exist: - with patch("builtins.open", mock_open()) as mock_file: - assert create_api_headers_configuration_file() - mock_file.assert_called_with(commands.API_HTTP_HEADERS_TARGET_PATH, "w") - mock_file.return_value.write.assert_called_with(commands.DEFAULT_API_HEADERS_FILE_CONTENT) - else: - assert not create_api_headers_configuration_file() diff --git a/octavia-cli/unit_tests/test_list/__init__.py b/octavia-cli/unit_tests/test_list/__init__.py deleted file mode 100644 index 46b7376756ec..000000000000 --- a/octavia-cli/unit_tests/test_list/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -# Copyright (c) 2021 Airbyte, Inc., all rights reserved. -# diff --git a/octavia-cli/unit_tests/test_list/test_commands.py b/octavia-cli/unit_tests/test_list/test_commands.py deleted file mode 100644 index 83dd50d984ba..000000000000 --- a/octavia-cli/unit_tests/test_list/test_commands.py +++ /dev/null @@ -1,62 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import pytest -from click.testing import CliRunner -from octavia_cli.list import commands - - -@pytest.fixture -def context_object(mock_api_client, mock_telemetry_client): - return {"API_CLIENT": mock_api_client, "WORKSPACE_ID": "my_workspace_id", "TELEMETRY_CLIENT": mock_telemetry_client} - - -def test_available_commands(): - assert commands.AVAILABLE_COMMANDS == [commands.connectors, commands.workspace] - - -def test_commands_in_list_group(): - list_commands = commands._list.commands.values() - for command in commands.AVAILABLE_COMMANDS: - assert command in list_commands - - -def test_connectors_sources(mocker, context_object): - mocker.patch.object(commands, "SourceConnectorsDefinitions", mocker.Mock(return_value="SourceConnectorsDefinitionsRepr")) - runner = CliRunner() - result = runner.invoke(commands.sources_connectors, obj=context_object) - commands.SourceConnectorsDefinitions.assert_called_with(context_object["API_CLIENT"]) - assert result.output == "SourceConnectorsDefinitionsRepr\n" - - -def test_connectors_destinations(mocker, context_object): - mocker.patch.object(commands, "DestinationConnectorsDefinitions", mocker.Mock(return_value="DestinationConnectorsDefinitionsRepr")) - runner = CliRunner() - result = runner.invoke(commands.destinations_connectors, obj=context_object) - commands.DestinationConnectorsDefinitions.assert_called_with(context_object["API_CLIENT"]) - assert result.output == "DestinationConnectorsDefinitionsRepr\n" - - -def test_sources(mocker, context_object): - mocker.patch.object(commands, "Sources", mocker.Mock(return_value="SourcesRepr")) - runner = CliRunner() - result = runner.invoke(commands.sources, obj=context_object) - commands.Sources.assert_called_with(context_object["API_CLIENT"], context_object["WORKSPACE_ID"]) - assert result.output == "SourcesRepr\n" - - -def test_destinations(mocker, context_object): - mocker.patch.object(commands, "Destinations", mocker.Mock(return_value="DestinationsRepr")) - runner = CliRunner() - result = runner.invoke(commands.destinations, obj=context_object) - commands.Destinations.assert_called_with(context_object["API_CLIENT"], context_object["WORKSPACE_ID"]) - assert result.output == "DestinationsRepr\n" - - -def test_connections(mocker, context_object): - mocker.patch.object(commands, "Connections", mocker.Mock(return_value="ConnectionsRepr")) - runner = CliRunner() - result = runner.invoke(commands.connections, obj=context_object) - commands.Connections.assert_called_with(context_object["API_CLIENT"], context_object["WORKSPACE_ID"]) - assert result.output == "ConnectionsRepr\n" diff --git a/octavia-cli/unit_tests/test_list/test_formatting.py b/octavia-cli/unit_tests/test_list/test_formatting.py deleted file mode 100644 index 1c0b037c45ac..000000000000 --- a/octavia-cli/unit_tests/test_list/test_formatting.py +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import pytest -from octavia_cli.list import formatting - -PADDING = 2 - - -@pytest.mark.parametrize( - "test_data,expected_columns_width", - [ - ([["a", "___10chars"], ["e", "f"]], [1 + PADDING, 10 + PADDING]), - ([["a", "___10chars"], ["e", "____11chars"]], [1 + PADDING, 11 + PADDING]), - ([[""]], [PADDING]), - ], -) -def test_compute_columns_width(test_data, expected_columns_width): - columns_width = formatting.compute_columns_width(test_data, PADDING) - assert columns_width == expected_columns_width - - -@pytest.mark.parametrize("input_camelcased,expected_output", [("camelCased", "CAMEL CASED"), ("notcamelcased", "NOTCAMELCASED")]) -def test_camelcased_to_uppercased_spaced(input_camelcased, expected_output): - assert formatting.camelcased_to_uppercased_spaced(input_camelcased) == expected_output - - -@pytest.mark.parametrize( - "test_data,columns_width,expected_output", - [ - ([["a", "___10chars"], ["e", "____11chars"]], [1 + PADDING, 11 + PADDING], "a ___10chars \ne ____11chars "), - ], -) -def test_display_as_table(mocker, test_data, columns_width, expected_output): - mocker.patch.object(formatting, "compute_columns_width", mocker.Mock(return_value=columns_width)) - assert formatting.display_as_table(test_data) == expected_output - - -def test_format_column_names(): - columns_to_format = ["camelCased"] - formatted_columns = formatting.format_column_names(columns_to_format) - assert len(formatted_columns) == 1 - for i, c in enumerate(formatted_columns): - assert c == formatting.camelcased_to_uppercased_spaced(columns_to_format[i]) diff --git a/octavia-cli/unit_tests/test_list/test_listings.py b/octavia-cli/unit_tests/test_list/test_listings.py deleted file mode 100644 index 7a43a4731363..000000000000 --- a/octavia-cli/unit_tests/test_list/test_listings.py +++ /dev/null @@ -1,154 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import pytest -from airbyte_api_client.api import connection_api, destination_api, destination_definition_api, source_api, source_definition_api -from octavia_cli.list import listings -from octavia_cli.list.listings import ( - BaseListing, - Connections, - DestinationConnectorsDefinitions, - Destinations, - SourceConnectorsDefinitions, - Sources, - WorkspaceListing, -) - - -class TestBaseListing: - @pytest.fixture - def patch_base_class(self, mocker): - # Mock abstract methods to enable instantiating abstract class - mocker.patch.object(BaseListing, "__abstractmethods__", set()) - mocker.patch.object(BaseListing, "list_function_name", "my_list_function_name") - mocker.patch.object(BaseListing, "api", mocker.Mock(my_list_function_name=mocker.Mock())) - - def test_init(self, patch_base_class, mock_api_client): - base_listing = BaseListing(mock_api_client) - assert base_listing._list_fn == BaseListing.api.my_list_function_name - assert base_listing.list_function_kwargs == {} - assert base_listing.api_instance == base_listing.api.return_value - base_listing.api.assert_called_with(mock_api_client) - assert base_listing.COMMON_LIST_FUNCTION_KWARGS == {"_check_return_type": False} - - def test_abstract_methods(self, mock_api_client): - assert BaseListing.__abstractmethods__ == {"api", "fields_to_display", "list_field_in_response", "list_function_name"} - with pytest.raises(TypeError): - BaseListing(mock_api_client) - - def test_parse_response(self, patch_base_class, mocker, mock_api_client): - mocker.patch.object(BaseListing, "fields_to_display", ["fieldA", "fieldB"]) - base_listing = BaseListing(mock_api_client) - api_response = {base_listing.list_field_in_response: []} - for i in range(5): - definition = {field: f"{field}_value_{i}" for field in base_listing.fields_to_display} - definition["discarded_field"] = "discarded_value" - api_response[base_listing.list_field_in_response].append(definition) - parsed_listing = base_listing._parse_response(api_response) - assert len(parsed_listing) == 5 - for i in range(5): - assert parsed_listing[i] == [f"{field}_value_{i}" for field in base_listing.fields_to_display] - assert "discarded_value" not in parsed_listing[i] - - def test_gest_listing(self, patch_base_class, mocker, mock_api_client): - mocker.patch.object(BaseListing, "_parse_response") - mocker.patch.object(BaseListing, "_list_fn") - base_listing = BaseListing(mock_api_client) - listing = base_listing.get_listing() - base_listing._list_fn.assert_called_with( - base_listing.api_instance, **base_listing.list_function_kwargs, **base_listing.COMMON_LIST_FUNCTION_KWARGS - ) - base_listing._parse_response.assert_called_with(base_listing._list_fn.return_value) - assert listing == base_listing._parse_response.return_value - - def test_repr(self, patch_base_class, mocker, mock_api_client): - headers = ["fieldA", "fieldB", "fieldC"] - api_response_listing = [["a", "b", "c"]] - mocker.patch.object(BaseListing, "fields_to_display", headers) - mocker.patch.object(BaseListing, "get_listing", mocker.Mock(return_value=api_response_listing)) - mocker.patch.object(listings, "formatting") - base_listing = BaseListing(mock_api_client) - representation = base_listing.__repr__() - listings.formatting.display_as_table.assert_called_with( - [listings.formatting.format_column_names.return_value] + api_response_listing - ) - assert representation == listings.formatting.display_as_table.return_value - - -class TestSourceConnectorsDefinitions: - def test_init(self, mock_api_client): - assert SourceConnectorsDefinitions.__base__ == BaseListing - source_connectors_definition = SourceConnectorsDefinitions(mock_api_client) - assert source_connectors_definition.api == source_definition_api.SourceDefinitionApi - assert source_connectors_definition.fields_to_display == ["name", "dockerRepository", "dockerImageTag", "sourceDefinitionId"] - assert source_connectors_definition.list_field_in_response == "source_definitions" - assert source_connectors_definition.list_function_name == "list_source_definitions" - - -class TestDestinationConnectorsDefinitions: - def test_init(self, mock_api_client): - assert DestinationConnectorsDefinitions.__base__ == BaseListing - destination_connectors_definition = DestinationConnectorsDefinitions(mock_api_client) - assert destination_connectors_definition.api == destination_definition_api.DestinationDefinitionApi - assert destination_connectors_definition.fields_to_display == [ - "name", - "dockerRepository", - "dockerImageTag", - "destinationDefinitionId", - ] - assert destination_connectors_definition.list_field_in_response == "destination_definitions" - assert destination_connectors_definition.list_function_name == "list_destination_definitions" - - -class TestWorkspaceListing: - @pytest.fixture - def patch_base_class(self, mocker): - # Mock abstract methods to enable instantiating abstract class - mocker.patch.object(WorkspaceListing, "__abstractmethods__", set()) - mocker.patch.object(WorkspaceListing, "api", mocker.Mock()) - - def test_init(self, patch_base_class, mocker, mock_api_client): - mocker.patch.object(listings, "WorkspaceIdRequestBody") - mocker.patch.object(BaseListing, "__init__") - assert WorkspaceListing.__base__ == BaseListing - sources_and_destinations = WorkspaceListing(mock_api_client, "my_workspace_id") - - assert sources_and_destinations.workspace_id == "my_workspace_id" - assert sources_and_destinations.list_function_kwargs == {"workspace_id_request_body": listings.WorkspaceIdRequestBody.return_value} - listings.WorkspaceIdRequestBody.assert_called_with(workspace_id="my_workspace_id") - BaseListing.__init__.assert_called_with(mock_api_client) - - def test_abstract(self, mock_api_client): - with pytest.raises(TypeError): - WorkspaceListing(mock_api_client) - - -class TestSources: - def test_init(self, mock_api_client): - assert Sources.__base__ == WorkspaceListing - sources = Sources(mock_api_client, "my_workspace_id") - assert sources.api == source_api.SourceApi - assert sources.fields_to_display == ["name", "sourceName", "sourceId"] - assert sources.list_field_in_response == "sources" - assert sources.list_function_name == "list_sources_for_workspace" - - -class TestDestinations: - def test_init(self, mock_api_client): - assert Destinations.__base__ == WorkspaceListing - destinations = Destinations(mock_api_client, "my_workspace_id") - assert destinations.api == destination_api.DestinationApi - assert destinations.fields_to_display == ["name", "destinationName", "destinationId"] - assert destinations.list_field_in_response == "destinations" - assert destinations.list_function_name == "list_destinations_for_workspace" - - -class TestConnections: - def test_init(self, mock_api_client): - assert Connections.__base__ == WorkspaceListing - connections = Connections(mock_api_client, "my_workspace_id") - assert connections.api == connection_api.ConnectionApi - assert connections.fields_to_display == ["name", "connectionId", "status", "sourceId", "destinationId"] - assert connections.list_field_in_response == "connections" - assert connections.list_function_name == "list_connections_for_workspace" diff --git a/octavia-cli/unit_tests/test_telemetry.py b/octavia-cli/unit_tests/test_telemetry.py deleted file mode 100644 index 77263c354422..000000000000 --- a/octavia-cli/unit_tests/test_telemetry.py +++ /dev/null @@ -1,124 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import click -import pytest -from octavia_cli import telemetry - - -def test_build_user_agent(): - ua = telemetry.build_user_agent("my_octavia_version") - assert ua == "octavia-cli/my_octavia_version" - - -class TestTelemetryClient: - @pytest.mark.parametrize("send_data", [True, False]) - def test_init(self, mocker, send_data): - assert isinstance(telemetry.TelemetryClient.WRITE_KEY, str) - mocker.patch.object(telemetry.TelemetryClient, "write_key", "my_write_key") - mocker.patch.object(telemetry.analytics, "Client") - telemetry_client = telemetry.TelemetryClient(send_data) - assert telemetry_client.segment_client == telemetry.analytics.Client.return_value - telemetry.analytics.Client.assert_called_with("my_write_key", send=send_data) - - @pytest.fixture - def telemetry_client(self, mocker): - mocker.patch.object(telemetry.analytics, "Client") - return telemetry.TelemetryClient(True) - - @pytest.mark.parametrize("octavia_custom_write_key", ["my_custom_write_key", None]) - def test_write_key(self, mocker, telemetry_client, octavia_custom_write_key): - mocker.patch.object(telemetry.os, "getenv", mocker.Mock(return_value=octavia_custom_write_key)) - assert telemetry_client.write_key == telemetry.os.getenv.return_value - telemetry.os.getenv.assert_called_with("OCTAVIA_TELEMETRY_WRITE_KEY", telemetry_client.WRITE_KEY) - - @pytest.mark.parametrize("extra_info_name", ["foo", None]) - def test__create_command_name_multi_contexts(self, mocker, telemetry_client, extra_info_name): - grand_parent_ctx = click.Context(mocker.Mock(), None, "grand_parent_command") - parent_ctx = click.Context(mocker.Mock(), grand_parent_ctx, "parent_command") - ctx = click.Context(mocker.Mock(), parent_ctx, "child_command") - command_name = telemetry_client._create_command_name(ctx, extra_info_name=extra_info_name) - if extra_info_name: - assert command_name == f"grand_parent_command parent_command child_command {extra_info_name}" - else: - assert command_name == "grand_parent_command parent_command child_command" - - @pytest.mark.parametrize("extra_info_name", ["foo", None]) - def test__create_command_name_single_context(self, mocker, telemetry_client, extra_info_name): - ctx = click.Context(mocker.Mock(), None, "child_command") - command_name = telemetry_client._create_command_name(ctx, extra_info_name=extra_info_name) - if extra_info_name: - assert command_name == f"child_command {extra_info_name}" - else: - assert command_name == "child_command" - - @pytest.mark.parametrize( - "workspace_id, anonymous_data_collection, airbyte_role, project_is_initialized, octavia_version, error, expected_success, expected_error_type, is_help", - [ - (None, None, None, None, None, None, True, None, False), - (None, None, None, None, None, Exception(), False, "Exception", False), - (None, None, None, None, None, AttributeError(), False, "AttributeError", False), - (None, True, None, None, None, None, True, None, False), - (None, True, None, None, None, Exception(), False, "Exception", False), - (None, True, None, None, None, AttributeError(), False, "AttributeError", False), - ("my_workspace_id", False, None, None, None, None, True, None, False), - ("my_workspace_id", False, None, None, None, Exception(), False, "Exception", False), - ("my_workspace_id", True, None, None, None, None, True, None, False), - ("my_workspace_id", True, None, None, None, Exception(), False, "Exception", False), - ("my_workspace_id", True, "airbyter", None, None, None, True, None, False), - ("my_workspace_id", True, "non_airbyter", None, None, Exception(), False, "Exception", False), - ("my_workspace_id", True, "airbyter", True, None, None, True, None, False), - ("my_workspace_id", True, "non_airbyter", False, None, Exception(), False, "Exception", False), - ("my_workspace_id", True, "airbyter", True, None, None, True, None, False), - ("my_workspace_id", True, "non_airbyter", False, "0.1.0", Exception(), False, "Exception", False), - ("my_workspace_id", True, "non_airbyter", False, "0.1.0", None, True, None, False), - ("my_workspace_id", True, "non_airbyter", False, "0.1.0", None, True, None, True), - ], - ) - def test_send_command_telemetry( - self, - mocker, - telemetry_client, - workspace_id, - anonymous_data_collection, - airbyte_role, - project_is_initialized, - octavia_version, - error, - expected_success, - expected_error_type, - is_help, - ): - extra_info_name = "foo" - mocker.patch.object(telemetry.os, "getenv", mocker.Mock(return_value=airbyte_role)) - expected_user_id = workspace_id if workspace_id is not None and anonymous_data_collection is False else None - expected_anonymous_id = "anonymous" if expected_user_id is None else None - mock_ctx = mocker.Mock( - obj={ - "OCTAVIA_VERSION": octavia_version, - "PROJECT_IS_INITIALIZED": project_is_initialized, - "WORKSPACE_ID": workspace_id, - "ANONYMOUS_DATA_COLLECTION": anonymous_data_collection, - } - ) - expected_segment_context = {"app": {"name": "octavia-cli", "version": octavia_version}} - expected_properties = { - "success": expected_success, - "is_help": is_help, - "error_type": expected_error_type, - "project_is_initialized": project_is_initialized, - "airbyter": airbyte_role == "airbyter", - } - telemetry_client.segment_client = mocker.Mock() - telemetry_client._create_command_name = mocker.Mock(return_value="my_command") - - telemetry_client.send_command_telemetry(mock_ctx, error=error, extra_info_name=extra_info_name, is_help=is_help) - telemetry_client._create_command_name.assert_called_with(mock_ctx, extra_info_name=extra_info_name) - telemetry_client.segment_client.track.assert_called_with( - user_id=expected_user_id, - anonymous_id=expected_anonymous_id, - event="my_command", - properties=expected_properties, - context=expected_segment_context, - ) diff --git a/tools/bin/integration_tests_octavia.sh b/tools/bin/integration_tests_octavia.sh deleted file mode 100755 index 576f45506721..000000000000 --- a/tools/bin/integration_tests_octavia.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -set -e -. run-ab-platform.sh -d # download the platform docker files necessary to run docker compose -. tools/lib/lib.sh - -assert_root - -echo "Starting app..." - -# Detach so we can run subsequent commands -VERSION=dev TRACKING_STRATEGY=logging BASIC_AUTH_USERNAME="" BASIC_AUTH_PASSWORD="" docker compose up -d - -# Sometimes source/dest containers using airbyte volumes survive shutdown, which need to be killed in order to shut down properly. -shutdown_cmd="docker compose down -v || docker kill \$(docker ps -a -f volume=airbyte_workspace -f volume=airbyte_data -f volume=airbyte_db -q) && docker compose down -v" -trap "echo 'docker compose logs:' && docker compose logs -t --tail 1000 && $shutdown_cmd" EXIT - -echo "Waiting for services to begin" -while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8000/api/v1/health)" != "200" ]]; do echo "Waiting for docker deployment.."; sleep 5; done - -echo "Running integration tests via gradle" -./gradlew :octavia-cli:integrationTest --rerun-tasks --scan diff --git a/tools/bin/release_version_octavia.sh b/tools/bin/release_version_octavia.sh deleted file mode 100755 index 9425da663bac..000000000000 --- a/tools/bin/release_version_octavia.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -set -e - -. tools/lib/lib.sh - -if test -z "${DOCKER_HUB_USERNAME}"; then - echo 'DOCKER_HUB_USERNNAME not set.'; - exit 1; -fi - -if test -z "${DOCKER_HUB_PASSWORD}"; then - echo 'DOCKER_HUB_PASSWORD for docker user not set.'; - exit 1; -fi - -docker login --username "${DOCKER_HUB_USERNAME}" --password "${DOCKER_HUB_PASSWORD}" - -source ./tools/bin/bump_version.sh - -echo "Building and publishing OCTAVIA version ${NEW_VERSION} for git revision ${GIT_REVISION}..." -VERSION=$NEW_VERSION ./gradlew clean :octavia-cli:build --scan -./octavia-cli/publish.sh ${NEW_VERSION} ${GIT_REVISION} -echo "Completed building and publishing OCTAVIA..." From 2d132c59d0310813a45dc6da9be2b86b3387ff26 Mon Sep 17 00:00:00 2001 From: Marcos Marx Date: Fri, 16 Feb 2024 18:26:38 -0300 Subject: [PATCH 17/43] Docs: update k8s instructions for upgrade (#35108) --- docs/operator-guides/upgrading-airbyte.md | 95 ++++------------------- 1 file changed, 13 insertions(+), 82 deletions(-) diff --git a/docs/operator-guides/upgrading-airbyte.md b/docs/operator-guides/upgrading-airbyte.md index e11192859ea1..5a4da98d9904 100644 --- a/docs/operator-guides/upgrading-airbyte.md +++ b/docs/operator-guides/upgrading-airbyte.md @@ -84,91 +84,22 @@ This will completely reset your Airbyte deployment back to scratch and you will ::: -## Upgrading on K8s (0.27.0-alpha and above) +## Upgrading on K8s using Helm -If you are upgrading from (i.e. your current version of Airbyte is) Airbyte version **0.27.0-alpha or above** on Kubernetes : - -1. In a terminal, on the host where Airbyte is running, turn off Airbyte. - - ```bash - kubectl delete deployments airbyte-db airbyte-worker airbyte-server airbyte-temporal airbyte-webapp --namespace= - ``` - -2. Upgrade the kube deployment to new version. - - i. If you are running Airbyte from a cloned version of the Airbyte GitHub repo and want to use the current most recent stable version, just `git pull`. - -3. Bring Airbyte back online. - - ```bash - kubectl apply -k kube/overlays/stable - ``` - - After 2-5 minutes, `kubectl get pods | grep airbyte` should show `Running` as the status for all the core Airbyte pods. This may take longer on Kubernetes clusters with slow internet connections. - - Run `kubectl port-forward svc/airbyte-webapp-svc 8000:80` to allow access to the UI/API. - -## Upgrading on K8s (0.26.4-alpha and below) - -If you are upgrading from (i.e. your current version of Airbyte is) Airbyte version **before 0.27.0-alpha** on Kubernetes we **do not** support automatic migration. Please follow the following steps to upgrade your Airbyte Kubernetes deployment. - -1. Switching over to your browser, navigate to the Admin page in the UI. Then go to the Configuration Tab. Click Export. This will download a compressed back-up archive \(gzipped tarball\) of all of your Airbyte configuration data and sync history locally. - - _Note: Any secrets that you have entered into Airbyte will be in this archive, so you should treat it as a secret._ - -2. Back to the terminal, migrate the local archive to the new version using the Migration App (packaged in a docker container). +The instructions below are for users using custom deployment and have a `values.yaml`. If you're not using a `values.yaml` to deploy Airbyte using Helm can jump directly to step `4.`. +1. Access [Airbyte ArtifactHub](https://artifacthub.io/packages/helm/airbyte/airbyte) and select the version you want to upgrade. +2. You can click in `Default Values` and compare the value file between the new version and version you're running. You can run `helm list -n ` to check the CHART version you're using. +3. Update your `values.yaml` file if necessary. +4. Upgrade the Helm app running: ```bash - docker run --rm -v :/config airbyte/migration: --\ - --input /config/airbyte_archive.tar.gz\ - --output \ - [ --target-version ] + helm upgrade --install airbyte/airbyte --values --version ``` - Here's an example of what it might look like with the values filled in. It assumes that the downloaded `airbyte_archive.tar.gz` is in `/tmp`. - + After 2-5 minutes, Helm will print a message showing how to port-forward Airbyte. This may take longer on Kubernetes clusters with slow internet connections. In general the message is the following: ```bash - docker run --rm -v /tmp:/config airbyte/migration:0.50.50 --\ - --input /config/airbyte_archive.tar.gz\ - --output /config/airbyte_archive_migrated.tar.gz - ``` - -3. Turn off Airbyte fully and **(see warning)** delete the existing Airbyte Kubernetes volumes. - - _WARNING: Make sure you have already exported your data \(step 1\). This command is going to delete your data in Kubernetes, you may lose your airbyte configurations!_ - - This is where all airbyte configurations are saved. Those configuration files need to be upgraded and restored with the proper version in the following steps. - - ```bash - # Careful, this is deleting data! - kubectl delete -k kube/overlays/stable - ``` - -4. Follow **Step 2** in the `Upgrading on Docker` section to check out the most recent version of Airbyte. Although it is possible to migrate by changing the `.env` file in the kube overlay directory, this is not recommended as it does not capture any changes to the Kubernetes manifests. -5. Bring Airbyte back up. - - ```bash - kubectl apply -k kube/overlays/stable - ``` - -6. Switching over to your browser, navigate to the Admin page in the UI. Then go to the Configuration Tab and click on Import. Upload your migrated archive. - -If you prefer to import and export your data via API instead the UI, follow these instructions: - -1. Instead of Step 3 above use the following curl command to export the archive: - - ```bash - curl -H "Content-Type: application/json" -X POST localhost:8000/api/v1/deployment/export --output /tmp/airbyte_archive.tar.gz - ``` - -2. Instead of Step X above user the following curl command to import the migrated archive: - - ```bash - curl -H "Content-Type: application/x-gzip" -X POST localhost:8000/api/v1/deployment/import --data-binary @ - ``` - -Here is an example of what this request might look like assuming that the migrated archive is called `airbyte_archive_migrated.tar.gz` and is in the `/tmp` directory. - -```bash -curl -H "Content-Type: application/x-gzip" -X POST localhost:8000/api/v1/deployment/import --data-binary @/tmp/airbyte_archive_migrated.tar.gz -``` + export POD_NAME=$(kubectl get pods -l "app.kubernetes.io/name=webapp" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl port-forward $POD_NAME 8080:$CONTAINER_PORT + ``` From 6bbaa324586150a5cec2f1564cfa6ab1ccb5c0ed Mon Sep 17 00:00:00 2001 From: Edward Gao Date: Fri, 16 Feb 2024 13:36:06 -0800 Subject: [PATCH 18/43] Destination redshift: delete some unused files (#35314) --- airbyte-cdk/java/airbyte-cdk/README.md | 1 + .../src/main/resources/version.properties | 2 +- .../jdbc/copy/s3/S3StreamCopier.java | 241 --------------- .../jdbc/copy/s3/S3StreamCopierFactory.java | 53 ---- .../jdbc/copy/s3/S3StreamCopierTest.java | 290 ------------------ .../copiers/RedshiftStreamCopier.java | 171 ----------- .../copiers/RedshiftStreamCopierFactory.java | 33 -- .../copiers/RedshiftStreamCopierTest.java | 161 ---------- 8 files changed, 2 insertions(+), 950 deletions(-) delete mode 100644 airbyte-cdk/java/airbyte-cdk/s3-destinations/src/main/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopier.java delete mode 100644 airbyte-cdk/java/airbyte-cdk/s3-destinations/src/main/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopierFactory.java delete mode 100644 airbyte-cdk/java/airbyte-cdk/s3-destinations/src/test/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopierTest.java delete mode 100644 airbyte-integrations/connectors/destination-redshift/src/main/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopier.java delete mode 100644 airbyte-integrations/connectors/destination-redshift/src/main/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopierFactory.java delete mode 100644 airbyte-integrations/connectors/destination-redshift/src/test/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopierTest.java diff --git a/airbyte-cdk/java/airbyte-cdk/README.md b/airbyte-cdk/java/airbyte-cdk/README.md index d982ff531bd3..e4e8a8f01c44 100644 --- a/airbyte-cdk/java/airbyte-cdk/README.md +++ b/airbyte-cdk/java/airbyte-cdk/README.md @@ -166,6 +166,7 @@ MavenLocal debugging steps: | Version | Date | Pull Request | Subject | |:--------|:-----------|:-----------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0.21.0 | 2024-02-16 | [\#35314](https://github.com/airbytehq/airbyte/pull/35314) | Delete S3StreamCopier classes. These have been superseded by the async destinations framework. | | 0.20.9 | 2024-02-15 | [\#35240](https://github.com/airbytehq/airbyte/pull/35240) | Make state emission to platform inside state manager itself. | | 0.20.8 | 2024-02-15 | [\#35285](https://github.com/airbytehq/airbyte/pull/35285) | Improve blobstore module structure. | | 0.20.7 | 2024-02-13 | [\#35236](https://github.com/airbytehq/airbyte/pull/35236) | output logs to files in addition to stdout when running tests | diff --git a/airbyte-cdk/java/airbyte-cdk/core/src/main/resources/version.properties b/airbyte-cdk/java/airbyte-cdk/core/src/main/resources/version.properties index 55d88e2da2a2..9af4b1f631da 100644 --- a/airbyte-cdk/java/airbyte-cdk/core/src/main/resources/version.properties +++ b/airbyte-cdk/java/airbyte-cdk/core/src/main/resources/version.properties @@ -1 +1 @@ -version=0.20.9 \ No newline at end of file +version=0.21.0 diff --git a/airbyte-cdk/java/airbyte-cdk/s3-destinations/src/main/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopier.java b/airbyte-cdk/java/airbyte-cdk/s3-destinations/src/main/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopier.java deleted file mode 100644 index bdf669194a91..000000000000 --- a/airbyte-cdk/java/airbyte-cdk/s3-destinations/src/main/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopier.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (c) 2023 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.cdk.integrations.destination.jdbc.copy.s3; - -import com.amazonaws.services.s3.AmazonS3; -import com.google.common.annotations.VisibleForTesting; -import io.airbyte.cdk.db.jdbc.JdbcDatabase; -import io.airbyte.cdk.integrations.destination.StandardNameTransformer; -import io.airbyte.cdk.integrations.destination.jdbc.SqlOperations; -import io.airbyte.cdk.integrations.destination.jdbc.copy.StreamCopier; -import io.airbyte.cdk.integrations.destination.s3.S3DestinationConfig; -import io.airbyte.cdk.integrations.destination.s3.S3FormatConfig; -import io.airbyte.cdk.integrations.destination.s3.csv.S3CsvFormatConfig; -import io.airbyte.cdk.integrations.destination.s3.csv.S3CsvWriter; -import io.airbyte.cdk.integrations.destination.s3.csv.StagingDatabaseCsvSheetGenerator; -import io.airbyte.cdk.integrations.destination.s3.util.CompressionType; -import io.airbyte.cdk.integrations.destination.s3.writer.DestinationFileWriter; -import io.airbyte.protocol.models.v0.AirbyteRecordMessage; -import io.airbyte.protocol.models.v0.ConfiguredAirbyteStream; -import io.airbyte.protocol.models.v0.DestinationSyncMode; -import java.io.IOException; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import org.apache.commons.csv.CSVFormat; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public abstract class S3StreamCopier implements StreamCopier { - - private static final Logger LOGGER = LoggerFactory.getLogger(S3StreamCopier.class); - - private static final int DEFAULT_UPLOAD_THREADS = 10; // The S3 cli uses 10 threads by default. - private static final int DEFAULT_QUEUE_CAPACITY = DEFAULT_UPLOAD_THREADS; - - protected final AmazonS3 s3Client; - protected final S3DestinationConfig s3Config; - protected final String tmpTableName; - protected final String schemaName; - protected final String streamName; - protected final JdbcDatabase db; - protected final ConfiguredAirbyteStream configuredAirbyteStream; - protected final String stagingFolder; - protected final Map stagingWritersByFile = new HashMap<>(); - private final DestinationSyncMode destSyncMode; - private final StandardNameTransformer nameTransformer; - private final SqlOperations sqlOperations; - private final Timestamp uploadTime; - protected final Set activeStagingWriterFileNames = new HashSet<>(); - protected final Set stagingFileNames = new LinkedHashSet<>(); - private final boolean purgeStagingData; - - // The number of batches of records that will be inserted into each file. - private final int maxPartsPerFile; - // The number of batches inserted into the current file. - private int partsAddedToCurrentFile; - private String currentFile; - - public S3StreamCopier(final String stagingFolder, - final String schema, - final AmazonS3 client, - final JdbcDatabase db, - final S3CopyConfig config, - final StandardNameTransformer nameTransformer, - final SqlOperations sqlOperations, - final ConfiguredAirbyteStream configuredAirbyteStream, - final Timestamp uploadTime, - final int maxPartsPerFile) { - this.destSyncMode = configuredAirbyteStream.getDestinationSyncMode(); - this.schemaName = schema; - this.streamName = configuredAirbyteStream.getStream().getName(); - this.stagingFolder = stagingFolder; - this.db = db; - this.nameTransformer = nameTransformer; - this.sqlOperations = sqlOperations; - this.configuredAirbyteStream = configuredAirbyteStream; - this.uploadTime = uploadTime; - this.tmpTableName = nameTransformer.getTmpTableName(this.streamName); - this.s3Client = client; - this.s3Config = config.s3Config(); - this.purgeStagingData = config.purgeStagingData(); - - this.maxPartsPerFile = maxPartsPerFile; - this.partsAddedToCurrentFile = 0; - } - - @Override - public String prepareStagingFile() { - if (partsAddedToCurrentFile == 0) { - - try { - // The Flattening value is actually ignored, because we pass an explicit CsvSheetGenerator. So just - // pass in null. - final S3FormatConfig csvFormatConfig = new S3CsvFormatConfig(null, CompressionType.NO_COMPRESSION); - final S3DestinationConfig writerS3Config = S3DestinationConfig.create(s3Config).withFormatConfig(csvFormatConfig).get(); - final S3CsvWriter writer = new S3CsvWriter.Builder( - writerS3Config, - s3Client, - configuredAirbyteStream, - uploadTime) - .uploadThreads(DEFAULT_UPLOAD_THREADS) - .queueCapacity(DEFAULT_QUEUE_CAPACITY) - .csvSettings(CSVFormat.DEFAULT) - .withHeader(false) - .csvSheetGenerator(new StagingDatabaseCsvSheetGenerator()) - .build(); - currentFile = writer.getOutputPath(); - stagingWritersByFile.put(currentFile, writer); - activeStagingWriterFileNames.add(currentFile); - stagingFileNames.add(currentFile); - } catch (final IOException e) { - throw new RuntimeException(e); - } - } - partsAddedToCurrentFile = (partsAddedToCurrentFile + 1) % maxPartsPerFile; - return currentFile; - } - - @Override - public void write(final UUID id, final AirbyteRecordMessage recordMessage, final String filename) throws Exception { - if (stagingWritersByFile.containsKey(filename)) { - stagingWritersByFile.get(filename).write(id, recordMessage); - } - } - - @Override - public void closeNonCurrentStagingFileWriters() throws Exception { - final Set removedKeys = new HashSet<>(); - for (final String key : activeStagingWriterFileNames) { - if (!key.equals(currentFile)) { - stagingWritersByFile.get(key).close(false); - stagingWritersByFile.remove(key); - removedKeys.add(key); - } - } - activeStagingWriterFileNames.removeAll(removedKeys); - } - - @Override - public void closeStagingUploader(final boolean hasFailed) throws Exception { - for (final DestinationFileWriter writer : stagingWritersByFile.values()) { - writer.close(hasFailed); - } - } - - @Override - public void createDestinationSchema() throws Exception { - LOGGER.info("Creating schema in destination if it doesn't exist: {}", schemaName); - sqlOperations.createSchemaIfNotExists(db, schemaName); - } - - @Override - public void createTemporaryTable() throws Exception { - LOGGER.info("Preparing tmp table in destination for stream: {}, schema: {}, tmp table name: {}.", streamName, schemaName, tmpTableName); - sqlOperations.createTableIfNotExists(db, schemaName, tmpTableName); - } - - @Override - public void copyStagingFileToTemporaryTable() throws Exception { - LOGGER.info("Starting copy to tmp table: {} in destination for stream: {}, schema: {}, .", tmpTableName, streamName, schemaName); - for (final String fileName : stagingFileNames) { - copyS3CsvFileIntoTable(db, getFullS3Path(s3Config.getBucketName(), fileName), schemaName, tmpTableName, s3Config); - } - LOGGER.info("Copy to tmp table {} in destination for stream {} complete.", tmpTableName, streamName); - } - - @Override - public String createDestinationTable() throws Exception { - final var destTableName = nameTransformer.getRawTableName(streamName); - LOGGER.info("Preparing table {} in destination.", destTableName); - sqlOperations.createTableIfNotExists(db, schemaName, destTableName); - LOGGER.info("Table {} in destination prepared.", tmpTableName); - - return destTableName; - } - - @Override - public String generateMergeStatement(final String destTableName) { - LOGGER.info("Preparing to merge tmp table {} to dest table: {}, schema: {}, in destination.", tmpTableName, destTableName, schemaName); - final var queries = new StringBuilder(); - if (destSyncMode.equals(DestinationSyncMode.OVERWRITE)) { - queries.append(sqlOperations.truncateTableQuery(db, schemaName, destTableName)); - LOGGER.info("Destination OVERWRITE mode detected. Dest table: {}, schema: {}, truncated.", destTableName, schemaName); - } - queries.append(sqlOperations.insertTableQuery(db, schemaName, tmpTableName, destTableName)); - return queries.toString(); - } - - @Override - public void removeFileAndDropTmpTable() throws Exception { - if (purgeStagingData) { - for (final String fileName : stagingFileNames) { - s3Client.deleteObject(s3Config.getBucketName(), fileName); - LOGGER.info("S3 staging file {} cleaned.", fileName); - } - } - - LOGGER.info("Begin cleaning {} tmp table in destination.", tmpTableName); - sqlOperations.dropTableIfExists(db, schemaName, tmpTableName); - LOGGER.info("{} tmp table in destination cleaned.", tmpTableName); - } - - @Override - public String getCurrentFile() { - return currentFile; - } - - protected static String getFullS3Path(final String s3BucketName, final String s3StagingFile) { - return String.join("/", "s3:/", s3BucketName, s3StagingFile); - } - - @VisibleForTesting - public String getTmpTableName() { - return tmpTableName; - } - - @VisibleForTesting - public Map getStagingWritersByFile() { - return stagingWritersByFile; - } - - @VisibleForTesting - public Set getStagingFiles() { - return stagingFileNames; - } - - public abstract void copyS3CsvFileIntoTable(JdbcDatabase database, - String s3FileLocation, - String schema, - String tableName, - S3DestinationConfig s3Config) - throws SQLException; - -} diff --git a/airbyte-cdk/java/airbyte-cdk/s3-destinations/src/main/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopierFactory.java b/airbyte-cdk/java/airbyte-cdk/s3-destinations/src/main/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopierFactory.java deleted file mode 100644 index b9b94c72c329..000000000000 --- a/airbyte-cdk/java/airbyte-cdk/s3-destinations/src/main/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopierFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2023 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.cdk.integrations.destination.jdbc.copy.s3; - -import com.amazonaws.services.s3.AmazonS3; -import io.airbyte.cdk.db.jdbc.JdbcDatabase; -import io.airbyte.cdk.integrations.destination.StandardNameTransformer; -import io.airbyte.cdk.integrations.destination.jdbc.SqlOperations; -import io.airbyte.cdk.integrations.destination.jdbc.copy.StreamCopier; -import io.airbyte.cdk.integrations.destination.jdbc.copy.StreamCopierFactory; -import io.airbyte.protocol.models.v0.AirbyteStream; -import io.airbyte.protocol.models.v0.ConfiguredAirbyteStream; - -public abstract class S3StreamCopierFactory implements StreamCopierFactory { - - /** - * Used by the copy consumer. - */ - @Override - public StreamCopier create(final String configuredSchema, - final S3CopyConfig config, - final String stagingFolder, - final ConfiguredAirbyteStream configuredStream, - final StandardNameTransformer nameTransformer, - final JdbcDatabase db, - final SqlOperations sqlOperations) { - try { - final AirbyteStream stream = configuredStream.getStream(); - final String schema = StreamCopierFactory.getSchema(stream.getNamespace(), configuredSchema, nameTransformer); - final AmazonS3 s3Client = config.s3Config().getS3Client(); - - return create(stagingFolder, schema, s3Client, db, config, nameTransformer, sqlOperations, configuredStream); - } catch (final Exception e) { - throw new RuntimeException(e); - } - } - - /** - * For specific copier suppliers to implement. - */ - protected abstract StreamCopier create(String stagingFolder, - String schema, - AmazonS3 s3Client, - JdbcDatabase db, - S3CopyConfig config, - StandardNameTransformer nameTransformer, - SqlOperations sqlOperations, - ConfiguredAirbyteStream configuredStream) - throws Exception; - -} diff --git a/airbyte-cdk/java/airbyte-cdk/s3-destinations/src/test/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopierTest.java b/airbyte-cdk/java/airbyte-cdk/s3-destinations/src/test/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopierTest.java deleted file mode 100644 index 770643e875e4..000000000000 --- a/airbyte-cdk/java/airbyte-cdk/s3-destinations/src/test/java/io/airbyte/cdk/integrations/destination/jdbc/copy/s3/S3StreamCopierTest.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (c) 2023 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.cdk.integrations.destination.jdbc.copy.s3; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockConstruction; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import com.amazonaws.services.s3.AmazonS3Client; -import com.google.common.collect.Lists; -import io.airbyte.cdk.db.jdbc.JdbcDatabase; -import io.airbyte.cdk.integrations.base.DestinationConfig; -import io.airbyte.cdk.integrations.destination.StandardNameTransformer; -import io.airbyte.cdk.integrations.destination.jdbc.SqlOperations; -import io.airbyte.cdk.integrations.destination.s3.S3DestinationConfig; -import io.airbyte.cdk.integrations.destination.s3.csv.CsvSheetGenerator; -import io.airbyte.cdk.integrations.destination.s3.csv.S3CsvFormatConfig; -import io.airbyte.cdk.integrations.destination.s3.csv.S3CsvWriter; -import io.airbyte.cdk.integrations.destination.s3.csv.StagingDatabaseCsvSheetGenerator; -import io.airbyte.cdk.integrations.destination.s3.util.CompressionType; -import io.airbyte.commons.json.Jsons; -import io.airbyte.protocol.models.v0.AirbyteStream; -import io.airbyte.protocol.models.v0.ConfiguredAirbyteStream; -import io.airbyte.protocol.models.v0.DestinationSyncMode; -import io.airbyte.protocol.models.v0.SyncMode; -import java.sql.Timestamp; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import org.apache.commons.csv.CSVFormat; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.MockedConstruction; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class S3StreamCopierTest { - - private static final Logger LOGGER = LoggerFactory.getLogger(S3StreamCopierTest.class); - - private static final S3DestinationConfig S3_CONFIG = S3DestinationConfig.create( - "fake-bucket", - "fake-bucketPath", - "fake-region") - .withEndpoint("fake-endpoint") - .withAccessKeyCredential("fake-access-key-id", "fake-secret-access-key") - .get(); - private static final ConfiguredAirbyteStream CONFIGURED_STREAM = new ConfiguredAirbyteStream() - .withDestinationSyncMode(DestinationSyncMode.APPEND) - .withStream(new AirbyteStream() - .withName("fake-stream") - .withNamespace("fake-namespace") - .withSupportedSyncModes(Lists.newArrayList(SyncMode.FULL_REFRESH))); - private static final int UPLOAD_THREADS = 10; - private static final int QUEUE_CAPACITY = 10; - // equivalent to Thu, 09 Dec 2021 19:17:54 GMT - private static final Timestamp UPLOAD_TIME = Timestamp.from(Instant.ofEpochMilli(1639077474000L)); - private static final int MAX_PARTS_PER_FILE = 42; - - private AmazonS3Client s3Client; - private JdbcDatabase db; - private SqlOperations sqlOperations; - private S3StreamCopier copier; - - private MockedConstruction csvWriterMockedConstruction; - private List csvWriterConstructorArguments; - - private List copyArguments; - - private record S3CsvWriterArguments(S3DestinationConfig config, - ConfiguredAirbyteStream stream, - Timestamp uploadTime, - int uploadThreads, - int queueCapacity, - boolean writeHeader, - CSVFormat csvSettings, - CsvSheetGenerator csvSheetGenerator) { - - } - - private record CopyArguments(JdbcDatabase database, - String s3FileLocation, - String schema, - String tableName, - S3DestinationConfig s3Config) { - - } - - @BeforeEach - public void setup() { - DestinationConfig.initialize(Jsons.emptyObject()); - - s3Client = mock(AmazonS3Client.class); - db = mock(JdbcDatabase.class); - sqlOperations = mock(SqlOperations.class); - - csvWriterConstructorArguments = new ArrayList<>(); - copyArguments = new ArrayList<>(); - - // This is basically RETURNS_SELF, except with getMultiPartOutputStreams configured correctly. - // Other non-void methods (e.g. toString()) will return null. - csvWriterMockedConstruction = mockConstruction( - S3CsvWriter.class, - (mock, context) -> { - // Normally, the S3CsvWriter would return a path that ends in a UUID, but this mock will generate an - // int ID to make our asserts easier. - doReturn(String.format("fakeOutputPath-%05d", csvWriterConstructorArguments.size())).when(mock).getOutputPath(); - - // Mockito doesn't seem to provide an easy way to actually retrieve these arguments later on, so - // manually store them on construction. - // _PowerMockito_ does, but I didn't want to set up that additional dependency. - final List arguments = context.arguments(); - csvWriterConstructorArguments.add(new S3CsvWriterArguments( - (S3DestinationConfig) arguments.get(0), - (ConfiguredAirbyteStream) arguments.get(2), - (Timestamp) arguments.get(3), - (int) arguments.get(4), - (int) arguments.get(5), - (boolean) arguments.get(6), - (CSVFormat) arguments.get(7), - (CsvSheetGenerator) arguments.get(8))); - }); - - copier = new S3StreamCopier( - // In reality, this is normally a UUID - see CopyConsumerFactory#createWriteConfigs - "fake-staging-folder", - "fake-schema", - s3Client, - db, - new S3CopyConfig(true, S3_CONFIG), - new StandardNameTransformer(), - sqlOperations, - CONFIGURED_STREAM, - UPLOAD_TIME, - MAX_PARTS_PER_FILE) { - - @Override - public void copyS3CsvFileIntoTable( - final JdbcDatabase database, - final String s3FileLocation, - final String schema, - final String tableName, - final S3DestinationConfig s3Config) { - copyArguments.add(new CopyArguments(database, s3FileLocation, schema, tableName, s3Config)); - } - - }; - } - - @AfterEach - public void teardown() { - csvWriterMockedConstruction.close(); - } - - @Test - public void createSequentialStagingFiles_when_multipleFilesRequested() { - // When we call prepareStagingFile() the first time, it should create exactly one S3CsvWriter. The - // next (MAX_PARTS_PER_FILE - 1) invocations - // should reuse that same writer. - for (var i = 0; i < MAX_PARTS_PER_FILE; i++) { - final String file = copier.prepareStagingFile(); - assertEquals("fakeOutputPath-00000", file, "preparing file number " + i); - assertEquals(1, csvWriterMockedConstruction.constructed().size()); - checkCsvWriterArgs(csvWriterConstructorArguments.get(0)); - } - - // Now that we've hit the MAX_PARTS_PER_FILE, we should start a new writer - final String secondFile = copier.prepareStagingFile(); - assertEquals("fakeOutputPath-00001", secondFile); - final List secondManagers = csvWriterMockedConstruction.constructed(); - assertEquals(2, secondManagers.size()); - checkCsvWriterArgs(csvWriterConstructorArguments.get(1)); - } - - private void checkCsvWriterArgs(final S3CsvWriterArguments args) { - final S3DestinationConfig s3Config = S3DestinationConfig.create(S3_CONFIG) - .withFormatConfig(new S3CsvFormatConfig(null, CompressionType.NO_COMPRESSION)) - .get(); - assertEquals(s3Config, args.config); - assertEquals(CONFIGURED_STREAM, args.stream); - assertEquals(UPLOAD_TIME, args.uploadTime); - assertEquals(UPLOAD_THREADS, args.uploadThreads); - assertEquals(QUEUE_CAPACITY, args.queueCapacity); - assertFalse(args.writeHeader); - assertEquals(CSVFormat.DEFAULT, args.csvSettings); - assertTrue( - args.csvSheetGenerator instanceof StagingDatabaseCsvSheetGenerator, - "Sheet generator was actually a " + args.csvSheetGenerator.getClass()); - } - - @Test - public void closesS3Upload_when_stagingUploaderClosedSuccessfully() throws Exception { - copier.prepareStagingFile(); - - copier.closeStagingUploader(false); - - final List managers = csvWriterMockedConstruction.constructed(); - final S3CsvWriter manager = managers.get(0); - verify(manager).close(false); - } - - @Test - public void closesS3Upload_when_stagingUploaderClosedFailingly() throws Exception { - copier.prepareStagingFile(); - - copier.closeStagingUploader(true); - - final List managers = csvWriterMockedConstruction.constructed(); - final S3CsvWriter manager = managers.get(0); - verify(manager).close(true); - } - - @Test - public void deletesStagingFiles() throws Exception { - copier.prepareStagingFile(); - doReturn(true).when(s3Client).doesObjectExist("fake-bucket", "fakeOutputPath-00000"); - - copier.removeFileAndDropTmpTable(); - - verify(s3Client).deleteObject("fake-bucket", "fakeOutputPath-00000"); - } - - @Test - public void doesNotDeleteStagingFiles_if_purgeStagingDataDisabled() throws Exception { - copier = new S3StreamCopier( - "fake-staging-folder", - "fake-schema", - s3Client, - db, - // Explicitly disable purgeStagingData - new S3CopyConfig(false, S3_CONFIG), - new StandardNameTransformer(), - sqlOperations, - CONFIGURED_STREAM, - UPLOAD_TIME, - MAX_PARTS_PER_FILE) { - - @Override - public void copyS3CsvFileIntoTable( - final JdbcDatabase database, - final String s3FileLocation, - final String schema, - final String tableName, - final S3DestinationConfig s3Config) { - copyArguments.add(new CopyArguments(database, s3FileLocation, schema, tableName, s3Config)); - } - - }; - - copier.prepareStagingFile(); - doReturn(true).when(s3Client).doesObjectExist("fake-bucket", "fakeOutputPath-00000"); - - copier.removeFileAndDropTmpTable(); - - verify(s3Client, never()).deleteObject("fake-bucket", "fakeOutputPath-00000"); - } - - @Test - public void copiesCorrectFilesToTable() throws Exception { - // Generate two files - for (int i = 0; i < MAX_PARTS_PER_FILE + 1; i++) { - copier.prepareStagingFile(); - } - - copier.copyStagingFileToTemporaryTable(); - - assertEquals(2, copyArguments.size(), "Number of invocations was actually " + copyArguments.size() + ". Arguments were " + copyArguments); - - // S3StreamCopier operates on these from a HashMap, so need to sort them in order to assert in a - // sane way. - final List sortedArgs = copyArguments.stream().sorted(Comparator.comparing(arg -> arg.s3FileLocation)).toList(); - for (int i = 0; i < sortedArgs.size(); i++) { - LOGGER.info("Checking arguments for index {}", i); - final CopyArguments args = sortedArgs.get(i); - assertEquals(String.format("s3://fake-bucket/fakeOutputPath-%05d", i), args.s3FileLocation); - assertEquals("fake-schema", args.schema); - assertTrue(args.tableName.endsWith("fake_stream"), "Table name was actually " + args.tableName); - } - } - -} diff --git a/airbyte-integrations/connectors/destination-redshift/src/main/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopier.java b/airbyte-integrations/connectors/destination-redshift/src/main/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopier.java deleted file mode 100644 index 3a8f801c4689..000000000000 --- a/airbyte-integrations/connectors/destination-redshift/src/main/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopier.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2023 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.destination.redshift.copiers; - -import com.amazonaws.services.s3.AmazonS3; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.annotations.VisibleForTesting; -import io.airbyte.cdk.db.jdbc.JdbcDatabase; -import io.airbyte.cdk.integrations.destination.StandardNameTransformer; -import io.airbyte.cdk.integrations.destination.jdbc.SqlOperations; -import io.airbyte.cdk.integrations.destination.jdbc.copy.s3.S3CopyConfig; -import io.airbyte.cdk.integrations.destination.jdbc.copy.s3.S3StreamCopier; -import io.airbyte.cdk.integrations.destination.s3.S3DestinationConfig; -import io.airbyte.cdk.integrations.destination.s3.credential.S3AccessKeyCredentialConfig; -import io.airbyte.commons.lang.Exceptions; -import io.airbyte.integrations.destination.redshift.manifest.Entry; -import io.airbyte.integrations.destination.redshift.manifest.Manifest; -import io.airbyte.protocol.models.v0.ConfiguredAirbyteStream; -import java.sql.Timestamp; -import java.time.Instant; -import java.util.Optional; -import java.util.UUID; -import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RedshiftStreamCopier extends S3StreamCopier { - - private static final Logger LOGGER = LoggerFactory.getLogger(RedshiftStreamCopier.class); - // From https://docs.aws.amazon.com/redshift/latest/dg/t_loading-tables-from-s3.html - // "Split your load data files so that the files are about equal size, between 1 MB and 1 GB after - // compression" - public static final int MAX_PARTS_PER_FILE = 4; - - private final ObjectMapper objectMapper; - private String manifestFilePath = null; - - public RedshiftStreamCopier(final String stagingFolder, - final String schema, - final AmazonS3 client, - final JdbcDatabase db, - final S3CopyConfig config, - final StandardNameTransformer nameTransformer, - final SqlOperations sqlOperations, - final ConfiguredAirbyteStream configuredAirbyteStream) { - this( - stagingFolder, - schema, - client, - db, - config, - nameTransformer, - sqlOperations, - Timestamp.from(Instant.now()), - configuredAirbyteStream); - } - - @VisibleForTesting - RedshiftStreamCopier(final String stagingFolder, - final String schema, - final AmazonS3 client, - final JdbcDatabase db, - final S3CopyConfig config, - final StandardNameTransformer nameTransformer, - final SqlOperations sqlOperations, - final Timestamp uploadTime, - final ConfiguredAirbyteStream configuredAirbyteStream) { - super(stagingFolder, - schema, - client, - db, - config, - nameTransformer, - sqlOperations, - configuredAirbyteStream, - uploadTime, - MAX_PARTS_PER_FILE); - objectMapper = new ObjectMapper(); - } - - @Override - public void copyStagingFileToTemporaryTable() { - final var possibleManifest = Optional.ofNullable(createManifest()); - LOGGER.info("Starting copy to tmp table: {} in destination for stream: {}, schema: {}, .", tmpTableName, streamName, schemaName); - possibleManifest.stream() - .map(this::putManifest) - .forEach(this::executeCopy); - LOGGER.info("Copy to tmp table {} in destination for stream {} complete.", tmpTableName, streamName); - } - - @Override - public void copyS3CsvFileIntoTable(final JdbcDatabase database, - final String s3FileLocation, - final String schema, - final String tableName, - final S3DestinationConfig s3Config) { - throw new RuntimeException("Redshift Stream Copier should not copy individual files without use of a manifest"); - } - - @Override - public void removeFileAndDropTmpTable() throws Exception { - super.removeFileAndDropTmpTable(); - if (manifestFilePath != null) { - LOGGER.info("Begin cleaning s3 manifest file {}.", manifestFilePath); - if (s3Client.doesObjectExist(s3Config.getBucketName(), manifestFilePath)) { - s3Client.deleteObject(s3Config.getBucketName(), manifestFilePath); - } - LOGGER.info("S3 manifest file {} cleaned.", manifestFilePath); - } - } - - /** - * Creates the contents of a manifest file given the `s3StagingFiles`. There must be at least one - * entry in a manifest file otherwise it is not considered valid for the COPY command. - * - * @return null if no stagingFiles exist otherwise the manifest body String - */ - private String createManifest() { - if (getStagingFiles().isEmpty()) { - return null; - } - - final var s3FileEntries = getStagingFiles().stream() - .map(filePath -> new Entry(getFullS3Path(s3Config.getBucketName(), filePath))) - .collect(Collectors.toList()); - final var manifest = new Manifest(s3FileEntries); - - return Exceptions.toRuntime(() -> objectMapper.writeValueAsString(manifest)); - } - - /** - * Upload the supplied manifest file to S3 - * - * @param manifestContents the manifest contents, never null - * @return the path where the manifest file was placed in S3 - */ - private String putManifest(final String manifestContents) { - manifestFilePath = - String.join("/", s3Config.getBucketPath(), stagingFolder, schemaName, String.format("%s.manifest", UUID.randomUUID())); - - s3Client.putObject(s3Config.getBucketName(), manifestFilePath, manifestContents); - - return manifestFilePath; - } - - /** - * Run Redshift COPY command with the given manifest file - * - * @param manifestPath the path in S3 to the manifest file - */ - private void executeCopy(final String manifestPath) { - final S3AccessKeyCredentialConfig credentialConfig = (S3AccessKeyCredentialConfig) s3Config.getS3CredentialConfig(); - final var copyQuery = String.format( - "COPY %s.%s FROM '%s'\n" - + "CREDENTIALS 'aws_access_key_id=%s;aws_secret_access_key=%s'\n" - + "CSV REGION '%s' TIMEFORMAT 'auto'\n" - + "STATUPDATE OFF\n" - + "MANIFEST;", - schemaName, - tmpTableName, - getFullS3Path(s3Config.getBucketName(), manifestPath), - credentialConfig.getAccessKeyId(), - credentialConfig.getSecretAccessKey(), - s3Config.getBucketRegion()); - - Exceptions.toRuntime(() -> db.execute(copyQuery)); - } - -} diff --git a/airbyte-integrations/connectors/destination-redshift/src/main/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopierFactory.java b/airbyte-integrations/connectors/destination-redshift/src/main/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopierFactory.java deleted file mode 100644 index 5527002288bc..000000000000 --- a/airbyte-integrations/connectors/destination-redshift/src/main/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopierFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.destination.redshift.copiers; - -import com.amazonaws.services.s3.AmazonS3; -import io.airbyte.cdk.db.jdbc.JdbcDatabase; -import io.airbyte.cdk.integrations.destination.StandardNameTransformer; -import io.airbyte.cdk.integrations.destination.jdbc.SqlOperations; -import io.airbyte.cdk.integrations.destination.jdbc.copy.StreamCopier; -import io.airbyte.cdk.integrations.destination.jdbc.copy.s3.S3CopyConfig; -import io.airbyte.cdk.integrations.destination.jdbc.copy.s3.S3StreamCopierFactory; -import io.airbyte.protocol.models.v0.ConfiguredAirbyteStream; - -/** - * Very similar to the {@link S3StreamCopierFactory}, but we need some additional - */ -public class RedshiftStreamCopierFactory extends S3StreamCopierFactory { - - @Override - public StreamCopier create(final String stagingFolder, - final String schema, - final AmazonS3 s3Client, - final JdbcDatabase db, - final S3CopyConfig config, - final StandardNameTransformer nameTransformer, - final SqlOperations sqlOperations, - final ConfiguredAirbyteStream configuredStream) { - return new RedshiftStreamCopier(stagingFolder, schema, s3Client, db, config, nameTransformer, sqlOperations, configuredStream); - } - -} diff --git a/airbyte-integrations/connectors/destination-redshift/src/test/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopierTest.java b/airbyte-integrations/connectors/destination-redshift/src/test/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopierTest.java deleted file mode 100644 index 5c029abc5e58..000000000000 --- a/airbyte-integrations/connectors/destination-redshift/src/test/java/io/airbyte/integrations/destination/redshift/copiers/RedshiftStreamCopierTest.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2023 Airbyte, Inc., all rights reserved. - */ - -package io.airbyte.integrations.destination.redshift.copiers; - -import static java.util.Comparator.comparing; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import com.amazonaws.services.s3.AmazonS3Client; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.Lists; -import io.airbyte.cdk.db.jdbc.JdbcDatabase; -import io.airbyte.cdk.integrations.base.DestinationConfig; -import io.airbyte.cdk.integrations.destination.StandardNameTransformer; -import io.airbyte.cdk.integrations.destination.jdbc.SqlOperations; -import io.airbyte.cdk.integrations.destination.jdbc.copy.s3.S3CopyConfig; -import io.airbyte.cdk.integrations.destination.s3.S3DestinationConfig; -import io.airbyte.commons.json.Jsons; -import io.airbyte.protocol.models.v0.AirbyteStream; -import io.airbyte.protocol.models.v0.ConfiguredAirbyteStream; -import io.airbyte.protocol.models.v0.DestinationSyncMode; -import io.airbyte.protocol.models.v0.SyncMode; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.time.Instant; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicReference; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class RedshiftStreamCopierTest { - - private static final Logger LOGGER = LoggerFactory.getLogger(RedshiftStreamCopierTest.class); - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - // The full path would be something like - // "fake-namespace/fake_stream/2021_12_09_1639077474000_e549e712-b89c-4272-9496-9690ba7f973e.csv" - // The namespace and stream have their hyphens replaced by underscores. Not super clear that that's - // actually required. - // 2021_12_09_1639077474000 is generated from the timestamp. It's followed by a random UUID, in case - // we need to create multiple files. - private static final String EXPECTED_OBJECT_BEGINNING = "fake-bucketPath/fake_namespace/fake_stream/2021_12_09_1639077474000_"; - private static final String EXPECTED_OBJECT_ENDING = ".csv"; - - // equivalent to Thu, 09 Dec 2021 19:17:54 GMT - private static final Timestamp UPLOAD_TIME = Timestamp.from(Instant.ofEpochMilli(1639077474000L)); - - private AmazonS3Client s3Client; - private JdbcDatabase db; - private SqlOperations sqlOperations; - private RedshiftStreamCopier copier; - - @BeforeEach - public void setup() { - DestinationConfig.initialize(Jsons.emptyObject()); - s3Client = mock(AmazonS3Client.class, RETURNS_DEEP_STUBS); - db = mock(JdbcDatabase.class); - sqlOperations = mock(SqlOperations.class); - - final S3DestinationConfig s3Config = S3DestinationConfig.create( - "fake-bucket", - "fake-bucketPath", - "fake-region") - .withEndpoint("fake-endpoint") - .withAccessKeyCredential("fake-access-key-id", "fake-secret-access-key") - .get(); - - copier = new RedshiftStreamCopier( - // In reality, this is normally a UUID - see CopyConsumerFactory#createWriteConfigs - "fake-staging-folder", - "fake-schema", - s3Client, - db, - new S3CopyConfig(true, s3Config), - new StandardNameTransformer(), - sqlOperations, - UPLOAD_TIME, - new ConfiguredAirbyteStream() - .withDestinationSyncMode(DestinationSyncMode.APPEND) - .withStream(new AirbyteStream() - .withName("fake-stream") - .withSupportedSyncModes(Lists.newArrayList(SyncMode.FULL_REFRESH)) - .withNamespace("fake-namespace"))); - } - - @Test - public void copiesCorrectFilesToTable() throws SQLException { - // Generate two files - final String file1 = copier.prepareStagingFile(); - for (int i = 0; i < RedshiftStreamCopier.MAX_PARTS_PER_FILE - 1; i++) { - copier.prepareStagingFile(); - } - final String file2 = copier.prepareStagingFile(); - final List expectedFiles = List.of(file1, file2).stream().sorted().toList(); - - copier.copyStagingFileToTemporaryTable(); - - final AtomicReference manifestUuid = new AtomicReference<>(); - verify(s3Client).putObject( - eq("fake-bucket"), - argThat(path -> { - final boolean startsCorrectly = path.startsWith("fake-bucketPath/fake-staging-folder/fake-schema/"); - final boolean endsCorrectly = path.endsWith(".manifest"); - // Make sure that we have a valid UUID - manifestUuid.set(path.replaceFirst("^fake-bucketPath/fake-staging-folder/fake-schema/", "").replaceFirst(".manifest$", "")); - UUID.fromString(manifestUuid.get()); - - return startsCorrectly && endsCorrectly; - }), - (String) argThat(manifestStr -> { - try { - final JsonNode manifest = OBJECT_MAPPER.readTree((String) manifestStr); - final List entries = Lists.newArrayList(manifest.get("entries").elements()).stream() - .sorted(comparing(entry -> entry.get("url").asText())).toList(); - - boolean entriesAreCorrect = true; - for (int i = 0; i < 2; i++) { - final String expectedFilename = expectedFiles.get(i); - final JsonNode manifestEntry = entries.get(i); - entriesAreCorrect &= isManifestEntryCorrect(manifestEntry, expectedFilename); - if (!entriesAreCorrect) { - LOGGER.error("Invalid entry: {}", manifestEntry); - } - } - - return entriesAreCorrect && entries.size() == 2; - } catch (final JsonProcessingException e) { - throw new RuntimeException(e); - } - })); - - verify(db).execute(String.format( - """ - COPY fake-schema.%s FROM 's3://fake-bucket/fake-bucketPath/fake-staging-folder/fake-schema/%s.manifest' - CREDENTIALS 'aws_access_key_id=fake-access-key-id;aws_secret_access_key=fake-secret-access-key' - CSV REGION 'fake-region' TIMEFORMAT 'auto' - STATUPDATE OFF - MANIFEST;""", - copier.getTmpTableName(), - manifestUuid.get())); - } - - private static boolean isManifestEntryCorrect(final JsonNode entry, final String expectedFilename) { - final String url = entry.get("url").asText(); - final boolean mandatory = entry.get("mandatory").asBoolean(); - - return ("s3://fake-bucket/" + expectedFilename).equals(url) && mandatory; - } - -} From 8d924388c129ac17948cbdf583bbb93d45699d12 Mon Sep 17 00:00:00 2001 From: Evan Tahler Date: Fri, 16 Feb 2024 15:09:57 -0800 Subject: [PATCH 19/43] re-add destination-kvdb as archived connector (#35377) --- .../connectors/destination-kvdb/icon.svg | 83 +++++++++++++++++++ .../connectors/destination-kvdb/metadata.yaml | 25 ++++++ docs/integrations/destinations/kvdb.md | 2 +- 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 airbyte-integrations/connectors/destination-kvdb/icon.svg create mode 100644 airbyte-integrations/connectors/destination-kvdb/metadata.yaml diff --git a/airbyte-integrations/connectors/destination-kvdb/icon.svg b/airbyte-integrations/connectors/destination-kvdb/icon.svg new file mode 100644 index 000000000000..249b913e9424 --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/icon.svg @@ -0,0 +1,83 @@ + + + + + diff --git a/airbyte-integrations/connectors/destination-kvdb/metadata.yaml b/airbyte-integrations/connectors/destination-kvdb/metadata.yaml new file mode 100644 index 000000000000..4408eae38888 --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/metadata.yaml @@ -0,0 +1,25 @@ +data: + registries: + cloud: + enabled: false + oss: + enabled: false + connectorSubtype: api + connectorType: destination + definitionId: f2e549cd-8e2a-48f8-822d-cc13630eb42d + dockerImageTag: 0.1.0 + dockerRepository: airbyte/destination-kvdb + githubIssueLabel: destination-kvdb + icon: kvdb.svg + license: MIT + name: KVdb + releaseDate: 2023-07-15 + releaseStage: alpha + documentationUrl: https://docs.airbyte.com/integrations/destinations/kvdb + tags: + - language:python + ab_internal: + sl: 100 + ql: 100 + supportLevel: archived +metadataSpecVersion: "1.0" diff --git a/docs/integrations/destinations/kvdb.md b/docs/integrations/destinations/kvdb.md index 5ca1dfa0526b..1d9a4341e8fc 100644 --- a/docs/integrations/destinations/kvdb.md +++ b/docs/integrations/destinations/kvdb.md @@ -1,4 +1,4 @@ -# KVDB [ARCHIVED] +# KVDB The KVDB destination for Airbyte From 60465814b30360cb1a16042965953166dc7e750e Mon Sep 17 00:00:00 2001 From: Evan Tahler Date: Fri, 16 Feb 2024 15:38:28 -0800 Subject: [PATCH 20/43] destination-kvdb - publish for real (#35379) --- .../connectors/destination-kvdb/.dockerignore | 5 + .../connectors/destination-kvdb/Dockerfile | 38 ++++++ .../connectors/destination-kvdb/README.md | 118 ++++++++++++++++++ .../destination_kvdb/__init__.py | 26 ++++ .../destination_kvdb/client.py | 78 ++++++++++++ .../destination_kvdb/destination.py | 72 +++++++++++ .../destination_kvdb/spec.json | 26 ++++ .../destination_kvdb/writer.py | 46 +++++++ .../connectors/destination-kvdb/main.py | 11 ++ .../destination-kvdb/requirements.txt | 1 + .../connectors/destination-kvdb/setup.py | 26 ++++ .../destination-kvdb/unit_tests/unit_test.py | 7 ++ 12 files changed, 454 insertions(+) create mode 100644 airbyte-integrations/connectors/destination-kvdb/.dockerignore create mode 100644 airbyte-integrations/connectors/destination-kvdb/Dockerfile create mode 100644 airbyte-integrations/connectors/destination-kvdb/README.md create mode 100644 airbyte-integrations/connectors/destination-kvdb/destination_kvdb/__init__.py create mode 100644 airbyte-integrations/connectors/destination-kvdb/destination_kvdb/client.py create mode 100644 airbyte-integrations/connectors/destination-kvdb/destination_kvdb/destination.py create mode 100644 airbyte-integrations/connectors/destination-kvdb/destination_kvdb/spec.json create mode 100644 airbyte-integrations/connectors/destination-kvdb/destination_kvdb/writer.py create mode 100644 airbyte-integrations/connectors/destination-kvdb/main.py create mode 100644 airbyte-integrations/connectors/destination-kvdb/requirements.txt create mode 100644 airbyte-integrations/connectors/destination-kvdb/setup.py create mode 100644 airbyte-integrations/connectors/destination-kvdb/unit_tests/unit_test.py diff --git a/airbyte-integrations/connectors/destination-kvdb/.dockerignore b/airbyte-integrations/connectors/destination-kvdb/.dockerignore new file mode 100644 index 000000000000..1b4b5767b554 --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/.dockerignore @@ -0,0 +1,5 @@ +* +!Dockerfile +!main.py +!destination_kvdb +!setup.py diff --git a/airbyte-integrations/connectors/destination-kvdb/Dockerfile b/airbyte-integrations/connectors/destination-kvdb/Dockerfile new file mode 100644 index 000000000000..b0493da1cfc1 --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/Dockerfile @@ -0,0 +1,38 @@ +FROM python:3.9.11-alpine3.15 as base + +# build and load all requirements +FROM base as builder +WORKDIR /airbyte/integration_code + +# upgrade pip to the latest version +RUN apk --no-cache upgrade \ + && pip install --upgrade pip \ + && apk --no-cache add tzdata build-base + + +COPY setup.py ./ +# install necessary packages to a temporary folder +RUN pip install --prefix=/install . + +# build a clean environment +FROM base +WORKDIR /airbyte/integration_code + +# copy all loaded and built libraries to a pure basic image +COPY --from=builder /install /usr/local +# add default timezone settings +COPY --from=builder /usr/share/zoneinfo/Etc/UTC /etc/localtime +RUN echo "Etc/UTC" > /etc/timezone + +# bash is installed for more convenient debugging. +RUN apk --no-cache add bash + +# copy payload code only +COPY main.py ./ +COPY destination_kvdb ./destination_kvdb + +ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" +ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] + +LABEL io.airbyte.version=0.1.0 +LABEL io.airbyte.name=airbyte/destination-kvdb diff --git a/airbyte-integrations/connectors/destination-kvdb/README.md b/airbyte-integrations/connectors/destination-kvdb/README.md new file mode 100644 index 000000000000..b834894111b6 --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/README.md @@ -0,0 +1,118 @@ +# Kvdb Destination + +This is the repository for the [Kvdb](https://kvdb.io) destination connector, written in Python. It is intended to be an example for how to write a Python destination. KvDB is a very simple key value store, which makes it great for the purposes of illustrating how to write a Python destination connector. + +## Local development + +### Prerequisites +**To iterate on this connector, make sure to complete this prerequisites section.** + +#### Minimum Python version required `= 3.7.0` + +#### Build & Activate Virtual Environment and install dependencies +From this connector directory, create a virtual environment: +``` +python -m venv .venv +``` + +This will generate a virtualenv for this module in `.venv/`. Make sure this venv is active in your +development environment of choice. To activate it from the terminal, run: +``` +source .venv/bin/activate +pip install -r requirements.txt +``` +If you are in an IDE, follow your IDE's instructions to activate the virtualenv. + +Note that while we are installing dependencies from `requirements.txt`, you should only edit `setup.py` for your dependencies. `requirements.txt` is +used for editable installs (`pip install -e`) to pull in Python dependencies from the monorepo and will call `setup.py`. +If this is mumbo jumbo to you, don't worry about it, just put your deps in `setup.py` but install using `pip install -r requirements.txt` and everything +should work as you expect. + +#### Building via Gradle +From the Airbyte repository root, run: +``` +./gradlew :airbyte-integrations:connectors:destination-kvdb:build +``` + +#### Create credentials +**If you are a community contributor**, generate the necessary credentials from [Kvdb](https://kvdb.io/docs/api/), and then create a file `secrets/config.json` conforming to the `destination_kvdb/spec.json` file. +Note that the `secrets` directory is gitignored by default, so there is no danger of accidentally checking in sensitive information. +See `integration_tests/sample_config.json` for a sample config file. + +**If you are an Airbyte core member**, copy the credentials in Lastpass under the secret name `destination kvdb test creds` +and place them into `secrets/config.json`. + +### Locally running the connector +``` +python main.py spec +python main.py check --config secrets/config.json +python main.py discover --config secrets/config.json +python main.py read --config secrets/config.json --catalog integration_tests/configured_catalog.json +``` + +### Locally running the connector docker image + + + +#### Build +**Via [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md) (recommended):** +```bash +airbyte-ci connectors --name=destination-kvdb build +``` + +An image will be built with the tag `airbyte/destination-kvdb:dev`. + +**Via `docker build`:** +```bash +docker build -t airbyte/destination-kvdb:dev . +``` +#### Run +Then run any of the connector commands as follows: +``` +docker run --rm airbyte/destination-kvdb:dev spec +docker run --rm -v $(pwd)/secrets:/secrets airbyte/destination-kvdb:dev check --config /secrets/config.json +# messages.jsonl is a file containing line-separated JSON representing AirbyteMessages +cat messages.jsonl | docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/destination-kvdb:dev write --config /secrets/config.json --catalog /integration_tests/configured_catalog.json +``` +## Testing + Make sure to familiarize yourself with [pytest test discovery](https://docs.pytest.org/en/latest/goodpractices.html#test-discovery) to know how your test files and methods should be named. +First install test dependencies into your virtual environment: +``` +pip install .[tests] +``` +### Unit Tests +To run unit tests locally, from the connector directory run: +``` +python -m pytest unit_tests +``` + +### Integration Tests +There are two types of integration tests: Acceptance Tests (Airbyte's test suite for all destination connectors) and custom integration tests (which are specific to this connector). +#### Custom Integration tests +Place custom tests inside `integration_tests/` folder, then, from the connector root, run +``` +python -m pytest integration_tests +``` +#### Acceptance Tests +You can run our full test suite locally using [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md): +```bash +airbyte-ci connectors --name=destination-kvdb test +``` + + +## Dependency Management +All of your dependencies should go in `setup.py`, NOT `requirements.txt`. The requirements file is only used to connect internal Airbyte dependencies in the monorepo for local development. +We split dependencies between two groups, dependencies that are: +* required for your connector to work need to go to `MAIN_REQUIREMENTS` list. +* required for the testing need to go to `TEST_REQUIREMENTS` list + +### Publishing a new version of the connector +You've checked out the repo, implemented a million dollar feature, and you're ready to share your changes with the world. Now what? +1. Make sure your changes are passing our test suite: `airbyte-ci connectors --name=destination-kvdb test` +2. Bump the connector version in `metadata.yaml`: increment the `dockerImageTag` value. Please follow [semantic versioning for connectors](https://docs.airbyte.com/contributing-to-airbyte/resources/pull-requests-handbook/#semantic-versioning-for-connectors). +3. Make sure the `metadata.yaml` content is up to date. +4. Make the connector documentation and its changelog is up to date (`docs/integrations/destinations/kvdb.md`). +5. Create a Pull Request: use [our PR naming conventions](https://docs.airbyte.com/contributing-to-airbyte/resources/pull-requests-handbook/#pull-request-title-convention). +6. Pat yourself on the back for being an awesome contributor. +7. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master. + diff --git a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/__init__.py b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/__init__.py new file mode 100644 index 000000000000..5f3b041035bf --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/__init__.py @@ -0,0 +1,26 @@ +# MIT License +# +# Copyright (c) 2020 Airbyte +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +from .destination import DestinationKvdb + +__all__ = ["DestinationKvdb"] diff --git a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/client.py b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/client.py new file mode 100644 index 000000000000..74d9f41176f5 --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/client.py @@ -0,0 +1,78 @@ +# +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. +# + +from typing import Any, Iterable, List, Mapping, Tuple, Union + +import requests + + +class KvDbClient: + base_url = "https://kvdb.io" + PAGE_SIZE = 1000 + + def __init__(self, bucket_id: str, secret_key: str = None): + self.secret_key = secret_key + self.bucket_id = bucket_id + + def write(self, key: str, value: Mapping[str, Any]): + return self.batch_write([(key, value)]) + + def batch_write(self, keys_and_values: List[Tuple[str, Mapping[str, Any]]]): + """ + https://kvdb.io/docs/api/#execute-transaction + """ + request_body = {"txn": [{"set": key, "value": value} for key, value in keys_and_values]} + return self._request("POST", json=request_body) + + def list_keys(self, list_values: bool = False, prefix: str = None) -> Iterable[Union[str, List]]: + """ + https://kvdb.io/docs/api/#list-keys + """ + # TODO handle rate limiting + pagination_complete = False + offset = 0 + + while not pagination_complete: + response = self._request( + "GET", + params={ + "limit": self.PAGE_SIZE, + "skip": offset, + "format": "json", + "prefix": prefix or "", + "values": "true" if list_values else "false", + }, + endpoint="/", # the "list" endpoint doesn't work without adding a trailing slash to the URL + ) + + response_json = response.json() + yield from response_json + + pagination_complete = len(response_json) < self.PAGE_SIZE + offset += self.PAGE_SIZE + + def delete(self, key: Union[str, List[str]]): + """ + https://kvdb.io/docs/api/#execute-transaction + """ + key_list = key if isinstance(key, List) else [key] + request_body = {"txn": [{"delete": k} for k in key_list]} + return self._request("POST", json=request_body) + + def _get_base_url(self) -> str: + return f"{self.base_url}/{self.bucket_id}" + + def _get_auth_headers(self) -> Mapping[str, Any]: + return {"Authorization": f"Bearer {self.secret_key}"} if self.secret_key else {} + + def _request( + self, http_method: str, endpoint: str = None, params: Mapping[str, Any] = None, json: Mapping[str, Any] = None + ) -> requests.Response: + url = self._get_base_url() + (endpoint or "") + headers = {"Accept": "application/json", **self._get_auth_headers()} + + response = requests.request(method=http_method, params=params, url=url, headers=headers, json=json) + + response.raise_for_status() + return response diff --git a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/destination.py b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/destination.py new file mode 100644 index 000000000000..33ab8565fae4 --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/destination.py @@ -0,0 +1,72 @@ +# +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. +# + + +import time +import traceback +import uuid +from typing import Any, Iterable, Mapping + +from airbyte_cdk import AirbyteLogger +from airbyte_cdk.destinations import Destination +from airbyte_cdk.models import AirbyteConnectionStatus, AirbyteMessage, ConfiguredAirbyteCatalog, DestinationSyncMode, Status, Type +from destination_kvdb.client import KvDbClient +from destination_kvdb.writer import KvDbWriter + + +class DestinationKvdb(Destination): + def write( + self, config: Mapping[str, Any], configured_catalog: ConfiguredAirbyteCatalog, input_messages: Iterable[AirbyteMessage] + ) -> Iterable[AirbyteMessage]: + + """ + Reads the input stream of messages, config, and catalog to write data to the destination. + + This method returns an iterable (typically a generator of AirbyteMessages via yield) containing state messages received + in the input message stream. Outputting a state message means that every AirbyteRecordMessage which came before it has been + successfully persisted to the destination. This is used to ensure fault tolerance in the case that a sync fails before fully completing, + then the source is given the last state message output from this method as the starting point of the next sync. + """ + writer = KvDbWriter(KvDbClient(**config)) + + for configured_stream in configured_catalog.streams: + if configured_stream.destination_sync_mode == DestinationSyncMode.overwrite: + writer.delete_stream_entries(configured_stream.stream.name) + + for message in input_messages: + if message.type == Type.STATE: + # Emitting a state message indicates that all records which came before it have been written to the destination. So we flush + # the queue to ensure writes happen, then output the state message to indicate it's safe to checkpoint state + writer.flush() + yield message + elif message.type == Type.RECORD: + record = message.record + writer.queue_write_operation( + record.stream, record.data, time.time_ns() / 1_000_000 + ) # convert from nanoseconds to milliseconds + else: + # ignore other message types for now + continue + + # Make sure to flush any records still in the queue + writer.flush() + + def check(self, logger: AirbyteLogger, config: Mapping[str, Any]) -> AirbyteConnectionStatus: + """ + Tests if the input configuration can be used to successfully connect to the destination with the needed permissions + e.g: if a provided API token or password can be used to connect and write to the destination. + """ + try: + # Verify write access by attempting to write and then delete to a random key + client = KvDbClient(**config) + random_key = str(uuid.uuid4()) + client.write(random_key, {"value": "_airbyte_connection_check"}) + client.delete(random_key) + except Exception as e: + traceback.print_exc() + return AirbyteConnectionStatus( + status=Status.FAILED, message=f"An exception occurred: {e}. \nStacktrace: \n{traceback.format_exc()}" + ) + else: + return AirbyteConnectionStatus(status=Status.SUCCEEDED) diff --git a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/spec.json b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/spec.json new file mode 100644 index 000000000000..0ced52c17a22 --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/spec.json @@ -0,0 +1,26 @@ +{ + "documentationUrl": "https://kvdb.io/docs/api/", + "supported_destination_sync_modes": ["overwrite", "append"], + "supportsIncremental": true, + "connectionSpecification": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Destination KVdb", + "type": "object", + "required": ["bucket_id", "secret_key"], + "additionalProperties": false, + "properties": { + "bucket_id": { + "title": "Bucket ID", + "type": "string", + "description": "The ID of your KVdb bucket.", + "order": 1 + }, + "secret_key": { + "title": "Secret Key", + "type": "string", + "description": "Your bucket Secret Key.", + "order": 2 + } + } + } +} diff --git a/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/writer.py b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/writer.py new file mode 100644 index 000000000000..33acbf8a22fb --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/destination_kvdb/writer.py @@ -0,0 +1,46 @@ +# +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. +# + +from collections import Mapping + +from destination_kvdb.client import KvDbClient + + +class KvDbWriter: + """ + Data is written to KvDB in the following format: + key: stream_name__ab__ + value: a JSON object representing the record's data + + This is because unless a data source explicitly designates a primary key, we don't know what to key the record on. + Since KvDB allows reading records with certain prefixes, we treat it more like a message queue, expecting the reader to + read messages with a particular prefix e.g: name__ab__123, where 123 is the timestamp they last read data from. + """ + + write_buffer = [] + flush_interval = 1000 + + def __init__(self, client: KvDbClient): + self.client = client + + def delete_stream_entries(self, stream_name: str): + """Deletes all the records belonging to the input stream""" + keys_to_delete = [] + for key in self.client.list_keys(prefix=f"{stream_name}__ab__"): + keys_to_delete.append(key) + if len(keys_to_delete) == self.flush_interval: + self.client.delete(keys_to_delete) + keys_to_delete.clear() + if len(keys_to_delete) > 0: + self.client.delete(keys_to_delete) + + def queue_write_operation(self, stream_name: str, record: Mapping, written_at: int): + kv_pair = (f"{stream_name}__ab__{written_at}", record) + self.write_buffer.append(kv_pair) + if len(self.write_buffer) == self.flush_interval: + self.flush() + + def flush(self): + self.client.batch_write(self.write_buffer) + self.write_buffer.clear() diff --git a/airbyte-integrations/connectors/destination-kvdb/main.py b/airbyte-integrations/connectors/destination-kvdb/main.py new file mode 100644 index 000000000000..178789589e5a --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/main.py @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. +# + + +import sys + +from destination_kvdb import DestinationKvdb + +if __name__ == "__main__": + DestinationKvdb().run(sys.argv[1:]) diff --git a/airbyte-integrations/connectors/destination-kvdb/requirements.txt b/airbyte-integrations/connectors/destination-kvdb/requirements.txt new file mode 100644 index 000000000000..d6e1198b1ab1 --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/requirements.txt @@ -0,0 +1 @@ +-e . diff --git a/airbyte-integrations/connectors/destination-kvdb/setup.py b/airbyte-integrations/connectors/destination-kvdb/setup.py new file mode 100644 index 000000000000..dab5520718ab --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/setup.py @@ -0,0 +1,26 @@ +# +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. +# + + +from setuptools import find_packages, setup + +MAIN_REQUIREMENTS = [ + "airbyte-cdk", + "requests", +] + +TEST_REQUIREMENTS = ["pytest~=6.1"] + +setup( + name="destination_kvdb", + description="Destination implementation for Kvdb.", + author="Airbyte", + author_email="contact@airbyte.io", + packages=find_packages(), + install_requires=MAIN_REQUIREMENTS, + package_data={"": ["*.json"]}, + extras_require={ + "tests": TEST_REQUIREMENTS, + }, +) diff --git a/airbyte-integrations/connectors/destination-kvdb/unit_tests/unit_test.py b/airbyte-integrations/connectors/destination-kvdb/unit_tests/unit_test.py new file mode 100644 index 000000000000..219ae0142c72 --- /dev/null +++ b/airbyte-integrations/connectors/destination-kvdb/unit_tests/unit_test.py @@ -0,0 +1,7 @@ +# +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. +# + + +def test_example_method(): + assert True From 385a70d89d3387d2e1cdb135dda659b07fba845d Mon Sep 17 00:00:00 2001 From: Alex Birdsall Date: Fri, 16 Feb 2024 15:53:26 -0800 Subject: [PATCH 21/43] Support user-specified test read limits in `connector_builder` code (#35312) --- .../airbyte_cdk/connector_builder/README.md | 1 + .../connector_builder_handler.py | 2 +- .../connector_builder/message_grouper.py | 4 +-- .../connector_builder/test_message_grouper.py | 35 +++++++++++-------- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/airbyte-cdk/python/airbyte_cdk/connector_builder/README.md b/airbyte-cdk/python/airbyte_cdk/connector_builder/README.md index 3f3402fab536..6788a6f226b1 100644 --- a/airbyte-cdk/python/airbyte_cdk/connector_builder/README.md +++ b/airbyte-cdk/python/airbyte_cdk/connector_builder/README.md @@ -22,6 +22,7 @@ Note: *See [ConnectionSpecification](https://docs.airbyte.com/understanding-airbyte/airbyte-protocol/#actor-specification) for details on the `"config"` key if needed. - When the `__command` is `resolve_manifest`, the argument to `catalog` should be an empty string. +- The config can optionally contain an object under the `__test_read_config` key which can define custom test read limits with `max_records`, `max_slices`, and `max_pages_per_slice` properties. All custom limits are optional; a default will be used for any limit that is not provided. ### Locally running the docker image diff --git a/airbyte-cdk/python/airbyte_cdk/connector_builder/connector_builder_handler.py b/airbyte-cdk/python/airbyte_cdk/connector_builder/connector_builder_handler.py index c53bda0dfc62..4dfe4a3dd05d 100644 --- a/airbyte-cdk/python/airbyte_cdk/connector_builder/connector_builder_handler.py +++ b/airbyte-cdk/python/airbyte_cdk/connector_builder/connector_builder_handler.py @@ -57,7 +57,7 @@ def read_stream( source: DeclarativeSource, config: Mapping[str, Any], configured_catalog: ConfiguredAirbyteCatalog, limits: TestReadLimits ) -> AirbyteMessage: try: - handler = MessageGrouper(limits.max_pages_per_slice, limits.max_slices) + handler = MessageGrouper(limits.max_pages_per_slice, limits.max_slices, limits.max_records) stream_name = configured_catalog.streams[0].stream.name # The connector builder only supports a single stream stream_read = handler.get_message_groups(source, config, configured_catalog, limits.max_records) return AirbyteMessage( diff --git a/airbyte-cdk/python/airbyte_cdk/connector_builder/message_grouper.py b/airbyte-cdk/python/airbyte_cdk/connector_builder/message_grouper.py index 42a0e1051b52..b30a3a3744f4 100644 --- a/airbyte-cdk/python/airbyte_cdk/connector_builder/message_grouper.py +++ b/airbyte-cdk/python/airbyte_cdk/connector_builder/message_grouper.py @@ -52,8 +52,8 @@ def get_message_groups( configured_catalog: ConfiguredAirbyteCatalog, record_limit: Optional[int] = None, ) -> StreamRead: - if record_limit is not None and not (1 <= record_limit <= 1000): - raise ValueError(f"Record limit must be between 1 and 1000. Got {record_limit}") + if record_limit is not None and not (1 <= record_limit <= self._max_record_limit): + raise ValueError(f"Record limit must be between 1 and {self._max_record_limit}. Got {record_limit}") schema_inferrer = SchemaInferrer() datetime_format_inferrer = DatetimeFormatInferrer() diff --git a/airbyte-cdk/python/unit_tests/connector_builder/test_message_grouper.py b/airbyte-cdk/python/unit_tests/connector_builder/test_message_grouper.py index ae98f6ad70ab..437a775dd8de 100644 --- a/airbyte-cdk/python/unit_tests/connector_builder/test_message_grouper.py +++ b/airbyte-cdk/python/unit_tests/connector_builder/test_message_grouper.py @@ -218,14 +218,14 @@ def test_get_grouped_messages_with_logs(mock_entrypoint_read: Mock) -> None: @pytest.mark.parametrize( - "request_record_limit, max_record_limit", + "request_record_limit, max_record_limit, should_fail", [ - pytest.param(1, 3, id="test_create_request_with_record_limit"), - pytest.param(3, 1, id="test_create_request_record_limit_exceeds_max"), + pytest.param(1, 3, False, id="test_create_request_with_record_limit"), + pytest.param(3, 1, True, id="test_create_request_record_limit_exceeds_max"), ], ) @patch("airbyte_cdk.connector_builder.message_grouper.AirbyteEntrypoint.read") -def test_get_grouped_messages_record_limit(mock_entrypoint_read: Mock, request_record_limit: int, max_record_limit: int) -> None: +def test_get_grouped_messages_record_limit(mock_entrypoint_read: Mock, request_record_limit: int, max_record_limit: int, should_fail: bool) -> None: url = "https://demonslayers.com/api/v1/hashiras?era=taisho" request = { "headers": {"Content-Type": "application/json"}, @@ -249,16 +249,23 @@ def test_get_grouped_messages_record_limit(mock_entrypoint_read: Mock, request_r record_limit = min(request_record_limit, max_record_limit) api = MessageGrouper(MAX_PAGES_PER_SLICE, MAX_SLICES, max_record_limit=max_record_limit) - actual_response: StreamRead = api.get_message_groups( - mock_source, config=CONFIG, configured_catalog=create_configured_catalog("hashiras"), record_limit=request_record_limit - ) - single_slice = actual_response.slices[0] - total_records = 0 - for i, actual_page in enumerate(single_slice.pages): - total_records += len(actual_page.records) - assert total_records == min([record_limit, n_records]) - - assert (total_records >= max_record_limit) == actual_response.test_read_limit_reached + # this is the call we expect to raise an exception + if should_fail: + with pytest.raises(ValueError): + api.get_message_groups( + mock_source, config=CONFIG, configured_catalog=create_configured_catalog("hashiras"), record_limit=request_record_limit + ) + else: + actual_response: StreamRead = api.get_message_groups( + mock_source, config=CONFIG, configured_catalog=create_configured_catalog("hashiras"), record_limit=request_record_limit + ) + single_slice = actual_response.slices[0] + total_records = 0 + for i, actual_page in enumerate(single_slice.pages): + total_records += len(actual_page.records) + assert total_records == min([record_limit, n_records]) + + assert (total_records >= max_record_limit) == actual_response.test_read_limit_reached @pytest.mark.parametrize( From c99c0b1333add6ce0f0d343693a458bdfc9f0818 Mon Sep 17 00:00:00 2001 From: ambirdsall Date: Fri, 16 Feb 2024 23:59:31 +0000 Subject: [PATCH 22/43] =?UTF-8?q?=F0=9F=A4=96=20Bump=20patch=20version=20o?= =?UTF-8?q?f=20Python=20CDK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- airbyte-cdk/python/.bumpversion.cfg | 2 +- airbyte-cdk/python/CHANGELOG.md | 3 +++ airbyte-cdk/python/Dockerfile | 4 ++-- airbyte-cdk/python/setup.py | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/airbyte-cdk/python/.bumpversion.cfg b/airbyte-cdk/python/.bumpversion.cfg index a2e957bf86c2..94bc67c38d2d 100644 --- a/airbyte-cdk/python/.bumpversion.cfg +++ b/airbyte-cdk/python/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.63.1 +current_version = 0.63.2 commit = False [bumpversion:file:setup.py] diff --git a/airbyte-cdk/python/CHANGELOG.md b/airbyte-cdk/python/CHANGELOG.md index 3853c061679e..29e2a40bccfa 100644 --- a/airbyte-cdk/python/CHANGELOG.md +++ b/airbyte-cdk/python/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 0.63.2 +Correct handling of custom max_records limits in connector_builder + ## 0.63.1 File-based CDK: fix record enqueuing diff --git a/airbyte-cdk/python/Dockerfile b/airbyte-cdk/python/Dockerfile index bba8e056a664..727c254e13c4 100644 --- a/airbyte-cdk/python/Dockerfile +++ b/airbyte-cdk/python/Dockerfile @@ -10,7 +10,7 @@ RUN apk --no-cache upgrade \ && apk --no-cache add tzdata build-base # install airbyte-cdk -RUN pip install --prefix=/install airbyte-cdk==0.63.1 +RUN pip install --prefix=/install airbyte-cdk==0.63.2 # build a clean environment FROM base @@ -32,5 +32,5 @@ ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] # needs to be the same as CDK -LABEL io.airbyte.version=0.63.1 +LABEL io.airbyte.version=0.63.2 LABEL io.airbyte.name=airbyte/source-declarative-manifest diff --git a/airbyte-cdk/python/setup.py b/airbyte-cdk/python/setup.py index 0598d8a0ef54..efb68903ff90 100644 --- a/airbyte-cdk/python/setup.py +++ b/airbyte-cdk/python/setup.py @@ -36,7 +36,7 @@ name="airbyte-cdk", # The version of the airbyte-cdk package is used at runtime to validate manifests. That validation must be # updated if our semver format changes such as using release candidate versions. - version="0.63.1", + version="0.63.2", description="A framework for writing Airbyte Connectors.", long_description=README, long_description_content_type="text/markdown", From 6301a20dc5633ff0bccd0664c8baed0707919a92 Mon Sep 17 00:00:00 2001 From: Evan Tahler Date: Fri, 16 Feb 2024 16:02:57 -0800 Subject: [PATCH 23/43] destination-kvdb bump to publish (#35381) --- .../connectors/destination-kvdb/Dockerfile | 2 +- .../connectors/destination-kvdb/metadata.yaml | 2 +- docs/integrations/destinations/kvdb.md | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/airbyte-integrations/connectors/destination-kvdb/Dockerfile b/airbyte-integrations/connectors/destination-kvdb/Dockerfile index b0493da1cfc1..0fb6a071dc8f 100644 --- a/airbyte-integrations/connectors/destination-kvdb/Dockerfile +++ b/airbyte-integrations/connectors/destination-kvdb/Dockerfile @@ -34,5 +34,5 @@ COPY destination_kvdb ./destination_kvdb ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.0 +LABEL io.airbyte.version=0.1.1 LABEL io.airbyte.name=airbyte/destination-kvdb diff --git a/airbyte-integrations/connectors/destination-kvdb/metadata.yaml b/airbyte-integrations/connectors/destination-kvdb/metadata.yaml index 4408eae38888..d700e915c1fd 100644 --- a/airbyte-integrations/connectors/destination-kvdb/metadata.yaml +++ b/airbyte-integrations/connectors/destination-kvdb/metadata.yaml @@ -7,7 +7,7 @@ data: connectorSubtype: api connectorType: destination definitionId: f2e549cd-8e2a-48f8-822d-cc13630eb42d - dockerImageTag: 0.1.0 + dockerImageTag: 0.1.1 dockerRepository: airbyte/destination-kvdb githubIssueLabel: destination-kvdb icon: kvdb.svg diff --git a/docs/integrations/destinations/kvdb.md b/docs/integrations/destinations/kvdb.md index 1d9a4341e8fc..587b428d3a83 100644 --- a/docs/integrations/destinations/kvdb.md +++ b/docs/integrations/destinations/kvdb.md @@ -4,6 +4,7 @@ The KVDB destination for Airbyte ## Changelog -| Version | Date | Pull Request | Subject | -| :------ | :--------- | :----------------------------------------------------- | :---------------------------- | -| 0.1.0 | 2021-07-19 | [4786](https://github.com/airbytehq/airbyte/pull/4786) | Python Demo Destination: KVDB | +| Version | Date | Pull Request | Subject | +| :------ | :--------- | :------------------------------------------------------- | :-------------------------------- | +| 0.1.1 | 2024-02-16 | [35370](https://github.com/airbytehq/airbyte/pull/35370) | bump connector version to publish | +| 0.1.0 | 2021-07-19 | [4786](https://github.com/airbytehq/airbyte/pull/4786) | Python Demo Destination: KVDB | From 27abc6d88106e608a17bd772dbcce1641dd3ee81 Mon Sep 17 00:00:00 2001 From: Jose Gerardo Pineda Date: Fri, 16 Feb 2024 18:25:57 -0600 Subject: [PATCH 24/43] =?UTF-8?q?=E2=9C=A8=20Source=20Paypal=20Transaction?= =?UTF-8?q?s:=20Siver=20Certification=20=20(#34510)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alexandre Girard Co-authored-by: alafanechere Co-authored-by: Augustin --- .../source-paypal-transaction/.coveragerc | 3 + .../source-paypal-transaction/CHANGELOG.md | 9 + .../source-paypal-transaction/README.md | 138 +++++- .../acceptance-test-config.yml | 81 ++-- .../bin/disputes_generator.py | 89 ++++ .../source-paypal-transaction/bin/invoices.py | 197 ++++++++ .../bin/payments_generator.py | 106 ++++ .../bin/paypal_transaction_generator.py | 59 ++- .../bin/product_catalog.py | 115 +++++ .../integration_tests/configured_catalog.json | 52 ++ .../configured_catalog_list_disputes.json | 15 + .../configured_catalog_list_payments.json | 15 + .../configured_catalog_list_products.json | 14 + .../configured_catalog_search_invoices.json | 14 + ...nfigured_catalog_show_product_details.json | 14 + .../integration_tests/expected_records.jsonl | 1 - .../expected_records_sandbox.jsonl | 4 - .../full_refresh_catalog.json | 47 ++ .../incremental_catalog.json | 47 ++ .../invalid_config_oauth.json | 11 - .../integration_tests/sample_config.json | 6 - .../{ => sample_files}/abnormal_state.json | 22 + .../sample_files/expected_records.jsonl | 16 + .../expected_records_sandbox.jsonl | 85 ++++ .../{ => sample_files}/invalid_config.json | 0 .../sample_files/sample_config.json | 12 + .../{ => sample_files}/sample_state.json | 0 .../{ => sample_files}/state.json | 0 .../source-paypal-transaction/metadata.yaml | 9 +- .../source-paypal-transaction/poetry.lock | 263 ++++++++-- .../source-paypal-transaction/pyproject.toml | 10 +- .../source_paypal_transaction/components.py | 24 +- .../source_paypal_transaction/manifest.yaml | 323 ++++++++++--- .../schemas/list_disputes.json | 32 ++ .../schemas/list_payments.json | 204 ++++++++ .../schemas/list_products.json | 26 + .../schemas/search_invoices.json | 357 ++++++++++++++ .../schemas/show_product_details.json | 28 ++ .../source_paypal_transaction/source.py | 2 +- .../source_paypal_transaction/spec.yaml | 78 +++ .../unit_tests/auth_components_test.py | 88 ++++ .../unit_tests/conftest.py | 53 ++ .../unit_tests/pagination_cursor.py | 146 ++++++ .../unit_tests/pagination_increment.py | 79 +++ .../unit_tests/test_files/page_1.json | 135 ++++++ .../unit_tests/test_files/page_2.json | 160 +++++++ .../token_PAY-0L38757939422510JMW5ZJVA.json | 451 ++++++++++++++++++ .../token_PAYID-MW5XXZY5YL87592N34454913.json | 391 +++++++++++++++ .../test_files/token_page_init.json | 399 ++++++++++++++++ .../sources/paypal-transaction.md | 289 +++++++++-- 50 files changed, 4471 insertions(+), 248 deletions(-) create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/.coveragerc create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/bin/disputes_generator.py create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/bin/invoices.py create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/bin/payments_generator.py create mode 100755 airbyte-integrations/connectors/source-paypal-transaction/bin/product_catalog.py create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_disputes.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_payments.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_products.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_search_invoices.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_show_product_details.json delete mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/expected_records.jsonl delete mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/expected_records_sandbox.jsonl create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/full_refresh_catalog.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/incremental_catalog.json delete mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/invalid_config_oauth.json delete mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_config.json rename airbyte-integrations/connectors/source-paypal-transaction/integration_tests/{ => sample_files}/abnormal_state.json (50%) create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/expected_records.jsonl create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/expected_records_sandbox.jsonl rename airbyte-integrations/connectors/source-paypal-transaction/integration_tests/{ => sample_files}/invalid_config.json (100%) create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/sample_config.json rename airbyte-integrations/connectors/source-paypal-transaction/integration_tests/{ => sample_files}/sample_state.json (100%) rename airbyte-integrations/connectors/source-paypal-transaction/integration_tests/{ => sample_files}/state.json (100%) create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_disputes.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_payments.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_products.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/search_invoices.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/show_product_details.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/spec.yaml create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/unit_tests/auth_components_test.py create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/unit_tests/conftest.py create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/unit_tests/pagination_cursor.py create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/unit_tests/pagination_increment.py create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/page_1.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/page_2.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_PAY-0L38757939422510JMW5ZJVA.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_PAYID-MW5XXZY5YL87592N34454913.json create mode 100644 airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_page_init.json diff --git a/airbyte-integrations/connectors/source-paypal-transaction/.coveragerc b/airbyte-integrations/connectors/source-paypal-transaction/.coveragerc new file mode 100644 index 000000000000..4e4eba3bda57 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/.coveragerc @@ -0,0 +1,3 @@ +[run] +omit = + source_paypal_transaction/run.py \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-paypal-transaction/CHANGELOG.md b/airbyte-integrations/connectors/source-paypal-transaction/CHANGELOG.md index d84557504900..7cddffd5f108 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/CHANGELOG.md +++ b/airbyte-integrations/connectors/source-paypal-transaction/CHANGELOG.md @@ -2,3 +2,12 @@ ## 0.1.0 Source implementation with support of Transactions and Balances streams + +## 1.0.0 +Mark Client ID and Client Secret as required files + +## 2.1.0 +Migration to Low code + +## 2.3.0 +Adding New Streams - Payments, Disputes, Invoices, Product Catalog \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-paypal-transaction/README.md b/airbyte-integrations/connectors/source-paypal-transaction/README.md index 82d0043bf6e4..6cff7acce3aa 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/README.md +++ b/airbyte-integrations/connectors/source-paypal-transaction/README.md @@ -1,54 +1,89 @@ # Paypal-Transaction source connector - This is the repository for the Paypal-Transaction source connector, written in Python. For information about how to use this connector within Airbyte, see [the documentation](https://docs.airbyte.com/integrations/sources/paypal-transaction). ## Local development -### Prerequisites -* Python (~=3.9) -* Poetry (~=1.7) - installation instructions [here](https://python-poetry.org/docs/#installation) +#### Prerequisites + * Python (~=3.9) + * Poetry (~=1.7) - installation instructions [here](https://python-poetry.org/docs/#installation) + * Paypal Client ID and Client Secret + * If you are going to use the data generator scripts you need to setup yourPaypal Sandbox and a Buyer user in your sandbox, to simulate the data. YOu cna get that information in the [Apps & Credentials page](https://developer.paypal.com/dashboard/applications/live). + * Buyer Username + * Buyer Password + * Payer ID (Account ID) ### Installing the connector + From this connector directory, run: ```bash poetry install --with dev ``` - ### Create credentials + **If you are a community contributor**, follow the instructions in the [documentation](https://docs.airbyte.com/integrations/sources/paypal-transaction) to generate the necessary credentials. Then create a file `secrets/config.json` conforming to the `source_paypal_transaction/spec.yaml` file. Note that any directory named `secrets` is gitignored across the entire Airbyte repo, so there is no danger of accidentally checking in sensitive information. See `sample_files/sample_config.json` for a sample config file. +* You must have created your credentials under the `secrets/` folder +* For the read command, you can create separate catalogs to test the streams individually. All catalogs are under the folder `integration_tests`. Select the one you want to test with the read command. + ### Locally running the connector + ``` poetry run source-paypal-transaction spec poetry run source-paypal-transaction check --config secrets/config.json poetry run source-paypal-transaction discover --config secrets/config.json -poetry run source-paypal-transaction read --config secrets/config.json --catalog sample_files/configured_catalog.json +#Example with list_payments catalog and the debug flag +poetry run source-paypal-transaction read --config secrets/config.json --catalog integration_tests/configured_catalog_list_payments.json --debug ``` ### Running unit tests To run unit tests locally, from the connector directory run: + ``` poetry run pytest unit_tests ``` ### Building the docker image + 1. Install [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md) 2. Run the following command to build the docker image: + + +### Installing the connector +From this connector directory, run: ```bash -airbyte-ci connectors --name=source-paypal-transaction build +poetry install --with dev +``` + +##### Customizing our build process +When contributing on our connector you might need to customize the build process to add a system dependency or set an env var. +You can customize our build process by adding a `build_customization.py` module to your connector. +This module should contain a `pre_connector_install` and `post_connector_install` async function that will mutate the base image and the connector container respectively. +It will be imported at runtime by our build process and the functions will be called if they exist. + +Here is an example of a `build_customization.py` module: +```python +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + # Feel free to check the dagger documentation for more information on the Container object and its methods. + # https://dagger-io.readthedocs.io/en/sdk-python-v0.6.4/ + from dagger import Container ``` An image will be available on your host with the tag `airbyte/source-paypal-transaction:dev`. + ### Running as a docker container Then run any of the connector commands as follows: ``` @@ -58,23 +93,110 @@ docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-paypal-transaction:dev docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/source-paypal-transaction:dev read --config /secrets/config.json --catalog /integration_tests/configured_catalog.json ``` + ### Running our CI test suite + You can run our full test suite locally using [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md): + ```bash airbyte-ci connectors --name=source-paypal-transaction test ``` +If you are testing locally, you can use your local credentials (config.json file) by using `--use-local-secrets` + +```bash +airbyte-ci connectors --name source-paypal-transaction --use-local-secrets test +``` + ### Customizing acceptance Tests Customize `acceptance-test-config.yml` file to configure acceptance tests. See [Connector Acceptance Tests](https://docs.airbyte.com/connector-development/testing-connectors/connector-acceptance-tests-reference) for more information. If your connector requires to create or destroy resources for use during acceptance tests create fixtures for it and place them inside integration_tests/acceptance.py. -### Dependency Management + +## Running Unit tests locally + +To run unit tests locally, form the root `source_paypal_transaction` directory run: + +```bash +python -m pytest unit_test +``` + +## Test changes in the sandbox + +If you have a [Paypal Sandbox](https://developer.paypal.com/tools/sandbox/accounts/) you will be able to use some APIs to create new data and test how data is being created in your destinaiton and choose the best syn strategy that suits better your use case. +Some endpoints will require special permissions on the sandbox to update and change some values. + +In the `bin` folder you will find several data generator scripts: + +* **disputes_generator.py:** + * Update dispute: Uses the _PATCH_ method of the `https://api-m.paypal.com/v1/customer/disputes/{dispute_id}` endpoint. You need the ID and create a payload to pass it as an argument. See more information [here](https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_patch). + + ```bash + python disputes_generator.py update DISPUTE_ID ''[{"op": "replace", "path": "/reason", "value": "The new reason"}]' + ``` + + * Update Evidence status: Uses the _POST_ method of the `https://api-m.paypal.com/v1/customer/disputes/{dispute_id}/require-evidence` endpoint. You need the ID and select an option to pass it as an argument. See more information [here](https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_require-evidence) + ```bash + python update_dispute.py require-evidence DISPUTE_ID SELLER_EVIDENCE + ``` + +* **invoices.py:** + * Create draft invoice: Uses the _POST_ method of the `https://api-m.sandbox.paypal.com/v2/invoicing/invoices` endpoint. It will automatically generate an invoice (no need to pass any parameters). See more information [here](https://developer.paypal.com/docs/api/invoicing/v2/#invoices_create). + + ```bash + python invoices.py create_draft + ``` + + * Send a Draft Invoice: Uses the _POST_ method of the `https://api-m.sandbox.paypal.com/v2/invoicing/invoices/{invoice_id}/send` endpoint. You need the Invoice ID, a subject and a note (just to have something to update) and an email as an argument. See more information [here](https://developer.paypal.com/docs/api/invoicing/v2/#invoices_send) + ```bash + python invoices.py send_draft --invoice_id "INV2-XXXX-XXXX-XXXX-XXXX" --subject "Your Invoice Subject" --note "Your custom note" --additional_recipients example@email.com + ``` + +* **payments_generator.py:** + * Partially update payment: Uses the _PATCH_ method of the `https://api-m.paypal.com/v1/payments/payment/{payment_id}` endpoint. You need the payment ID and a payload with new values. (no need to pass any parameters). See more information [here](https://developer.paypal.com/docs/api/invoicing/v2/#invoices_create). + + ```bash + python script_name.py update PAYMENT_ID '[{"op": "replace", "path": "/transactions/0/amount", "value": {"total": "50.00", "currency": "USD"}}]' + ``` + +* **paypal_transaction_generator.py:** + Make sure you have the `buyer_username`, `buyer_password` and `payer_id` in your config file. You can get the sample configuratin in the `sample_config.json`. + + * Generate transactions: This uses Selenium, so you will be prompted to your account to simulate the complete transaction flow. You can add a number at the end of the command to do more than one transaction. By default the script runs 3 transactions. + + **NOTE: Be midnfu of the number of transactions, as it will be interacting with your machine, and you may not be able to use it while creating the transactions** + + ```bash + python paypal_transaction_generator.py [NUMBER_OF_DESIRED_TRANSACTIONS] + ``` + +* **product_catalog.py:** + * Create a product: Uses the _POST_ method of the `https://api-m.sandbox.paypal.com/v1/catalogs/products` endpoint. You need to add the description and the category in the command line. For the proper category see more information [here](https://developer.paypal.com/docs/api/catalog-products/v1/#products_create). + + ```bash + python product_catalog.py --action create --description "YOUR DESCRIPTION" --category PAYPAL_CATEGORY + ``` + + * Update a product: Uses the _PATCH_ method of the `https://developer.paypal.com/docs/api/catalog-products/v1/#products_patch` endpoint. You need the product ID, a description and the Category as an argument. See more information [here](https://developer.paypal.com/docs/api/catalog-products/v1/#products_patch) + ```bash + python product_catalog.py --action update --product_id PRODUCT_ID --update_payload '[{"op": "replace", "path": "/description", "value": "My Update. Does it changes it?"}]' + ``` + +## Dependency Management +All of your dependencies should go in `setup.py`, NOT `requirements.txt`. The requirements file is only used to connect internal Airbyte dependencies in the monorepo for local development. +We split dependencies between two groups, dependencies that are: +* required for your connector to work need to go to `MAIN_REQUIREMENTS` list. +* required for the testing need to go to `TEST_REQUIREMENTS` list + + All of your dependencies should be managed via Poetry. + To add a new dependency, run: ```bash poetry add ``` + Please commit the changes to `pyproject.toml` and `poetry.lock` files. ## Publishing a new version of the connector diff --git a/airbyte-integrations/connectors/source-paypal-transaction/acceptance-test-config.yml b/airbyte-integrations/connectors/source-paypal-transaction/acceptance-test-config.yml index c4ebc718cf3b..f4682c9534da 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/acceptance-test-config.yml +++ b/airbyte-integrations/connectors/source-paypal-transaction/acceptance-test-config.yml @@ -1,69 +1,84 @@ # See [Connector Acceptance Tests](https://docs.airbyte.com/connector-development/testing-connectors/connector-acceptance-tests-reference) # for more information about how to configure these tests +# Make sure the paths you have in each path matches with your data. +#For multiple env testing, you can duplicate the tests and change the path to the proper credentials file connector_image: airbyte/source-paypal-transaction:dev test_strictness_level: high acceptance_tests: spec: tests: + #Test with Prod credentials (Make sure you purt the right ones) - spec_path: "source_paypal_transaction/spec.yaml" - config_path: secrets/config_oauth.json + config_path: secrets/config.json backward_compatibility_tests_config: disable_for_version: "0.1.13" connection: tests: - - config_path: secrets/config_oauth.json + #Test With Prod Credentials + - config_path: secrets/config.json status: succeed - - config_path: secrets/config_oauth_sandbox.json - status: succeed - - config_path: integration_tests/invalid_config.json - status: failed - - config_path: integration_tests/invalid_config_oauth.json + #Test with Invalid Credentials + - config_path: integration_tests/sample_files/invalid_config.json status: failed + #Test with Sandbox Credentials + # - config_path: secrets/config_sandbox.json + # status: succeed discovery: tests: - - config_path: secrets/config_oauth.json + - config_path: secrets/config.json + # - config_path: secrets/config_sandbox.json backward_compatibility_tests_config: disable_for_version: "2.0.0" # Change in cursor field for transactions stream basic_read: tests: - - config_path: secrets/config_oauth.json - ignored_fields: - balances: - - name: last_refresh_time - bypass_reason: "field changes during every read" + #Test Prod Environment - Uncomment and change according to your prod setup + #Change the expected records, remember to align them with the timeframe you have selected + #Do not select streams that take more than 5 mins to load data as that can lead to timeouts + #You can comment the lines if you are sure you have data for the below streams. + - config_path: secrets/config.json + # - config_path: secrets/config_sandbox.json empty_streams: - - name: transactions - bypass_reason: "can not populate" - timeout_seconds: 1200 - expect_records: - path: "integration_tests/expected_records.jsonl" - extra_fields: no - exact_order: no - extra_records: yes - - config_path: secrets/config_oauth_sandbox.json + - name: show_product_details + bypass_reason: "Products may not exist" + - name: list_products + bypass_reason: "Product List may be too big causing timeout errors" + - name: search_invoices + bypass_reason: "Order makes the diff fail." + #Have to add for testing PR CI. + - name: list_disputes + bypass_reason: "Disputes may not exist." ignored_fields: balances: - name: last_refresh_time bypass_reason: "field changes during every read" - timeout_seconds: 1200 + list_products: + - name: description + bypass_reason: "Sometimes it is not contained in the response" + timeout_seconds: 3200 expect_records: - path: "integration_tests/expected_records_sandbox.jsonl" - extra_fields: no - exact_order: no - extra_records: yes - fail_on_extra_columns: false + path: "integration_tests/sample_files/expected_records_sandbox.jsonl" + #path: "integration_tests/sample_files/expected_records.jsonl" + extra_fields: yes + exact_order: yes + extra_records: no + fail_on_extra_columns: False incremental: tests: - - config_path: secrets/config_oauth.json - configured_catalog_path: integration_tests/configured_catalog.json + - config_path: secrets/config.json + # - config_path: secrets/config_sandbox.json + configured_catalog_path: integration_tests/incremental_catalog.json future_state: - future_state_path: integration_tests/abnormal_state.json + future_state_path: integration_tests/sample_files/abnormal_state.json skip_comprehensive_incremental_tests: true full_refresh: tests: - - config_path: secrets/config_oauth.json + - config_path: secrets/config.json + # - config_path: secrets/config_sandbox.json + configured_catalog_path: integration_tests/full_refresh_catalog.json ignored_fields: balances: - name: last_refresh_time bypass_reason: "field changes during every read" - configured_catalog_path: integration_tests/configured_catalog.json + list_products: + - name: description + bypass_reason: "Sometimes it is not contained in the response" diff --git a/airbyte-integrations/connectors/source-paypal-transaction/bin/disputes_generator.py b/airbyte-integrations/connectors/source-paypal-transaction/bin/disputes_generator.py new file mode 100644 index 000000000000..c371024b7ff9 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/bin/disputes_generator.py @@ -0,0 +1,89 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + +# REQUIREMENTS: +# 1. Put your sandbox credentials in ../secrets/config.json (Create them if it doesn't exist). +# Use the following body (change all the values): +# { +# "client_id": "YOUT_CLIENT_ID", +# "client_secret": "YOUR_SECRET_CLIENT_ID", +# "start_date": "2021-06-01T00:00:00Z", +# "end_date": "2024-06-10T00:00:00Z", +# "is_sandbox": true +# } + +# HOW TO USE: +# To create a new payment: python script_name.py create +# To update an existing dispute: +# python disputes_generator.py update DISPUTE_ID ''[{"op": "replace", "path": "/reason", "value": "The new reason"}]' +# To update a dispute status +# python update_dispute.py require-evidence DISPUTE_ID SELLER_EVIDENCE + +import base64 +import json +import sys + +import requests + + +# Function to get a PayPal OAuth token +def get_paypal_token(client_id, secret_id): + url = "https://api-m.sandbox.paypal.com/v1/oauth2/token" + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "Authorization": "Basic " + base64.b64encode(f"{client_id}:{secret_id}".encode()).decode(), + } + payload = {"grant_type": "client_credentials"} + response = requests.post(url=url, data=payload, headers=headers) + return response.json().get("access_token") + + +def update_dispute(token, dispute_id, updates): + """Update a PayPal dispute.""" + url = f"https://api-m.paypal.com/v1/customer/disputes/{dispute_id}" + headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"} + response = requests.patch(url, headers=headers, json=updates) + print("RESPONSE: ", response.text) + return response.json() + + +def require_evidence(token, dispute_id, action): + """Require evidence for a PayPal dispute.""" + url = f"https://api-m.paypal.com/v1/customer/disputes/{dispute_id}/require-evidence" + headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"} + payload = {"action": action} + response = requests.post(url, headers=headers, json=payload) + print("RESPONSE: ", response.text) + return response.json() + + +def read_json(filepath): + with open(filepath, "r") as f: + return json.loads(f.read()) + + +def main(): + + operation = sys.argv[1] + + CREDS = read_json("../secrets/config.json") + client_id = CREDS.get("client_id") + secret_id = CREDS.get("client_secret") + token = get_paypal_token(client_id, secret_id) + + if operation == "update": + dispute_id = sys.argv[2] + updates = json.loads(sys.argv[3]) # Expecting JSON string as the third argument + update_response = update_dispute(token, dispute_id, updates) + print("Update Response:", update_response) + + elif sys.argv[1] == "require-evidence": + dispute_id = sys.argv[2] + action = sys.argv[3] # Either 'BUYER_EVIDENCE' or 'SELLER_EVIDENCE' + evidence_response = require_evidence(token, dispute_id, action) + print("Evidence Requirement Response:", evidence_response) + else: + print("Invalid command. Use 'create', 'update', or 'require-evidence'.") + + +if __name__ == "__main__": + main() diff --git a/airbyte-integrations/connectors/source-paypal-transaction/bin/invoices.py b/airbyte-integrations/connectors/source-paypal-transaction/bin/invoices.py new file mode 100644 index 000000000000..005a11c06169 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/bin/invoices.py @@ -0,0 +1,197 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + +# REQUIREMENTS: +# 1. Put your sandbox credentials in ../secrets/config.json (Create them if it doesn't exist). +# Use the following body (change all the values): +# { +# "client_id": "YOUT_CLIENT_ID", +# "client_secret": "YOUR_SECRET_CLIENT_ID", +# "start_date": "2021-06-01T00:00:00Z", +# "end_date": "2024-06-10T00:00:00Z", +# "is_sandbox": true +# } +# How to Use: +# To Create a Draft Invoice: +# Execute the script with create_draft to generate a new invoice draft. +# The script automatically sets the invoice and due dates based on the current date and a 30-day term. +# python invoices.py create_draft +# To Send a Draft Invoice: +# Use send_draft action along with the required --invoice_id parameter, and optional parameters for email subject, note, and additional recipients. +# python invoices.py send_draft --invoice_id "INV2-XXXX-XXXX-XXXX-XXXX" --subject "Your Invoice Subject" --note "Your custom note" --additional_recipients example@email.com + +import argparse +import base64 +import json +import random +import string +from datetime import datetime, timedelta + +import requests + + +# Function to generate a random alphanumeric string +def generate_random_string(length=10): + return "".join(random.choices(string.ascii_letters + string.digits, k=length)) + + +def read_json(filepath): + with open(filepath, "r") as f: + return json.loads(f.read()) + + +# Function to get a PayPal OAuth token +def get_paypal_token(client_id, secret_id): + url = "https://api-m.sandbox.paypal.com/v1/oauth2/token" + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "Authorization": "Basic " + base64.b64encode(f"{client_id}:{secret_id}".encode()).decode(), + } + payload = {"grant_type": "client_credentials"} + response = requests.post(url=url, data=payload, headers=headers) + return response.json().get("access_token") + + +# Function to create a draft invoice +def create_draft_invoice(access_token, invoice_date, term_type, due_date): + url = "https://api-m.sandbox.paypal.com/v2/invoicing/invoices" + headers = {"Content-Type": "application/json", "Authorization": f"Bearer {access_token}"} + data = { + "detail": { + "invoice_number": generate_random_string(8), + "invoice_date": invoice_date, + "payment_term": {"term_type": term_type, "due_date": due_date}, + "currency_code": "USD", + "reference": "", + "note": "", + "terms_and_conditions": "", + "memo": "", + }, + "invoicer": { + "name": {"given_name": "David", "surname": "Larusso"}, + "address": { + "address_line_1": "123 Townsend St", + "address_line_2": "Floor 6", + "admin_area_2": "San Francisco", + "admin_area_1": "CA", + "postal_code": "94107", + "country_code": "US", + }, + "phones": [{"country_code": "001", "national_number": "4085551234", "phone_type": "MOBILE"}], + "website": "www.example.com", + "tax_id": "XX-XXXXXXX", + "logo_url": "https://example.com/logo.png", + "additional_notes": "", + }, + "primary_recipients": [ + { + "billing_info": { + "name": {"given_name": "Stephanie", "surname": "Meyers"}, + "address": { + "address_line_1": "1234 Main Street", + "admin_area_2": "Anytown", + "admin_area_1": "CA", + "postal_code": "98765", + "country_code": "US", + }, + "email_address": "foobuyer@example.com", + "phones": [{"country_code": "001", "national_number": "4884551234", "phone_type": "HOME"}], + "additional_info_value": "add-info", + }, + "shipping_info": { + "name": {"given_name": "Stephanie", "surname": "Meyers"}, + "address": { + "address_line_1": "1234 Main Street", + "admin_area_2": "Anytown", + "admin_area_1": "CA", + "postal_code": "98765", + "country_code": "US", + }, + }, + } + ], + "items": [ + { + "name": "Yoga Mat", + "description": "Elastic mat to practice yoga.", + "quantity": "1", + "unit_amount": {"currency_code": "USD", "value": "50.00"}, + "tax": {"name": "Sales Tax", "percent": "7.25"}, + "discount": {"percent": "5"}, + "unit_of_measure": "QUANTITY", + }, + { + "name": "Yoga t-shirt", + "quantity": "1", + "unit_amount": {"currency_code": "USD", "value": "10.00"}, + "tax": {"name": "Sales Tax", "percent": "7.25"}, + "discount": {"amount": {"currency_code": "USD", "value": "5.00"}}, + "unit_of_measure": "QUANTITY", + }, + ], + "configuration": { + "partial_payment": {"allow_partial_payment": True, "minimum_amount_due": {"currency_code": "USD", "value": "20.00"}}, + "allow_tip": True, + "tax_calculated_after_discount": True, + "tax_inclusive": False, + }, + "amount": { + "breakdown": { + "custom": {"label": "Packing Charges", "amount": {"currency_code": "USD", "value": "10.00"}}, + "shipping": {"amount": {"currency_code": "USD", "value": "10.00"}, "tax": {"name": "Sales Tax", "percent": "7.25"}}, + "discount": {"invoice_discount": {"percent": "5"}}, + } + }, + } + response = requests.post(url, headers=headers, json=data) + return response.json() + + +# Function to send an existing draft invoice +def send_draft_invoice(access_token, invoice_id, subject, note, additional_recipients): + url = f"https://api-m.sandbox.paypal.com/v2/invoicing/invoices/{invoice_id}/send" + headers = {"Content-Type": "application/json", "Authorization": f"Bearer {access_token}"} + data = { + "subject": subject, + "note": note, + "send_to_recipient": True, + "additional_recipients": additional_recipients, + "send_to_invoicer": False, + } + response = requests.post(url, headers=headers, json=data) + return response.json() + + +# Main function +def main(): + parser = argparse.ArgumentParser(description="PayPal Invoice Actions") + parser.add_argument("action", help="Action to perform: create_draft or send_draft") + parser.add_argument("--invoice_id", help="Invoice ID (required for send_draft)") + parser.add_argument("--subject", help="Subject for the invoice email") + parser.add_argument("--note", help="Note for the invoice email") + parser.add_argument("--additional_recipients", nargs="*", help="Additional recipients for the invoice email") + args = parser.parse_args() + + CREDS = read_json("../secrets/config.json") + + client_id = CREDS.get("client_id") + secret_id = CREDS.get("client_secret") + access_token = get_paypal_token(client_id, secret_id) + + if args.action == "create_draft": + invoice_date = datetime.now().strftime("%Y-%m-%d") + term_type = "NET_30" + due_date = (datetime.now() + timedelta(days=30)).strftime("%Y-%m-%d") + result = create_draft_invoice(access_token, invoice_date, term_type, due_date) + print("Draft Invoice Created:", result) + elif args.action == "send_draft": + if not args.invoice_id: + print("Invoice ID is required for sending a draft invoice.") + return + result = send_draft_invoice(access_token, args.invoice_id, args.subject, args.note, args.additional_recipients) + print("Draft Invoice Sent:", result) + else: + print("Invalid action specified") + + +if __name__ == "__main__": + main() diff --git a/airbyte-integrations/connectors/source-paypal-transaction/bin/payments_generator.py b/airbyte-integrations/connectors/source-paypal-transaction/bin/payments_generator.py new file mode 100644 index 000000000000..6a2f46c3b524 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/bin/payments_generator.py @@ -0,0 +1,106 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + +# REQUIREMENTS: +# 1. Put your sandbox credentials in ../secrets/config.json (Create them if it doesn't exist). +# Use the following body (change all the values): +# { +# "client_id": "YOUT_CLIENT_ID", +# "client_secret": "YOUR_SECRET_CLIENT_ID", +# "start_date": "2021-06-01T00:00:00Z", +# "end_date": "2024-06-10T00:00:00Z", +# "is_sandbox": true +# } + +# HOW TO USE: +# To create a new payment: python script_name.py create +# To update an existing product: +# python script_name.py update PAYMENT_ID '[{"op": "replace", "path": "/transactions/0/amount", "value": {"total": "50.00", "currency": "USD"}}]' +# +# NOTE: This is version does not work for CREATE PAYMENT as the HEADER requires data I can't get +# +# You may need to add a security context, but you need the proper set of permissions in your account to be able to send this context +# security_context = '{"actor":{"account_number":"","party_id":"","auth_claims":["AUTHORIZATION_CODE"],"auth_state":"ANONYMOUS","client_id":"zf3..4BQ0T9aw-ngFr9dm....Zx9D-Lf4"},"auth_token":"","auth_token_type":"ACCESS_TOKEN","last_validated":1393560555,"scopes":["https://api-m.sandbox.paypal.com/v1/payments/.*","https://api-m.sandbox.paypal.com/v1/vault/credit-card/.*","openid","https://uri.paypal.com/services/payments/futurepayments","https://api-m.sandbox.paypal.com/v1/vault/credit-card","https://api-m.sandbox.paypal.com/v1/payments/.*"],"subjects":[{"subject":{"account_number":"","party_id":"","auth_claims":["PASSWORD"],"auth_state":"LOGGEDIN"}}]}' + + +import base64 +import json +import sys + +import requests + + +# Function to get a PayPal OAuth token +def get_paypal_token(client_id, secret_id): + url = "https://api-m.sandbox.paypal.com/v1/oauth2/token" + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "Authorization": "Basic " + base64.b64encode(f"{client_id}:{secret_id}".encode()).decode(), + } + payload = {"grant_type": "client_credentials"} + response = requests.post(url=url, data=payload, headers=headers) + return response.json().get("access_token") + + +def create_payment(token, security_context): + """Create a PayPal payment.""" + url = "https://api-m.paypal.com/v1/payments/payment" + headers = { + "Content-Type": "application/json", + # "Authorization": f"Bearer {token}", + "X-PAYPAL-SECURITY-CONTEXT": security_context, + } + payload = { + "intent": "sale", + "transactions": [ + { + "amount": {"total": "30.00", "currency": "USD", "details": {"subtotal": "30.00"}}, + "description": "This is a test - Pines test.", + "item_list": { + "items": [{"name": "My item", "sku": "123445667", "price": "15.00", "currency": "USD", "quantity": 2}], + }, + } + ], + "payer": {"payment_method": "paypal"}, + "redirect_urls": {"return_url": "https://example.com/return", "cancel_url": "https://example.com/cancel"}, + } + + response = requests.post(url, headers=headers, json=payload) + return response.json() + + +def update_payment(token, payment_id, updates): + """Update a PayPal payment.""" + url = f"https://api-m.paypal.com/v1/payments/payment/{payment_id}" + headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"} + response = requests.patch(url, headers=headers, json=updates) + return response.json() + + +def read_json(filepath): + with open(filepath, "r") as f: + return json.loads(f.read()) + + +def main(): + + CREDS = read_json("../secrets/config.json") + client_id = CREDS.get("client_id") + secret_id = CREDS.get("client_secret") + token = get_paypal_token(client_id, secret_id) + + if sys.argv[1] == "create": + payment = create_payment(token, security_context) + print("Created Payment:", payment) + + elif sys.argv[1] == "update": + payment_id = sys.argv[2] + updates = json.loads(sys.argv[3]) # Expecting JSON string as the third argument + update_response = update_payment(token, payment_id, updates) + print("Update Response:", update_response) + + else: + print("Invalid command. Use 'create' or 'update'.") + + +if __name__ == "__main__": + main() diff --git a/airbyte-integrations/connectors/source-paypal-transaction/bin/paypal_transaction_generator.py b/airbyte-integrations/connectors/source-paypal-transaction/bin/paypal_transaction_generator.py index 8fa96fae513f..d8067ec1e2bf 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/bin/paypal_transaction_generator.py +++ b/airbyte-integrations/connectors/source-paypal-transaction/bin/paypal_transaction_generator.py @@ -6,7 +6,18 @@ # REQUIREMENTS: # 1. sudo apt-get install chromium-chromedriver # 2. pip install selenium -# 3. ../secrets/creds.json with buyers email/password and account client_id/secret +# 3. ../secrets/config.json with buyers email/password and account client_id/secret +# { +# "client_id": "YOUT_CLIENT_ID", +# "client_secret": "YOUR_SECRET_CLIENT_ID", +# "start_date": "2021-06-01T00:00:00Z", +# "end_date": "2024-06-10T00:00:00Z", +# "is_sandbox": true, +# "buyer_username": "", #This could be also your test Sandbox email generated by the system +# "buyer_password": "", #This could be also your test Sandbox pawd generated by the system +# "payer_id": "" # This is the Account ID, yours or your Sandbox generated user + +# } # HOW TO USE: # python paypal_transaction_generator.py - will generate 3 transactions by default @@ -95,7 +106,7 @@ def read_json(filepath): def get_api_token(): client_id = CREDS.get("client_id") - secret = CREDS.get("secret") + secret = CREDS.get("client_secret") token_refresh_endpoint = "https://api-m.sandbox.paypal.com/v1/oauth2/token" data = "grant_type=client_credentials" @@ -103,7 +114,7 @@ def get_api_token(): auth = (client_id, secret) response = requests.request(method="POST", url=token_refresh_endpoint, data=data, headers=headers, auth=auth) response_json = response.json() - # print(response_json) + print("RESPONSE -->", response_json) API_TOKEN = response_json["access_token"] return API_TOKEN @@ -142,15 +153,16 @@ def make_payment(): # APPROVE PAYMENT def login(): - driver = webdriver.Chrome("/usr/bin/chromedriver") + # driver = webdriver.Chrome("/usr/bin/chromedriver") + driver = webdriver.Chrome() # SIGN_IN driver.get("https://www.sandbox.paypal.com/ua/signin") - driver.find_element_by_id("email").send_keys(CREDS["buyer_username"]) - driver.find_element_by_id("btnNext").click() + driver.find_element(By.ID, "email").send_keys(CREDS["buyer_username"]) + driver.find_element(By.ID, "btnNext").click() sleep(2) - driver.find_element_by_id("password").send_keys(CREDS["buyer_password"]) - driver.find_element_by_id("btnLogin").click() + driver.find_element(By.ID, "password").send_keys(CREDS["buyer_password"]) + driver.find_element(By.ID, "btnLogin").click() return driver @@ -160,13 +172,14 @@ def approve_payment(driver, url): sleep(3) if not cookies_accepted: - cookies = driver.find_element_by_id("acceptAllButton") - if cookies: - cookies.click() + try: + cookies_button = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "acceptAllButton"))) + cookies_button.click() + cookies_accepted = True + except Exception as e: + print("Could not find the accept all cookies button, exception:", e) - cookies_accepted = True driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") - element = WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.ID, "payment-submit-btn"))) sleep(1) element.click() @@ -180,14 +193,26 @@ def approve_payment(driver, url): def execute_payment(url): - response = requests.request(method="POST", url=url, data='{"payer_id": "ZE5533HZPGMC6"}', headers=headers) - response_json = response.json() - print(f'Payment executed: {url} with STATE: {response_json["state"]}') + try: + # Attempt to make the POST request + response = requests.post(url, data=json.dumps({"payer_id": CREDS.get("payer_id")}), headers=headers) + response_json = response.json() + # Check if the request was successful + if response.status_code == 200: + print(f"Your payment has been successfully executed to {url} with STATE: {response_json['state']}") + else: + # If the response code is not 200, print the error message + print( + f"Your payment execution was not successful. You got {response.status_code} with message {response.json().get('message', 'No message available')}." + ) + except requests.exceptions.RequestException as e: + # If an error occurs during the request, print the error + print(f"An error occurred: {e}") TOTAL_TRANSACTIONS = int(sys.argv[1]) if len(sys.argv) > 1 else 3 -CREDS = read_json("../secrets/creds.json") +CREDS = read_json("../secrets/config.json") headers = {"Authorization": f"Bearer {get_api_token()}", "Content-Type": "application/json"} driver = login() cookies_accepted = False diff --git a/airbyte-integrations/connectors/source-paypal-transaction/bin/product_catalog.py b/airbyte-integrations/connectors/source-paypal-transaction/bin/product_catalog.py new file mode 100755 index 000000000000..9ad9a7553814 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/bin/product_catalog.py @@ -0,0 +1,115 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + +# +# REQUIREMENTS: +# 1. Put your sandbox credentials in ../secrets/config.json (Create them if it doesn't exist). +# Use the following body (change all the values): +# { +# "client_id": "YOUT_CLIENT_ID", +# "client_secret": "YOUR_SECRET_CLIENT_ID", +# "start_date": "2021-06-01T00:00:00Z", +# "end_date": "2024-06-10T00:00:00Z", +# "is_sandbox": true +# } + +# HOW TO USE: +# To create a new product: +# python product_catalog.py --action create --description "This is a test product" --category TRAVEL +# To update an existing product: +# python product_catalog.py --action update --product_id PRODUCT_ID --update_payload '[{"op": "replace", "path": "/description", "value": "My Update. Does it changes it?"}]' +# The CATEGORY must be one of the listed in this page: https://developer.paypal.com/docs/api/catalog-products/v1/#products_create +# NOTE: This is version one, it conly creates 1 product at a time. This has not been parametrized +# TODO: Generate N products in one run. + +import argparse +import base64 +import json +import random +import string + +import requests + + +def read_json(filepath): + with open(filepath, "r") as f: + return json.loads(f.read()) + + +def generate_random_string(length=10): + """Generate a random string of fixed length.""" + letters = string.ascii_letters + return "".join(random.choice(letters) for i in range(length)) + + +def get_paypal_token(client_id, secret_id): + """Get a bearer token from PayPal.""" + url = "https://api-m.sandbox.paypal.com/v1/oauth2/token" + headers = { + "Content-Type": "application/x-www-form-urlencoded", + "Authorization": "Basic " + base64.b64encode(f"{client_id}:{secret_id}".encode()).decode(), + } + payload = {"grant_type": "client_credentials"} + response = requests.post(url=url, data=payload, headers=headers) + return response.json().get("access_token") + + +def create_paypal_product(access_token, description="Cotton XL", category="clothing"): + """Create a product in PayPal.""" + url = "https://api-m.sandbox.paypal.com/v1/catalogs/products" + headers = {"Content-Type": "application/json", "Authorization": f"Bearer {access_token}"} + payload = { + "name": "Pines-T-Shirt-" + generate_random_string(5), + "type": "PHYSICAL", + "id": generate_random_string(10), + "description": description, + "category": category, + "image_url": "https://example.com/gallary/images/" + generate_random_string(10) + ".jpg", + "home_url": "https://example.com/catalog/" + generate_random_string(10) + ".jpg", + } + response = requests.post(url=url, json=payload, headers=headers) + return response.json() + + +def update_paypal_product(access_token, product_id, updates): + """Update a product in PayPal.""" + url = f"https://api-m.sandbox.paypal.com/v1/catalogs/products/{product_id}" + headers = {"Content-Type": "application/json", "Authorization": f"Bearer {access_token}"} + response = requests.patch(url=url, json=updates, headers=headers) + if response.status_code == 204: + print(f"Update Successful. Response {response.status_code}. This succesful repsonse has no response body") + return None + else: + print(f"Error: {response.status_code}, {response.text}") + return None + + +# Parse command line arguments +parser = argparse.ArgumentParser(description="Create or Update a PayPal Product.") +parser.add_argument("--action", choices=["create", "update"], required=True, help="Action to perform: create or update") +parser.add_argument("--description", help="Product description for create action", required=True) +parser.add_argument("--category", help="Product category for create action", required=True) +parser.add_argument("--product_id", help="Product ID for update action", required=True) +parser.add_argument("--update_payload", help="Operation for update action", required=True) + +args = parser.parse_args() + +# Common setup +CREDS = read_json("../secrets/config.json") +client_id = CREDS.get("client_id") +secret_id = CREDS.get("client_secret") +access_token = get_paypal_token(client_id, secret_id) + +# Perform action based on arguments +if args.action == "create": + product = create_paypal_product(access_token, args.description, args.category) + print("Created product:", product) +elif args.action == "update" and args.product_id and args.update_payload: + try: + # updates = [{"op": "replace", "path": "/description", "value": "My Update. Does it changes it?"}] + operations = json.loads(args.update_payload) + product = update_paypal_product(access_token, args.product_id, operations) + print("Updated product:", product) + except json.JSONDecodeError: + print(f"Invalid JSON in update payload") +else: + print("Invalid arguments") diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog.json index e0992dea17b0..0c7e6869f3a9 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog.json +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog.json @@ -20,6 +20,58 @@ }, "sync_mode": "incremental", "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "list_products", + "json_schema": {}, + "source_defined_cursor": false, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "show_product_details", + "json_schema": {}, + "source_defined_cursor": false, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "append" + }, + { + "stream": { + "name": "list_disputes", + "json_schema": {}, + "source_defined_cursor": true, + "default_cursor_field": ["update_time_cut"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "append" + }, + { + "stream": { + "name": "search_invoices", + "json_schema": {}, + "source_defined_cursor": false, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "append" + }, + { + "stream": { + "name": "list_payments", + "json_schema": {}, + "source_defined_cursor": true, + "default_cursor_field": ["update_time"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "append" } ] } diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_disputes.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_disputes.json new file mode 100644 index 000000000000..ce3ee289234a --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_disputes.json @@ -0,0 +1,15 @@ +{ + "streams": [ + { + "stream": { + "name": "list_disputes", + "json_schema": {}, + "source_defined_cursor": true, + "default_cursor_field": ["update_time_cut"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "append" + } + ] +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_payments.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_payments.json new file mode 100644 index 000000000000..07cca1e51c96 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_payments.json @@ -0,0 +1,15 @@ +{ + "streams": [ + { + "stream": { + "name": "list_payments", + "json_schema": {}, + "source_defined_cursor": true, + "default_cursor_field": ["update_time"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "append" + } + ] +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_products.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_products.json new file mode 100644 index 000000000000..2fc44b85cdb7 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_list_products.json @@ -0,0 +1,14 @@ +{ + "streams": [ + { + "stream": { + "name": "list_products", + "json_schema": {}, + "source_defined_cursor": false, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "overwrite" + } + ] +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_search_invoices.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_search_invoices.json new file mode 100644 index 000000000000..32b0401ece61 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_search_invoices.json @@ -0,0 +1,14 @@ +{ + "streams": [ + { + "stream": { + "name": "search_invoices", + "json_schema": {}, + "default_cursor_field": ["invoice_updated_date"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "append" + } + ] +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_show_product_details.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_show_product_details.json new file mode 100644 index 000000000000..556bfd63366a --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/configured_catalog_show_product_details.json @@ -0,0 +1,14 @@ +{ + "streams": [ + { + "stream": { + "name": "show_product_details", + "json_schema": {}, + "source_defined_cursor": false, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "append" + } + ] +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/expected_records.jsonl b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/expected_records.jsonl deleted file mode 100644 index 86cbdca7392b..000000000000 --- a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/expected_records.jsonl +++ /dev/null @@ -1 +0,0 @@ -{"stream": "balances", "data": {"balances": [{"currency": "USD", "primary": true, "total_balance": {"currency_code": "USD", "value": "0.00"}, "available_balance": {"currency_code": "USD", "value": "0.00"}, "withheld_balance": {"currency_code": "USD", "value": "0.00"}}], "account_id": "QJQSC8WXYCA2L", "as_of_time": "2021-07-03T00:00:00Z", "last_refresh_time": "2023-09-18T13:29:59Z"}, "emitted_at": 1695051482452} \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/expected_records_sandbox.jsonl b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/expected_records_sandbox.jsonl deleted file mode 100644 index da4775fecc29..000000000000 --- a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/expected_records_sandbox.jsonl +++ /dev/null @@ -1,4 +0,0 @@ -{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "23N61105X92314351", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-04T17:13:23+0000", "transaction_updated_date": "2021-07-04T17:13:23+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "202.58"}, "available_balance": {"currency_code": "USD", "value": "202.58"}, "invoice_id": "48787580055", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "48787580055"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "48787580055"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-04T17:13:23Z", "transaction_id": "23N61105X92314351"}, "emitted_at": 1694795587519} -{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "1FN09943JY662130R", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T22:56:54+0000", "transaction_updated_date": "2021-07-05T22:56:54+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "231.52"}, "available_balance": {"currency_code": "USD", "value": "231.52"}, "invoice_id": "65095789448", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "65095789448"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "65095789448"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T22:56:54Z", "transaction_id": "1FN09943JY662130R"}, "emitted_at": 1694795587522} -{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "0M443597T0019954R", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:01:13+0000", "transaction_updated_date": "2021-07-05T23:01:13+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "260.46"}, "available_balance": {"currency_code": "USD", "value": "260.46"}, "invoice_id": "41468340464", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "41468340464"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "41468340464"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:01:13Z", "transaction_id": "0M443597T0019954R"}, "emitted_at": 1694795587524} -{"stream": "balances", "data": {"balances": [{"currency": "USD", "primary": true, "total_balance": {"currency_code": "USD", "value": "173.64"}, "available_balance": {"currency_code": "USD", "value": "173.64"}, "withheld_balance": {"currency_code": "USD", "value": "0.00"}}], "account_id": "MDXWPD67GEP5W", "as_of_time": "2021-07-03T00:00:00Z", "last_refresh_time": "2023-09-18T08:59:59Z"}, "emitted_at": 1695051579296} \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/full_refresh_catalog.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/full_refresh_catalog.json new file mode 100644 index 000000000000..b50a9c88795a --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/full_refresh_catalog.json @@ -0,0 +1,47 @@ +{ + "streams": [ + { + "stream": { + "name": "transactions", + "json_schema": {}, + "source_defined_cursor": true, + "default_cursor_field": ["transaction_updated_date"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "list_disputes", + "json_schema": {}, + "source_defined_cursor": true, + "default_cursor_field": ["update_time_cut"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "append" + }, + { + "stream": { + "name": "search_invoices", + "json_schema": {}, + "source_defined_cursor": false, + "supported_sync_modes": ["full_refresh"] + }, + "sync_mode": "full_refresh", + "destination_sync_mode": "append" + }, + { + "stream": { + "name": "list_payments", + "json_schema": {}, + "source_defined_cursor": true, + "default_cursor_field": ["update_time"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "append" + } + ] +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/incremental_catalog.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/incremental_catalog.json new file mode 100644 index 000000000000..4d75f9e3b060 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/incremental_catalog.json @@ -0,0 +1,47 @@ +{ + "streams": [ + { + "stream": { + "name": "transactions", + "json_schema": {}, + "source_defined_cursor": true, + "default_cursor_field": ["transaction_updated_date"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "balances", + "json_schema": {}, + "default_cursor_field": ["as_of_time"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "overwrite" + }, + { + "stream": { + "name": "list_disputes", + "json_schema": {}, + "source_defined_cursor": true, + "default_cursor_field": ["update_time_cut"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "append" + }, + { + "stream": { + "name": "list_payments", + "json_schema": {}, + "source_defined_cursor": true, + "default_cursor_field": ["update_time"], + "supported_sync_modes": ["full_refresh", "incremental"] + }, + "sync_mode": "incremental", + "destination_sync_mode": "append" + } + ] +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/invalid_config_oauth.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/invalid_config_oauth.json deleted file mode 100644 index 771ae5dbac0a..000000000000 --- a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/invalid_config_oauth.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "credentials": { - "auth_type": "oauth2.0", - "client_id": "AWA__", - "client_secret": "ENC__", - "refresh_token": "__" - }, - "start_date": "2021-07-03T00:00:00+00:00", - "end_date": "2021-07-04T23:59:59+00:00", - "is_sandbox": false -} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_config.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_config.json deleted file mode 100644 index 11d8539eeb3f..000000000000 --- a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "client_id": "PAYPAL_CLIENT_ID", - "client_secret": "PAYPAL_SECRET", - "start_date": "2021-06-01T00:00:00+00:00", - "is_sandbox": false -} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/abnormal_state.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/abnormal_state.json similarity index 50% rename from airbyte-integrations/connectors/source-paypal-transaction/integration_tests/abnormal_state.json rename to airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/abnormal_state.json index dc44c707ad24..2465b3a531dc 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/abnormal_state.json +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/abnormal_state.json @@ -20,5 +20,27 @@ "name": "transactions" } } + }, + { + "type": "STREAM", + "stream": { + "stream_state": { + "update_time": "2033-06-09T00:00:00Z" + }, + "stream_descriptor": { + "name": "list_payments" + } + } + }, + { + "type": "STREAM", + "stream": { + "stream_state": { + "updated_time_cut": "2033-06-09T00:00:00.000Z" + }, + "stream_descriptor": { + "name": "list_disputes" + } + } } ] diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/expected_records.jsonl b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/expected_records.jsonl new file mode 100644 index 000000000000..dfc00c24767c --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/expected_records.jsonl @@ -0,0 +1,16 @@ +{"stream": "transactions", "data": {"transaction_info": {"transaction_id": "69B759611M2733128","transaction_event_code": "T1503","transaction_initiation_date": "2024-02-01T00:01:23+0000","transaction_updated_date": "2024-02-01T00:01:23+0000","transaction_amount": {"currency_code": "USD","value": "-60.75"},"transaction_status": "S","ending_balance": {"currency_code": "USD","value": "309800.06"},"available_balance": {"currency_code": "USD","value": "309800.06"},"protection_eligibility": "02"},"payer_info": {"address_status": "N","payer_name": {}},"shipping_info": {},"cart_info": {},"store_info": {},"auction_info": {},"incentive_info": {}}, "emitted_at": 1695051482452} +{"stream": "transactions", "data": {"transaction_info": {"transaction_id": "1N809273356042704","transaction_event_code": "T0001","transaction_initiation_date": "2024-02-01T00:01:24+0000","transaction_updated_date": "2024-02-01T00:01:24+0000","transaction_amount": {"currency_code": "USD","value": "-10.00"},"fee_amount": {"currency_code": "USD","value": "-0.25"},"transaction_status": "P","transaction_subject": "You have a payout!","transaction_note": "Thanks for your patronage!","ending_balance": {"currency_code": "USD","value": "309789.81"},"available_balance": {"currency_code": "USD","value": "309789.81"},"custom_field": "201403140001","protection_eligibility": "02"},"payer_info": {"email_address": "Alexa.Dietrich@gmail.com","address_status": "N","payer_name": {}},"shipping_info": {"name": "John, Merchant"},"cart_info": {},"store_info": {},"auction_info": {},"incentive_info": {}}, "emitted_at": 1695052482453} +{"stream": "transactions", "data": {"transaction_info": {"transaction_id": "70B03706PU258313Y","paypal_reference_id": "1N809273356042704","paypal_reference_id_type": "TXN","transaction_event_code": "T1105","transaction_initiation_date": "2024-02-01T00:01:24+0000","transaction_updated_date": "2024-02-01T00:01:24+0000","transaction_amount": {"currency_code": "USD","value": "10.25"},"transaction_status": "S","transaction_subject": "You have a payout!","transaction_note": "Thanks for your patronage!","ending_balance": {"currency_code": "USD","value": "309800.06"},"available_balance": {"currency_code": "USD","value": "309800.06"},"protection_eligibility": "02"},"payer_info": {"address_status": "N","payer_name": {}},"shipping_info": {},"cart_info": {},"store_info": {},"auction_info": {},"incentive_info": {}}, "emitted_at": 1695053482454} +{"stream": "transactions", "data": {"transaction_info": {"transaction_id": "60D327402F0012324","transaction_event_code": "T0001","transaction_initiation_date": "2024-02-01T00:01:24+0000","transaction_updated_date": "2024-02-01T00:01:24+0000","transaction_amount": {"currency_code": "USD","value": "-20.00"},"fee_amount": {"currency_code": "USD","value": "-0.25"},"transaction_status": "P","transaction_subject": "You have a payout!","transaction_note": "Thanks for your support!","ending_balance": {"currency_code": "USD","value": "309779.81"},"available_balance": {"currency_code": "USD","value": "309779.81"},"custom_field": "201403140002","protection_eligibility": "02"},"payer_info": {"address_status": "N","payer_name": {}},"shipping_info": {"name": "John, Merchant"},"cart_info": {},"store_info": {},"auction_info": {},"incentive_info": {}}, "emitted_at": 1695054482455} +{"stream": "balances", "data": {"balances":[{"currency":"CHF","total_balance":{"currency_code":"CHF","value":"1001.19"},"available_balance":{"currency_code":"CHF","value":"1001.19"},"withheld_balance":{"currency_code":"CHF","value":"0.00"}},{"currency":"HKD","total_balance":{"currency_code":"HKD","value":"10833.47"},"available_balance":{"currency_code":"HKD","value":"10833.47"},"withheld_balance":{"currency_code":"HKD","value":"0.00"}},{"currency":"TWD","total_balance":{"currency_code":"TWD","value":"6289.00"},"available_balance":{"currency_code":"TWD","value":"6289.00"},"withheld_balance":{"currency_code":"TWD","value":"0.00"}},{"currency":"MXN","total_balance":{"currency_code":"MXN","value":"3827706.05"},"available_balance":{"currency_code":"MXN","value":"3827706.05"},"withheld_balance":{"currency_code":"MXN","value":"0.00"}},{"currency":"EUR","total_balance":{"currency_code":"EUR","value":"418736.68"},"available_balance":{"currency_code":"EUR","value":"418736.68"},"withheld_balance":{"currency_code":"EUR","value":"0.00"}},{"currency":"USD","primary":true,"total_balance":{"currency_code":"USD","value":"309860.81"},"available_balance":{"currency_code":"USD","value":"309860.81"},"withheld_balance":{"currency_code":"USD","value":"0.00"}},{"currency":"CAD","total_balance":{"currency_code":"CAD","value":"1158.92"},"available_balance":{"currency_code":"CAD","value":"1158.92"},"withheld_balance":{"currency_code":"CAD","value":"0.00"}},{"currency":"NOK","total_balance":{"currency_code":"NOK","value":"0.85"},"available_balance":{"currency_code":"NOK","value":"0.85"},"withheld_balance":{"currency_code":"NOK","value":"0.00"}},{"currency":"THB","total_balance":{"currency_code":"THB","value":"96658.02"},"available_balance":{"currency_code":"THB","value":"96658.02"},"withheld_balance":{"currency_code":"THB","value":"0.00"}},{"currency":"AUD","total_balance":{"currency_code":"AUD","value":"2405.19"},"available_balance":{"currency_code":"AUD","value":"2405.19"},"withheld_balance":{"currency_code":"AUD","value":"0.00"}},{"currency":"ILS","total_balance":{"currency_code":"ILS","value":"0.00"},"available_balance":{"currency_code":"ILS","value":"0.00"},"withheld_balance":{"currency_code":"ILS","value":"0.00"}},{"currency":"SGD","total_balance":{"currency_code":"SGD","value":"5841.51"},"available_balance":{"currency_code":"SGD","value":"5841.51"},"withheld_balance":{"currency_code":"SGD","value":"0.00"}},{"currency":"JPY","total_balance":{"currency_code":"JPY","value":"45608"},"available_balance":{"currency_code":"JPY","value":"45608"},"withheld_balance":{"currency_code":"JPY","value":"0"}},{"currency":"PLN","total_balance":{"currency_code":"PLN","value":"621.42"},"available_balance":{"currency_code":"PLN","value":"621.42"},"withheld_balance":{"currency_code":"PLN","value":"0.00"}},{"currency":"GBP","total_balance":{"currency_code":"GBP","value":"671250.65"},"available_balance":{"currency_code":"GBP","value":"671250.65"},"withheld_balance":{"currency_code":"GBP","value":"0.00"}},{"currency":"HUF","total_balance":{"currency_code":"HUF","value":"0.00"},"available_balance":{"currency_code":"HUF","value":"0.00"},"withheld_balance":{"currency_code":"HUF","value":"0.00"}},{"currency":"SEK","total_balance":{"currency_code":"SEK","value":"90.92"},"available_balance":{"currency_code":"SEK","value":"90.92"},"withheld_balance":{"currency_code":"SEK","value":"0.00"}},{"currency":"NZD","total_balance":{"currency_code":"NZD","value":"813.27"},"available_balance":{"currency_code":"NZD","value":"813.27"},"withheld_balance":{"currency_code":"NZD","value":"0.00"}},{"currency":"PHP","total_balance":{"currency_code":"PHP","value":"291489.92"},"available_balance":{"currency_code":"PHP","value":"291489.92"},"withheld_balance":{"currency_code":"PHP","value":"0.00"}},{"currency":"BRL","total_balance":{"currency_code":"BRL","value":"0.00"},"available_balance":{"currency_code":"BRL","value":"0.00"},"withheld_balance":{"currency_code":"BRL","value":"0.00"}},{"currency":"RUB","total_balance":{"currency_code":"RUB","value":"274.53"},"available_balance":{"currency_code":"RUB","value":"274.53"},"withheld_balance":{"currency_code":"RUB","value":"0.00"}}],"account_id":"C7CYMKZDG8D6E","as_of_time":"2024-02-01T00:00:00Z","last_refresh_time":"2024-02-05T17:59:59Z"}, "emitted_at": 1695051579296} +{"stream": "list_disputes", "data": {"dispute_id":"PP-R-PNP-10089600","create_time":"2024-01-26T15:31:02.000Z","update_time":"2024-02-04T12:06:03.000Z","disputed_transactions":[{"buyer_transaction_id":"5CW48839XK1160452","seller":{"merchant_id":"C7CYMKZDG8D6E"}}],"reason":"MERCHANDISE_OR_SERVICE_NOT_RECEIVED","status":"RESOLVED","dispute_state":"RESOLVED","dispute_amount":{"currency_code":"USD","value":"40.00"},"dispute_life_cycle_stage":"INQUIRY","dispute_channel":"INTERNAL","outcome":"LOST","links":[{"href":"https://api-m.sandbox.paypal.com/v1/customer/disputes/PP-R-PNP-10089600","rel":"self","method":"GET"}]}, "emitted_at": 1695051579296} +{"stream": "list_products", "data": {"id": "1647236710","name": "Blue M","description": "Blue M","create_time": "2022-03-14T05:45:06Z","links": [{"href": "https://api.sandbox.paypal.com/v1/catalogs/products/1647236710","rel": "self","method": "GET"}]}, "emitted_at": 1695051579296} +{"stream": "list_products", "data": {"id": "1647236727","name": "Licenza Oro","create_time": "2022-03-14T05:45:23Z","links": [{"href": "https://api.sandbox.paypal.com/v1/catalogs/products/1647236727","rel": "self","method": "GET"}]}, "emitted_at": 1695051579396} +{"stream": "list_products", "data": {"id": "1647285840","name": "Licenza Premium","create_time": "2022-03-14T19:24:00Z","links": [{"href": "https://api.sandbox.paypal.com/v1/catalogs/products/1647285840","rel": "self","method": "GET"}]}, "emitted_at": 1695051579496} +{"stream": "list_products", "data": {"id": "1647288288","name": "T-Shirt","description": "Blue M","create_time": "2022-03-14T20:04:47Z","links": [{"href": "https://api.sandbox.paypal.com/v1/catalogs/products/1647288288","rel": "self","method": "GET"}]}, "emitted_at": 1695051579596} +{"stream": "search_invoices", "data": {"id":"INV2-BGPS-PKE7-6XSD-YWC7","status":"DRAFT","detail":{"currency_code":"USD","invoice_number":"1706813643331","invoice_date":"2023-12-14","viewed_by_recipient":false,"group_draft":false,"metadata":{"create_time":"2024-02-01T18:54:03Z"}},"primary_recipients":[{"billing_info":{"name":{"given_name":"Shehroz","surname":"Asmat","full_name":"Shehroz Asmat"},"email_address":"sasmat@trythunderbird.com"}}],"amount":{"currency_code":"USD","value":"50.00"},"due_amount":{"currency_code":"USD","value":"50.00"},"links":[{"href":"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-BGPS-PKE7-6XSD-YWC7","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-BGPS-PKE7-6XSD-YWC7/send","rel":"send","method":"POST"},{"href":"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-BGPS-PKE7-6XSD-YWC7","rel":"replace","method":"PUT"},{"href":"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-BGPS-PKE7-6XSD-YWC7","rel":"delete","method":"DELETE"},{"href":"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-BGPS-PKE7-6XSD-YWC7/payments","rel":"record-payment","method":"POST"}],"unilateral":false}, "emitted_at": 1695051679296} +{"stream": "search_invoices", "data": {"id":"INV2-6GP9-WLLD-6Q7K-ZYQ2","status":"DRAFT","detail":{"reference":"","currency_code":"USD","note":"","memo":"","invoice_number":"0042","invoice_date":"2022-02-04","payment_term":{"due_date":"2022-02-14"},"viewed_by_recipient":false,"group_draft":false,"metadata":{"create_time":"2024-02-01T11:01:58Z"}},"primary_recipients":[{"billing_info":{"name":{"given_name":"Stephanie","surname":"Meyers","full_name":"Stephanie Meyers"},"email_address":"sb-yww0b28455377@personal.example.com"},"shipping_info":{"name":{"given_name":"Stephanie","surname":"Meyers","full_name":"Stephanie Meyers"}}}],"amount":{"currency_code":"USD","value":"74.21"},"due_amount":{"currency_code":"USD","value":"74.21"},"links":[{"href":"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-6GP9-WLLD-6Q7K-ZYQ2","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-6GP9-WLLD-6Q7K-ZYQ2/send","rel":"send","method":"POST"},{"href":"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-6GP9-WLLD-6Q7K-ZYQ2","rel":"replace","method":"PUT"},{"href":"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-6GP9-WLLD-6Q7K-ZYQ2","rel":"delete","method":"DELETE"},{"href":"https://api.sandbox.paypal.com/v2/invoicing/invoices/INV2-6GP9-WLLD-6Q7K-ZYQ2/payments","rel":"record-payment","method":"POST"}],"unilateral":false}, "emitted_at": 1695051779296} +{"stream": "list_payments", "data": {"id":"PAYID-MW55RCA31D103955T218492B","intent":"sale","state":"approved","cart":"06J27273EH485262V","payer":{"payment_method":"paypal","status":"VERIFIED","payer_info":{"email":"sb-vxpcr15413769@personal.example.com","first_name":"John","last_name":"Doe","payer_id":"TWL7BJVYNS7GU","shipping_address":{"recipient_name":"John Doe","line1":"1 Main St","city":"San Jose","state":"CA","postal_code":"95131","country_code":"US"},"phone":"4083068029","country_code":"US"}},"transactions":[{"reference_id":"1000000000047","amount":{"total":"343.80","currency":"USD","details":{"subtotal":"343.80","shipping":"0.00","insurance":"0.00","handling_fee":"0.00","shipping_discount":"0.00","discount":"0.00"}},"payee":{"merchant_id":"C7CYMKZDG8D6E","email":"john_merchant@example.com"},"item_list":{"shipping_address":{"recipient_name":"John Doe","line1":"1 Main St","city":"San Jose","state":"CA","postal_code":"95131","country_code":"US"}},"related_resources":[{"sale":{"id":"7PE037460E080360M","state":"completed","amount":{"total":"343.80","currency":"USD","details":{"subtotal":"343.80","shipping":"0.00","insurance":"0.00","handling_fee":"0.00","shipping_discount":"0.00","discount":"0.00"}},"payment_mode":"INSTANT_TRANSFER","protection_eligibility":"ELIGIBLE","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","transaction_fee":{"value":"12.49","currency":"USD"},"purchase_unit_reference_id":"1000000000047","parent_payment":"PAYID-MW55RCA31D103955T218492B","create_time":"2024-02-01T17:44:40Z","update_time":"2024-02-01T17:44:40Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/sale/7PE037460E080360M","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/sale/7PE037460E080360M/refund","rel":"refund","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW55RCA31D103955T218492B","rel":"parent_payment","method":"GET"}]}}]}],"create_time":"2024-02-01T17:44:40Z","update_time":"2024-02-01T17:44:40Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW55RCA31D103955T218492B","rel":"self","method":"GET"}]}, "emitted_at": 1695051779296} +{"stream": "list_payments", "data": {"id":"PAYID-MW53UPA6UB45753B0034831X","intent":"sale","state":"approved","cart":"9A220393SG7753433","payer":{"payment_method":"paypal","status":"VERIFIED","payer_info":{"email":"sb-g43l4x28821325@personal.example.com","first_name":"John","last_name":"Doe","payer_id":"889X39VDHV8QY","shipping_address":{"recipient_name":"John Doe","line1":"Via Unit? d'Italia, 5783296","city":"Napoli","state":"Napoli","postal_code":"80127","country_code":"IT"},"phone":"9393358454","country_code":"IT"}},"transactions":[{"reference_id":"default","amount":{"total":"100.00","currency":"USD","details":{"subtotal":"100.00","shipping":"0.00","insurance":"0.00","handling_fee":"0.00","shipping_discount":"0.00","discount":"0.00"}},"payee":{"merchant_id":"C7CYMKZDG8D6E","email":"john_merchant@example.com"},"description":"T-Shirt","item_list":{"items":[{"name":"T-Shirt","description":"Green XL","price":"100.00","currency":"USD","tax":"0.00","quantity":1}],"shipping_address":{"recipient_name":"John Doe","line1":"Via Unit? d'Italia, 5783296","city":"Napoli","state":"Napoli","postal_code":"80127","country_code":"IT"}},"related_resources":[{"sale":{"id":"29N28023XB153584X","state":"completed","amount":{"total":"100.00","currency":"USD","details":{"subtotal":"100.00","shipping":"0.00","insurance":"0.00","handling_fee":"0.00","shipping_discount":"0.00","discount":"0.00"}},"payment_mode":"INSTANT_TRANSFER","protection_eligibility":"ELIGIBLE","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","transaction_fee":{"value":"5.48","currency":"USD"},"receivable_amount":{"value":"100.00","currency":"USD"},"exchange_rate":"1.098848913950027","purchase_unit_reference_id":"default","parent_payment":"PAYID-MW53UPA6UB45753B0034831X","create_time":"2024-02-01T15:35:25Z","update_time":"2024-02-01T15:35:25Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/sale/29N28023XB153584X","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/sale/29N28023XB153584X/refund","rel":"refund","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW53UPA6UB45753B0034831X","rel":"parent_payment","method":"GET"}]}}]}],"create_time":"2024-02-01T15:35:24Z","update_time":"2024-02-01T15:35:25Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW53UPA6UB45753B0034831X","rel":"self","method":"GET"}]}, "emitted_at": 1695061579296} +{"stream": "list_payments", "data": {"id":"PAY-81S181868H8011217MW526OI","intent":"authorize","state":"approved","payer":{"payment_method":"paypal","status":"VERIFIED","payer_info":{"email":"mihai.streza1@mi-pay.com","first_name":"Mihai","last_name":"Streza","payer_id":"QHD3E8SRDDSQL","shipping_address":{"recipient_name":"Mihai Streza"},"phone":"07534201211","country_code":"GB"}},"transactions":[{"amount":{"total":"20.00","currency":"EUR","details":{"subtotal":"20.00"}},"payee":{"merchant_id":"C7CYMKZDG8D6E"},"description":"topup","invoice_number":"100000000188917","soft_descriptor":"PAYPAL *JOHNMERCHAN","item_list":{"items":[{"name":"topup","price":"20.00","currency":"EUR","tax":"0.00","quantity":1}],"shipping_address":{"recipient_name":"Mihai Streza"}},"related_resources":[{"authorization":{"id":"05D21713M12255848","state":"captured","amount":{"total":"20.00","currency":"EUR","details":{"subtotal":"20.00"}},"payment_mode":"INSTANT_TRANSFER","protection_eligibility":"ELIGIBLE","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","billing_agreement_id":"B-2B029484VC167663Y","parent_payment":"PAY-81S181868H8011217MW526OI","valid_until":"2024-03-01T14:48:26Z","create_time":"2024-02-01T14:48:26Z","update_time":"2024-02-01T14:48:30Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/05D21713M12255848","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/05D21713M12255848/capture","rel":"capture","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/05D21713M12255848/void","rel":"void","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/05D21713M12255848/reauthorize","rel":"reauthorize","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-81S181868H8011217MW526OI","rel":"parent_payment","method":"GET"}]}},{"capture":{"id":"546282867R0022639","amount":{"total":"20.00","currency":"EUR"},"state":"completed","custom":"","transaction_fee":{"value":"1.39","currency":"EUR"},"parent_payment":"PAY-81S181868H8011217MW526OI","invoice_number":"100000000188917","create_time":"2024-02-01T14:48:30Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/capture/546282867R0022639","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/capture/546282867R0022639/refund","rel":"refund","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/05D21713M12255848","rel":"authorization","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-81S181868H8011217MW526OI","rel":"parent_payment","method":"GET"}]}}]}],"create_time":"2024-02-01T14:48:25Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-81S181868H8011217MW526OI","rel":"self","method":"GET"}]}, "emitted_at": 1695071579296} +{"stream": "list_payments", "data": {"id":"PAY-0L38757939422510JMW5ZJVA","intent":"authorize","state":"approved","payer":{"payment_method":"paypal","status":"VERIFIED","payer_info":{"email":"mihai.streza1@mi-pay.com","first_name":"Mihai","last_name":"Streza","payer_id":"QHD3E8SRDDSQL","shipping_address":{"recipient_name":"Mihai Streza"},"phone":"07534201211","country_code":"GB"}},"transactions":[{"amount":{"total":"20.00","currency":"EUR","details":{"subtotal":"20.00"}},"payee":{"merchant_id":"C7CYMKZDG8D6E"},"description":"topup","invoice_number":"100000000188897","soft_descriptor":"PAYPAL *JOHNMERCHAN","item_list":{"items":[{"name":"topup","price":"20.00","currency":"EUR","tax":"0.00","quantity":1}],"shipping_address":{"recipient_name":"Mihai Streza"}},"related_resources":[{"authorization":{"id":"3S025738SW168153S","state":"captured","amount":{"total":"20.00","currency":"EUR","details":{"subtotal":"20.00"}},"payment_mode":"INSTANT_TRANSFER","protection_eligibility":"ELIGIBLE","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","billing_agreement_id":"B-42217126VD515152H","parent_payment":"PAY-0L38757939422510JMW5ZJVA","valid_until":"2024-03-01T12:55:48Z","create_time":"2024-02-01T12:55:48Z","update_time":"2024-02-01T12:55:51Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/3S025738SW168153S","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/3S025738SW168153S/capture","rel":"capture","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/3S025738SW168153S/void","rel":"void","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/3S025738SW168153S/reauthorize","rel":"reauthorize","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-0L38757939422510JMW5ZJVA","rel":"parent_payment","method":"GET"}]}},{"capture":{"id":"26U95072LD470800B","amount":{"total":"20.00","currency":"EUR"},"state":"completed","custom":"","transaction_fee":{"value":"1.39","currency":"EUR"},"parent_payment":"PAY-0L38757939422510JMW5ZJVA","invoice_number":"100000000188897","create_time":"2024-02-01T12:55:51Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/capture/26U95072LD470800B","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/capture/26U95072LD470800B/refund","rel":"refund","method":"POST"},{"href":"https://api.sandbox.paypal.com/v1/payments/authorization/3S025738SW168153S","rel":"authorization","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-0L38757939422510JMW5ZJVA","rel":"parent_payment","method":"GET"}]}}]}],"create_time":"2024-02-01T12:55:48Z","links":[{"href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-0L38757939422510JMW5ZJVA","rel":"self","method":"GET"}]}, "emitted_at": 1695081579296} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/expected_records_sandbox.jsonl b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/expected_records_sandbox.jsonl new file mode 100644 index 000000000000..74d573c4ee73 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/expected_records_sandbox.jsonl @@ -0,0 +1,85 @@ +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "23N61105X92314351", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-04T17:13:23+0000", "transaction_updated_date": "2021-07-04T17:13:23+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "202.58"}, "available_balance": {"currency_code": "USD", "value": "202.58"}, "invoice_id": "48787580055", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "48787580055"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "48787580055"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-04T17:13:23Z", "transaction_id": "23N61105X92314351"}, "emitted_at": 1707238889137} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "1FN09943JY662130R", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T22:56:54+0000", "transaction_updated_date": "2021-07-05T22:56:54+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "231.52"}, "available_balance": {"currency_code": "USD", "value": "231.52"}, "invoice_id": "65095789448", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "65095789448"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "65095789448"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T22:56:54Z", "transaction_id": "1FN09943JY662130R"}, "emitted_at": 1707238889139} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "0M443597T0019954R", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:01:13+0000", "transaction_updated_date": "2021-07-05T23:01:13+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "260.46"}, "available_balance": {"currency_code": "USD", "value": "260.46"}, "invoice_id": "41468340464", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "41468340464"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "41468340464"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:01:13Z", "transaction_id": "0M443597T0019954R"}, "emitted_at": 1707238889142} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "19C257131E850262B", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:02:46+0000", "transaction_updated_date": "2021-07-05T23:02:46+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "289.40"}, "available_balance": {"currency_code": "USD", "value": "289.40"}, "invoice_id": "23749371955", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "23749371955"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "23749371955"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:02:46Z", "transaction_id": "19C257131E850262B"}, "emitted_at": 1707238889144} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "6S892278N6406494Y", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:06:12+0000", "transaction_updated_date": "2021-07-05T23:06:12+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "318.34"}, "available_balance": {"currency_code": "USD", "value": "318.34"}, "invoice_id": "62173333941", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "62173333941"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "62173333941"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:06:12Z", "transaction_id": "6S892278N6406494Y"}, "emitted_at": 1707238889146} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "0T320567TS5587836", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:09:04+0000", "transaction_updated_date": "2021-07-05T23:09:04+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "347.28"}, "available_balance": {"currency_code": "USD", "value": "347.28"}, "invoice_id": "56028534885", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "56028534885"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "56028534885"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:09:04Z", "transaction_id": "0T320567TS5587836"}, "emitted_at": 1707238889148} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "3DF69605L9958744R", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:12:40+0000", "transaction_updated_date": "2021-07-05T23:12:40+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "376.22"}, "available_balance": {"currency_code": "USD", "value": "376.22"}, "invoice_id": "31766547902", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "31766547902"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "31766547902"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:12:40Z", "transaction_id": "3DF69605L9958744R"}, "emitted_at": 1707238889150} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "2F535603PS249601F", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:12:57+0000", "transaction_updated_date": "2021-07-05T23:12:57+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "405.16"}, "available_balance": {"currency_code": "USD", "value": "405.16"}, "invoice_id": "32577611997", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "32577611997"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "32577611997"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:12:57Z", "transaction_id": "2F535603PS249601F"}, "emitted_at": 1707238889153} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "243514451L952570P", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:14:02+0000", "transaction_updated_date": "2021-07-05T23:14:02+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "434.10"}, "available_balance": {"currency_code": "USD", "value": "434.10"}, "invoice_id": "23612058730", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "23612058730"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "23612058730"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:14:02Z", "transaction_id": "243514451L952570P"}, "emitted_at": 1707238889155} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "27881589Y9461861H", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:14:19+0000", "transaction_updated_date": "2021-07-05T23:14:19+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "463.04"}, "available_balance": {"currency_code": "USD", "value": "463.04"}, "invoice_id": "53296156982", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "53296156982"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "53296156982"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:14:19Z", "transaction_id": "27881589Y9461861H"}, "emitted_at": 1707238889157} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "3MG39755337297727", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:14:36+0000", "transaction_updated_date": "2021-07-05T23:14:36+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "491.98"}, "available_balance": {"currency_code": "USD", "value": "491.98"}, "invoice_id": "53235397043", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "53235397043"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "53235397043"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:14:36Z", "transaction_id": "3MG39755337297727"}, "emitted_at": 1707238889159} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "32J59182JY5989507", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:14:52+0000", "transaction_updated_date": "2021-07-05T23:14:52+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "520.92"}, "available_balance": {"currency_code": "USD", "value": "520.92"}, "invoice_id": "18208641465", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "18208641465"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "18208641465"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:14:52Z", "transaction_id": "32J59182JY5989507"}, "emitted_at": 1707238889161} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "52795774C7828234R", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:15:09+0000", "transaction_updated_date": "2021-07-05T23:15:09+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "549.86"}, "available_balance": {"currency_code": "USD", "value": "549.86"}, "invoice_id": "32274344746", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "32274344746"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "32274344746"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:15:09Z", "transaction_id": "52795774C7828234R"}, "emitted_at": 1707238889163} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "19B82038T92822940", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:15:26+0000", "transaction_updated_date": "2021-07-05T23:15:26+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "578.80"}, "available_balance": {"currency_code": "USD", "value": "578.80"}, "invoice_id": "36419288277", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "36419288277"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "36419288277"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:15:26Z", "transaction_id": "19B82038T92822940"}, "emitted_at": 1707238889166} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "61G749036D552760G", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:15:42+0000", "transaction_updated_date": "2021-07-05T23:15:42+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "607.74"}, "available_balance": {"currency_code": "USD", "value": "607.74"}, "invoice_id": "88092228645", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "88092228645"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "88092228645"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:15:42Z", "transaction_id": "61G749036D552760G"}, "emitted_at": 1707238889168} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "5EL311302L108363J", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:15:58+0000", "transaction_updated_date": "2021-07-05T23:15:58+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "636.68"}, "available_balance": {"currency_code": "USD", "value": "636.68"}, "invoice_id": "25494061224", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "25494061224"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "25494061224"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:15:58Z", "transaction_id": "5EL311302L108363J"}, "emitted_at": 1707238889170} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "3VP82838NP358133N", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:16:15+0000", "transaction_updated_date": "2021-07-05T23:16:15+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "665.62"}, "available_balance": {"currency_code": "USD", "value": "665.62"}, "invoice_id": "82173600275", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "82173600275"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "82173600275"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:16:15Z", "transaction_id": "3VP82838NP358133N"}, "emitted_at": 1707238889172} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "2N796839EY2539153", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:16:32+0000", "transaction_updated_date": "2021-07-05T23:16:32+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "694.56"}, "available_balance": {"currency_code": "USD", "value": "694.56"}, "invoice_id": "10442581967", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "10442581967"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "10442581967"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:16:32Z", "transaction_id": "2N796839EY2539153"}, "emitted_at": 1707238889174} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "5WX252723D093564T", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:23:29+0000", "transaction_updated_date": "2021-07-05T23:23:29+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "723.50"}, "available_balance": {"currency_code": "USD", "value": "723.50"}, "invoice_id": "71987080514", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "71987080514"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "71987080514"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:23:29Z", "transaction_id": "5WX252723D093564T"}, "emitted_at": 1707238889176} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "4PW76195NN227720S", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:23:40+0000", "transaction_updated_date": "2021-07-05T23:23:40+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "752.44"}, "available_balance": {"currency_code": "USD", "value": "752.44"}, "invoice_id": "93025400757", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "93025400757"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "93025400757"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:23:40Z", "transaction_id": "4PW76195NN227720S"}, "emitted_at": 1707238889178} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "0VE851712U5895412", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:23:51+0000", "transaction_updated_date": "2021-07-05T23:23:51+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "781.38"}, "available_balance": {"currency_code": "USD", "value": "781.38"}, "invoice_id": "46225965444", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "46225965444"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "46225965444"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:23:51Z", "transaction_id": "0VE851712U5895412"}, "emitted_at": 1707238889180} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "63U003588S1135607", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:29:26+0000", "transaction_updated_date": "2021-07-05T23:29:26+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "810.32"}, "available_balance": {"currency_code": "USD", "value": "810.32"}, "invoice_id": "34635559567", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "34635559567"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "34635559567"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:29:26Z", "transaction_id": "63U003588S1135607"}, "emitted_at": 1707238889182} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "2AJ081444T051123A", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:29:37+0000", "transaction_updated_date": "2021-07-05T23:29:37+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "839.26"}, "available_balance": {"currency_code": "USD", "value": "839.26"}, "invoice_id": "92544485996", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "92544485996"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "92544485996"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:29:37Z", "transaction_id": "2AJ081444T051123A"}, "emitted_at": 1707238889184} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "2KU13114TJ604181E", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:29:48+0000", "transaction_updated_date": "2021-07-05T23:29:48+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "868.20"}, "available_balance": {"currency_code": "USD", "value": "868.20"}, "invoice_id": "10184574713", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "10184574713"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "10184574713"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:29:48Z", "transaction_id": "2KU13114TJ604181E"}, "emitted_at": 1707238889186} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "1ST090036H2235215", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:31:35+0000", "transaction_updated_date": "2021-07-05T23:31:35+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "897.14"}, "available_balance": {"currency_code": "USD", "value": "897.14"}, "invoice_id": "50350860865", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "50350860865"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "50350860865"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:31:35Z", "transaction_id": "1ST090036H2235215"}, "emitted_at": 1707238889188} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "5BJ418934Y425901G", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:31:46+0000", "transaction_updated_date": "2021-07-05T23:31:46+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "926.08"}, "available_balance": {"currency_code": "USD", "value": "926.08"}, "invoice_id": "12278283055", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "12278283055"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "12278283055"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:31:46Z", "transaction_id": "5BJ418934Y425901G"}, "emitted_at": 1707238889190} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "0SD21997LN026020M", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:31:56+0000", "transaction_updated_date": "2021-07-05T23:31:56+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "955.02"}, "available_balance": {"currency_code": "USD", "value": "955.02"}, "invoice_id": "52396214250", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "52396214250"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "52396214250"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:31:56Z", "transaction_id": "0SD21997LN026020M"}, "emitted_at": 1707238889192} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "3BH630398E562901G", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:42:41+0000", "transaction_updated_date": "2021-07-05T23:42:41+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "983.96"}, "available_balance": {"currency_code": "USD", "value": "983.96"}, "invoice_id": "18793521512", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "18793521512"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "18793521512"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:42:41Z", "transaction_id": "3BH630398E562901G"}, "emitted_at": 1707238889194} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "03D88325GF8461705", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:42:52+0000", "transaction_updated_date": "2021-07-05T23:42:52+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1012.90"}, "available_balance": {"currency_code": "USD", "value": "1012.90"}, "invoice_id": "71793513892", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "71793513892"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "71793513892"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:42:52Z", "transaction_id": "03D88325GF8461705"}, "emitted_at": 1707238889196} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "51852852PL0100404", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:43:03+0000", "transaction_updated_date": "2021-07-05T23:43:03+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1041.84"}, "available_balance": {"currency_code": "USD", "value": "1041.84"}, "invoice_id": "98653187889", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "98653187889"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "98653187889"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:43:03Z", "transaction_id": "51852852PL0100404"}, "emitted_at": 1707238889198} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "8MF4324694292993B", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:44:21+0000", "transaction_updated_date": "2021-07-05T23:44:21+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1070.78"}, "available_balance": {"currency_code": "USD", "value": "1070.78"}, "invoice_id": "12489150471", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "12489150471"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "12489150471"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:44:21Z", "transaction_id": "8MF4324694292993B"}, "emitted_at": 1707238889201} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "87S73342AS6001233", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:44:32+0000", "transaction_updated_date": "2021-07-05T23:44:32+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1099.72"}, "available_balance": {"currency_code": "USD", "value": "1099.72"}, "invoice_id": "99595079917", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "99595079917"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "99595079917"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:44:32Z", "transaction_id": "87S73342AS6001233"}, "emitted_at": 1707238889203} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "112146346A741221U", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:44:44+0000", "transaction_updated_date": "2021-07-05T23:44:44+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1128.66"}, "available_balance": {"currency_code": "USD", "value": "1128.66"}, "invoice_id": "93286331651", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "93286331651"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "93286331651"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:44:44Z", "transaction_id": "112146346A741221U"}, "emitted_at": 1707238889205} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "0N2242037Y9449344", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:44:54+0000", "transaction_updated_date": "2021-07-05T23:44:54+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1157.60"}, "available_balance": {"currency_code": "USD", "value": "1157.60"}, "invoice_id": "71349988314", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "71349988314"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "71349988314"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:44:54Z", "transaction_id": "0N2242037Y9449344"}, "emitted_at": 1707238889207} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "9NH78349H0388780F", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:45:05+0000", "transaction_updated_date": "2021-07-05T23:45:05+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1186.54"}, "available_balance": {"currency_code": "USD", "value": "1186.54"}, "invoice_id": "83951023481", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "83951023481"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "83951023481"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:45:05Z", "transaction_id": "9NH78349H0388780F"}, "emitted_at": 1707238889209} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "10S137566E4828249", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:45:16+0000", "transaction_updated_date": "2021-07-05T23:45:16+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1215.48"}, "available_balance": {"currency_code": "USD", "value": "1215.48"}, "invoice_id": "88168198250", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "88168198250"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "88168198250"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:45:16Z", "transaction_id": "10S137566E4828249"}, "emitted_at": 1707238889211} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "7N749695W59419057", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:45:27+0000", "transaction_updated_date": "2021-07-05T23:45:27+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1244.42"}, "available_balance": {"currency_code": "USD", "value": "1244.42"}, "invoice_id": "38296993497", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "38296993497"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "38296993497"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:45:27Z", "transaction_id": "7N749695W59419057"}, "emitted_at": 1707238889213} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "43X058357A257931N", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:45:39+0000", "transaction_updated_date": "2021-07-05T23:45:39+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1273.36"}, "available_balance": {"currency_code": "USD", "value": "1273.36"}, "invoice_id": "33391419042", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "33391419042"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "33391419042"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:45:39Z", "transaction_id": "43X058357A257931N"}, "emitted_at": 1707238889215} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "5WL82051VY277550S", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:45:50+0000", "transaction_updated_date": "2021-07-05T23:45:50+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1302.30"}, "available_balance": {"currency_code": "USD", "value": "1302.30"}, "invoice_id": "69341308548", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "69341308548"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "69341308548"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:45:50Z", "transaction_id": "5WL82051VY277550S"}, "emitted_at": 1707238889217} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "9CG36572NK0728016", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:46:01+0000", "transaction_updated_date": "2021-07-05T23:46:01+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1331.24"}, "available_balance": {"currency_code": "USD", "value": "1331.24"}, "invoice_id": "70491310163", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "70491310163"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "70491310163"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:46:01Z", "transaction_id": "9CG36572NK0728016"}, "emitted_at": 1707238889219} +{"stream": "transactions", "data": {"transaction_info": {"paypal_account_id": "ZE5533HZPGMC6", "transaction_id": "9K759703FU663194K", "transaction_event_code": "T0006", "transaction_initiation_date": "2021-07-05T23:46:43+0000", "transaction_updated_date": "2021-07-05T23:46:43+0000", "transaction_amount": {"currency_code": "USD", "value": "30.11"}, "fee_amount": {"currency_code": "USD", "value": "-1.17"}, "insurance_amount": {"currency_code": "USD", "value": "0.01"}, "shipping_amount": {"currency_code": "USD", "value": "1.03"}, "shipping_discount_amount": {"currency_code": "USD", "value": "1.00"}, "transaction_status": "S", "transaction_subject": "This is the payment transaction description.", "ending_balance": {"currency_code": "USD", "value": "1360.18"}, "available_balance": {"currency_code": "USD", "value": "1360.18"}, "invoice_id": "44794712899", "custom_field": "EBAY_EMS_90048630020055", "protection_eligibility": "01"}, "payer_info": {"account_id": "ZE5533HZPGMC6", "email_address": "integration-test-buyer@airbyte.io", "address_status": "Y", "payer_status": "Y", "payer_name": {"given_name": "test", "surname": "buyer", "alternate_full_name": "test buyer"}, "country_code": "US"}, "shipping_info": {"name": "Hello World", "address": {"line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "country_code": "US", "postal_code": "95131"}}, "cart_info": {"item_details": [{"item_code": "1", "item_name": "hat", "item_description": "Brown color hat", "item_quantity": "5", "item_unit_price": {"currency_code": "USD", "value": "3.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.05"}}], "total_item_amount": {"currency_code": "USD", "value": "15.05"}, "invoice_number": "44794712899"}, {"item_code": "product34", "item_name": "handbag", "item_description": "Black color hand bag", "item_quantity": "1", "item_unit_price": {"currency_code": "USD", "value": "15.00"}, "item_amount": {"currency_code": "USD", "value": "15.00"}, "tax_amounts": [{"tax_amount": {"currency_code": "USD", "value": "0.02"}}], "total_item_amount": {"currency_code": "USD", "value": "15.02"}, "invoice_number": "44794712899"}]}, "store_info": {}, "auction_info": {}, "incentive_info": {}, "transaction_updated_date": "2021-07-05T23:46:43Z", "transaction_id": "9K759703FU663194K"}, "emitted_at": 1707238889222} +{"stream": "balances", "data": {"balances": [{"currency": "USD", "primary": true, "total_balance": {"currency_code": "USD", "value": "173.64"}, "available_balance": {"currency_code": "USD", "value": "173.64"}, "withheld_balance": {"currency_code": "USD", "value": "0.00"}}], "account_id": "MDXWPD67GEP5W", "as_of_time": "2021-07-01T00:00:00Z", "last_refresh_time": "2024-02-06T09:59:59Z"}, "emitted_at": 1707239624675} +{"stream": "list_products", "data": {"id": "bELKLtzpiO", "name": "Pines-T-Shirt-sSUVV", "description": "Anothe rUpdate. Let's see if something changes or not", "create_time": "2024-01-25T20:16:36Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/catalogs/products/bELKLtzpiO", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239715683} +{"stream": "list_products", "data": {"id": "oObfKeWCTO", "name": "Pines-T-Shirt-HZBfE", "description": "My Update. Does it changes it?", "create_time": "2024-01-26T20:07:11Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/catalogs/products/oObfKeWCTO", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239715685} +{"stream": "list_products", "data": {"id": "GXASPmLVeA", "name": "Pines-T-Shirt-vtpna", "description": "Cotton XL", "create_time": "2024-01-26T23:00:52Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/catalogs/products/GXASPmLVeA", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239715687} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZTWI4W4210034A4751008", "intent": "sale", "state": "approved", "cart": "94M68693F5918712T", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "44794712899", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "9K759703FU663194K", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZTWI4W4210034A4751008", "create_time": "2021-07-05T23:46:43Z", "update_time": "2021-07-05T23:46:43Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/9K759703FU663194K", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/9K759703FU663194K/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTWI4W4210034A4751008", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:46:33Z", "update_time": "2021-07-05T23:46:43Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTWI4W4210034A4751008", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814718} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZTMA8WD99999KH443990H", "intent": "sale", "state": "approved", "cart": "8BD080945B510293Y", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "70491310163", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "9CG36572NK0728016", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZTMA8WD99999KH443990H", "create_time": "2021-07-05T23:46:01Z", "update_time": "2021-07-05T23:46:01Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/9CG36572NK0728016", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/9CG36572NK0728016/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTMA8WD99999KH443990H", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:45:52Z", "update_time": "2021-07-05T23:46:01Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTMA8WD99999KH443990H", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814721} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZTJA3GY064023P159724A", "intent": "sale", "state": "approved", "cart": "4XU51704H63205015", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "69341308548", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "5WL82051VY277550S", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZTJA3GY064023P159724A", "create_time": "2021-07-05T23:45:50Z", "update_time": "2021-07-05T23:45:50Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/5WL82051VY277550S", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/5WL82051VY277550S/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTJA3GY064023P159724A", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:45:40Z", "update_time": "2021-07-05T23:45:50Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTJA3GY064023P159724A", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814724} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZTGI9UK71240VU8020618", "intent": "sale", "state": "approved", "cart": "0RJ70999M3464401U", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "33391419042", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "43X058357A257931N", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZTGI9UK71240VU8020618", "create_time": "2021-07-05T23:45:39Z", "update_time": "2021-07-05T23:45:39Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/43X058357A257931N", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/43X058357A257931N/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTGI9UK71240VU8020618", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:45:29Z", "update_time": "2021-07-05T23:45:39Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTGI9UK71240VU8020618", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814727} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZTDQ5FS07530F9282151W", "intent": "sale", "state": "approved", "cart": "4JA813678M224812W", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "38296993497", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "7N749695W59419057", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZTDQ5FS07530F9282151W", "create_time": "2021-07-05T23:45:27Z", "update_time": "2021-07-05T23:45:27Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/7N749695W59419057", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/7N749695W59419057/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTDQ5FS07530F9282151W", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:45:18Z", "update_time": "2021-07-05T23:45:27Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTDQ5FS07530F9282151W", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814730} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZTAY2N7514653J745150Y", "intent": "sale", "state": "approved", "cart": "4VA72722KX1105219", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "88168198250", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "10S137566E4828249", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZTAY2N7514653J745150Y", "create_time": "2021-07-05T23:45:16Z", "update_time": "2021-07-05T23:45:16Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/10S137566E4828249", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/10S137566E4828249/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTAY2N7514653J745150Y", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:45:07Z", "update_time": "2021-07-05T23:45:16Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZTAY2N7514653J745150Y", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814733} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZS6A3M9912977L184341S", "intent": "sale", "state": "approved", "cart": "4JY24848DR959552K", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "83951023481", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "9NH78349H0388780F", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZS6A3M9912977L184341S", "create_time": "2021-07-05T23:45:05Z", "update_time": "2021-07-05T23:45:05Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/9NH78349H0388780F", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/9NH78349H0388780F/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZS6A3M9912977L184341S", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:44:56Z", "update_time": "2021-07-05T23:45:05Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZS6A3M9912977L184341S", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814735} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZS3I50756242KE8498014", "intent": "sale", "state": "approved", "cart": "3PS97109CA147652A", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "71349988314", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "0N2242037Y9449344", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZS3I50756242KE8498014", "create_time": "2021-07-05T23:44:54Z", "update_time": "2021-07-05T23:44:54Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/0N2242037Y9449344", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/0N2242037Y9449344/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZS3I50756242KE8498014", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:44:45Z", "update_time": "2021-07-05T23:44:54Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZS3I50756242KE8498014", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814738} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZSYQ8A757181MC817782A", "intent": "sale", "state": "approved", "cart": "4KH490105A375162P", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "93286331651", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "112146346A741221U", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZSYQ8A757181MC817782A", "create_time": "2021-07-05T23:44:44Z", "update_time": "2021-07-05T23:44:44Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/112146346A741221U", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/112146346A741221U/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZSYQ8A757181MC817782A", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:44:34Z", "update_time": "2021-07-05T23:44:44Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZSYQ8A757181MC817782A", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814741} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZSVY92X22655TL083163M", "intent": "sale", "state": "approved", "cart": "1K4366307V579334M", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "99595079917", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "87S73342AS6001233", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZSVY92X22655TL083163M", "create_time": "2021-07-05T23:44:32Z", "update_time": "2021-07-05T23:44:32Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/87S73342AS6001233", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/87S73342AS6001233/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZSVY92X22655TL083163M", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:44:23Z", "update_time": "2021-07-05T23:44:32Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZSVY92X22655TL083163M", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814743} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZSSY3AX23091XE567400S", "intent": "sale", "state": "approved", "cart": "5FW555787Y189635P", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "12489150471", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "8MF4324694292993B", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZSSY3AX23091XE567400S", "create_time": "2021-07-05T23:44:21Z", "update_time": "2021-07-05T23:44:21Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/8MF4324694292993B", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/8MF4324694292993B/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZSSY3AX23091XE567400S", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:44:11Z", "update_time": "2021-07-05T23:44:21Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZSSY3AX23091XE567400S", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814746} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZR7Q47A34643F6939564E", "intent": "sale", "state": "approved", "cart": "3CY93437B5650311M", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "98653187889", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "51852852PL0100404", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZR7Q47A34643F6939564E", "create_time": "2021-07-05T23:43:03Z", "update_time": "2021-07-05T23:43:03Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/51852852PL0100404", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/51852852PL0100404/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZR7Q47A34643F6939564E", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:42:54Z", "update_time": "2021-07-05T23:43:03Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZR7Q47A34643F6939564E", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814749} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZR4Y96946691TM615464M", "intent": "sale", "state": "approved", "cart": "0WG02233VF623084T", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "71793513892", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "03D88325GF8461705", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZR4Y96946691TM615464M", "create_time": "2021-07-05T23:42:52Z", "update_time": "2021-07-05T23:42:52Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/03D88325GF8461705", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/03D88325GF8461705/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZR4Y96946691TM615464M", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:42:43Z", "update_time": "2021-07-05T23:42:52Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZR4Y96946691TM615464M", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814751} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZRZY3BY320090L305572M", "intent": "sale", "state": "approved", "cart": "4RY36168C0517143X", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "18793521512", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "3BH630398E562901G", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZRZY3BY320090L305572M", "create_time": "2021-07-05T23:42:41Z", "update_time": "2021-07-05T23:42:41Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/3BH630398E562901G", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/3BH630398E562901G/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZRZY3BY320090L305572M", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:42:31Z", "update_time": "2021-07-05T23:42:41Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZRZY3BY320090L305572M", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814754} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZMYY6H275806JK843330N", "intent": "sale", "state": "approved", "cart": "9RC74442JD1611818", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "52396214250", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "0SD21997LN026020M", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZMYY6H275806JK843330N", "create_time": "2021-07-05T23:31:56Z", "update_time": "2021-07-05T23:31:56Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/0SD21997LN026020M", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/0SD21997LN026020M/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZMYY6H275806JK843330N", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:31:47Z", "update_time": "2021-07-05T23:31:56Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZMYY6H275806JK843330N", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814756} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZMWA7HV06523LM984963Y", "intent": "sale", "state": "approved", "cart": "4HC02299JX0560832", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "12278283055", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "5BJ418934Y425901G", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZMWA7HV06523LM984963Y", "create_time": "2021-07-05T23:31:46Z", "update_time": "2021-07-05T23:31:46Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/5BJ418934Y425901G", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/5BJ418934Y425901G/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZMWA7HV06523LM984963Y", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:31:36Z", "update_time": "2021-07-05T23:31:46Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZMWA7HV06523LM984963Y", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814758} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZMTI4X39217868749053E", "intent": "sale", "state": "approved", "cart": "5N3647919D810380T", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "50350860865", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "1ST090036H2235215", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZMTI4X39217868749053E", "create_time": "2021-07-05T23:31:35Z", "update_time": "2021-07-05T23:31:35Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/1ST090036H2235215", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/1ST090036H2235215/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZMTI4X39217868749053E", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:31:25Z", "update_time": "2021-07-05T23:31:35Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZMTI4X39217868749053E", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814760} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZLYY9RB64928LK030220F", "intent": "sale", "state": "approved", "cart": "31F66461BJ2308523", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "10184574713", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "2KU13114TJ604181E", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZLYY9RB64928LK030220F", "create_time": "2021-07-05T23:29:48Z", "update_time": "2021-07-05T23:29:48Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/2KU13114TJ604181E", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/2KU13114TJ604181E/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZLYY9RB64928LK030220F", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:29:39Z", "update_time": "2021-07-05T23:29:48Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZLYY9RB64928LK030220F", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814763} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZLWA09E67167RS362822V", "intent": "sale", "state": "approved", "cart": "1B944298P8820581S", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "92544485996", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "2AJ081444T051123A", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZLWA09E67167RS362822V", "create_time": "2021-07-05T23:29:37Z", "update_time": "2021-07-05T23:29:37Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/2AJ081444T051123A", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/2AJ081444T051123A/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZLWA09E67167RS362822V", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:29:28Z", "update_time": "2021-07-05T23:29:37Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZLWA09E67167RS362822V", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814765} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZLTA1857385502613571B", "intent": "sale", "state": "approved", "cart": "07W53209604004921", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "34635559567", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "63U003588S1135607", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZLTA1857385502613571B", "create_time": "2021-07-05T23:29:26Z", "update_time": "2021-07-05T23:29:26Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/63U003588S1135607", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/63U003588S1135607/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZLTA1857385502613571B", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:29:16Z", "update_time": "2021-07-05T23:29:26Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZLTA1857385502613571B", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239814767} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZI7Q61590832VE058581A", "intent": "sale", "state": "approved", "cart": "47F08854HR292433A", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "46225965444", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "0VE851712U5895412", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZI7Q61590832VE058581A", "create_time": "2021-07-05T23:23:51Z", "update_time": "2021-07-05T23:23:51Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/0VE851712U5895412", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/0VE851712U5895412/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZI7Q61590832VE058581A", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:23:42Z", "update_time": "2021-07-05T23:23:51Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZI7Q61590832VE058581A", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816765} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZI4Y1FS16045MX748772D", "intent": "sale", "state": "approved", "cart": "6JA90337U5912522U", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "93025400757", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "4PW76195NN227720S", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZI4Y1FS16045MX748772D", "create_time": "2021-07-05T23:23:40Z", "update_time": "2021-07-05T23:23:40Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/4PW76195NN227720S", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/4PW76195NN227720S/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZI4Y1FS16045MX748772D", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:23:31Z", "update_time": "2021-07-05T23:23:40Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZI4Y1FS16045MX748772D", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816770} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZIZY0YE90251N2470191A", "intent": "sale", "state": "approved", "cart": "79F61111E7201332F", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "71987080514", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "5WX252723D093564T", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZIZY0YE90251N2470191A", "create_time": "2021-07-05T23:23:29Z", "update_time": "2021-07-05T23:23:29Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/5WX252723D093564T", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/5WX252723D093564T/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZIZY0YE90251N2470191A", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:23:19Z", "update_time": "2021-07-05T23:23:29Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZIZY0YE90251N2470191A", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816774} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZFQI6GD87350UE545773N", "intent": "sale", "state": "approved", "cart": "1FP43302U0478942X", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "10442581967", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "2N796839EY2539153", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZFQI6GD87350UE545773N", "create_time": "2021-07-05T23:16:32Z", "update_time": "2021-07-05T23:16:32Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/2N796839EY2539153", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/2N796839EY2539153/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZFQI6GD87350UE545773N", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:16:17Z", "update_time": "2021-07-05T23:16:32Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZFQI6GD87350UE545773N", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816778} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZFMA0B969784C6725002V", "intent": "sale", "state": "approved", "cart": "8L091901278803646", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "82173600275", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "3VP82838NP358133N", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZFMA0B969784C6725002V", "create_time": "2021-07-05T23:16:15Z", "update_time": "2021-07-05T23:16:15Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/3VP82838NP358133N", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/3VP82838NP358133N/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZFMA0B969784C6725002V", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:16:00Z", "update_time": "2021-07-05T23:16:15Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZFMA0B969784C6725002V", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816781} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZFHY7SJ7565124295670P", "intent": "sale", "state": "approved", "cart": "2SM08874YP816313V", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "25494061224", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "5EL311302L108363J", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZFHY7SJ7565124295670P", "create_time": "2021-07-05T23:15:58Z", "update_time": "2021-07-05T23:15:58Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/5EL311302L108363J", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/5EL311302L108363J/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZFHY7SJ7565124295670P", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:15:43Z", "update_time": "2021-07-05T23:15:58Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZFHY7SJ7565124295670P", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816785} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZFDY16477729A65752911", "intent": "sale", "state": "approved", "cart": "31E8174415946984X", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "88092228645", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "61G749036D552760G", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZFDY16477729A65752911", "create_time": "2021-07-05T23:15:42Z", "update_time": "2021-07-05T23:15:42Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/61G749036D552760G", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/61G749036D552760G/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZFDY16477729A65752911", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:15:27Z", "update_time": "2021-07-05T23:15:42Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZFDY16477729A65752911", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816788} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZE7Y09K97910J19191835", "intent": "sale", "state": "approved", "cart": "52852967MK8398427", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "36419288277", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "19B82038T92822940", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZE7Y09K97910J19191835", "create_time": "2021-07-05T23:15:26Z", "update_time": "2021-07-05T23:15:26Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/19B82038T92822940", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/19B82038T92822940/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZE7Y09K97910J19191835", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:15:11Z", "update_time": "2021-07-05T23:15:26Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZE7Y09K97910J19191835", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816791} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZE3Q7MV3302078506752V", "intent": "sale", "state": "approved", "cart": "8DT33424FM6083023", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "32274344746", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "52795774C7828234R", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZE3Q7MV3302078506752V", "create_time": "2021-07-05T23:15:09Z", "update_time": "2021-07-05T23:15:09Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/52795774C7828234R", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/52795774C7828234R/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZE3Q7MV3302078506752V", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:14:54Z", "update_time": "2021-07-05T23:15:09Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZE3Q7MV3302078506752V", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816794} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZEXI6AC38094H2421312E", "intent": "sale", "state": "approved", "cart": "934109456G4946916", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "18208641465", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "32J59182JY5989507", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZEXI6AC38094H2421312E", "create_time": "2021-07-05T23:14:52Z", "update_time": "2021-07-05T23:14:52Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/32J59182JY5989507", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/32J59182JY5989507/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZEXI6AC38094H2421312E", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:14:37Z", "update_time": "2021-07-05T23:14:52Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZEXI6AC38094H2421312E", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816797} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZETI37A91239LN8311810", "intent": "sale", "state": "approved", "cart": "83D98649PY104524E", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "53235397043", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "3MG39755337297727", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZETI37A91239LN8311810", "create_time": "2021-07-05T23:14:36Z", "update_time": "2021-07-05T23:14:36Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/3MG39755337297727", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/3MG39755337297727/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZETI37A91239LN8311810", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:14:21Z", "update_time": "2021-07-05T23:14:36Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZETI37A91239LN8311810", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816799} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZEPA540480516L1460710", "intent": "sale", "state": "approved", "cart": "7GV22540700208350", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "53296156982", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "27881589Y9461861H", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZEPA540480516L1460710", "create_time": "2021-07-05T23:14:19Z", "update_time": "2021-07-05T23:14:19Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/27881589Y9461861H", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/27881589Y9461861H/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZEPA540480516L1460710", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:14:04Z", "update_time": "2021-07-05T23:14:19Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZEPA540480516L1460710", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816802} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZEKQ6CT67951NS8257540", "intent": "sale", "state": "approved", "cart": "9GV5180502759472M", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "23612058730", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "243514451L952570P", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZEKQ6CT67951NS8257540", "create_time": "2021-07-05T23:14:02Z", "update_time": "2021-07-05T23:14:02Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/243514451L952570P", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/243514451L952570P/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZEKQ6CT67951NS8257540", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:13:46Z", "update_time": "2021-07-05T23:14:02Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZEKQ6CT67951NS8257540", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816805} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZD2Q3A0909139J3152203", "intent": "sale", "state": "approved", "cart": "6AJ421654S4873922", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "32577611997", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "2F535603PS249601F", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZD2Q3A0909139J3152203", "create_time": "2021-07-05T23:12:57Z", "update_time": "2021-07-05T23:12:57Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/2F535603PS249601F", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/2F535603PS249601F/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZD2Q3A0909139J3152203", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:12:42Z", "update_time": "2021-07-05T23:12:57Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZD2Q3A0909139J3152203", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816807} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZDWI4V162188CW455701G", "intent": "sale", "state": "approved", "cart": "6D196635J17794229", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "31766547902", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "3DF69605L9958744R", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZDWI4V162188CW455701G", "create_time": "2021-07-05T23:12:40Z", "update_time": "2021-07-05T23:12:40Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/3DF69605L9958744R", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/3DF69605L9958744R/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZDWI4V162188CW455701G", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:12:25Z", "update_time": "2021-07-05T23:12:40Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZDWI4V162188CW455701G", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816810} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZB7Y8EC76174AW4613112", "intent": "sale", "state": "approved", "cart": "6FK6522150836620E", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "56028534885", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "0T320567TS5587836", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZB7Y8EC76174AW4613112", "create_time": "2021-07-05T23:09:04Z", "update_time": "2021-07-05T23:09:04Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/0T320567TS5587836", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/0T320567TS5587836/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZB7Y8EC76174AW4613112", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:08:47Z", "update_time": "2021-07-05T23:09:04Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZB7Y8EC76174AW4613112", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816813} +{"stream": "list_payments", "data": {"id": "PAYID-MDRZAUY1KV14872K8421472G", "intent": "sale", "state": "approved", "cart": "19W34946AD354311P", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "62173333941", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "6S892278N6406494Y", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRZAUY1KV14872K8421472G", "create_time": "2021-07-05T23:06:12Z", "update_time": "2021-07-05T23:06:12Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/6S892278N6406494Y", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/6S892278N6406494Y/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZAUY1KV14872K8421472G", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:05:55Z", "update_time": "2021-07-05T23:06:12Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRZAUY1KV14872K8421472G", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816816} +{"stream": "list_payments", "data": {"id": "PAYID-MDRY7BY3W991940VB486043B", "intent": "sale", "state": "approved", "cart": "1B350164A39756210", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "23749371955", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "19C257131E850262B", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRY7BY3W991940VB486043B", "create_time": "2021-07-05T23:02:46Z", "update_time": "2021-07-05T23:02:46Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/19C257131E850262B", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/19C257131E850262B/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRY7BY3W991940VB486043B", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:02:31Z", "update_time": "2021-07-05T23:02:46Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRY7BY3W991940VB486043B", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816818} +{"stream": "list_payments", "data": {"id": "PAYID-MDRY6KI3Y0452638X128114D", "intent": "sale", "state": "approved", "cart": "19Y331413K071511U", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "41468340464", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "0M443597T0019954R", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRY6KI3Y0452638X128114D", "create_time": "2021-07-05T23:01:13Z", "update_time": "2021-07-05T23:01:13Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/0M443597T0019954R", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/0M443597T0019954R/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRY6KI3Y0452638X128114D", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T23:00:57Z", "update_time": "2021-07-05T23:01:13Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRY6KI3Y0452638X128114D", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816820} +{"stream": "list_payments", "data": {"id": "PAYID-MDRY4JY42461888J3529050W", "intent": "sale", "state": "approved", "cart": "3NN161683Y756203T", "payer": {"payment_method": "paypal", "status": "VERIFIED", "payer_info": {"email": "integration-test-buyer@airbyte.io", "first_name": "test", "last_name": "buyer", "payer_id": "ZE5533HZPGMC6", "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}, "phone": "4086104434", "country_code": "US"}}, "transactions": [{"amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payee": {"merchant_id": "MDXWPD67GEP5W", "email": "integration-test-facilitator@airbyte.io"}, "description": "This is the payment transaction description.", "custom": "EBAY_EMS_90048630020055", "invoice_number": "65095789448", "item_list": {"items": [{"name": "hat", "sku": "1", "description": "Brown color hat", "price": "3.00", "currency": "USD", "tax": "0.01", "quantity": 5}, {"name": "handbag", "sku": "product34", "description": "Black color hand bag", "price": "15.00", "currency": "USD", "tax": "0.02", "quantity": 1}], "shipping_address": {"recipient_name": "Hello World", "line1": "4thFloor", "line2": "unit#34", "city": "SAn Jose", "state": "CA", "postal_code": "95131", "country_code": "US"}}, "related_resources": [{"sale": {"id": "1FN09943JY662130R", "state": "completed", "amount": {"total": "30.11", "currency": "USD", "details": {"subtotal": "30.00", "tax": "0.07", "shipping": "0.03", "insurance": "0.01", "handling_fee": "1.00", "shipping_discount": "-1.00", "discount": "0.00"}}, "payment_mode": "INSTANT_TRANSFER", "protection_eligibility": "ELIGIBLE", "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", "transaction_fee": {"value": "1.17", "currency": "USD"}, "parent_payment": "PAYID-MDRY4JY42461888J3529050W", "create_time": "2021-07-05T22:56:54Z", "update_time": "2021-07-05T22:56:54Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/1FN09943JY662130R", "rel": "self", "method": "GET"}, {"href": "https://api.sandbox.paypal.com/v1/payments/sale/1FN09943JY662130R/refund", "rel": "refund", "method": "POST"}, {"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRY4JY42461888J3529050W", "rel": "parent_payment", "method": "GET"}]}}]}], "create_time": "2021-07-05T22:56:39Z", "update_time": "2021-07-05T22:56:54Z", "links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MDRY4JY42461888J3529050W", "rel": "self", "method": "GET"}]}, "emitted_at": 1707239816823} \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/invalid_config.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/invalid_config.json similarity index 100% rename from airbyte-integrations/connectors/source-paypal-transaction/integration_tests/invalid_config.json rename to airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/invalid_config.json diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/sample_config.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/sample_config.json new file mode 100644 index 000000000000..9cfcf4147ffe --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/sample_config.json @@ -0,0 +1,12 @@ +{ + "client_id": "PAYPAL_CLIENT_ID", + "client_secret": "PAYPAL_SECRET", + "start_date": "2024-01-20T00:00:00Z", + "end_date": "2024-02-01T23:59:00Z", + "dispute_start_date": "2024-02-01T00:00:00.000Z", + "dispute_end_date": "2024-02-05T23:59:00.000Z", + "is_sandbox": true, + "buyer_username": "BUYER_USERNAME@SOMETHING.com", + "buyer_password": "BUYER_PASSWORD", + "payer_id": "ACCOUNT_ID" +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_state.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/sample_state.json similarity index 100% rename from airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_state.json rename to airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/sample_state.json diff --git a/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/state.json b/airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/state.json similarity index 100% rename from airbyte-integrations/connectors/source-paypal-transaction/integration_tests/state.json rename to airbyte-integrations/connectors/source-paypal-transaction/integration_tests/sample_files/state.json diff --git a/airbyte-integrations/connectors/source-paypal-transaction/metadata.yaml b/airbyte-integrations/connectors/source-paypal-transaction/metadata.yaml index 19cd8658d79b..3449c818497c 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/metadata.yaml +++ b/airbyte-integrations/connectors/source-paypal-transaction/metadata.yaml @@ -1,6 +1,6 @@ data: ab_internal: - ql: 200 + ql: 400 sl: 200 allowedHosts: hosts: @@ -11,7 +11,7 @@ data: connectorSubtype: api connectorType: source definitionId: d913b0f2-cc51-4e55-a44c-8ba1697b9239 - dockerImageTag: 2.2.2 + dockerImageTag: 2.3.0 dockerRepository: airbyte/source-paypal-transaction documentationUrl: https://docs.airbyte.com/integrations/sources/paypal-transaction githubIssueLabel: source-paypal-transaction @@ -34,6 +34,11 @@ data: 2.1.0: message: 'Version 2.1.0 changes the format of the state. The format of the cursor changed from "2021-06-18T16:24:13+03:00" to "2021-06-18T16:24:13Z". The state key for the transactions stream changed to "transaction_updated_date" and the key for the balances stream change to "as_of_time". The upgrade is safe, but rolling back is not.' upgradeDeadline: "2023-09-18" + suggestedStreams: + streams: + - transactions + - balances + - list_payments supportLevel: certified tags: - language:low-code diff --git a/airbyte-integrations/connectors/source-paypal-transaction/poetry.lock b/airbyte-integrations/connectors/source-paypal-transaction/poetry.lock index 38356ea1da73..421031229419 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/poetry.lock +++ b/airbyte-integrations/connectors/source-paypal-transaction/poetry.lock @@ -2,13 +2,13 @@ [[package]] name = "airbyte-cdk" -version = "0.58.8" +version = "0.62.0" description = "A framework for writing Airbyte Connectors." optional = false python-versions = ">=3.8" files = [ - {file = "airbyte-cdk-0.58.8.tar.gz", hash = "sha256:80cfad673302802e0f5d485879f1bd2f3679a4e3b12b2af42bd7bb37a3991a71"}, - {file = "airbyte_cdk-0.58.8-py3-none-any.whl", hash = "sha256:5b0b19745e96ba3f20683c48530d58a00be48361dfa34ec3c38cef8da03ba330"}, + {file = "airbyte-cdk-0.62.0.tar.gz", hash = "sha256:622f56bd7101493a74f11c33a45a31c251032333989996f137cac8370873c614"}, + {file = "airbyte_cdk-0.62.0-py3-none-any.whl", hash = "sha256:b21330a566b33dbdddde33243eb9855f086ad4272e3585ca626be1225451a3b8"}, ] [package.dependencies] @@ -51,16 +51,6 @@ files = [ [package.dependencies] pydantic = ">=1.9.2,<2.0.0" -[[package]] -name = "atomicwrites" -version = "1.4.1" -description = "Atomic file writes." -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, -] - [[package]] name = "attrs" version = "23.2.0" @@ -149,6 +139,70 @@ files = [ {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] +[[package]] +name = "cffi" +version = "1.16.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[package.dependencies] +pycparser = "*" + [[package]] name = "charset-normalizer" version = "3.3.2" @@ -311,6 +365,17 @@ files = [ {file = "genson-1.2.2.tar.gz", hash = "sha256:8caf69aa10af7aee0e1a1351d1d06801f4696e005f06cedef438635384346a16"}, ] +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + [[package]] name = "idna" version = "3.6" @@ -465,6 +530,20 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] +[[package]] +name = "outcome" +version = "1.3.0.post0" +description = "Capture the outcome of Python function calls." +optional = false +python-versions = ">=3.7" +files = [ + {file = "outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b"}, + {file = "outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8"}, +] + +[package.dependencies] +attrs = ">=19.2.0" + [[package]] name = "packaging" version = "23.2" @@ -541,14 +620,14 @@ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] [[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" +name = "pycparser" +version = "2.21" +description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] [[package]] @@ -659,29 +738,39 @@ files = [ {file = "pyrsistent-0.20.0.tar.gz", hash = "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4"}, ] +[[package]] +name = "pysocks" +version = "1.7.1" +description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"}, + {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"}, + {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, +] + [[package]] name = "pytest" -version = "6.2.5" +version = "8.0.0" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, - {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, + {file = "pytest-8.0.0-py3-none-any.whl", hash = "sha256:50fb9cbe836c3f20f0dfa99c565201fb75dc54c8d76373cd1bde06b06657bdb6"}, + {file = "pytest-8.0.0.tar.gz", hash = "sha256:249b1b0864530ba251b7438274c4d251c58d868edaaec8762893ad4a0d71c36c"}, ] [package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -toml = "*" +pluggy = ">=1.3.0,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-mock" @@ -750,7 +839,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -855,20 +943,38 @@ six = "*" fixture = ["fixtures"] test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "testtools"] +[[package]] +name = "selenium" +version = "4.17.2" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "selenium-4.17.2-py3-none-any.whl", hash = "sha256:5aee79026c07985dc1b0c909f34084aa996dfe5b307602de9016d7a621a473f2"}, + {file = "selenium-4.17.2.tar.gz", hash = "sha256:d43d6972e516855fb242ef9ce4ce759057b115070e702e7b1c1032fe7b38d87b"}, +] + +[package.dependencies] +certifi = ">=2021.10.8" +trio = ">=0.17,<1.0" +trio-websocket = ">=0.9,<1.0" +typing_extensions = ">=4.9.0" +urllib3 = {version = ">=1.26,<3", extras = ["socks"]} + [[package]] name = "setuptools" -version = "69.0.3" +version = "69.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, + {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] @@ -883,16 +989,74 @@ files = [ ] [[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "*" files = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, + {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, + {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "trio" +version = "0.24.0" +description = "A friendly Python library for async concurrency and I/O" +optional = false +python-versions = ">=3.8" +files = [ + {file = "trio-0.24.0-py3-none-any.whl", hash = "sha256:c3bd3a4e3e3025cd9a2241eae75637c43fe0b9e88b4c97b9161a55b9e54cd72c"}, + {file = "trio-0.24.0.tar.gz", hash = "sha256:ffa09a74a6bf81b84f8613909fb0beaee84757450183a7a2e0b47b455c0cac5d"}, +] + +[package.dependencies] +attrs = ">=20.1.0" +cffi = {version = ">=1.14", markers = "os_name == \"nt\" and implementation_name != \"pypy\""} +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +idna = "*" +outcome = "*" +sniffio = ">=1.3.0" +sortedcontainers = "*" + +[[package]] +name = "trio-websocket" +version = "0.11.1" +description = "WebSocket library for Trio" +optional = false +python-versions = ">=3.7" +files = [ + {file = "trio-websocket-0.11.1.tar.gz", hash = "sha256:18c11793647703c158b1f6e62de638acada927344d534e3c7628eedcb746839f"}, + {file = "trio_websocket-0.11.1-py3-none-any.whl", hash = "sha256:520d046b0d030cf970b8b2b2e00c4c2245b3807853ecd44214acd33d74581638"}, +] + +[package.dependencies] +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +trio = ">=0.11" +wsproto = ">=0.14" + [[package]] name = "typing-extensions" version = "4.9.0" @@ -929,6 +1093,9 @@ files = [ {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, ] +[package.dependencies] +pysocks = {version = ">=1.5.6,<1.5.7 || >1.5.7,<2.0", optional = true, markers = "extra == \"socks\""} + [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] h2 = ["h2 (>=4,<5)"] @@ -1028,7 +1195,21 @@ files = [ {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] +[[package]] +name = "wsproto" +version = "1.2.0" +description = "WebSockets state-machine based protocol implementation" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"}, + {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"}, +] + +[package.dependencies] +h11 = ">=0.9.0,<1" + [metadata] lock-version = "2.0" python-versions = "^3.9,<3.12" -content-hash = "e84fb1ef10aa196681fe4654bd062fb4175cecb50abce5640cffe5b91b75ae12" +content-hash = "734a63a70fbb15f2bba2328a4f124785e30c369ad58062eb68afc53df56a5ef0" diff --git a/airbyte-integrations/connectors/source-paypal-transaction/pyproject.toml b/airbyte-integrations/connectors/source-paypal-transaction/pyproject.toml index 14b3120395c6..00533e610e8a 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/pyproject.toml +++ b/airbyte-integrations/connectors/source-paypal-transaction/pyproject.toml @@ -3,7 +3,7 @@ requires = [ "poetry-core>=1.0.0",] build-backend = "poetry.core.masonry.api" [tool.poetry] -version = "2.2.2" +version = "2.3.0" name = "source-paypal-transaction" description = "Source implementation for Paypal Transaction." authors = [ "Airbyte ",] @@ -17,12 +17,14 @@ include = "source_paypal_transaction" [tool.poetry.dependencies] python = "^3.9,<3.12" -airbyte-cdk = "==0.58.8" +airbyte-cdk = "==0.62.0" + [tool.poetry.scripts] source-paypal-transaction = "source_paypal_transaction.run:run" [tool.poetry.group.dev.dependencies] -pytest = "^6.1" -pytest-mock = "^3.6" +pytest = "^8.0" +pytest-mock = "^3.12" requests-mock = "^1.11.0" +selenium = "^4.17.2" diff --git a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/components.py b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/components.py index 332549f3b617..af883e9c1c19 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/components.py +++ b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/components.py @@ -5,10 +5,14 @@ import base64 import logging from dataclasses import dataclass +from datetime import datetime, timedelta +from typing import Any, Iterable, Mapping, MutableMapping, Optional import backoff import requests from airbyte_cdk.sources.declarative.auth import DeclarativeOauth2Authenticator +from airbyte_cdk.sources.declarative.requesters.http_requester import HttpRequester +from airbyte_cdk.sources.declarative.types import StreamSlice, StreamState from airbyte_cdk.sources.streams.http.exceptions import DefaultBackoffException logger = logging.getLogger("airbyte") @@ -42,6 +46,7 @@ def get_headers(self): @backoff.on_exception( backoff.expo, DefaultBackoffException, + max_tries=2, on_backoff=lambda details: logger.info( f"Caught retryable error after {details['tries']} tries. Waiting {details['wait']} seconds then retrying..." ), @@ -49,14 +54,25 @@ def get_headers(self): ) def _get_refresh_access_token_response(self): try: - response = requests.request( - method="POST", url=self.get_token_refresh_endpoint(), data=self.build_refresh_request_body(), headers=self.get_headers() - ) + request_url = self.get_token_refresh_endpoint() + request_headers = self.get_headers() + request_body = self.build_refresh_request_body() + + logger.info(f"Sending request to URL: {request_url}") + + response = requests.request(method="POST", url=request_url, data=request_body, headers=request_headers) + self._log_response(response) response.raise_for_status() + + response_json = response.json() + + self.access_token = response_json.get("access_token") + return response.json() + except requests.exceptions.RequestException as e: - if e.response.status_code == 429 or e.response.status_code >= 500: + if e.response and (e.response.status_code == 429 or e.response.status_code >= 500): raise DefaultBackoffException(request=e.response.request, response=e.response) raise except Exception as e: diff --git a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/manifest.yaml b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/manifest.yaml index 58f6d026171a..ddc8283179c2 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/manifest.yaml +++ b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/manifest.yaml @@ -1,11 +1,6 @@ version: 0.50.2 type: DeclarativeSource -check: - type: CheckStream - stream_names: - - balances - definitions: selector: type: RecordSelector @@ -16,7 +11,7 @@ definitions: requester: type: HttpRequester - url_base: 'https://api-m.{{ "sandbox." if config["is_sandbox"] }}paypal.com/v1/reporting/' + url_base: 'https://api-m.{{ "sandbox." if config["is_sandbox"] }}paypal.com/' path: "{{ parameters.path }}" http_method: GET request_headers: @@ -38,9 +33,15 @@ definitions: - type: DefaultErrorHandler backoff_strategies: - type: ConstantBackoffStrategy - backoff_time_in_seconds: 300 + backoff_time_in_seconds: 100 request_body_json: {} + #NOTE: The streams Payments, Orders and Subscriptions require a webhook so you can register + #the Ids of each event as these endpoints do not have a GET method to list the Ids and use it + #in other streams + + #Stream Transactions + #Paypal API only has V1 for this stream transactions_stream: type: DeclarativeStream primary_key: transaction_id @@ -67,6 +68,15 @@ definitions: $ref: "#/definitions/requester" request_parameters: fields: all + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + description: "Handle HTTP 400 with error message: Data for the given start date is not available. " + response_filters: + - http_codes: [400] + action: IGNORE + predicate: "{{ 'Data for the given start date is not available' in response['message']}}" transformations: - type: AddFields fields: @@ -89,26 +99,29 @@ definitions: start_datetime: type: MinMaxDatetime datetime: >- - {{ max( format_datetime(config['start_date'], '%Y-%m-%dT%H:%M:%SZ'), day_delta(-1095, format='%Y-%m-%dT%H:%M:%SZ') ) }} + {{ max( format_datetime(config.get('start_date'), '%Y-%m-%dT%H:%M:%SZ'), day_delta(-1095, format='%Y-%m-%dT%H:%M:%SZ') ) }} datetime_format: "%Y-%m-%dT%H:%M:%SZ" start_time_option: type: RequestOption field_name: start_date inject_into: request_parameter + end_datetime: + type: MinMaxDatetime + datetime: >- + {{ format_datetime(config.get('end_date') if config.get('end_date') else now_utc(), '%Y-%m-%dT%H:%M:%SZ') }} end_time_option: type: RequestOption field_name: end_date inject_into: request_parameter - end_datetime: - type: MinMaxDatetime - datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" datetime_format: "%Y-%m-%dT%H:%M:%SZ" step: "P{{ config.get('time_window', 7) }}D" cursor_granularity: PT1S $parameters: - path: "transactions" + path: "v1/reporting/transactions" field_path: transaction_details + #Stream balances + #Paypal API only has V1 for this stream balances_stream: type: DeclarativeStream primary_key: as_of_time @@ -143,70 +156,244 @@ definitions: start_datetime: type: MinMaxDatetime datetime: >- - {{ max( format_datetime(config['start_date'], '%Y-%m-%dT%H:%M:%SZ'), day_delta(-1095, format='%Y-%m-%dT%H:%M:%SZ') ) }} + {{ max( format_datetime(config.get('start_date'), '%Y-%m-%dT%H:%M:%SZ'), day_delta(-1095, format='%Y-%m-%dT%H:%M:%SZ') ) }} datetime_format: "%Y-%m-%dT%H:%M:%SZ" start_time_option: type: RequestOption field_name: as_of_time inject_into: request_parameter $parameters: - path: "balances" + path: "v1/reporting/balances" + + #New Stream - List Product + #Paypal API only has V1 for this stream + list_products_stream: + type: DeclarativeStream + primary_key: id + name: "list_products" + retriever: + type: SimpleRetriever + record_selector: + $ref: "#/definitions/selector" + paginator: + type: DefaultPaginator + pagination_strategy: + type: PageIncrement + start_from_page: 1 + page_size: 20 + page_token_option: + type: RequestOption + inject_into: request_parameter + field_name: page + page_size_option: + inject_into: request_parameter + field_name: page_size + type: RequestOption + requester: + $ref: "#/definitions/requester" + http_method: GET + request_headers: + Content-Type: application/json + $parameters: + path: "v1/catalogs/products" + field_path: products + + # New Stream - Show Product Details + #Paypal API only has V1 for this stream + #This can't be incremental as there is no time filtering. If you need to have the updates, you need to Append in the full_sync + # This stream works, however has some challenges with performance. Whith a big catalog it can take up to 3 hrs. + show_product_details_stream: + type: DeclarativeStream + primary_key: id + name: "show_product_details" + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/requester" + path: "/v1/catalogs/products/{{ stream_slice.id }}" + record_selector: + $ref: "#/definitions/selector" + extractor: + type: DpathExtractor + field_path: [] + paginator: + type: NoPagination + partition_router: + type: SubstreamPartitionRouter + parent_stream_configs: + - type: ParentStreamConfig + parent_key: "id" + partition_field: "id" + stream: + $ref: "#/definitions/list_products_stream" + + #Stream List Disputes + #Paypal API only has V1 for this stream + list_disputes_stream: + type: DeclarativeStream + primary_key: dispute_id + name: "list_disputes" + retriever: + type: SimpleRetriever + record_selector: + $ref: "#/definitions/selector" + paginator: + type: DefaultPaginator + page_token_option: + type: RequestOption + inject_into: request_parameter + field_name: next_page_token + page_size_option: + type: RequestOption + inject_into: request_parameter + field_name: page_size + pagination_strategy: + type: PageIncrement + start_from_page: 1 + page_size: 50 + requester: + $ref: "#/definitions/requester" + http_method: GET + transformations: + - type: AddFields + fields: + - path: + - updated_time_cut + value: >- + {{ record['update_time'] }} + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_time_cut + datetime_format: "%Y-%m-%dT%H:%M:%S.%fZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ format_datetime(config.get('dispute_start_date') if config.get('dispute_start_date') else (now_utc() - duration('P179D')), '%Y-%m-%dT%H:%M:%S.%fZ')[:23] + 'Z' }}" + datetime_format: "%Y-%m-%dT%H:%M:%S.%fZ" + end_datetime: + type: MinMaxDatetime + #Adding a time delta as the API has a problem with the slice being too close to the now_utc. Set to 30M + datetime: >- + {{ format_datetime(config.get('dispute_end_date') if config.get('dispute_end_date') else (now_utc() - duration('PT30M')), '%Y-%m-%dT%H:%M:%S.%fZ')[:23] + 'Z'}} + datetime_format: "%Y-%m-%dT%H:%M:%S.%fZ" + start_time_option: + type: RequestOption + field_name: update_time_after + inject_into: request_parameter + end_time_option: + type: RequestOption + field_name: update_time_before + inject_into: request_parameter + step: "P{{ config.get('time_window', 7) }}D" + cursor_granularity: PT1S + $parameters: + path: "v1/customer/disputes" + field_path: items + + #Stream Search Invoices + # Currently it does not support incremental sync as metadata does not contain last_update_date + search_invoices_stream: + type: DeclarativeStream + primary_key: id + name: "search_invoices" + retriever: + type: SimpleRetriever + record_selector: + $ref: "#/definitions/selector" + paginator: + type: DefaultPaginator + page_token_option: + type: RequestOption + inject_into: request_parameter + field_name: page + page_size_option: + inject_into: request_parameter + field_name: page_size + type: RequestOption + pagination_strategy: + type: PageIncrement + start_from_page: 1 + page_size: 100 + requester: + $ref: "#/definitions/requester" + http_method: POST + request_headers: + Content-Type: application/json + request_body_json: + creation_date_range: + start: "{{ config.get('start_date') }}" + end: >- + {{ format_datetime(config.get('end_date') if config.get('end_date') else now_utc(), '%Y-%m-%dT%H:%M:%SZ') }} + $parameters: + field_path: items + path: "v2/invoicing/search-invoices" + + #Stream List Payments + #Currently uses V1 which is about to be derecated + #But there is no endpoint in v2 for listing payments + list_payments_stream: + type: DeclarativeStream + primary_key: id + name: "list_payments" + retriever: + type: SimpleRetriever + record_selector: + $ref: "#/definitions/selector" + paginator: + type: DefaultPaginator + pagination_strategy: + type: CursorPagination + cursor_value: "{{ response.next_id}}" + stop_condition: "{{ response.next_id == ''}}" + page_size: 20 + page_token_option: + type: RequestOption + field_name: start_id + inject_into: request_parameter + page_size_option: + type: RequestOption + field_name: count + inject_into: request_parameter + requester: + $ref: "#/definitions/requester" + request_parameters: + start_time: "{{ stream_interval.start_time.strftime('%Y-%m-%dT%H:%M:%SZ') }}" + end_time: "{{ stream_interval.end_time.strftime('%Y-%m-%dT%H:%M:%SZ') }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: update_time + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + #type: MinMaxDatetime + datetime: "{{ config.get('start_date') }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + end_datetime: + type: MinMaxDatetime + datetime: >- + {{ format_datetime(config.get('end_date') if config.get('end_date') else now_utc(), '%Y-%m-%dT%H:%M:%SZ') }} + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: start_time + inject_into: request_parameter + end_time_option: + type: RequestOption + field_name: end_time + inject_into: request_parameter + step: "P{{ config.get('time_window', 7) }}D" + cursor_granularity: PT1S + $parameters: + path: "v1/payments/payment" + field_path: payments streams: - "#/definitions/transactions_stream" - "#/definitions/balances_stream" + - "#/definitions/list_products_stream" + - "#/definitions/show_product_details_stream" + - "#/definitions/list_disputes_stream" + - "#/definitions/search_invoices_stream" + - "#/definitions/list_payments_stream" -spec: - type: Spec - documentation_url: https://docs.airbyte.com/integrations/sources/paypal-transactions - connection_specification: - $schema: http://json-schema.org/draft-07/schema# - type: object - additionalProperties: true - required: - - client_id - - client_secret - - start_date - - is_sandbox - properties: - client_id: - type: string - title: Client ID - description: "The Client ID of your Paypal developer application." - airbyte_secret: true - order: 0 - client_secret: - type: string - title: Client secret - description: "The Client Secret of your Paypal developer application." - airbyte_secret: true - order: 1 - start_date: - title: Start Date - description: >- - Start Date for data extraction in ISO - format. Date must be in range from 3 years till 12 hrs before - present time. - type: string - examples: ["2021-06-11T23:59:59", "2021-06-11T23:59:59+00:00"] - pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(|Z|[+-][0-9]{2}:[0-9]{2})$ - format: "date-time" - order: 2 - is_sandbox: - title: "Sandbox" - description: "Determines whether to use the sandbox or production environment." - type: "boolean" - default: false - refresh_token: - type: "string" - title: "Refresh token" - description: "The key to refresh the expired access token." - airbyte_secret: true - time_window: - type: "integer" - title: "Number of days per request" - description: "The number of days per request. Must be a number between 1 and 31." - default: 7 - minimum: 1 - maximum: 31 +check: + stream_names: + - "balances" diff --git a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_disputes.json b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_disputes.json new file mode 100644 index 000000000000..8d4c9ff57a97 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_disputes.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "dispute_id": { "type": ["null", "string"] }, + "create_time": { "type": "string", "format": "date-time" }, + "update_time": { "type": "string", "format": "date-time" }, + "updated_time_cut": { "type": "string", "format": "date-time" }, + "status": { "type": ["null", "string"] }, + "reason": { "type": ["null", "string"] }, + "dispute_state": { "type": ["null", "string"] }, + "dispute_amount": { + "type": ["null", "object"], + "properties": { + "currency_code": { "type": ["null", "string"] }, + "value": { "type": ["null", "string"] } + } + }, + "links": { + "type": ["null", "array"], + "items": { + "type": ["null", "object"], + "properties": { + "href": { "type": ["null", "string"] }, + "rel": { "type": ["null", "string"] }, + "method": { "type": ["null", "string"] } + } + } + } + } +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_payments.json b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_payments.json new file mode 100644 index 000000000000..6ce37d9d6d3e --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_payments.json @@ -0,0 +1,204 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "id": { "type": ["null", "string"] }, + "intent": { "type": ["null", "string"] }, + "state": { "type": ["null", "string"] }, + "cart": { "type": ["null", "string"] }, + "payer": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "payment_method": { "type": ["null", "string"] }, + "status": { "type": ["null", "string"] }, + "payer_info": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "email": { "type": ["null", "string"] }, + "first_name": { "type": ["null", "string"] }, + "last_name": { "type": ["null", "string"] }, + "payer_id": { "type": ["null", "string"] }, + "shipping_address": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "recipient_name": { "type": ["null", "string"] }, + "line1": { "type": ["null", "string"] }, + "city": { "type": ["null", "string"] }, + "state": { "type": ["null", "string"] }, + "postal_code": { "type": ["null", "string"] }, + "country_code": { "type": ["null", "string"] } + } + }, + "phone": { "type": ["null", "string"] }, + "country_code": { "type": ["null", "string"] } + } + } + } + }, + "transactions": { + "type": ["null", "array"], + "items": { + "type": "object", + "properties": { + "reference_id": { "type": ["null", "string"] }, + "amount": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "total": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "details": { + "type": ["null", "object"], + "properties": { + "subtotal": { "type": ["null", "string"] }, + "shipping": { "type": ["null", "string"] }, + "insurance": { "type": ["null", "string"] }, + "handling_fee": { "type": ["null", "string"] }, + "shipping_discount": { "type": ["null", "string"] }, + "discount": { "type": ["null", "string"] } + } + } + } + }, + "payee": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "merchant_id": { "type": ["null", "string"] }, + "email": { "type": ["null", "string"] } + } + }, + "description": { "type": ["null", "string"] }, + "item_list": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "items": { + "type": ["null", "array"], + "items": { + "type": "object", + "properties": { + "name": { "type": ["null", "string"] }, + "description": { "type": ["null", "string"] }, + "price": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "tax": { "type": ["null", "string"] }, + "quantity": { "type": ["null", "integer"] }, + "image_url": { "type": ["null", "string"] } + } + } + }, + "shipping_address": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "recipient_name": { "type": ["null", "string"] }, + "line1": { "type": ["null", "string"] }, + "city": { "type": ["null", "string"] }, + "state": { "type": ["null", "string"] }, + "postal_code": { "type": ["null", "string"] }, + "country_code": { "type": ["null", "string"] } + } + } + } + }, + "related_resources": { + "type": ["null", "array"], + "items": { + "type": "object", + "properties": { + "sale": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "id": { "type": ["null", "string"] }, + "state": { "type": ["null", "string"] }, + "amount": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "total": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] }, + "details": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "subtotal": { "type": ["null", "string"] }, + "shipping": { "type": ["null", "string"] }, + "insurance": { "type": ["null", "string"] }, + "handling_fee": { "type": ["null", "string"] }, + "shipping_discount": { "type": ["null", "string"] }, + "discount": { "type": ["null", "string"] } + } + } + } + }, + "payment_mode": { "type": ["null", "string"] }, + "protection_eligibility": { "type": ["null", "string"] }, + "protection_eligibility_type": { + "type": ["null", "string"] + }, + "transaction_fee": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "value": { "type": ["null", "string"] }, + "currency": { "type": ["null", "string"] } + } + }, + "purchase_unit_reference_id": { + "type": ["null", "string"] + }, + "parent_payment": { "type": ["null", "string"] }, + "create_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "update_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "links": { + "type": "array", + "items": { + "type": "object", + "properties": { + "href": { "type": ["null", "string"] }, + "rel": { "type": ["null", "string"] }, + "method": { "type": ["null", "string"] } + } + } + } + } + } + } + } + } + } + } + }, + "create_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "update_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "links": { + "type": "array", + "items": { + "type": "object", + "properties": { + "href": { "type": ["null", "string"] }, + "rel": { "type": ["null", "string"] }, + "method": { "type": ["null", "string"] } + } + } + } + } +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_products.json b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_products.json new file mode 100644 index 000000000000..b700519c4c72 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/list_products.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "id": { "type": ["null", "string"] }, + "name": { "type": ["null", "string"] }, + "description": { "type": ["null", "string"] }, + "create_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "links": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true, + "properties": { + "href": { "type": ["null", "string"] }, + "rel": { "type": ["null", "string"] }, + "method": { "type": ["null", "string"] } + } + } + } + } +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/search_invoices.json b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/search_invoices.json new file mode 100644 index 000000000000..e0887a02b9e1 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/search_invoices.json @@ -0,0 +1,357 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "id": { "type": ["null", "string"] }, + "status": { "type": ["null", "string"] }, + "primary_recipients": { + "type": ["null", "array"], + "items": { + "type": ["null", "object"], + "properties": { + "billing_info": { + "type": ["null", "object"], + "properties": { + "business_name": { "type": ["null", "string"] }, + "name": { + "type": ["null", "object"], + "properties": { + "prefix": { "type": ["null", "string"] }, + "given_name": { "type": ["null", "string"] }, + "surname": { "type": ["null", "string"] }, + "middle_name": { "type": ["null", "string"] }, + "suffix": { "type": ["null", "string"] }, + "alternate_full_name": { "type": ["null", "string"] }, + "full_name": { "type": ["null", "string"] } + } + }, + "address": { + "type": ["null", "object"], + "properties": { + "address_line_1": { "type": ["null", "string"] }, + "address_line_2": { "type": ["null", "string"] }, + "address_line_3": { "type": ["null", "string"] }, + "address_line_4": { "type": ["null", "string"] }, + "admin_area_1": { "type": ["null", "string"] }, + "admin_area_2": { "type": ["null", "string"] }, + "admin_area_3": { "type": ["null", "string"] }, + "postal_code": { "type": ["null", "string"] }, + "country_code": { "type": ["null", "string"] }, + "address_details": { "type": ["null", "object"] }, + "phones": { "type": ["null", "array"] }, + "additiona_info": { "type": ["null", "string"] }, + "email_address": { "type": ["null", "string"] }, + "language": { "type": ["null", "string"] } + } + } + } + }, + "shipping_info": { + "type": ["null", "object"], + "properties": { + "business_name": { "type": ["null", "string"] }, + "name": { + "type": ["null", "object"], + "properties": { + "prefix": { "type": ["null", "string"] }, + "given_name": { "type": ["null", "string"] }, + "surname": { "type": ["null", "string"] }, + "middle_name": { "type": ["null", "string"] }, + "suffix": { "type": ["null", "string"] }, + "alternate_full_name": { "type": ["null", "string"] }, + "full_name": { "type": ["null", "string"] } + } + }, + "address": { + "type": ["null", "object"], + "properties": { + "address_line_1": { "type": ["null", "string"] }, + "address_line_2": { "type": ["null", "string"] }, + "address_line_3": { "type": ["null", "string"] }, + "address_line_4": { "type": ["null", "string"] }, + "admin_area_1": { "type": ["null", "string"] }, + "admin_area_2": { "type": ["null", "string"] }, + "admin_area_3": { "type": ["null", "string"] }, + "postal_code": { "type": ["null", "string"] }, + "country_code": { "type": ["null", "string"] }, + "address_details": { "type": ["null", "object"] } + } + } + } + } + } + } + }, + "additional_recipients": { "type": ["null", "array"] }, + "detail": { + "type": ["null", "object"], + "properties": { + "reference": { "type": ["null", "string"] }, + "note": { "type": ["null", "string"] }, + "terms_and_conditions": { "type": ["null", "string"] }, + "memo": { "type": ["null", "string"] }, + "attachments": { + "type": ["null", "array"], + "items": { + "type": ["null", "object"], + "properties": { + "id": { "type": ["null", "string"] }, + "reference_url": { "type": ["null", "string"] }, + "content_type": { "type": ["null", "string"] }, + "size": { "type": ["null", "string"] }, + "create_time": { "type": ["null", "string"] } + } + } + }, + "currency_code": { "type": ["null", "string"] }, + "invoice_number": { "type": ["null", "string"] }, + "invoice_date": { "type": ["null", "string"], "format": "date" }, + "payment_term": { + "type": ["null", "object"], + "properties": { + "term_type": { "type": ["null", "string"] }, + "due_date": { "type": ["null", "string"], "format": "date" } + } + }, + "metadata": { + "type": ["null", "object"], + "properties": { + "created_by": { "type": ["null", "string"] }, + "last_updated_by": { "type": ["null", "string"] }, + "create_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "last_update_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "cancelled_by": { "type": ["null", "string"] }, + "last_seen_by": { "type": ["null", "string"] }, + "recipient_view_url": { "type": ["null", "string"] }, + "invoicer_view_url": { "type": ["null", "string"] }, + "cancel_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "first_sent_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "last_sent_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "created_by_flow": { "type": ["null", "string"] } + } + } + } + }, + "last_update_time": { + "type": ["null", "string"], + "format": "date-time" + }, + "invoicer": { + "type": ["null", "object"], + "properties": { + "business_name": { "type": ["null", "string"] }, + "name": { + "type": ["null", "object"], + "properties": { + "prefix": { "type": ["null", "string"] }, + "given_name": { "type": ["null", "string"] }, + "surname": { "type": ["null", "string"] }, + "middle_name": { "type": ["null", "string"] }, + "suffix": { "type": ["null", "string"] }, + "alternate_full_name": { "type": ["null", "string"] }, + "full_name": { "type": ["null", "string"] } + }, + "address": { + "type": ["null", "object"], + "properties": { + "address_line_1": { "type": ["null", "string"] }, + "address_line_2": { "type": ["null", "string"] }, + "address_line_3": { "type": ["null", "string"] }, + "admin_area_1": { "type": ["null", "string"] }, + "admin_area_2": { "type": ["null", "string"] }, + "admin_area_3": { "type": ["null", "string"] }, + "postal_code": { "type": ["null", "string"] }, + "country_code": { "type": ["null", "string"] }, + "address_details": { "type": ["null", "object"] } + }, + "phones": { + "type": ["null", "array"], + "items": { + "type": ["null", "object"], + "properties": { + "country_code": { "type": ["null", "string"] }, + "national_number": { "type": ["null", "string"] }, + "extension_number": { "type": ["null", "string"] }, + "phone_type": { "type": ["null", "string"] } + } + } + }, + "website": { "type": ["null", "string"] }, + "tax_id": { "type": ["null", "string"] }, + "additional_notes": { "type": ["null", "string"] }, + "email_address": { "type": ["null", "string"] } + } + } + } + }, + "configuration": { + "type": ["null", "object"], + "properties": { + "tax_calculated_after_discount": { "type": ["null", "string"] }, + "tax_inclusive": { "type": ["null", "string"] }, + "allow_tip": { "type": ["null", "string"] }, + "partial_payment": { + "type": ["null", "object"], + "properties": { + "allow_partial_payment": { "type": ["null", "string"] }, + "minimum_amount_due": { "type": ["null", "object"] } + } + }, + "template_id": { "type": ["null", "string"] } + } + }, + "amount": { + "type": ["null", "object"], + "properties": { + "currency_code": { "type": ["null", "string"] }, + "value": { "type": ["null", "string"] }, + "breakdown": { + "type": ["null", "object"], + "properties": { + "item_total": { "type": ["null", "object"] }, + "discount": { "type": ["null", "object"] }, + "tax_total": { "type": ["null", "object"] }, + "shipping": { "type": ["null", "object"] }, + "custom": { "type": ["null", "object"] } + } + } + } + }, + "due_amount": { + "type": ["null", "object"], + "properties": { + "currency_code": { "type": ["null", "string"] }, + "value": { "type": ["null", "string"] } + } + }, + "gratuity": { + "type": ["null", "object"], + "properties": { + "currency_code": { "type": ["null", "string"] }, + "value": { "type": ["null", "string"] } + } + }, + "payments": { + "transactions": { + "type": ["null", "array"], + "items": { + "type": ["null", "object"], + "properties": { + "payment_id": { "type": ["null", "string"] }, + "note": { "type": ["null", "string"] }, + "type": { "type": ["null", "string"] }, + "payment_date": { + "type": ["null", "string"], + "format": "date-time" + }, + "method": { "type": ["null", "string"] }, + "amount": { + "type": ["null", "object"], + "properties": { + "currency_code": { "type": ["null", "string"] }, + "value": { "type": ["null", "string"] } + } + }, + "shipping_info": { + "type": ["null", "object"], + "properties": { + "business_name": { "type": ["null", "string"] }, + "name": { + "type": ["null", "object"], + "properties": { + "prefix": { "type": ["null", "string"] }, + "given_name": { "type": ["null", "string"] }, + "surname": { "type": ["null", "string"] }, + "middle_name": { "type": ["null", "string"] }, + "suffix": { "type": ["null", "string"] }, + "alternate_full_name": { "type": ["null", "string"] }, + "full_name": { "type": ["null", "string"] } + } + }, + "address": { + "type": ["null", "object"], + "properties": { + "address_line_1": { "type": ["null", "string"] }, + "address_line_2": { "type": ["null", "string"] }, + "address_line_3": { "type": ["null", "string"] }, + "admin_area_1": { "type": ["null", "string"] }, + "admin_area_2": { "type": ["null", "string"] }, + "admin_area_3": { "type": ["null", "string"] }, + "postal_code": { "type": ["null", "string"] }, + "country_code": { "type": ["null", "string"] }, + "address_details": { "type": ["null", "object"] } + } + } + } + } + } + } + }, + "paid_amount": { + "type": ["null", "object"], + "properties": { + "currency_code": { "type": ["null", "string"] }, + "value": { "type": ["null", "string"] } + } + } + }, + "refunds": { + "transactions": { + "type": ["null", "array"], + "items": { + "type": ["null", "object"], + "properties": { + "refund_id": { "type": ["null", "string"] }, + "type": { "type": ["null", "string"] }, + "refund_date": { + "type": ["null", "string"], + "format": "date-time" + }, + "method": { "type": ["null", "string"] }, + "amount": { + "type": ["null", "object"], + "properties": { + "currency_code": { "type": ["null", "string"] }, + "value": { "type": ["null", "string"] } + } + } + } + } + }, + "refund_amount": { + "type": ["null", "object"], + "properties": { + "currency_code": { "type": ["null", "string"] }, + "value": { "type": ["null", "string"] } + } + } + }, + "links": { + "type": ["null", "array"], + "items": { + "type": ["null", "object"], + "properties": { + "href": { "type": ["null", "string"], "format": "uri" }, + "rel": { "type": ["null", "string"] }, + "method": { "type": ["null", "string"] } + } + } + } + } +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/show_product_details.json b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/show_product_details.json new file mode 100644 index 000000000000..822b85737f60 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/schemas/show_product_details.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "id": { "type": ["null", "string"] }, + "name": { "type": ["null", "string"] }, + "description": { "type": ["null", "string"] }, + "type": { "type": ["null", "string"] }, + "category": { "type": ["null", "string"] }, + "image_url": { "type": ["null", "string"] }, + "home_url": { "type": ["null", "string"] }, + "create_time": { "type": ["null", "string"], "format": "date-time" }, + "update_time": { "type": ["null", "string"], "format": "date-time" }, + "links": { + "type": "array", + "items": { + "type": ["null", "object"], + "additionalProperties": true, + "properties": { + "href": { "type": ["null", "string"] }, + "rel": { "type": ["null", "string"] }, + "method": { "type": ["null", "string"] } + } + } + } + } +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/source.py b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/source.py index afd56a9278a1..4260da59befa 100644 --- a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/source.py +++ b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/source.py @@ -2,6 +2,7 @@ # Copyright (c) 2023 Airbyte, Inc., all rights reserved. # +from airbyte_cdk import AirbyteLogger from airbyte_cdk.sources.declarative.yaml_declarative_source import YamlDeclarativeSource """ @@ -11,7 +12,6 @@ WARNING: Do not modify this file. """ - # Declarative Source class SourcePaypalTransaction(YamlDeclarativeSource): def __init__(self): diff --git a/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/spec.yaml b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/spec.yaml new file mode 100644 index 000000000000..8f3379e51cf6 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/source_paypal_transaction/spec.yaml @@ -0,0 +1,78 @@ +documentationUrl: https://docs.airbyte.com/integrations/sources/paypal-transactions +connectionSpecification: + $schema: http://json-schema.org/draft-07/schema# + type: object + additionalProperties: true + required: + - client_id + - client_secret + - start_date + - is_sandbox + properties: + client_id: + type: string + title: Client ID + description: "The Client ID of your Paypal developer application." + airbyte_secret: true + order: 0 + client_secret: + type: string + title: Client secret + description: "The Client Secret of your Paypal developer application." + airbyte_secret: true + order: 1 + start_date: + title: Start Date + description: >- + Start Date for data extraction in ISO + format. Date must be in range from 3 years till 12 hrs before + present time. + type: string + examples: ["2021-06-11T23:59:59Z", "2021-06-11T23:59:59+00:00"] + pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(|Z|[+-][0-9]{2}:[0-9]{2})$ + format: "date-time" + order: 2 + is_sandbox: + title: "Sandbox" + description: "Determines whether to use the sandbox or production environment." + type: "boolean" + default: false + dispute_start_date: + title: Dispute Start Date Range + description: >- + Start Date parameter for the list dispute endpoint in ISO + format. This Start Date must be in range within 180 days before + present time, and requires ONLY 3 miliseconds(mandatory). + If you don't use this option, it defaults to a start date set 180 days in the past. + type: string + examples: ["2021-06-11T23:59:59.000Z"] + pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z$ + format: "date-time" + order: 3 + end_date: + title: End Date + description: >- + End Date for data extraction in ISO + format. This can be help you select specific range of time, mainly for test purposes + or data integrity tests. When this is not used, now_utc() is used by the streams. + This does not apply to Disputes and Product streams. + type: string + examples: ["2021-06-11T23:59:59Z", "2021-06-11T23:59:59+00:00"] + pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(|Z|[+-][0-9]{2}:[0-9]{2})$ + format: "date-time" + order: 4 + refresh_token: + type: "string" + title: "Refresh token" + description: "The key to refresh the expired access token." + airbyte_secret: true + time_window: + type: "integer" + title: "Number of days per request" + description: "The number of days per request. Must be a number between 1 and 31." + default: 7 + minimum: 1 + maximum: 31 diff --git a/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/auth_components_test.py b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/auth_components_test.py new file mode 100644 index 000000000000..dd19b6306e77 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/auth_components_test.py @@ -0,0 +1,88 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + +import logging +import time +from unittest.mock import patch + +import pytest +import requests +import requests_mock +from airbyte_cdk.sources.streams.http.exceptions import DefaultBackoffException +from source_paypal_transaction.components import PayPalOauth2Authenticator + + +@pytest.fixture +def mock_authenticator(): + return PayPalOauth2Authenticator( + config={}, + parameters={}, + client_id='test_client_id', + client_secret='test_client_secret', + token_refresh_endpoint='https://test.token.endpoint', + grant_type='test_grant_type' + ) + +def test_get_refresh_access_token_response(mock_authenticator): + expected_response_json = {'access_token': 'test_access_token', 'expires_in': 3600} + with requests_mock.Mocker() as mock_request: + mock_request.post('https://test.token.endpoint', json=expected_response_json, status_code=200) + # Call _get_refresh method + mock_authenticator._get_refresh_access_token_response() + + assert mock_authenticator.access_token == expected_response_json['access_token'] + +def test_token_expiration(mock_authenticator): + # Mock response for initial token request + initial_response_json = {'access_token': 'initial_access_token', 'expires_in': 1} + # Mock response for token refresh request + refresh_response_json = {'access_token': 'refreshed_access_token', 'expires_in': 3600} + with requests_mock.Mocker() as mock_request: + + mock_request.post('https://test.token.endpoint', json=initial_response_json, status_code=200) + mock_authenticator._get_refresh_access_token_response() + + # Assert that the initial access token is set correctly + assert mock_authenticator.access_token == initial_response_json['access_token'] + time.sleep(2) + + mock_request.post('https://test.token.endpoint', json=refresh_response_json, status_code=200) + mock_authenticator._get_refresh_access_token_response() + + # Assert that the access token is refreshed + assert mock_authenticator.access_token == refresh_response_json['access_token'] + + +def test_backoff_retry(mock_authenticator, caplog): + + mock_response = {'access_token': 'test_access_token', 'expires_in': 3600} + mock_reason = "Too Many Requests" + + with requests_mock.Mocker() as mock_request: + mock_request.post('https://test.token.endpoint', json=mock_response, status_code=429, reason=mock_reason) + with caplog.at_level(logging.INFO): + try: + mock_authenticator._get_refresh_access_token_response() + except requests.exceptions.HTTPError: + pass # Ignore the HTTPError + else: + pytest.fail("Expected DefaultBackoffException to be raised") + +@pytest.fixture +def authenticator_parameters(): + return { + "client_id": "test_client_id", + "client_secret": "test_client_secret", + "config": {}, + "parameters": {}, + "token_refresh_endpoint": "https://test.token.endpoint", + "grant_type": "test_grant_type" + } + +def test_get_headers(authenticator_parameters): + expected_basic_auth = "Basic dGVzdF9jbGllbnRfaWQ6dGVzdF9jbGllbnRfc2VjcmV0" + authenticator = PayPalOauth2Authenticator(**authenticator_parameters) + headers = authenticator.get_headers() + assert headers == {"Authorization": expected_basic_auth} + + + diff --git a/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/conftest.py b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/conftest.py new file mode 100644 index 000000000000..06dd08dc74a6 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/conftest.py @@ -0,0 +1,53 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + +# conftest.py +import json +from datetime import datetime +from unittest.mock import patch + +import pytest +from source_paypal_transaction import SourcePaypalTransaction + + +@pytest.fixture(name="config") +def config_fixture(): + #From File test + # with open('../secrets/config.json') as f: + # return json.load(f) + #Mock test + return { + "client_id": "your_client_id", + "client_secret": "your_client_secret", + "start_date": "2024-01-30T00:00:00Z", + "end_date": "2024-02-01T00:00:00Z", + "dispute_start_date": "2024-02-01T00:00:00.000Z", + "dispute_end_date": "2024-02-05T23:59:00.000Z", + "buyer_username": "Your Buyer email", + "buyer_password": "Your Buyer Password", + "payer_id": "ypur ACCOUNT ID", + "is_sandbox": True + } + + +@pytest.fixture(name="source") +def source_fixture(): + return SourcePaypalTransaction() + +def validate_date_format(date_str, format): + try: + datetime.strptime(date_str, format) + return True + except ValueError: + return False + +def test_date_formats_in_config(config): + start_date_format = "%Y-%m-%dT%H:%M:%SZ" + dispute_date_format = "%Y-%m-%dT%H:%M:%S.%fZ" + assert validate_date_format(config['start_date'], start_date_format), "Start date format is incorrect" + assert validate_date_format(config['end_date'], start_date_format), "End date format is incorrect" + assert validate_date_format(config['dispute_start_date'], dispute_date_format), "Dispute start date format is incorrect" + assert validate_date_format(config['dispute_end_date'], dispute_date_format), "Dispute end date format is incorrect" + +@pytest.fixture(name="logger_mock") +def logger_mock_fixture(): + return patch("source_paypal_transactions.source.AirbyteLogger") \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/pagination_cursor.py b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/pagination_cursor.py new file mode 100644 index 000000000000..958db41262da --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/pagination_cursor.py @@ -0,0 +1,146 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + +import json +import os +from dataclasses import dataclass, field +from typing import Any, List, Mapping, Optional, Union + +import pytest +import requests +import requests_mock +from airbyte_cdk.sources.declarative.decoders.decoder import Decoder +from airbyte_cdk.sources.declarative.decoders.json_decoder import JsonDecoder +from airbyte_cdk.sources.declarative.interpolation.interpolated_boolean import InterpolatedBoolean +from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString +from airbyte_cdk.sources.declarative.requesters.paginators.strategies.pagination_strategy import PaginationStrategy +from airbyte_cdk.sources.declarative.types import Config + + +@dataclass +class CursorPaginationStrategy(PaginationStrategy): + """ + Pagination strategy that evaluates an interpolated string to define the next page token + Attributes: + page_size (Optional[int]): the number of records to request + cursor_value (Union[InterpolatedString, str]): template string evaluating to the cursor value + config (Config): connection config + stop_condition (Optional[InterpolatedBoolean]): template string evaluating when to stop paginating + decoder (Decoder): decoder to decode the response + """ + cursor_value: Union[InterpolatedString, str] + config: Config + parameters: Mapping[str, Any] + page_size: Optional[int] = None + stop_condition: Optional[Union[InterpolatedBoolean, str]] = None + decoder: Decoder = field(default_factory=JsonDecoder) + + def __post_init__(self): + if isinstance(self.cursor_value, str): + self.cursor_value = InterpolatedString.create(self.cursor_value, parameters=self.parameters) + if isinstance(self.stop_condition, str): + self.stop_condition = InterpolatedBoolean(condition=self.stop_condition, parameters=self.parameters) + + @property + def initial_token(self) -> Optional[Any]: + return None + + + def next_page_token(self, response: requests.Response, last_records: List[Mapping[str, Any]]) -> Optional[Any]: + decoded_response = self.decoder.decode(response) + headers = response.headers + headers["link"] = response.links + + print("STOP CONDITION", self.stop_condition) + + if self.stop_condition: + should_stop = self.stop_condition.eval(self.config, response=decoded_response, headers=headers, last_records=last_records) + if should_stop: + print("Stopping...") + return None + + # Update cursor_value with the next_id from the response + self.cursor_value = InterpolatedString.create(decoded_response.get("next_id"), parameters=self.parameters) + token = self.cursor_value.eval(config=self.config, last_records=last_records, response=decoded_response, headers=headers) + print("TOKEN", token) + return token if token else None + + def reset(self): + pass + + def get_page_size(self) -> Optional[int]: + return self.page_size + + +@pytest.fixture +def mock_responses(): + return [ + "token_page_init.json", + "token_PAY-0L38757939422510JMW5ZJVA.json", + "token_PAYID-MW5XXZY5YL87592N34454913.json" + ] + +@pytest.fixture +def cursor_pagination_strategy(mock_responses, stop_condition = None): + parameters = {} + decoder = JsonDecoder(parameters=parameters) + cursor_value = "start_id" # Initialize with a default value + + for response_file in mock_responses: + if cursor_value == "start_id": + cursor_value = load_mock_data(response_file).get("next_id") + else: + break # Stop after getting the next_id from the first response + + return CursorPaginationStrategy( + cursor_value=cursor_value, + config={}, + parameters=parameters, + page_size=3, + stop_condition=stop_condition, + decoder=decoder + ) + + +def load_mock_data(filename): + with open(os.path.join("./unit_tests/test_files", filename), "r") as file: + return json.load(file) + +def test_cursor_pagination(cursor_pagination_strategy, mock_responses): + with requests_mock.Mocker() as m: + base_url = "http://example.com/api/resource" + + # Mock responses + for i, response_file in enumerate(mock_responses): + print("") + print("####################################") + if i == 0: + url = f"{base_url}?count=3" + print("FIRST ITERATION:", response_file, i, url) + + if i > 0: + url += f"&start_id={next_id}" + print("NEXT ITERATIONS:", response_file, i, url) + m.get(url, json=load_mock_data(response_file), status_code=200) + # Get next_id from the response if it's not the last response + + if i < len(mock_responses) - 1: + next_id = load_mock_data(response_file)["next_id"] + print("FOUND NEXT ID:", next_id) + + else: + next_id = None + cursor_pagination_strategy(mock_responses, stop_condition = True) + + # Make API call and process response + response = requests.get(url) + print("GET RESPONSE:", response) + assert response.status_code == 200 + + decoded_response = response.json() + last_records = decoded_response["payments"] + next_id = cursor_pagination_strategy.next_page_token(response, last_records) + print("NEXT ID:", next_id) + + # Verify the pagination stopped + assert next_id is None + print("No more pages") diff --git a/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/pagination_increment.py b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/pagination_increment.py new file mode 100644 index 000000000000..05b98d04f90a --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/pagination_increment.py @@ -0,0 +1,79 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + +import os +import re + +import pytest +import requests +import requests_mock +from airbyte_cdk.sources.declarative.requesters.paginators import DefaultPaginator, PaginationStrategy + + +class MockPaginationStrategy(PaginationStrategy): + def __init__(self, page_size): + self.page_size = page_size + self.current_page = 1 + + @property + def initial_token(self): + return self.current_page + + def next_page_token(self, response, last_records): + self.current_page += 1 + return self.current_page if self.current_page <= 5 else None + + def reset(self): + self.current_page = 1 + + @property + def get_page_size(self): + return self.page_size + +@pytest.fixture +def mock_pagination_strategy(): + return MockPaginationStrategy(page_size=500) + +@pytest.fixture +def paginator(): + pagination_strategy = MockPaginationStrategy(page_size=3) + return DefaultPaginator( + pagination_strategy=pagination_strategy, + config={}, + url_base="http://example.com/v1/reporting/transactions", + parameters={} + ) + +def load_mock_data(page): + with open(f"./unit_tests/test_files/page_{page}.json", "r") as file: + return file.read() + +# Test to verify pagination logic transitions from page 1 to page 2 +def test_pagination_logic(paginator): + page_1_data = load_mock_data(1) + page_2_data = load_mock_data(2) + + paginator_url_1 = f"{paginator.url_base.string}?page=1&page_size={paginator.pagination_strategy.get_page_size}" + paginator_url_2 = f"{paginator.url_base.string}?page=2&page_size={paginator.pagination_strategy.get_page_size}" + + with requests_mock.Mocker() as m: + m.get(paginator_url_1, text=page_1_data, status_code=200) + m.get(paginator_url_2, text=page_2_data, status_code=200) + + response_page_1 = requests.get(paginator_url_1) + response_page_1._content = str.encode(page_1_data) + response_page_2 = requests.get(paginator_url_2) + response_page_2._content = str.encode(page_2_data) + + + # Simulate getting the next page token from page 1's response + next_page_token_page_1 = paginator.next_page_token(response_page_1, []) + print("NEXT PAGE TOKEN", next_page_token_page_1) + + # Assert that the next page token indicates moving to page 2 + assert next_page_token_page_1['next_page_token'] == 2, "Failed to transition from page 1 to page 2" + + + # Check that the correct page size is used in requests and that we have the right number of pages + assert len(m.request_history) == 2 + assert "page_size=3" in m.request_history[0].url + assert "page_size=3" in m.request_history[1].url \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/page_1.json b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/page_1.json new file mode 100644 index 000000000000..8e567afe7c7d --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/page_1.json @@ -0,0 +1,135 @@ +{ + "transaction_details": [ + { + "transaction_info": { + "transaction_id": "2N603077GD600560F", + "transaction_event_code": "T1503", + "transaction_initiation_date": "2024-02-10T00:01:56+0000", + "transaction_updated_date": "2024-02-10T00:01:56+0000", + "transaction_amount": { + "currency_code": "USD", + "value": "-60.75" + }, + "transaction_status": "S", + "ending_balance": { + "currency_code": "USD", + "value": "2048018.30" + }, + "available_balance": { + "currency_code": "USD", + "value": "2048018.30" + }, + "protection_eligibility": "02" + }, + "payer_info": { + "address_status": "N", + "payer_name": {} + }, + "shipping_info": {}, + "cart_info": {}, + "store_info": {}, + "auction_info": {}, + "incentive_info": {} + }, + { + "transaction_info": { + "transaction_id": "0JN65120FU073310V", + "transaction_event_code": "T0001", + "transaction_initiation_date": "2024-02-10T00:01:57+0000", + "transaction_updated_date": "2024-02-10T00:01:57+0000", + "transaction_amount": { + "currency_code": "USD", + "value": "-10.00" + }, + "fee_amount": { + "currency_code": "USD", + "value": "-0.25" + }, + "transaction_status": "P", + "transaction_subject": "You have a payout!", + "transaction_note": "Thanks for your patronage!", + "ending_balance": { + "currency_code": "USD", + "value": "2048008.05" + }, + "available_balance": { + "currency_code": "USD", + "value": "2048008.05" + }, + "custom_field": "201403140001", + "protection_eligibility": "02" + }, + "payer_info": { + "email_address": "Ernesto.Witting@yahoo.com", + "address_status": "N", + "payer_name": {} + }, + "shipping_info": { + "name": "John, Merchant" + }, + "cart_info": {}, + "store_info": {}, + "auction_info": {}, + "incentive_info": {} + }, + { + "transaction_info": { + "transaction_id": "4XL46752RR472362C", + "paypal_reference_id": "0JN65120FU073310V", + "paypal_reference_id_type": "TXN", + "transaction_event_code": "T1105", + "transaction_initiation_date": "2024-02-10T00:01:57+0000", + "transaction_updated_date": "2024-02-10T00:01:57+0000", + "transaction_amount": { + "currency_code": "USD", + "value": "10.25" + }, + "transaction_status": "S", + "transaction_subject": "You have a payout!", + "transaction_note": "Thanks for your patronage!", + "ending_balance": { + "currency_code": "USD", + "value": "2048018.30" + }, + "available_balance": { + "currency_code": "USD", + "value": "2048018.30" + }, + "protection_eligibility": "02" + }, + "payer_info": { + "address_status": "N", + "payer_name": {} + }, + "shipping_info": {}, + "cart_info": {}, + "store_info": {}, + "auction_info": {}, + "incentive_info": {} + } + ], + "account_number": "C7CYMKZDG8D6E", + "start_date": "2024-02-10T00:00:00+0000", + "end_date": "2024-02-10T05:20:00+0000", + "last_refreshed_datetime": "2024-02-14T01:59:59+0000", + "page": 1, + "total_items": 352, + "total_pages": 118, + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/reporting/transactions?fields=transaction_info%2Cpayer_info%2Cshipping_info%2Cauction_info%2Ccart_info%2Cincentive_info%2Cstore_info&end_date=2024-02-10T05%3A20%3A00Z&start_date=2024-02-10T00%3A00%3A00Z&page_size=3&page=118", + "rel": "last", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/reporting/transactions?fields=transaction_info%2Cpayer_info%2Cshipping_info%2Cauction_info%2Ccart_info%2Cincentive_info%2Cstore_info&end_date=2024-02-10T05%3A20%3A00Z&start_date=2024-02-10T00%3A00%3A00Z&page_size=3&page=2", + "rel": "next", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/reporting/transactions?fields=transaction_info%2Cpayer_info%2Cshipping_info%2Cauction_info%2Ccart_info%2Cincentive_info%2Cstore_info&end_date=2024-02-10T05%3A20%3A00Z&start_date=2024-02-10T00%3A00%3A00Z&page_size=3&page=1", + "rel": "self", + "method": "GET" + } + ] +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/page_2.json b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/page_2.json new file mode 100644 index 000000000000..e27274a5d72f --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/page_2.json @@ -0,0 +1,160 @@ +{ + "transaction_details": [ + { + "transaction_info": { + "transaction_id": "794702034R094742N", + "transaction_event_code": "T0001", + "transaction_initiation_date": "2024-02-10T00:01:57+0000", + "transaction_updated_date": "2024-02-10T00:01:57+0000", + "transaction_amount": { + "currency_code": "USD", + "value": "-20.00" + }, + "fee_amount": { + "currency_code": "USD", + "value": "-0.25" + }, + "transaction_status": "P", + "transaction_subject": "You have a payout!", + "transaction_note": "Thanks for your support!", + "ending_balance": { + "currency_code": "USD", + "value": "2047998.05" + }, + "available_balance": { + "currency_code": "USD", + "value": "2047998.05" + }, + "custom_field": "201403140002", + "protection_eligibility": "02" + }, + "payer_info": { + "address_status": "N", + "payer_name": {} + }, + "shipping_info": { + "name": "John, Merchant" + }, + "cart_info": {}, + "store_info": {}, + "auction_info": {}, + "incentive_info": {} + }, + { + "transaction_info": { + "transaction_id": "74734003LC191551G", + "paypal_reference_id": "794702034R094742N", + "paypal_reference_id_type": "TXN", + "transaction_event_code": "T1105", + "transaction_initiation_date": "2024-02-10T00:01:57+0000", + "transaction_updated_date": "2024-02-10T00:01:57+0000", + "transaction_amount": { + "currency_code": "USD", + "value": "20.25" + }, + "transaction_status": "S", + "transaction_subject": "You have a payout!", + "transaction_note": "Thanks for your support!", + "ending_balance": { + "currency_code": "USD", + "value": "2048018.30" + }, + "available_balance": { + "currency_code": "USD", + "value": "2048018.30" + }, + "protection_eligibility": "02" + }, + "payer_info": { + "address_status": "N", + "payer_name": {} + }, + "shipping_info": {}, + "cart_info": {}, + "store_info": {}, + "auction_info": {}, + "incentive_info": {} + }, + { + "transaction_info": { + "paypal_account_id": "5DEJUG27PZB9J", + "transaction_id": "44R34480PG8833736", + "transaction_event_code": "T0001", + "transaction_initiation_date": "2024-02-10T00:01:57+0000", + "transaction_updated_date": "2024-02-10T00:01:57+0000", + "transaction_amount": { + "currency_code": "USD", + "value": "-30.00" + }, + "fee_amount": { + "currency_code": "USD", + "value": "-0.25" + }, + "transaction_status": "S", + "transaction_subject": "You have a payout!", + "transaction_note": "Thanks for your patronage!", + "ending_balance": { + "currency_code": "USD", + "value": "2047988.05" + }, + "available_balance": { + "currency_code": "USD", + "value": "2047988.05" + }, + "custom_field": "201403140003", + "protection_eligibility": "02" + }, + "payer_info": { + "account_id": "5DEJUG27PZB9J", + "email_address": "sb-59loi25655860@business.example.com", + "address_status": "N", + "payer_status": "N", + "payer_name": { + "alternate_full_name": "Test Store" + }, + "country_code": "US" + }, + "shipping_info": { + "name": "John, Merchant" + }, + "cart_info": {}, + "store_info": {}, + "auction_info": {}, + "incentive_info": {} + } + ], + "account_number": "C7CYMKZDG8D6E", + "start_date": "2024-02-10T00:00:00+0000", + "end_date": "2024-02-10T05:20:00+0000", + "last_refreshed_datetime": "2024-02-14T01:59:59+0000", + "page": 2, + "total_items": 352, + "total_pages": 118, + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/reporting/transactions?fields=transaction_info%2Cpayer_info%2Cshipping_info%2Cauction_info%2Ccart_info%2Cincentive_info%2Cstore_info&start_date=2024-02-10T00%3A00%3A00Z&end_date=2024-02-10T05%3A20%3A00Z&page_size=3&page=1", + "rel": "first", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/reporting/transactions?fields=transaction_info%2Cpayer_info%2Cshipping_info%2Cauction_info%2Ccart_info%2Cincentive_info%2Cstore_info&start_date=2024-02-10T00%3A00%3A00Z&end_date=2024-02-10T05%3A20%3A00Z&page_size=3&page=118", + "rel": "last", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/reporting/transactions?fields=transaction_info%2Cpayer_info%2Cshipping_info%2Cauction_info%2Ccart_info%2Cincentive_info%2Cstore_info&start_date=2024-02-10T00%3A00%3A00Z&end_date=2024-02-10T05%3A20%3A00Z&page_size=3&page=3", + "rel": "next", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/reporting/transactions?fields=transaction_info%2Cpayer_info%2Cshipping_info%2Cauction_info%2Ccart_info%2Cincentive_info%2Cstore_info&start_date=2024-02-10T00%3A00%3A00Z&end_date=2024-02-10T05%3A20%3A00Z&page_size=3&page=1", + "rel": "prev", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/reporting/transactions?fields=transaction_info%2Cpayer_info%2Cshipping_info%2Cauction_info%2Ccart_info%2Cincentive_info%2Cstore_info&start_date=2024-02-10T00%3A00%3A00Z&end_date=2024-02-10T05%3A20%3A00Z&page_size=3&page=2", + "rel": "self", + "method": "GET" + } + ] +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_PAY-0L38757939422510JMW5ZJVA.json b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_PAY-0L38757939422510JMW5ZJVA.json new file mode 100644 index 000000000000..b0a6520defec --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_PAY-0L38757939422510JMW5ZJVA.json @@ -0,0 +1,451 @@ +{ + "payments": [ + { + "id": "PAY-0L38757939422510JMW5ZJVA", + "intent": "authorize", + "state": "approved", + "payer": { + "payment_method": "paypal", + "status": "VERIFIED", + "payer_info": { + "email": "mihai.streza1@mi-pay.com", + "first_name": "Mihai", + "last_name": "Streza", + "payer_id": "QHD3E8SRDDSQL", + "shipping_address": { + "recipient_name": "Mihai Streza" + }, + "phone": "07534201211", + "country_code": "GB" + } + }, + "transactions": [ + { + "amount": { + "total": "20.00", + "currency": "EUR", + "details": { + "subtotal": "20.00" + } + }, + "payee": { + "merchant_id": "C7CYMKZDG8D6E" + }, + "description": "topup", + "invoice_number": "100000000188897", + "soft_descriptor": "PAYPAL *JOHNMERCHAN", + "item_list": { + "items": [ + { + "name": "topup", + "price": "20.00", + "currency": "EUR", + "tax": "0.00", + "quantity": 1 + } + ], + "shipping_address": { + "recipient_name": "Mihai Streza" + } + }, + "related_resources": [ + { + "authorization": { + "id": "3S025738SW168153S", + "state": "captured", + "amount": { + "total": "20.00", + "currency": "EUR", + "details": { + "subtotal": "20.00" + } + }, + "payment_mode": "INSTANT_TRANSFER", + "protection_eligibility": "ELIGIBLE", + "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", + "billing_agreement_id": "B-42217126VD515152H", + "parent_payment": "PAY-0L38757939422510JMW5ZJVA", + "valid_until": "2024-03-01T12:55:48Z", + "create_time": "2024-02-01T12:55:48Z", + "update_time": "2024-02-01T12:55:51Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/3S025738SW168153S", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/3S025738SW168153S/capture", + "rel": "capture", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/3S025738SW168153S/void", + "rel": "void", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/3S025738SW168153S/reauthorize", + "rel": "reauthorize", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-0L38757939422510JMW5ZJVA", + "rel": "parent_payment", + "method": "GET" + } + ] + } + }, + { + "capture": { + "id": "26U95072LD470800B", + "amount": { + "total": "20.00", + "currency": "EUR" + }, + "state": "completed", + "custom": "", + "transaction_fee": { + "value": "1.39", + "currency": "EUR" + }, + "parent_payment": "PAY-0L38757939422510JMW5ZJVA", + "invoice_number": "100000000188897", + "create_time": "2024-02-01T12:55:51Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/capture/26U95072LD470800B", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/capture/26U95072LD470800B/refund", + "rel": "refund", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/3S025738SW168153S", + "rel": "authorization", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-0L38757939422510JMW5ZJVA", + "rel": "parent_payment", + "method": "GET" + } + ] + } + } + ] + } + ], + "create_time": "2024-02-01T12:55:48Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-0L38757939422510JMW5ZJVA", + "rel": "self", + "method": "GET" + } + ] + }, + { + "id": "PAY-5UU821714H9319614MW5ZGTQ", + "intent": "authorize", + "state": "approved", + "payer": { + "payment_method": "paypal", + "status": "VERIFIED", + "payer_info": { + "email": "mihai.streza1@mi-pay.com", + "first_name": "Mihai", + "last_name": "Streza", + "payer_id": "QHD3E8SRDDSQL", + "shipping_address": { + "recipient_name": "Mihai Streza" + }, + "phone": "07534201211", + "country_code": "GB" + } + }, + "transactions": [ + { + "amount": { + "total": "20.00", + "currency": "EUR", + "details": { + "subtotal": "20.00" + } + }, + "payee": { + "merchant_id": "C7CYMKZDG8D6E" + }, + "description": "topup", + "invoice_number": "100000000188890", + "soft_descriptor": "PAYPAL *JOHNMERCHAN", + "item_list": { + "items": [ + { + "name": "topup", + "price": "20.00", + "currency": "EUR", + "tax": "0.00", + "quantity": 1 + } + ], + "shipping_address": { + "recipient_name": "Mihai Streza" + } + }, + "related_resources": [ + { + "authorization": { + "id": "4MN954876H428782W", + "state": "captured", + "amount": { + "total": "20.00", + "currency": "EUR", + "details": { + "subtotal": "20.00" + } + }, + "payment_mode": "INSTANT_TRANSFER", + "protection_eligibility": "ELIGIBLE", + "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", + "billing_agreement_id": "B-9YM05135W51321351", + "parent_payment": "PAY-5UU821714H9319614MW5ZGTQ", + "valid_until": "2024-03-01T12:49:18Z", + "create_time": "2024-02-01T12:49:18Z", + "update_time": "2024-02-01T12:49:21Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/4MN954876H428782W", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/4MN954876H428782W/capture", + "rel": "capture", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/4MN954876H428782W/void", + "rel": "void", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/4MN954876H428782W/reauthorize", + "rel": "reauthorize", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-5UU821714H9319614MW5ZGTQ", + "rel": "parent_payment", + "method": "GET" + } + ] + } + }, + { + "capture": { + "id": "3LS31047RT411632Y", + "amount": { + "total": "20.00", + "currency": "EUR" + }, + "state": "completed", + "custom": "", + "transaction_fee": { + "value": "1.39", + "currency": "EUR" + }, + "parent_payment": "PAY-5UU821714H9319614MW5ZGTQ", + "invoice_number": "100000000188890", + "create_time": "2024-02-01T12:49:21Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/capture/3LS31047RT411632Y", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/capture/3LS31047RT411632Y/refund", + "rel": "refund", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/4MN954876H428782W", + "rel": "authorization", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-5UU821714H9319614MW5ZGTQ", + "rel": "parent_payment", + "method": "GET" + } + ] + } + } + ] + } + ], + "create_time": "2024-02-01T12:49:18Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-5UU821714H9319614MW5ZGTQ", + "rel": "self", + "method": "GET" + } + ] + }, + { + "id": "PAYID-MW5Y7VQ3XR69795B78311812", + "intent": "sale", + "state": "approved", + "cart": "21D62257BL170881B", + "payer": { + "payment_method": "paypal", + "status": "VERIFIED", + "payer_info": { + "email": "ABpaypal@gmail.com", + "first_name": "kiran", + "last_name": "ingale", + "payer_id": "MEZSMT5X3R5HW", + "shipping_address": { + "recipient_name": "kiran ingale", + "line1": "3210 D Street", + "city": "SANFORD", + "state": "CA", + "postal_code": "27331", + "country_code": "US" + }, + "phone": "3333333333", + "country_code": "US" + } + }, + "transactions": [ + { + "reference_id": "default", + "amount": { + "total": "1434.45", + "currency": "USD", + "details": { + "subtotal": "1434.45", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payee": { + "merchant_id": "C7CYMKZDG8D6E", + "email": "john_merchant@example.com" + }, + "soft_descriptor": "JOHNMERCHAN JOHNMERCHAN", + "item_list": { + "shipping_address": { + "recipient_name": "kiran ingale", + "line1": "3210 D Street", + "city": "SANFORD", + "state": "CA", + "postal_code": "27331", + "country_code": "US" + } + }, + "related_resources": [ + { + "sale": { + "id": "6UA65534T65937149", + "state": "refunded", + "amount": { + "total": "1434.45", + "currency": "USD", + "details": { + "subtotal": "1434.45", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payment_mode": "INSTANT_TRANSFER", + "protection_eligibility": "ELIGIBLE", + "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", + "transaction_fee": { + "value": "50.55", + "currency": "USD" + }, + "purchase_unit_reference_id": "default", + "parent_payment": "PAYID-MW5Y7VQ3XR69795B78311812", + "create_time": "2024-02-01T12:34:30Z", + "update_time": "2024-02-01T12:35:49Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/6UA65534T65937149", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/6UA65534T65937149/refund", + "rel": "refund", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW5Y7VQ3XR69795B78311812", + "rel": "parent_payment", + "method": "GET" + } + ], + "soft_descriptor": "JOHNMERCHAN JOHNMERCHAN" + } + }, + { + "refund": { + "id": "9JS27953SE332473L", + "state": "completed", + "amount": { + "total": "-1434.45", + "currency": "USD" + }, + "parent_payment": "PAYID-MW5Y7VQ3XR69795B78311812", + "sale_id": "6UA65534T65937149", + "create_time": "2024-02-01T12:35:49Z", + "update_time": "2024-02-01T12:35:49Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/refund/9JS27953SE332473L", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW5Y7VQ3XR69795B78311812", + "rel": "parent_payment", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/6UA65534T65937149", + "rel": "sale", + "method": "GET" + } + ] + } + } + ] + } + ], + "create_time": "2024-02-01T12:34:30Z", + "update_time": "2024-02-01T12:35:49Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW5Y7VQ3XR69795B78311812", + "rel": "self", + "method": "GET" + } + ] + } + ], + "count": 3, + "next_id": "PAYID-MW5XXZY5YL87592N34454913" +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_PAYID-MW5XXZY5YL87592N34454913.json b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_PAYID-MW5XXZY5YL87592N34454913.json new file mode 100644 index 000000000000..dfee3371b093 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_PAYID-MW5XXZY5YL87592N34454913.json @@ -0,0 +1,391 @@ +{ + "payments": [ + { + "id": "PAYID-MW5XXZY5YL87592N34454913", + "intent": "sale", + "state": "approved", + "cart": "2P498024GJ403825S", + "payer": { + "payment_method": "paypal", + "status": "UNVERIFIED", + "payer_info": { + "email": "rahul21@yopmail.com", + "first_name": "d", + "last_name": "d", + "payer_id": "KZAHJGF7B2SBU", + "shipping_address": { + "recipient_name": "d d", + "line1": "gfd", + "line2": "gdgd", + "city": "dfgd", + "state": "CA", + "postal_code": "95388", + "country_code": "US" + }, + "phone": "8219746756", + "country_code": "US" + } + }, + "transactions": [ + { + "reference_id": "default", + "amount": { + "total": "100.00", + "currency": "USD", + "details": { + "subtotal": "100.00", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payee": { + "merchant_id": "C7CYMKZDG8D6E", + "email": "john_merchant@example.com" + }, + "soft_descriptor": "PAYPAL *JOHNMERCHAN JOHNMERCHAN", + "item_list": { + "shipping_address": { + "recipient_name": "d d", + "line1": "gfd", + "line2": "gdgd", + "city": "dfgd", + "state": "CA", + "postal_code": "95388", + "country_code": "US" + } + }, + "related_resources": [ + { + "sale": { + "id": "6W206643Y5829092B", + "state": "completed", + "amount": { + "total": "100.00", + "currency": "USD", + "details": { + "subtotal": "100.00", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payment_mode": "INSTANT_TRANSFER", + "protection_eligibility": "ELIGIBLE", + "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", + "transaction_fee": { + "value": "3.48", + "currency": "USD" + }, + "purchase_unit_reference_id": "default", + "receipt_id": "1732798430780793", + "parent_payment": "PAYID-MW5XXZY5YL87592N34454913", + "create_time": "2024-02-01T11:09:27Z", + "update_time": "2024-02-01T11:09:27Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/6W206643Y5829092B", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/6W206643Y5829092B/refund", + "rel": "refund", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW5XXZY5YL87592N34454913", + "rel": "parent_payment", + "method": "GET" + } + ], + "soft_descriptor": "PAYPAL *JOHNMERCHAN JOHNMERCHAN" + } + } + ] + } + ], + "create_time": "2024-02-01T11:09:27Z", + "update_time": "2024-02-01T11:09:27Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW5XXZY5YL87592N34454913", + "rel": "self", + "method": "GET" + } + ] + }, + { + "id": "PAYID-MW5W3EQ07B7347381105242R", + "intent": "sale", + "state": "approved", + "cart": "2FM93347R66426228", + "payer": { + "payment_method": "paypal", + "status": "UNVERIFIED", + "payer_info": { + "email": "admin@admin.com", + "first_name": "d", + "last_name": "d", + "payer_id": "N4KZ3KK4C2DFQ", + "shipping_address": { + "recipient_name": "d d", + "line1": "ytu", + "line2": "tyut", + "city": "tyut", + "state": "CA", + "postal_code": "95388", + "country_code": "US" + }, + "phone": "8219746756", + "country_code": "US" + } + }, + "transactions": [ + { + "reference_id": "default", + "amount": { + "total": "100.00", + "currency": "USD", + "details": { + "subtotal": "100.00", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payee": { + "merchant_id": "C7CYMKZDG8D6E", + "email": "john_merchant@example.com" + }, + "soft_descriptor": "PAYPAL *JOHNMERCHAN JOHNMERCHAN", + "item_list": { + "shipping_address": { + "recipient_name": "d d", + "line1": "ytu", + "line2": "tyut", + "city": "tyut", + "state": "CA", + "postal_code": "95388", + "country_code": "US" + } + }, + "related_resources": [ + { + "sale": { + "id": "17C62595GV9382350", + "state": "completed", + "amount": { + "total": "100.00", + "currency": "USD", + "details": { + "subtotal": "100.00", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payment_mode": "INSTANT_TRANSFER", + "protection_eligibility": "ELIGIBLE", + "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", + "transaction_fee": { + "value": "3.48", + "currency": "USD" + }, + "purchase_unit_reference_id": "default", + "receipt_id": "2958849288346255", + "parent_payment": "PAYID-MW5W3EQ07B7347381105242R", + "create_time": "2024-02-01T10:08:18Z", + "update_time": "2024-02-01T10:08:18Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/17C62595GV9382350", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/17C62595GV9382350/refund", + "rel": "refund", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW5W3EQ07B7347381105242R", + "rel": "parent_payment", + "method": "GET" + } + ], + "soft_descriptor": "PAYPAL *JOHNMERCHAN JOHNMERCHAN" + } + } + ] + } + ], + "create_time": "2024-02-01T10:08:18Z", + "update_time": "2024-02-01T10:08:18Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW5W3EQ07B7347381105242R", + "rel": "self", + "method": "GET" + } + ] + }, + { + "id": "PAYID-MW5WOVY25V45764MA349022Y", + "intent": "sale", + "state": "approved", + "cart": "7CP287511G6711412", + "payer": { + "payment_method": "paypal", + "status": "VERIFIED", + "payer_info": { + "email": "ABpaypal@gmail.com", + "first_name": "kiran", + "last_name": "ingale", + "payer_id": "MEZSMT5X3R5HW", + "shipping_address": { + "recipient_name": "kiran ingale", + "line1": "3210 D Street", + "city": "SANFORD", + "state": "CA", + "postal_code": "27331", + "country_code": "US" + }, + "phone": "3333333333", + "country_code": "US" + } + }, + "transactions": [ + { + "reference_id": "default", + "amount": { + "total": "1434.45", + "currency": "USD", + "details": { + "subtotal": "1434.45", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payee": { + "merchant_id": "C7CYMKZDG8D6E", + "email": "john_merchant@example.com" + }, + "soft_descriptor": "JOHNMERCHAN JOHNMERCHAN", + "item_list": { + "shipping_address": { + "recipient_name": "kiran ingale", + "line1": "3210 D Street", + "city": "SANFORD", + "state": "CA", + "postal_code": "27331", + "country_code": "US" + } + }, + "related_resources": [ + { + "sale": { + "id": "5SF16542W66927019", + "state": "refunded", + "amount": { + "total": "1434.45", + "currency": "USD", + "details": { + "subtotal": "1434.45", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payment_mode": "INSTANT_TRANSFER", + "protection_eligibility": "ELIGIBLE", + "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", + "transaction_fee": { + "value": "50.55", + "currency": "USD" + }, + "purchase_unit_reference_id": "default", + "parent_payment": "PAYID-MW5WOVY25V45764MA349022Y", + "create_time": "2024-02-01T09:41:44Z", + "update_time": "2024-02-01T09:45:35Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/5SF16542W66927019", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/5SF16542W66927019/refund", + "rel": "refund", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW5WOVY25V45764MA349022Y", + "rel": "parent_payment", + "method": "GET" + } + ], + "soft_descriptor": "JOHNMERCHAN JOHNMERCHAN" + } + }, + { + "refund": { + "id": "4P679266N7690881N", + "state": "completed", + "amount": { + "total": "-1434.45", + "currency": "USD" + }, + "parent_payment": "PAYID-MW5WOVY25V45764MA349022Y", + "sale_id": "5SF16542W66927019", + "create_time": "2024-02-01T09:45:35Z", + "update_time": "2024-02-01T09:45:35Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/refund/4P679266N7690881N", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW5WOVY25V45764MA349022Y", + "rel": "parent_payment", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/5SF16542W66927019", + "rel": "sale", + "method": "GET" + } + ] + } + } + ] + } + ], + "create_time": "2024-02-01T09:41:43Z", + "update_time": "2024-02-01T09:45:35Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW5WOVY25V45764MA349022Y", + "rel": "self", + "method": "GET" + } + ] + } + ], + "count": 3, + "next_id": "" +} diff --git a/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_page_init.json b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_page_init.json new file mode 100644 index 000000000000..025dfc513c85 --- /dev/null +++ b/airbyte-integrations/connectors/source-paypal-transaction/unit_tests/test_files/token_page_init.json @@ -0,0 +1,399 @@ +{ + "payments": [ + { + "id": "PAYID-MW55RCA31D103955T218492B", + "intent": "sale", + "state": "approved", + "cart": "06J27273EH485262V", + "payer": { + "payment_method": "paypal", + "status": "VERIFIED", + "payer_info": { + "email": "sb-vxpcr15413769@personal.example.com", + "first_name": "John", + "last_name": "Doe", + "payer_id": "TWL7BJVYNS7GU", + "shipping_address": { + "recipient_name": "John Doe", + "line1": "1 Main St", + "city": "San Jose", + "state": "CA", + "postal_code": "95131", + "country_code": "US" + }, + "phone": "4083068029", + "country_code": "US" + } + }, + "transactions": [ + { + "reference_id": "1000000000047", + "amount": { + "total": "343.80", + "currency": "USD", + "details": { + "subtotal": "343.80", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payee": { + "merchant_id": "C7CYMKZDG8D6E", + "email": "john_merchant@example.com" + }, + "item_list": { + "shipping_address": { + "recipient_name": "John Doe", + "line1": "1 Main St", + "city": "San Jose", + "state": "CA", + "postal_code": "95131", + "country_code": "US" + } + }, + "related_resources": [ + { + "sale": { + "id": "7PE037460E080360M", + "state": "completed", + "amount": { + "total": "343.80", + "currency": "USD", + "details": { + "subtotal": "343.80", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payment_mode": "INSTANT_TRANSFER", + "protection_eligibility": "ELIGIBLE", + "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", + "transaction_fee": { + "value": "12.49", + "currency": "USD" + }, + "purchase_unit_reference_id": "1000000000047", + "parent_payment": "PAYID-MW55RCA31D103955T218492B", + "create_time": "2024-02-01T17:44:40Z", + "update_time": "2024-02-01T17:44:40Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/7PE037460E080360M", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/7PE037460E080360M/refund", + "rel": "refund", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW55RCA31D103955T218492B", + "rel": "parent_payment", + "method": "GET" + } + ] + } + } + ] + } + ], + "create_time": "2024-02-01T17:44:40Z", + "update_time": "2024-02-01T17:44:40Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW55RCA31D103955T218492B", + "rel": "self", + "method": "GET" + } + ] + }, + { + "id": "PAYID-MW53UPA6UB45753B0034831X", + "intent": "sale", + "state": "approved", + "cart": "9A220393SG7753433", + "payer": { + "payment_method": "paypal", + "status": "VERIFIED", + "payer_info": { + "email": "sb-g43l4x28821325@personal.example.com", + "first_name": "John", + "last_name": "Doe", + "payer_id": "889X39VDHV8QY", + "shipping_address": { + "recipient_name": "John Doe", + "line1": "Via Unit? d'Italia, 5783296", + "city": "Napoli", + "state": "Napoli", + "postal_code": "80127", + "country_code": "IT" + }, + "phone": "9393358454", + "country_code": "IT" + } + }, + "transactions": [ + { + "reference_id": "default", + "amount": { + "total": "100.00", + "currency": "USD", + "details": { + "subtotal": "100.00", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payee": { + "merchant_id": "C7CYMKZDG8D6E", + "email": "john_merchant@example.com" + }, + "description": "T-Shirt", + "item_list": { + "items": [ + { + "name": "T-Shirt", + "description": "Green XL", + "price": "100.00", + "currency": "USD", + "tax": "0.00", + "quantity": 1 + } + ], + "shipping_address": { + "recipient_name": "John Doe", + "line1": "Via Unit? d'Italia, 5783296", + "city": "Napoli", + "state": "Napoli", + "postal_code": "80127", + "country_code": "IT" + } + }, + "related_resources": [ + { + "sale": { + "id": "29N28023XB153584X", + "state": "completed", + "amount": { + "total": "100.00", + "currency": "USD", + "details": { + "subtotal": "100.00", + "shipping": "0.00", + "insurance": "0.00", + "handling_fee": "0.00", + "shipping_discount": "0.00", + "discount": "0.00" + } + }, + "payment_mode": "INSTANT_TRANSFER", + "protection_eligibility": "ELIGIBLE", + "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", + "transaction_fee": { + "value": "5.48", + "currency": "USD" + }, + "receivable_amount": { + "value": "100.00", + "currency": "USD" + }, + "exchange_rate": "1.098848913950027", + "purchase_unit_reference_id": "default", + "parent_payment": "PAYID-MW53UPA6UB45753B0034831X", + "create_time": "2024-02-01T15:35:25Z", + "update_time": "2024-02-01T15:35:25Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/29N28023XB153584X", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/sale/29N28023XB153584X/refund", + "rel": "refund", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW53UPA6UB45753B0034831X", + "rel": "parent_payment", + "method": "GET" + } + ] + } + } + ] + } + ], + "create_time": "2024-02-01T15:35:24Z", + "update_time": "2024-02-01T15:35:25Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MW53UPA6UB45753B0034831X", + "rel": "self", + "method": "GET" + } + ] + }, + { + "id": "PAY-81S181868H8011217MW526OI", + "intent": "authorize", + "state": "approved", + "payer": { + "payment_method": "paypal", + "status": "VERIFIED", + "payer_info": { + "email": "mihai.streza1@mi-pay.com", + "first_name": "Mihai", + "last_name": "Streza", + "payer_id": "QHD3E8SRDDSQL", + "shipping_address": { + "recipient_name": "Mihai Streza" + }, + "phone": "07534201211", + "country_code": "GB" + } + }, + "transactions": [ + { + "amount": { + "total": "20.00", + "currency": "EUR", + "details": { + "subtotal": "20.00" + } + }, + "payee": { + "merchant_id": "C7CYMKZDG8D6E" + }, + "description": "topup", + "invoice_number": "100000000188917", + "soft_descriptor": "PAYPAL *JOHNMERCHAN", + "item_list": { + "items": [ + { + "name": "topup", + "price": "20.00", + "currency": "EUR", + "tax": "0.00", + "quantity": 1 + } + ], + "shipping_address": { + "recipient_name": "Mihai Streza" + } + }, + "related_resources": [ + { + "authorization": { + "id": "05D21713M12255848", + "state": "captured", + "amount": { + "total": "20.00", + "currency": "EUR", + "details": { + "subtotal": "20.00" + } + }, + "payment_mode": "INSTANT_TRANSFER", + "protection_eligibility": "ELIGIBLE", + "protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE", + "billing_agreement_id": "B-2B029484VC167663Y", + "parent_payment": "PAY-81S181868H8011217MW526OI", + "valid_until": "2024-03-01T14:48:26Z", + "create_time": "2024-02-01T14:48:26Z", + "update_time": "2024-02-01T14:48:30Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/05D21713M12255848", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/05D21713M12255848/capture", + "rel": "capture", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/05D21713M12255848/void", + "rel": "void", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/05D21713M12255848/reauthorize", + "rel": "reauthorize", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-81S181868H8011217MW526OI", + "rel": "parent_payment", + "method": "GET" + } + ] + } + }, + { + "capture": { + "id": "546282867R0022639", + "amount": { + "total": "20.00", + "currency": "EUR" + }, + "state": "completed", + "custom": "", + "transaction_fee": { + "value": "1.39", + "currency": "EUR" + }, + "parent_payment": "PAY-81S181868H8011217MW526OI", + "invoice_number": "100000000188917", + "create_time": "2024-02-01T14:48:30Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/capture/546282867R0022639", + "rel": "self", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/capture/546282867R0022639/refund", + "rel": "refund", + "method": "POST" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/authorization/05D21713M12255848", + "rel": "authorization", + "method": "GET" + }, + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-81S181868H8011217MW526OI", + "rel": "parent_payment", + "method": "GET" + } + ] + } + } + ] + } + ], + "create_time": "2024-02-01T14:48:25Z", + "links": [ + { + "href": "https://api.sandbox.paypal.com/v1/payments/payment/PAY-81S181868H8011217MW526OI", + "rel": "self", + "method": "GET" + } + ] + } + ], + "count": 3, + "next_id": "PAY-0L38757939422510JMW5ZJVA" +} diff --git a/docs/integrations/sources/paypal-transaction.md b/docs/integrations/sources/paypal-transaction.md index 8d3cf7c61b90..1c9504f55344 100644 --- a/docs/integrations/sources/paypal-transaction.md +++ b/docs/integrations/sources/paypal-transaction.md @@ -1,48 +1,60 @@ -# Paypal Transaction +# Paypal -This page contains the setup guide and reference information for the Paypal Transaction source connector. +This page contains the setup guide and reference information for the Paypal source connector. + +This connector uses [PayPal APIs](https://developer.paypal.com/api/rest/authentication/) OAuth 2.0 access token to authenticate requests. ## Prerequisites -The [Paypal Transaction API](https://developer.paypal.com/docs/api/transaction-search/v1/) is used to get the history of transactions for a PayPal account. +You will need a Paypal account, which you can get following [these steps](https://developer.paypal.com/docs/platforms/get-started/) + +In the same page, you will also find how to setup a Sandbox so you can test the connector before using it in production. ## Setup guide -### Step 1: Set up Paypal Transaction +### Step 1: Get your Paypal secrets + +After creating your account you will be able to get your `Client ID` and `Secret`. You can find them in your [Apps & Credentials page](https://developer.paypal.com/dashboard/applications/live). + + +### Step 2: Set up the Paypal Transaction connector in Airbyte + + +1. Log into your Airbyte account + - For Cloud [Log in here](https://cloud.airbyte.com/workspaces). + +2. In the left navigation bar, click **Sources**. + + a. If this is your first time creating a source, use the search bar and enter **Paypal Transaction** and select it. + + b. If you already have sources configured, go to the top-right corner and click **+new source**. Then enter **Paypal Transaction** in the searech bar and select the connector. + +3. Set the name for your source +4. Enter your `Client ID` +5. Enter your `Client secret` +6. `Start Date`: Use the provided datepicker or enter manually a UTC date and time in the format `YYYY-MM-DDTHH:MM:SSZ`. +7. Switch ON/Off the Sandbox toggle. By defaukt the toggle is OFF, meaning it work only in a produciton environment. +8. _(Optional) `Dispute Start Date Range`: Use the provided datepicker or enter manually a UTC date and time in the format `YYYY-MM-DDTHH:MM:SS.sssZ`. + - If you don't add a date and you sync the `lists_disputes stream`, it will use the default value of 180 days in the past to retrieve data + - It is mandatory to add the milliseconds is you enter a datetime. + - This option only works for `lists_disputes stream` -In order to get an `Client ID` and `Secret` please go to [this](https://developer.paypal.com/docs/platforms/get-started/) page and follow the instructions. After registration you may find your `Client ID` and `Secret` [here](https://developer.paypal.com/developer/accounts/). +9. _(Optional)`Refresh Token`:_ You can enter manually a refresh token. Right now the stream does this automatically. +10. _(Optional)`Number of days per request`:_ You can specify the days used by the connector when requesting data from the Paypal API. This helps in cases when you have a rate limit and you want to lower the window of retrieving data. + - Paypal has a 10K record limit per request. This option is useful if your sync is every week and you have more than 10K per week + - The default value is 7 + - This Max value you can enter is 31 days + +11. Click **Set up source** -:::note +:::info -Our Paypal Transactions Source Connector does not support OAuth at this time due to limitations outside of our control. If OAuth for Paypal Transactions is critical to your business, [please reach out to us](mailto:product@airbyte.io) to discuss how we may be able to partner on this effort. +By default, syncs are run with a slice period of 7 days. If you see errors with the message `Result set size is greater than the maximum limit` or an error code like `RESULTSET_TOO_LARGE`: + +- Try lower the the size of the slice period in your optional parameters in your connection configuration. +- You can try to lower the scheduling sync window in case a day slice period is not enough. Lowering the sync period it may help avoid reaching the 10K limit. ::: -## Step 2: Set up the Paypal Transaction connector in Airbyte - - -**For Airbyte Cloud:** - -1. [Log into your Airbyte Cloud](https://cloud.airbyte.com/workspaces) account. -2. In the left navigation bar, click **Sources**. In the top-right corner, click **+new source**. -3. On the Set up the source page, enter the name for the Paypal Transaction connector and select **Paypal Transaction** from the Source type dropdown. -4. Enter your client id -5. Enter your secret -6. Choose if your account is sandbox -7. Enter the date you want your sync to start from -8. Click **Set up source**. - - - -**For Airbyte Open Source:** - -1. Navigate to the Airbyte Open Source dashboard -2. Set the name for your source -3. Enter your client id -4. Enter your secret -5. Choose if your account is sandbox -6. Enter the date you want your sync to start from -7. Click **Set up source** - ## Supported sync modes @@ -54,25 +66,204 @@ The PayPal Transaction source connector supports the following [sync modes](http | Incremental - Append Sync | Yes | | Namespaces | No | + ## Supported Streams This Source is capable of syncing the following core Streams: * [Transactions](https://developer.paypal.com/docs/api/transaction-search/v1/#transactions) * [Balances](https://developer.paypal.com/docs/api/transaction-search/v1/#balances) +* [List Products](https://developer.paypal.com/docs/api/catalog-products/v1/#products_list) +* [Show Product Details](https://developer.paypal.com/docs/api/catalog-products/v1/#products_get) +* [List Disputes](https://developer.paypal.com/docs/api/customer-disputes/v1/#disputes_list) +* [Search Invoices](https://developer.paypal.com/docs/api/invoicing/v2/#invoices_search-invoices) +* [List Payments](https://developer.paypal.com/docs/api/payments/v1/#payment_list) + + +### Transactions Stream + +The below table contains the configuraiton parameters available for this connector and the default values and available features + +| **Param/Feature** | `Transactions` | +| :-------------------------- | :------------------------ | +| `Start Date` | Timestamp with TZ (no ms) | +| `Dispute Start Date Range` | NA | +| `Refresh token` | Auto | +| `Number of days per request`| Max 31 , 7(D) | +| `Pagination Strategy` | Page Increment | +| `Page size ` | Max 500 (F) | +| `Full Refresh` | :white_check_mark: | +| `Incremental` | :white_check_mark: (D) | + +**D:** Default configured Value + +**F:** Fixed Value. This means it is not configurable. + +___ + +### Balances Stream + +The below table contains the configuraiton parameters available for this connector and the default values and available features + +| **Param/Feature** |`Balances` | +| :-------------------------- |:------------------------ | +| `Start Date` |Timestamp with TZ (no ms) | +| `Dispute Start Date Range` |NA | +| `Refresh token` |Auto | +| `Number of days per request`|NA | +| `Pagination Strategy` |NA | +| `Page size ` |NA | +| `Full Refresh` |:white_check_mark: | +| `Incremental` |:white_check_mark: (D) | + +**D:** Default configured Value + +**F:** Fixed Value. This means it is not configurable. + +___ + + +### List Products Stream + +The below table contains the configuraiton parameters available for this connector and the default values and available features + + +| **Param/Feature** |`List Products` | +| :-------------------------- |:------------------------ | +| `Start Date` |NA | +| `Dispute Start Date Range` |NA | +| `Refresh token` |Auto | +| `Number of days per request`|NA | +| `Pagination Strategy` |Page Increment | +| `Page size ` |Max 20 (F) | +| `Full Refresh` |:white_check_mark: (D) | +| `Incremental` |:x: | + +**D:** Default configured Value + +**F:** Fixed Value. This means it is not configurable. + +:::caution + +When configuring your stream take in consideration that the way the API works limits the speed on retreiving data. In some cases a +30K catalog retrieval could take between 10-15 minutes. + +::: + +___ + +### Show Products Stream -## Performance considerations +The below table contains the configuraiton parameters available for this connector and the default values and available features -Paypal transaction API has some [limits](https://developer.paypal.com/docs/integration/direct/transaction-search/) +| **Param/Feature** |`Show Prod. Details` | +| :-------------------------- |:------------------------ | +| `Start Date` |NA | +| `Dispute Start Date Range` |NA | +| `Refresh token` |Auto | +| `Number of days per request`|NA | +| `Pagination Strategy` |NA | +| `Page size ` |NA | +| `Full Refresh` |:white_check_mark: (D) | +| `Incremental` |:x: | + +**D:** Default configured Value + +**F:** Fixed Value. This means it is not configurable. + + +:::caution + +When configuring this stream consider that the parent stream paginates with 20 number of items (Max alowed page size). The Paypal API calls are not concurrent, so the time it takes depends entirely on the server side. +This stream could take a considerable time syncing, so you should consider running the sync of this and the parent stream (`list_products`) at the end of the day. +Depending on the size of the catalog it could take several hours to sync. + +::: + +___ + +### List Disputes Stream + +The below table contains the configuraiton parameters available for this connector and the default values and available features + +| **Param/Feature** |`List Disputes` | +| :-------------------------- |:------------------------ | +| `Start Date` |NA | +| `Dispute Start Date Range` |Timestamp with TZ (w/ms) | +| `Refresh token` |Auto | +| `Number of days per request`|Max 180 , 7(D) | +| `Pagination Strategy` |Page Token | +| `Page size ` |Max 50 (F) | +| `Full Refresh` |:white_check_mark: | +| `Incremental` |:white_check_mark: (D) | + +**D:** Default configured Value + +**F:** Fixed Value. This means it is not configurable. + +___ + +### Search Invoices Stream + +The below table contains the configuraiton parameters available for this connector and the default values and available features + +| **Param/Feature** |`Search Invoices` | +| :-------------------------- |:------------------------ | +| `Start Date` |Timestamp with TZ (no ms) | +| `Dispute Start Date Range` |NA | +| `Refresh token` |Auto | +| `Number of days per request`|ND | +| `Pagination Strategy` |Page Number | +| `Page size ` |Max 100 (F) | +| `Full Refresh` |:white_check_mark: (D) | +| `Incremental` |:x: | + +**D:** Default configured Value + +**F:** Fixed Value. This means it is not configurable. + +**ND:** Not Defined in the source. + + +:::info + +The `start_end` from the configuration, is passed to the body of the request and uses the `creation_date_range.start` and `creation_date_range.end`. More information in the [Paypal Developer API documentation](https://developer.paypal.com/docs/api/invoicing/v2/#invoices_search-invoices). + +::: + + +___ + +### List Payments Stream + +The below table contains the configuraiton parameters available for this connector and the default values and available features. + +| **Param/Feature** |`List Payments` | +| :-------------------------- |:------------------------ | +| `Start Date` |Timestamp with TZ (no ms) | +| `Dispute Start Date Range` |NA | +| `Refresh token` |Auto | +| `Number of days per request`|NA , 7(D) | +| `Pagination Strategy` |Page Cursor | +| `Page size ` |Max 20 (F) | +| `Full Refresh` |:white_check_mark: | +| `Incremental` |:white_check_mark: (D) | + +**D:** Default configured Value + +**F:** Fixed Value. This means it is not configurable. + +___ + +## Performance Considerations + +* **Data Availability:** It takes a maximum of 3 hours for executed transactions to appear in the list transactions call. +* **Number of days per request:** The maximum supported date range is 31 days. +* **Historical Data:** You can't retrieve more than 3yrs of data for the `transactions` stream. For `dispute_start_date` you can only retrieve 180 days of data (see specifications per stream) +* `records_per_request`: The maximum number of records in a single request are 10K (API Server restriction) +* `page_size`: The maximum page size is 500. This has been configured by default. +* `requests_per_minute` = The maximum limit is 50 requests per minute from IP address to all endpoint (API Server restriction). -* `start_date_min` = 3 years, API call lists transaction for the previous three years. -* `start_date_max` = 1.5 days, it takes a maximum of three hours for executed transactions to appear in the list transactions call. It is set to 1.5 days by default based on experience, otherwise API throw an error. -* `stream_slice_period` = 7 day, the maximum supported date range is 31 days. -* `records_per_request` = 10000, the maximum number of records in a single request. -* `page_size` = 500, the maximum page size is 500. -* `requests_per_minute` = 30, maximum limit is 50 requests per minute from IP address to all endpoint -By default, syncs are performed with a slice period of 7 days. If you see errors with the message `Result set size is greater than the maximum limit. Change the filter criteria and try again.`, lower the size of the slice period in your connection configuration. ## Data type map @@ -83,15 +274,17 @@ By default, syncs are performed with a slice period of 7 days. If you see errors | `array` | `array` | | `object` | `object` | + ## Changelog | Version | Date | Pull Request | Subject | -| :------ | :--------- | :------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------- | -| 2.2.2 | 2024-02-09 | [35075](https://github.com/airbytehq/airbyte/pull/35075) | Manage dependencies with Poetry. | -| 2.2.1 | 2024-01-11 | [34155](https://github.com/airbytehq/airbyte/pull/34155) | prepare for airbyte-lib | -| 2.2.0 | 2023-10-25 | [31852](https://github.com/airbytehq/airbyte/pull/31852) | The size of the time_window can be configured | -| 2.1.2 | 2023-10-23 | [31759](https://github.com/airbytehq/airbyte/pull/31759) | Keep transaction_id as a string and fetch data in 7-day batches | -| 2.1.1 | 2023-10-19 | [31599](https://github.com/airbytehq/airbyte/pull/31599) | Base image migration: remove Dockerfile and use the python-connector-base image | +|:--------|:-----------|:---------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------| +| 2.3.0 | 2024-02-014 | [34510](https://github.com/airbytehq/airbyte/pull/34510) | Silver certified. New Streams Added | +| 2.2.2 | 2024-02-09 | [35075](https://github.com/airbytehq/airbyte/pull/35075) | Manage dependencies with Poetry. +| 2.2.1 | 2024-01-11 | [34155](https://github.com/airbytehq/airbyte/pull/34155) | prepare for airbyte-lib | +| 2.2.0 | 2023-10-25 | [31852](https://github.com/airbytehq/airbyte/pull/31852) | The size of the time_window can be configured | +| 2.1.2 | 2023-10-23 | [31759](https://github.com/airbytehq/airbyte/pull/31759) | Keep transaction_id as a string and fetch data in 7-day batches +| 2.1.1 | 2023-10-19 | [31599](https://github.com/airbytehq/airbyte/pull/31599) | Base image migration: remove Dockerfile and use the python-connector-base image | | 2.1.0 | 2023-08-14 | [29223](https://github.com/airbytehq/airbyte/pull/29223) | Migrate Python CDK to Low Code schema | | 2.0.0 | 2023-07-05 | [27916](https://github.com/airbytehq/airbyte/pull/27916) | Update `Balances` schema | | 1.0.0 | 2023-07-03 | [27968](https://github.com/airbytehq/airbyte/pull/27968) | mark `Client ID` and `Client Secret` as required fields | From 553c9b0f84e3bc833219d21b9c1c88f0e69dd144 Mon Sep 17 00:00:00 2001 From: Augustin Date: Mon, 19 Feb 2024 12:43:56 +0100 Subject: [PATCH 25/43] Revamp QA checks into a battery included package (#35322) --- .../connectors/connector_ops/poetry.lock | 879 +++--- .../connectors/connector_ops/pyproject.toml | 2 +- airbyte-ci/connectors/connectors_qa/README.md | 96 + .../connectors/connectors_qa/poetry.lock | 2457 +++++++++++++++++ .../connectors/connectors_qa/pyproject.toml | 43 + .../src/connectors_qa/__init__.py | 0 .../src/connectors_qa/checks/__init__.py | 14 + .../src/connectors_qa/checks/assets.py | 33 + .../src/connectors_qa/checks/documentation.py | 206 ++ .../src/connectors_qa/checks/metadata.py | 99 + .../src/connectors_qa/checks/packaging.py | 219 ++ .../src/connectors_qa/checks/security.py | 147 + .../connectors_qa/src/connectors_qa/cli.py | 113 + .../connectors_qa/src/connectors_qa/consts.py | 23 + .../connectors_qa/src/connectors_qa/models.py | 235 ++ .../src/connectors_qa/templates/__init__.py | 0 .../connectors_qa/templates/qa_checks.md.j2 | 17 + .../connectors_qa/src/connectors_qa/utils.py | 44 + .../connectors_qa/tests/__init__.py | 0 .../connectors_qa/tests/conftest.py | 11 + .../tests/unit_tests/__init__.py | 0 .../tests/unit_tests/test_checks/__init__.py | 0 .../unit_tests/test_checks/test_assets.py | 56 + .../test_checks/test_documentation.py | 358 +++ .../unit_tests/test_checks/test_metadata.py | 157 ++ .../unit_tests/test_checks/test_packaging.py | 290 ++ .../unit_tests/test_checks/test_security.py | 130 + .../tests/unit_tests/test_models.py | 52 + airbyte-ci/connectors/pipelines/README.md | 1 + .../pipelines/airbyte_ci/test/__init__.py | 1 + .../connectors/pipelines/pyproject.toml | 4 +- 31 files changed, 5205 insertions(+), 482 deletions(-) create mode 100644 airbyte-ci/connectors/connectors_qa/README.md create mode 100644 airbyte-ci/connectors/connectors_qa/poetry.lock create mode 100644 airbyte-ci/connectors/connectors_qa/pyproject.toml create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/__init__.py create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/__init__.py create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/assets.py create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/documentation.py create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/metadata.py create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/security.py create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/cli.py create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/consts.py create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/models.py create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/templates/__init__.py create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/templates/qa_checks.md.j2 create mode 100644 airbyte-ci/connectors/connectors_qa/src/connectors_qa/utils.py create mode 100644 airbyte-ci/connectors/connectors_qa/tests/__init__.py create mode 100644 airbyte-ci/connectors/connectors_qa/tests/conftest.py create mode 100644 airbyte-ci/connectors/connectors_qa/tests/unit_tests/__init__.py create mode 100644 airbyte-ci/connectors/connectors_qa/tests/unit_tests/test_checks/__init__.py create mode 100644 airbyte-ci/connectors/connectors_qa/tests/unit_tests/test_checks/test_assets.py create mode 100644 airbyte-ci/connectors/connectors_qa/tests/unit_tests/test_checks/test_documentation.py create mode 100644 airbyte-ci/connectors/connectors_qa/tests/unit_tests/test_checks/test_metadata.py create mode 100644 airbyte-ci/connectors/connectors_qa/tests/unit_tests/test_checks/test_packaging.py create mode 100644 airbyte-ci/connectors/connectors_qa/tests/unit_tests/test_checks/test_security.py create mode 100644 airbyte-ci/connectors/connectors_qa/tests/unit_tests/test_models.py diff --git a/airbyte-ci/connectors/connector_ops/poetry.lock b/airbyte-ci/connectors/connector_ops/poetry.lock index f852e65d56c7..3c39ea2bfe7d 100644 --- a/airbyte-ci/connectors/connector_ops/poetry.lock +++ b/airbyte-ci/connectors/connector_ops/poetry.lock @@ -1,25 +1,25 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "cachetools" -version = "5.3.1" +version = "5.3.2" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" files = [ - {file = "cachetools-5.3.1-py3-none-any.whl", hash = "sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590"}, - {file = "cachetools-5.3.1.tar.gz", hash = "sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b"}, + {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, + {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, ] [[package]] name = "certifi" -version = "2023.7.22" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] @@ -88,101 +88,101 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.3.0" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.0.tar.gz", hash = "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-win32.whl", hash = "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d"}, - {file = "charset_normalizer-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-win32.whl", hash = "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786"}, - {file = "charset_normalizer-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-win32.whl", hash = "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df"}, - {file = "charset_normalizer-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-win32.whl", hash = "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c"}, - {file = "charset_normalizer-3.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-win32.whl", hash = "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e"}, - {file = "charset_normalizer-3.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-win32.whl", hash = "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a"}, - {file = "charset_normalizer-3.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884"}, - {file = "charset_normalizer-3.3.0-py3-none-any.whl", hash = "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2"}, + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] [[package]] @@ -305,13 +305,13 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -319,13 +319,13 @@ test = ["pytest (>=6)"] [[package]] name = "freezegun" -version = "1.2.2" +version = "1.4.0" description = "Let your Python tests travel through time" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "freezegun-1.2.2-py3-none-any.whl", hash = "sha256:ea1b963b993cb9ea195adbd893a48d573fda951b0da64f60883d7e988b606c9f"}, - {file = "freezegun-1.2.2.tar.gz", hash = "sha256:cd22d1ba06941384410cd967d8a99d5ae2442f57dfafeff2fda5de8dc5c05446"}, + {file = "freezegun-1.4.0-py3-none-any.whl", hash = "sha256:55e0fc3c84ebf0a96a5aa23ff8b53d70246479e9a68863f1fcac5a3e52f19dd6"}, + {file = "freezegun-1.4.0.tar.gz", hash = "sha256:10939b0ba0ff5adaecf3b06a5c2f73071d9678e507c5eaedb23c761d56ac774b"}, ] [package.dependencies] @@ -333,13 +333,13 @@ python-dateutil = ">=2.7" [[package]] name = "gitdb" -version = "4.0.10" +version = "4.0.11" description = "Git Object Database" optional = false python-versions = ">=3.7" files = [ - {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, - {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, ] [package.dependencies] @@ -347,30 +347,30 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.37" +version = "3.1.42" description = "GitPython is a Python library used to interact with Git repositories" optional = false python-versions = ">=3.7" files = [ - {file = "GitPython-3.1.37-py3-none-any.whl", hash = "sha256:5f4c4187de49616d710a77e98ddf17b4782060a1788df441846bddefbb89ab33"}, - {file = "GitPython-3.1.37.tar.gz", hash = "sha256:f9b9ddc0761c125d5780eab2d64be4873fc6817c2899cbcb34b02344bdc7bc54"}, + {file = "GitPython-3.1.42-py3-none-any.whl", hash = "sha256:1bf9cd7c9e7255f77778ea54359e54ac22a72a5b51288c457c881057b7bb9ecd"}, + {file = "GitPython-3.1.42.tar.gz", hash = "sha256:2d99869e0fef71a73cbd242528105af1d6c1b108c60dfabd994bf292f76c3ceb"}, ] [package.dependencies] gitdb = ">=4.0.1,<5" [package.extras] -test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-sugar"] +test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar"] [[package]] name = "google-api-core" -version = "2.12.0" +version = "2.17.1" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.12.0.tar.gz", hash = "sha256:c22e01b1e3c4dcd90998494879612c38d0a3411d1f7b679eb89e2abe3ce1f553"}, - {file = "google_api_core-2.12.0-py3-none-any.whl", hash = "sha256:ec6054f7d64ad13b41e43d96f735acbd763b0f3b695dabaa2d579673f6a6e160"}, + {file = "google-api-core-2.17.1.tar.gz", hash = "sha256:9df18a1f87ee0df0bc4eea2770ebc4228392d8cc4066655b320e2cfccb15db95"}, + {file = "google_api_core-2.17.1-py3-none-any.whl", hash = "sha256:610c5b90092c360736baccf17bd3efbcb30dd380e7a6dc28a71059edb8bd0d8e"}, ] [package.dependencies] @@ -386,13 +386,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.23.3" +version = "2.28.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.23.3.tar.gz", hash = "sha256:6864247895eea5d13b9c57c9e03abb49cb94ce2dc7c58e91cba3248c7477c9e3"}, - {file = "google_auth-2.23.3-py2.py3-none-any.whl", hash = "sha256:a8f4608e65c244ead9e0538f181a96c6e11199ec114d41f1d7b1bffa96937bda"}, + {file = "google-auth-2.28.0.tar.gz", hash = "sha256:3cfc1b6e4e64797584fb53fc9bd0b7afa9b7c0dba2004fa7dcc9349e58cc3195"}, + {file = "google_auth-2.28.0-py2.py3-none-any.whl", hash = "sha256:7634d29dcd1e101f5226a23cbc4a0c6cda6394253bf80e281d9c5c6797869c53"}, ] [package.dependencies] @@ -409,13 +409,13 @@ requests = ["requests (>=2.20.0,<3.0.0.dev0)"] [[package]] name = "google-cloud-core" -version = "2.3.3" +version = "2.4.1" description = "Google Cloud API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-core-2.3.3.tar.gz", hash = "sha256:37b80273c8d7eee1ae816b3a20ae43585ea50506cb0e60f3cf5be5f87f1373cb"}, - {file = "google_cloud_core-2.3.3-py2.py3-none-any.whl", hash = "sha256:fbd11cad3e98a7e5b0343dc07cb1039a5ffd7a5bb96e1f1e27cee4bda4a90863"}, + {file = "google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073"}, + {file = "google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61"}, ] [package.dependencies] @@ -423,23 +423,24 @@ google-api-core = ">=1.31.6,<2.0.dev0 || >2.3.0,<3.0.0dev" google-auth = ">=1.25.0,<3.0dev" [package.extras] -grpc = ["grpcio (>=1.38.0,<2.0dev)"] +grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] [[package]] name = "google-cloud-storage" -version = "2.11.0" +version = "2.14.0" description = "Google Cloud Storage API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-storage-2.11.0.tar.gz", hash = "sha256:6fbf62659b83c8f3a0a743af0d661d2046c97c3a5bfb587c4662c4bc68de3e31"}, - {file = "google_cloud_storage-2.11.0-py2.py3-none-any.whl", hash = "sha256:88cbd7fb3d701c780c4272bc26952db99f25eb283fb4c2208423249f00b5fe53"}, + {file = "google-cloud-storage-2.14.0.tar.gz", hash = "sha256:2d23fcf59b55e7b45336729c148bb1c464468c69d5efbaee30f7201dd90eb97e"}, + {file = "google_cloud_storage-2.14.0-py2.py3-none-any.whl", hash = "sha256:8641243bbf2a2042c16a6399551fbb13f062cbc9a2de38d6c0bb5426962e9dbd"}, ] [package.dependencies] google-api-core = ">=1.31.5,<2.0.dev0 || >2.3.0,<3.0.0dev" -google-auth = ">=1.25.0,<3.0dev" +google-auth = ">=2.23.3,<3.0dev" google-cloud-core = ">=2.3.0,<3.0dev" +google-crc32c = ">=1.0,<2.0dev" google-resumable-media = ">=2.6.0" requests = ">=2.18.0,<3.0.0dev" @@ -528,13 +529,13 @@ testing = ["pytest"] [[package]] name = "google-resumable-media" -version = "2.6.0" +version = "2.7.0" description = "Utilities for Google Media Downloads and Resumable Uploads" optional = false python-versions = ">= 3.7" files = [ - {file = "google-resumable-media-2.6.0.tar.gz", hash = "sha256:972852f6c65f933e15a4a210c2b96930763b47197cdf4aa5f5bea435efb626e7"}, - {file = "google_resumable_media-2.6.0-py2.py3-none-any.whl", hash = "sha256:fc03d344381970f79eebb632a3c18bb1828593a2dc5572b5f90115ef7d11e81b"}, + {file = "google-resumable-media-2.7.0.tar.gz", hash = "sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b"}, + {file = "google_resumable_media-2.7.0-py2.py3-none-any.whl", hash = "sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08"}, ] [package.dependencies] @@ -546,13 +547,13 @@ requests = ["requests (>=2.18.0,<3.0.0dev)"] [[package]] name = "googleapis-common-protos" -version = "1.60.0" +version = "1.62.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.60.0.tar.gz", hash = "sha256:e73ebb404098db405ba95d1e1ae0aa91c3e15a71da031a2eeb6b2e23e7bc3708"}, - {file = "googleapis_common_protos-1.60.0-py2.py3-none-any.whl", hash = "sha256:69f9bbcc6acde92cab2db95ce30a70bd2b81d20b12eff3f1aabaffcbe8a93918"}, + {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, + {file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"}, ] [package.dependencies] @@ -563,13 +564,13 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] @@ -620,77 +621,47 @@ files = [ [[package]] name = "numpy" -version = "1.25.2" +version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"}, - {file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"}, - {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"}, - {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"}, - {file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"}, - {file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"}, - {file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"}, - {file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"}, - {file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"}, - {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"}, - {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"}, - {file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"}, - {file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"}, - {file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"}, - {file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"}, - {file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"}, - {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"}, - {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"}, - {file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"}, - {file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"}, - {file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"}, - {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, -] - -[[package]] -name = "numpy" -version = "1.26.0" -description = "Fundamental package for array computing in Python" -optional = false -python-versions = "<3.13,>=3.9" -files = [ - {file = "numpy-1.26.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8db2f125746e44dce707dd44d4f4efeea8d7e2b43aace3f8d1f235cfa2733dd"}, - {file = "numpy-1.26.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0621f7daf973d34d18b4e4bafb210bbaf1ef5e0100b5fa750bd9cde84c7ac292"}, - {file = "numpy-1.26.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51be5f8c349fdd1a5568e72713a21f518e7d6707bcf8503b528b88d33b57dc68"}, - {file = "numpy-1.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:767254ad364991ccfc4d81b8152912e53e103ec192d1bb4ea6b1f5a7117040be"}, - {file = "numpy-1.26.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:436c8e9a4bdeeee84e3e59614d38c3dbd3235838a877af8c211cfcac8a80b8d3"}, - {file = "numpy-1.26.0-cp310-cp310-win32.whl", hash = "sha256:c2e698cb0c6dda9372ea98a0344245ee65bdc1c9dd939cceed6bb91256837896"}, - {file = "numpy-1.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:09aaee96c2cbdea95de76ecb8a586cb687d281c881f5f17bfc0fb7f5890f6b91"}, - {file = "numpy-1.26.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:637c58b468a69869258b8ae26f4a4c6ff8abffd4a8334c830ffb63e0feefe99a"}, - {file = "numpy-1.26.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:306545e234503a24fe9ae95ebf84d25cba1fdc27db971aa2d9f1ab6bba19a9dd"}, - {file = "numpy-1.26.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c6adc33561bd1d46f81131d5352348350fc23df4d742bb246cdfca606ea1208"}, - {file = "numpy-1.26.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e062aa24638bb5018b7841977c360d2f5917268d125c833a686b7cbabbec496c"}, - {file = "numpy-1.26.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:546b7dd7e22f3c6861463bebb000646fa730e55df5ee4a0224408b5694cc6148"}, - {file = "numpy-1.26.0-cp311-cp311-win32.whl", hash = "sha256:c0b45c8b65b79337dee5134d038346d30e109e9e2e9d43464a2970e5c0e93229"}, - {file = "numpy-1.26.0-cp311-cp311-win_amd64.whl", hash = "sha256:eae430ecf5794cb7ae7fa3808740b015aa80747e5266153128ef055975a72b99"}, - {file = "numpy-1.26.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:166b36197e9debc4e384e9c652ba60c0bacc216d0fc89e78f973a9760b503388"}, - {file = "numpy-1.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f042f66d0b4ae6d48e70e28d487376204d3cbf43b84c03bac57e28dac6151581"}, - {file = "numpy-1.26.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5e18e5b14a7560d8acf1c596688f4dfd19b4f2945b245a71e5af4ddb7422feb"}, - {file = "numpy-1.26.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f6bad22a791226d0a5c7c27a80a20e11cfe09ad5ef9084d4d3fc4a299cca505"}, - {file = "numpy-1.26.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4acc65dd65da28060e206c8f27a573455ed724e6179941edb19f97e58161bb69"}, - {file = "numpy-1.26.0-cp312-cp312-win32.whl", hash = "sha256:bb0d9a1aaf5f1cb7967320e80690a1d7ff69f1d47ebc5a9bea013e3a21faec95"}, - {file = "numpy-1.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:ee84ca3c58fe48b8ddafdeb1db87388dce2c3c3f701bf447b05e4cfcc3679112"}, - {file = "numpy-1.26.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a873a8180479bc829313e8d9798d5234dfacfc2e8a7ac188418189bb8eafbd2"}, - {file = "numpy-1.26.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:914b28d3215e0c721dc75db3ad6d62f51f630cb0c277e6b3bcb39519bed10bd8"}, - {file = "numpy-1.26.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c78a22e95182fb2e7874712433eaa610478a3caf86f28c621708d35fa4fd6e7f"}, - {file = "numpy-1.26.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86f737708b366c36b76e953c46ba5827d8c27b7a8c9d0f471810728e5a2fe57c"}, - {file = "numpy-1.26.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b44e6a09afc12952a7d2a58ca0a2429ee0d49a4f89d83a0a11052da696440e49"}, - {file = "numpy-1.26.0-cp39-cp39-win32.whl", hash = "sha256:5671338034b820c8d58c81ad1dafc0ed5a00771a82fccc71d6438df00302094b"}, - {file = "numpy-1.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:020cdbee66ed46b671429c7265cf00d8ac91c046901c55684954c3958525dab2"}, - {file = "numpy-1.26.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0792824ce2f7ea0c82ed2e4fecc29bb86bee0567a080dacaf2e0a01fe7654369"}, - {file = "numpy-1.26.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d484292eaeb3e84a51432a94f53578689ffdea3f90e10c8b203a99be5af57d8"}, - {file = "numpy-1.26.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:186ba67fad3c60dbe8a3abff3b67a91351100f2661c8e2a80364ae6279720299"}, - {file = "numpy-1.26.0.tar.gz", hash = "sha256:f93fc78fe8bf15afe2b8d6b6499f1c73953169fad1e9a8dd086cdff3190e7fdf"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] @@ -706,138 +677,85 @@ files = [ [[package]] name = "pandas" -version = "2.1.0" -description = "Powerful data structures for data analysis, time series, and statistics" -optional = false -python-versions = ">=3.9" -files = [ - {file = "pandas-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:40dd20439ff94f1b2ed55b393ecee9cb6f3b08104c2c40b0cb7186a2f0046242"}, - {file = "pandas-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d4f38e4fedeba580285eaac7ede4f686c6701a9e618d8a857b138a126d067f2f"}, - {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e6a0fe052cf27ceb29be9429428b4918f3740e37ff185658f40d8702f0b3e09"}, - {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d81e1813191070440d4c7a413cb673052b3b4a984ffd86b8dd468c45742d3cc"}, - {file = "pandas-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eb20252720b1cc1b7d0b2879ffc7e0542dd568f24d7c4b2347cb035206936421"}, - {file = "pandas-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:38f74ef7ebc0ffb43b3d633e23d74882bce7e27bfa09607f3c5d3e03ffd9a4a5"}, - {file = "pandas-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cda72cc8c4761c8f1d97b169661f23a86b16fdb240bdc341173aee17e4d6cedd"}, - {file = "pandas-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d97daeac0db8c993420b10da4f5f5b39b01fc9ca689a17844e07c0a35ac96b4b"}, - {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c58b1113892e0c8078f006a167cc210a92bdae23322bb4614f2f0b7a4b510f"}, - {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:629124923bcf798965b054a540f9ccdfd60f71361255c81fa1ecd94a904b9dd3"}, - {file = "pandas-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:70cf866af3ab346a10debba8ea78077cf3a8cd14bd5e4bed3d41555a3280041c"}, - {file = "pandas-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d53c8c1001f6a192ff1de1efe03b31a423d0eee2e9e855e69d004308e046e694"}, - {file = "pandas-2.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86f100b3876b8c6d1a2c66207288ead435dc71041ee4aea789e55ef0e06408cb"}, - {file = "pandas-2.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f330845ad21c11db51e02d8d69acc9035edfd1116926ff7245c7215db57957"}, - {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9a6ccf0963db88f9b12df6720e55f337447aea217f426a22d71f4213a3099a6"}, - {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99e678180bc59b0c9443314297bddce4ad35727a1a2656dbe585fd78710b3b9"}, - {file = "pandas-2.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b31da36d376d50a1a492efb18097b9101bdbd8b3fbb3f49006e02d4495d4c644"}, - {file = "pandas-2.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0164b85937707ec7f70b34a6c3a578dbf0f50787f910f21ca3b26a7fd3363437"}, - {file = "pandas-2.1.0.tar.gz", hash = "sha256:62c24c7fc59e42b775ce0679cfa7b14a5f9bfb7643cfbe708c960699e05fb918"}, -] - -[package.dependencies] -numpy = {version = ">=1.23.2", markers = "python_version >= \"3.11\""} -python-dateutil = ">=2.8.2" -pytz = ">=2020.1" -tzdata = ">=2022.1" - -[package.extras] -all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] -aws = ["s3fs (>=2022.05.0)"] -clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] -compression = ["zstandard (>=0.17.0)"] -computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"] -consortium-standard = ["dataframe-api-compat (>=0.1.7)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"] -feather = ["pyarrow (>=7.0.0)"] -fss = ["fsspec (>=2022.05.0)"] -gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"] -hdf5 = ["tables (>=3.7.0)"] -html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"] -mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"] -parquet = ["pyarrow (>=7.0.0)"] -performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"] -plot = ["matplotlib (>=3.6.1)"] -postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] -spss = ["pyreadstat (>=1.1.5)"] -sql-other = ["SQLAlchemy (>=1.4.36)"] -test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.8.0)"] - -[[package]] -name = "pandas" -version = "2.1.1" +version = "2.2.0" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" files = [ - {file = "pandas-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58d997dbee0d4b64f3cb881a24f918b5f25dd64ddf31f467bb9b67ae4c63a1e4"}, - {file = "pandas-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02304e11582c5d090e5a52aec726f31fe3f42895d6bfc1f28738f9b64b6f0614"}, - {file = "pandas-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffa8f0966de2c22de408d0e322db2faed6f6e74265aa0856f3824813cf124363"}, - {file = "pandas-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1f84c144dee086fe4f04a472b5cd51e680f061adf75c1ae4fc3a9275560f8f4"}, - {file = "pandas-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:75ce97667d06d69396d72be074f0556698c7f662029322027c226fd7a26965cb"}, - {file = "pandas-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:4c3f32fd7c4dccd035f71734df39231ac1a6ff95e8bdab8d891167197b7018d2"}, - {file = "pandas-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e2959720b70e106bb1d8b6eadd8ecd7c8e99ccdbe03ee03260877184bb2877d"}, - {file = "pandas-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:25e8474a8eb258e391e30c288eecec565bfed3e026f312b0cbd709a63906b6f8"}, - {file = "pandas-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8bd1685556f3374520466998929bade3076aeae77c3e67ada5ed2b90b4de7f0"}, - {file = "pandas-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc3657869c7902810f32bd072f0740487f9e030c1a3ab03e0af093db35a9d14e"}, - {file = "pandas-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:05674536bd477af36aa2effd4ec8f71b92234ce0cc174de34fd21e2ee99adbc2"}, - {file = "pandas-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:b407381258a667df49d58a1b637be33e514b07f9285feb27769cedb3ab3d0b3a"}, - {file = "pandas-2.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c747793c4e9dcece7bb20156179529898abf505fe32cb40c4052107a3c620b49"}, - {file = "pandas-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3bcad1e6fb34b727b016775bea407311f7721db87e5b409e6542f4546a4951ea"}, - {file = "pandas-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5ec7740f9ccb90aec64edd71434711f58ee0ea7f5ed4ac48be11cfa9abf7317"}, - {file = "pandas-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29deb61de5a8a93bdd033df328441a79fcf8dd3c12d5ed0b41a395eef9cd76f0"}, - {file = "pandas-2.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4f99bebf19b7e03cf80a4e770a3e65eee9dd4e2679039f542d7c1ace7b7b1daa"}, - {file = "pandas-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:84e7e910096416adec68075dc87b986ff202920fb8704e6d9c8c9897fe7332d6"}, - {file = "pandas-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:366da7b0e540d1b908886d4feb3d951f2f1e572e655c1160f5fde28ad4abb750"}, - {file = "pandas-2.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e50e72b667415a816ac27dfcfe686dc5a0b02202e06196b943d54c4f9c7693e"}, - {file = "pandas-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc1ab6a25da197f03ebe6d8fa17273126120874386b4ac11c1d687df288542dd"}, - {file = "pandas-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0dbfea0dd3901ad4ce2306575c54348d98499c95be01b8d885a2737fe4d7a98"}, - {file = "pandas-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0489b0e6aa3d907e909aef92975edae89b1ee1654db5eafb9be633b0124abe97"}, - {file = "pandas-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:4cdb0fab0400c2cb46dafcf1a0fe084c8bb2480a1fa8d81e19d15e12e6d4ded2"}, - {file = "pandas-2.1.1.tar.gz", hash = "sha256:fecb198dc389429be557cde50a2d46da8434a17fe37d7d41ff102e3987fd947b"}, + {file = "pandas-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8108ee1712bb4fa2c16981fba7e68b3f6ea330277f5ca34fa8d557e986a11670"}, + {file = "pandas-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:736da9ad4033aeab51d067fc3bd69a0ba36f5a60f66a527b3d72e2030e63280a"}, + {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38e0b4fc3ddceb56ec8a287313bc22abe17ab0eb184069f08fc6a9352a769b18"}, + {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20404d2adefe92aed3b38da41d0847a143a09be982a31b85bc7dd565bdba0f4e"}, + {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ea3ee3f125032bfcade3a4cf85131ed064b4f8dd23e5ce6fa16473e48ebcaf5"}, + {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9670b3ac00a387620489dfc1bca66db47a787f4e55911f1293063a78b108df1"}, + {file = "pandas-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a946f210383c7e6d16312d30b238fd508d80d927014f3b33fb5b15c2f895430"}, + {file = "pandas-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a1b438fa26b208005c997e78672f1aa8138f67002e833312e6230f3e57fa87d5"}, + {file = "pandas-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ce2fbc8d9bf303ce54a476116165220a1fedf15985b09656b4b4275300e920b"}, + {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2707514a7bec41a4ab81f2ccce8b382961a29fbe9492eab1305bb075b2b1ff4f"}, + {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85793cbdc2d5bc32620dc8ffa715423f0c680dacacf55056ba13454a5be5de88"}, + {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cfd6c2491dc821b10c716ad6776e7ab311f7df5d16038d0b7458bc0b67dc10f3"}, + {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a146b9dcacc3123aa2b399df1a284de5f46287a4ab4fbfc237eac98a92ebcb71"}, + {file = "pandas-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbc1b53c0e1fdf16388c33c3cca160f798d38aea2978004dd3f4d3dec56454c9"}, + {file = "pandas-2.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a41d06f308a024981dcaa6c41f2f2be46a6b186b902c94c2674e8cb5c42985bc"}, + {file = "pandas-2.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:159205c99d7a5ce89ecfc37cb08ed179de7783737cea403b295b5eda8e9c56d1"}, + {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1e1f3861ea9132b32f2133788f3b14911b68102d562715d71bd0013bc45440"}, + {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:761cb99b42a69005dec2b08854fb1d4888fdf7b05db23a8c5a099e4b886a2106"}, + {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a20628faaf444da122b2a64b1e5360cde100ee6283ae8effa0d8745153809a2e"}, + {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f5be5d03ea2073627e7111f61b9f1f0d9625dc3c4d8dda72cc827b0c58a1d042"}, + {file = "pandas-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:a626795722d893ed6aacb64d2401d017ddc8a2341b49e0384ab9bf7112bdec30"}, + {file = "pandas-2.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9f66419d4a41132eb7e9a73dcec9486cf5019f52d90dd35547af11bc58f8637d"}, + {file = "pandas-2.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:57abcaeda83fb80d447f28ab0cc7b32b13978f6f733875ebd1ed14f8fbc0f4ab"}, + {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60f1f7dba3c2d5ca159e18c46a34e7ca7247a73b5dd1a22b6d59707ed6b899a"}, + {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb61dc8567b798b969bcc1fc964788f5a68214d333cade8319c7ab33e2b5d88a"}, + {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:52826b5f4ed658fa2b729264d63f6732b8b29949c7fd234510d57c61dbeadfcd"}, + {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bde2bc699dbd80d7bc7f9cab1e23a95c4375de615860ca089f34e7c64f4a8de7"}, + {file = "pandas-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:3de918a754bbf2da2381e8a3dcc45eede8cd7775b047b923f9006d5f876802ae"}, + {file = "pandas-2.2.0.tar.gz", hash = "sha256:30b83f7c3eb217fb4d1b494a57a2fda5444f17834f5df2de6b2ffff68dc3c8e2"}, ] [package.dependencies] numpy = [ - {version = ">=1.22.4", markers = "python_version < \"3.11\""}, - {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" -tzdata = ">=2022.1" +tzdata = ">=2022.7" [package.extras] -all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] -aws = ["s3fs (>=2022.05.0)"] -clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] -compression = ["zstandard (>=0.17.0)"] -computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"] +all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] +aws = ["s3fs (>=2022.11.0)"] +clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] +compression = ["zstandard (>=0.19.0)"] +computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] consortium-standard = ["dataframe-api-compat (>=0.1.7)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"] -feather = ["pyarrow (>=7.0.0)"] -fss = ["fsspec (>=2022.05.0)"] -gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"] -hdf5 = ["tables (>=3.7.0)"] -html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"] -mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"] -parquet = ["pyarrow (>=7.0.0)"] -performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"] -plot = ["matplotlib (>=3.6.1)"] -postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] -spss = ["pyreadstat (>=1.1.5)"] -sql-other = ["SQLAlchemy (>=1.4.36)"] -test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.8.0)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] +feather = ["pyarrow (>=10.0.1)"] +fss = ["fsspec (>=2022.11.0)"] +gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] +hdf5 = ["tables (>=3.8.0)"] +html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] +mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] +parquet = ["pyarrow (>=10.0.1)"] +performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] +plot = ["matplotlib (>=3.6.3)"] +postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +spss = ["pyreadstat (>=1.2.0)"] +sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.9.2)"] [[package]] name = "pluggy" -version = "1.3.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] [package.extras] @@ -846,35 +764,33 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "protobuf" -version = "4.24.4" +version = "4.25.3" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "protobuf-4.24.4-cp310-abi3-win32.whl", hash = "sha256:ec9912d5cb6714a5710e28e592ee1093d68c5ebfeda61983b3f40331da0b1ebb"}, - {file = "protobuf-4.24.4-cp310-abi3-win_amd64.whl", hash = "sha256:1badab72aa8a3a2b812eacfede5020472e16c6b2212d737cefd685884c191085"}, - {file = "protobuf-4.24.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8e61a27f362369c2f33248a0ff6896c20dcd47b5d48239cb9720134bef6082e4"}, - {file = "protobuf-4.24.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:bffa46ad9612e6779d0e51ae586fde768339b791a50610d85eb162daeb23661e"}, - {file = "protobuf-4.24.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:b493cb590960ff863743b9ff1452c413c2ee12b782f48beca77c8da3e2ffe9d9"}, - {file = "protobuf-4.24.4-cp37-cp37m-win32.whl", hash = "sha256:dbbed8a56e56cee8d9d522ce844a1379a72a70f453bde6243e3c86c30c2a3d46"}, - {file = "protobuf-4.24.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6b7d2e1c753715dcfe9d284a25a52d67818dd43c4932574307daf836f0071e37"}, - {file = "protobuf-4.24.4-cp38-cp38-win32.whl", hash = "sha256:02212557a76cd99574775a81fefeba8738d0f668d6abd0c6b1d3adcc75503dbe"}, - {file = "protobuf-4.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:2fa3886dfaae6b4c5ed2730d3bf47c7a38a72b3a1f0acb4d4caf68e6874b947b"}, - {file = "protobuf-4.24.4-cp39-cp39-win32.whl", hash = "sha256:b77272f3e28bb416e2071186cb39efd4abbf696d682cbb5dc731308ad37fa6dd"}, - {file = "protobuf-4.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:9fee5e8aa20ef1b84123bb9232b3f4a5114d9897ed89b4b8142d81924e05d79b"}, - {file = "protobuf-4.24.4-py3-none-any.whl", hash = "sha256:80797ce7424f8c8d2f2547e2d42bfbb6c08230ce5832d6c099a37335c9c90a92"}, - {file = "protobuf-4.24.4.tar.gz", hash = "sha256:5a70731910cd9104762161719c3d883c960151eea077134458503723b60e3667"}, + {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, + {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, + {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, + {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, + {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, + {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, + {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, + {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, + {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, ] [[package]] name = "pyasn1" -version = "0.5.0" +version = "0.5.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "pyasn1-0.5.0-py2.py3-none-any.whl", hash = "sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57"}, - {file = "pyasn1-0.5.0.tar.gz", hash = "sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde"}, + {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, + {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, ] [[package]] @@ -904,47 +820,47 @@ files = [ [[package]] name = "pydantic" -version = "1.10.13" +version = "1.10.14" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:efff03cc7a4f29d9009d1c96ceb1e7a70a65cfe86e89d34e4a5f2ab1e5693737"}, - {file = "pydantic-1.10.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ecea2b9d80e5333303eeb77e180b90e95eea8f765d08c3d278cd56b00345d01"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1740068fd8e2ef6eb27a20e5651df000978edce6da6803c2bef0bc74540f9548"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84bafe2e60b5e78bc64a2941b4c071a4b7404c5c907f5f5a99b0139781e69ed8"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bc0898c12f8e9c97f6cd44c0ed70d55749eaf783716896960b4ecce2edfd2d69"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:654db58ae399fe6434e55325a2c3e959836bd17a6f6a0b6ca8107ea0571d2e17"}, - {file = "pydantic-1.10.13-cp310-cp310-win_amd64.whl", hash = "sha256:75ac15385a3534d887a99c713aa3da88a30fbd6204a5cd0dc4dab3d770b9bd2f"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c553f6a156deb868ba38a23cf0df886c63492e9257f60a79c0fd8e7173537653"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e08865bc6464df8c7d61439ef4439829e3ab62ab1669cddea8dd00cd74b9ffe"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e31647d85a2013d926ce60b84f9dd5300d44535a9941fe825dc349ae1f760df9"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:210ce042e8f6f7c01168b2d84d4c9eb2b009fe7bf572c2266e235edf14bacd80"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8ae5dd6b721459bfa30805f4c25880e0dd78fc5b5879f9f7a692196ddcb5a580"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f8e81fc5fb17dae698f52bdd1c4f18b6ca674d7068242b2aff075f588301bbb0"}, - {file = "pydantic-1.10.13-cp311-cp311-win_amd64.whl", hash = "sha256:61d9dce220447fb74f45e73d7ff3b530e25db30192ad8d425166d43c5deb6df0"}, - {file = "pydantic-1.10.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4b03e42ec20286f052490423682016fd80fda830d8e4119f8ab13ec7464c0132"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f59ef915cac80275245824e9d771ee939133be38215555e9dc90c6cb148aaeb5"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a1f9f747851338933942db7af7b6ee8268568ef2ed86c4185c6ef4402e80ba8"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:97cce3ae7341f7620a0ba5ef6cf043975cd9d2b81f3aa5f4ea37928269bc1b87"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:854223752ba81e3abf663d685f105c64150873cc6f5d0c01d3e3220bcff7d36f"}, - {file = "pydantic-1.10.13-cp37-cp37m-win_amd64.whl", hash = "sha256:b97c1fac8c49be29486df85968682b0afa77e1b809aff74b83081cc115e52f33"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c958d053453a1c4b1c2062b05cd42d9d5c8eb67537b8d5a7e3c3032943ecd261"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c5370a7edaac06daee3af1c8b1192e305bc102abcbf2a92374b5bc793818599"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d6f6e7305244bddb4414ba7094ce910560c907bdfa3501e9db1a7fd7eaea127"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3a3c792a58e1622667a2837512099eac62490cdfd63bd407993aaf200a4cf1f"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c636925f38b8db208e09d344c7aa4f29a86bb9947495dd6b6d376ad10334fb78"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:678bcf5591b63cc917100dc50ab6caebe597ac67e8c9ccb75e698f66038ea953"}, - {file = "pydantic-1.10.13-cp38-cp38-win_amd64.whl", hash = "sha256:6cf25c1a65c27923a17b3da28a0bdb99f62ee04230c931d83e888012851f4e7f"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8ef467901d7a41fa0ca6db9ae3ec0021e3f657ce2c208e98cd511f3161c762c6"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:968ac42970f57b8344ee08837b62f6ee6f53c33f603547a55571c954a4225691"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9849f031cf8a2f0a928fe885e5a04b08006d6d41876b8bbd2fc68a18f9f2e3fd"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56e3ff861c3b9c6857579de282ce8baabf443f42ffba355bf070770ed63e11e1"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f00790179497767aae6bcdc36355792c79e7bbb20b145ff449700eb076c5f96"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:75b297827b59bc229cac1a23a2f7a4ac0031068e5be0ce385be1462e7e17a35d"}, - {file = "pydantic-1.10.13-cp39-cp39-win_amd64.whl", hash = "sha256:e70ca129d2053fb8b728ee7d1af8e553a928d7e301a311094b8a0501adc8763d"}, - {file = "pydantic-1.10.13-py3-none-any.whl", hash = "sha256:b87326822e71bd5f313e7d3bfdc77ac3247035ac10b0c0618bd99dcf95b1e687"}, - {file = "pydantic-1.10.13.tar.gz", hash = "sha256:32c8b48dcd3b2ac4e78b0ba4af3a2c2eb6048cb75202f0ea7b34feb740efc340"}, + {file = "pydantic-1.10.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7f4fcec873f90537c382840f330b90f4715eebc2bc9925f04cb92de593eae054"}, + {file = "pydantic-1.10.14-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e3a76f571970fcd3c43ad982daf936ae39b3e90b8a2e96c04113a369869dc87"}, + {file = "pydantic-1.10.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d886bd3c3fbeaa963692ef6b643159ccb4b4cefaf7ff1617720cbead04fd1d"}, + {file = "pydantic-1.10.14-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:798a3d05ee3b71967844a1164fd5bdb8c22c6d674f26274e78b9f29d81770c4e"}, + {file = "pydantic-1.10.14-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:23d47a4b57a38e8652bcab15a658fdb13c785b9ce217cc3a729504ab4e1d6bc9"}, + {file = "pydantic-1.10.14-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9f674b5c3bebc2eba401de64f29948ae1e646ba2735f884d1594c5f675d6f2a"}, + {file = "pydantic-1.10.14-cp310-cp310-win_amd64.whl", hash = "sha256:24a7679fab2e0eeedb5a8924fc4a694b3bcaac7d305aeeac72dd7d4e05ecbebf"}, + {file = "pydantic-1.10.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d578ac4bf7fdf10ce14caba6f734c178379bd35c486c6deb6f49006e1ba78a7"}, + {file = "pydantic-1.10.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa7790e94c60f809c95602a26d906eba01a0abee9cc24150e4ce2189352deb1b"}, + {file = "pydantic-1.10.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aad4e10efa5474ed1a611b6d7f0d130f4aafadceb73c11d9e72823e8f508e663"}, + {file = "pydantic-1.10.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1245f4f61f467cb3dfeced2b119afef3db386aec3d24a22a1de08c65038b255f"}, + {file = "pydantic-1.10.14-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:21efacc678a11114c765eb52ec0db62edffa89e9a562a94cbf8fa10b5db5c046"}, + {file = "pydantic-1.10.14-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:412ab4a3f6dbd2bf18aefa9f79c7cca23744846b31f1d6555c2ee2b05a2e14ca"}, + {file = "pydantic-1.10.14-cp311-cp311-win_amd64.whl", hash = "sha256:e897c9f35281f7889873a3e6d6b69aa1447ceb024e8495a5f0d02ecd17742a7f"}, + {file = "pydantic-1.10.14-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d604be0f0b44d473e54fdcb12302495fe0467c56509a2f80483476f3ba92b33c"}, + {file = "pydantic-1.10.14-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42c7d17706911199798d4c464b352e640cab4351efe69c2267823d619a937e5"}, + {file = "pydantic-1.10.14-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:596f12a1085e38dbda5cbb874d0973303e34227b400b6414782bf205cc14940c"}, + {file = "pydantic-1.10.14-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bfb113860e9288d0886e3b9e49d9cf4a9d48b441f52ded7d96db7819028514cc"}, + {file = "pydantic-1.10.14-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bc3ed06ab13660b565eed80887fcfbc0070f0aa0691fbb351657041d3e874efe"}, + {file = "pydantic-1.10.14-cp37-cp37m-win_amd64.whl", hash = "sha256:ad8c2bc677ae5f6dbd3cf92f2c7dc613507eafe8f71719727cbc0a7dec9a8c01"}, + {file = "pydantic-1.10.14-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c37c28449752bb1f47975d22ef2882d70513c546f8f37201e0fec3a97b816eee"}, + {file = "pydantic-1.10.14-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49a46a0994dd551ec051986806122767cf144b9702e31d47f6d493c336462597"}, + {file = "pydantic-1.10.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53e3819bd20a42470d6dd0fe7fc1c121c92247bca104ce608e609b59bc7a77ee"}, + {file = "pydantic-1.10.14-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbb503bbbbab0c588ed3cd21975a1d0d4163b87e360fec17a792f7d8c4ff29f"}, + {file = "pydantic-1.10.14-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:336709883c15c050b9c55a63d6c7ff09be883dbc17805d2b063395dd9d9d0022"}, + {file = "pydantic-1.10.14-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4ae57b4d8e3312d486e2498d42aed3ece7b51848336964e43abbf9671584e67f"}, + {file = "pydantic-1.10.14-cp38-cp38-win_amd64.whl", hash = "sha256:dba49d52500c35cfec0b28aa8b3ea5c37c9df183ffc7210b10ff2a415c125c4a"}, + {file = "pydantic-1.10.14-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c66609e138c31cba607d8e2a7b6a5dc38979a06c900815495b2d90ce6ded35b4"}, + {file = "pydantic-1.10.14-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d986e115e0b39604b9eee3507987368ff8148222da213cd38c359f6f57b3b347"}, + {file = "pydantic-1.10.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:646b2b12df4295b4c3148850c85bff29ef6d0d9621a8d091e98094871a62e5c7"}, + {file = "pydantic-1.10.14-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282613a5969c47c83a8710cc8bfd1e70c9223feb76566f74683af889faadc0ea"}, + {file = "pydantic-1.10.14-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:466669501d08ad8eb3c4fecd991c5e793c4e0bbd62299d05111d4f827cded64f"}, + {file = "pydantic-1.10.14-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:13e86a19dca96373dcf3190fcb8797d40a6f12f154a244a8d1e8e03b8f280593"}, + {file = "pydantic-1.10.14-cp39-cp39-win_amd64.whl", hash = "sha256:08b6ec0917c30861e3fe71a93be1648a2aa4f62f866142ba21670b24444d7fd8"}, + {file = "pydantic-1.10.14-py3-none-any.whl", hash = "sha256:8ee853cd12ac2ddbf0ecbac1c289f95882b2d4482258048079d13be700aa114c"}, + {file = "pydantic-1.10.14.tar.gz", hash = "sha256:46f17b832fe27de7850896f3afee50ea682220dd218f7e9c88d436788419dca6"}, ] [package.dependencies] @@ -956,20 +872,17 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pydash" -version = "7.0.6" +version = "6.0.2" description = "The kitchen sink of Python utility libraries for doing \"stuff\" in a functional way. Based on the Lo-Dash Javascript library." optional = false python-versions = ">=3.7" files = [ - {file = "pydash-7.0.6-py3-none-any.whl", hash = "sha256:10e506935953fde4b0d6fe21a88e17783cd1479256ae96f285b5f89063b4efd6"}, - {file = "pydash-7.0.6.tar.gz", hash = "sha256:7d9df7e9f36f2bbb08316b609480e7c6468185473a21bdd8e65dda7915565a26"}, + {file = "pydash-6.0.2-py3-none-any.whl", hash = "sha256:6d3ce5cbbc8ca3533c12782ac201c2ec756d1e1703ec3efc88f2b95d1ed2bb31"}, + {file = "pydash-6.0.2.tar.gz", hash = "sha256:35caa588e01d293713655e0870544d25128cd414c5e19477a0d63adc2b2ca03e"}, ] -[package.dependencies] -typing-extensions = ">=3.10,<4.6.0 || >4.6.0" - [package.extras] -dev = ["Sphinx", "black", "build", "coverage", "docformatter", "flake8", "flake8-black", "flake8-bugbear", "flake8-isort", "furo", "importlib-metadata (<5)", "invoke", "isort", "mypy", "pylint", "pytest", "pytest-cov", "pytest-mypy-testing", "sphinx-autodoc-typehints", "tox", "twine", "wheel"] +dev = ["Sphinx", "black", "build", "coverage", "docformatter", "flake8", "flake8-black", "flake8-bugbear", "flake8-isort", "importlib-metadata (<5)", "invoke", "isort", "pylint", "pytest", "pytest-cov", "sphinx-rtd-theme", "tox", "twine", "wheel"] [[package]] name = "pygithub" @@ -990,17 +903,18 @@ requests = ">=2.14.0" [[package]] name = "pygments" -version = "2.16.1" +version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.7" files = [ - {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, - {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] [package.extras] plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyjwt" @@ -1050,13 +964,13 @@ tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] [[package]] name = "pytest" -version = "7.4.2" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, - {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -1072,13 +986,13 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-mock" -version = "3.11.1" +version = "3.12.0" description = "Thin-wrapper around the mock package for easier use with pytest" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-mock-3.11.1.tar.gz", hash = "sha256:7f6b125602ac6d743e523ae0bfa71e1a697a2f5534064528c6ff84c2f7c2fc7f"}, - {file = "pytest_mock-3.11.1-py3-none-any.whl", hash = "sha256:21c279fff83d70763b05f8874cc9cfb3fcacd6d354247a976f9529d19f9acf39"}, + {file = "pytest-mock-3.12.0.tar.gz", hash = "sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9"}, + {file = "pytest_mock-3.12.0-py3-none-any.whl", hash = "sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f"}, ] [package.dependencies] @@ -1103,13 +1017,13 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2023.3.post1" +version = "2024.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, - {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] [[package]] @@ -1124,6 +1038,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1131,8 +1046,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1149,6 +1071,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1156,6 +1079,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1184,13 +1108,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rich" -version = "13.6.0" +version = "13.7.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.6.0-py3-none-any.whl", hash = "sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245"}, - {file = "rich-13.6.0.tar.gz", hash = "sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef"}, + {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, + {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, ] [package.dependencies] @@ -1260,128 +1184,123 @@ files = [ [[package]] name = "typing-extensions" -version = "4.8.0" +version = "4.9.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, ] [[package]] name = "tzdata" -version = "2023.3" +version = "2024.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, - {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [[package]] name = "urllib3" -version = "2.0.6" +version = "2.2.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "urllib3-2.0.6-py3-none-any.whl", hash = "sha256:7a7c7003b000adf9e7ca2a377c9688bbc54ed41b985789ed576570342a375cd2"}, - {file = "urllib3-2.0.6.tar.gz", hash = "sha256:b19e1a85d206b56d7df1d5e683df4a7725252a964e3993648dd0fb5a1c157564"}, + {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, + {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "wrapt" -version = "1.15.0" +version = "1.16.0" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.6" files = [ - {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"}, - {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"}, - {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"}, - {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"}, - {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"}, - {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"}, - {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"}, - {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"}, - {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"}, - {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"}, - {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"}, - {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"}, - {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"}, - {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"}, - {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"}, - {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"}, - {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"}, - {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"}, - {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "3d508b33cc7418c89765c36e163354db9f9f47c08c002a977725b27cc76e5c62" +content-hash = "d747e06c3998e49136a4bf3aa4f02e51e99b190b173e8f5d747579d262c2cf01" diff --git a/airbyte-ci/connectors/connector_ops/pyproject.toml b/airbyte-ci/connectors/connector_ops/pyproject.toml index 1d6960ba5d6f..3270d58e8be6 100644 --- a/airbyte-ci/connectors/connector_ops/pyproject.toml +++ b/airbyte-ci/connectors/connector_ops/pyproject.toml @@ -17,7 +17,7 @@ GitPython = "^3.1.29" pydantic = "^1.9" PyGithub = "^1.58.0" rich = "^13.0.0" -pydash = "^7.0.4" +pydash = "^6.0.2" google-cloud-storage = "^2.8.0" ci-credentials = {path = "../ci_credentials"} pandas = "^2.0.3" diff --git a/airbyte-ci/connectors/connectors_qa/README.md b/airbyte-ci/connectors/connectors_qa/README.md new file mode 100644 index 000000000000..a646fb8dcc85 --- /dev/null +++ b/airbyte-ci/connectors/connectors_qa/README.md @@ -0,0 +1,96 @@ +# Connectors QA + +This package has two main purposes: +* Running QA checks on connectors. +* Generating the QA checks documentation that are run on connectors. + + + +## Usage + +### Install + +```bash +pipx install . +``` + +This will make `connectors-qa` available in your `PATH`. + + +Feel free to run `connectors-qa --help` to see the available commands and options. + + +### Examples + +#### Running QA checks on one or more connectors: + +```bash +# This command must run from the root of the Airbyte repo +connectors-qa run --name=source-faker --name=source-google-sheets +``` +#### Running QA checks on all connectors: + +```bash +# This command must run from the root of the Airbyte repo +connectors-qa run --connector-directory=airbyte-integrations/connectors +``` + +#### Running QA checks on all connectors and generating a JSON report: + +```bash +### Generating documentation for QA checks: +connectors-qa run --connector-directory=airbyte-integrations/connectors --report-path=qa_report.json +``` + +#### Running only specific QA checks on one or more connectors: + +```bash +connectors-qa run --name=source-faker --name=source-google-sheets --check=CheckConnectorIconIsAvailable --check=CheckConnectorUsesPythonBaseImage +``` + +#### Running only specific QA checks on all connectors: + +```bash +connectors-qa run --connector-directory=airbyte-integrations/connectors --check=CheckConnectorIconIsAvailable --check=CheckConnectorUsesPythonBaseImage +``` + +#### Generating documentation for QA checks: + +```bash +connectors-qa generate-documentation qa_checks.md +``` + +## Development + +```bash +poetry install +``` + +### Dependencies +This package uses two local dependencies: +* [`connector_ops`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/connector_ops): To interact with the `Connector` object. +* [`metadata_service/lib`]((https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/metadata_service/lib)): To validate the metadata of the connectors. + +### Adding a new QA check + +To add a new QA check, you have to create add new class in one of the `checks` module. This class must inherit from `models.Check` and implement the `_run` method. Then, you need to add an instance of this class to the `ENABLED_CHECKS` list of the module. + +**Please run the `generate-doumentation` command to update the documentation with the new check and commit it in your PR.** + +### Running tests + +```bash +poe test +``` + +### Running type checks + +```bash +poe type_check +``` + +### Running the linter + +```bash +poe lint +``` \ No newline at end of file diff --git a/airbyte-ci/connectors/connectors_qa/poetry.lock b/airbyte-ci/connectors/connectors_qa/poetry.lock new file mode 100644 index 000000000000..8b772f849f2e --- /dev/null +++ b/airbyte-ci/connectors/connectors_qa/poetry.lock @@ -0,0 +1,2457 @@ +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. + +[[package]] +name = "airbyte-connectors-base-images" +version = "1.0.1" +description = "This package is used to generate and publish the base images for Airbyte Connectors." +optional = false +python-versions = "^3.10" +files = [] +develop = false + +[package.dependencies] +connector-ops = {path = "../connector_ops", develop = true} +dagger-io = "==0.9.6" +gitpython = "^3.1.35" +inquirer = "^3.1.3" +jinja2 = "^3.1.2" +rich = "^13.5.2" +semver = "^3.0.1" + +[package.source] +type = "directory" +url = "../base_images" + +[[package]] +name = "ansicon" +version = "1.89.0" +description = "Python wrapper for loading Jason Hood's ANSICON" +optional = false +python-versions = "*" +files = [ + {file = "ansicon-1.89.0-py2.py3-none-any.whl", hash = "sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec"}, + {file = "ansicon-1.89.0.tar.gz", hash = "sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1"}, +] + +[[package]] +name = "anyio" +version = "4.2.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, + {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] + +[[package]] +name = "asyncclick" +version = "8.1.7.1" +description = "Composable command line interface toolkit, async version" +optional = false +python-versions = ">=3.7" +files = [ + {file = "asyncclick-8.1.7.1-py3-none-any.whl", hash = "sha256:e0fea5f0223ac45cfc26153cc80a58cc65fc077ac8de79be49248c918e8c3422"}, + {file = "asyncclick-8.1.7.1.tar.gz", hash = "sha256:a47b61258a689212cf9463fbf3b4cc52d05bfd03185f6ead2315fc03fd17ef75"}, +] + +[package.dependencies] +anyio = "*" +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "asyncer" +version = "0.0.4" +description = "Asyncer, async and await, focused on developer experience." +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "asyncer-0.0.4-py3-none-any.whl", hash = "sha256:bc27f6bcea231a78c6fb730dff5977c74b0ee5a6f2ea080e273a03fac17ca3d1"}, + {file = "asyncer-0.0.4.tar.gz", hash = "sha256:d9400418d4b508e5f3e819809bd3e7b9cd43d99a65c0a5eada14d41583164ca6"}, +] + +[package.dependencies] +anyio = ">=3.4.0,<5.0" + +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + +[[package]] +name = "backoff" +version = "2.2.1" +description = "Function decoration for backoff and retry" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, + {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, +] + +[[package]] +name = "beartype" +version = "0.17.2" +description = "Unbearably fast runtime type checking in pure Python." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "beartype-0.17.2-py3-none-any.whl", hash = "sha256:c22b21e1f785cfcf5c4d3d13070f532b6243a3ad67e68d2298ff08d539847dce"}, + {file = "beartype-0.17.2.tar.gz", hash = "sha256:e911e1ae7de4bccd15745f7643609d8732f64de5c2fb844e89cbbed1c5a8d495"}, +] + +[package.extras] +all = ["typing-extensions (>=3.10.0.0)"] +dev = ["autoapi (>=0.9.0)", "coverage (>=5.5)", "equinox", "mypy (>=0.800)", "numpy", "pandera", "pydata-sphinx-theme (<=0.7.2)", "pytest (>=4.0.0)", "sphinx", "sphinx (>=4.2.0,<6.0.0)", "sphinxext-opengraph (>=0.7.5)", "tox (>=3.20.1)", "typing-extensions (>=3.10.0.0)"] +doc-rtd = ["autoapi (>=0.9.0)", "pydata-sphinx-theme (<=0.7.2)", "sphinx (>=4.2.0,<6.0.0)", "sphinxext-opengraph (>=0.7.5)"] +test-tox = ["equinox", "mypy (>=0.800)", "numpy", "pandera", "pytest (>=4.0.0)", "sphinx", "typing-extensions (>=3.10.0.0)"] +test-tox-coverage = ["coverage (>=5.5)"] + +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, +] + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "blessed" +version = "1.20.0" +description = "Easy, practical library for making terminal apps, by providing an elegant, well-documented interface to Colors, Keyboard input, and screen Positioning capabilities." +optional = false +python-versions = ">=2.7" +files = [ + {file = "blessed-1.20.0-py2.py3-none-any.whl", hash = "sha256:0c542922586a265e699188e52d5f5ac5ec0dd517e5a1041d90d2bbf23f906058"}, + {file = "blessed-1.20.0.tar.gz", hash = "sha256:2cdd67f8746e048f00df47a2880f4d6acbcdb399031b604e34ba8f71d5787680"}, +] + +[package.dependencies] +jinxed = {version = ">=1.1.0", markers = "platform_system == \"Windows\""} +six = ">=1.9.0" +wcwidth = ">=0.1.4" + +[[package]] +name = "cachetools" +version = "5.3.2" +description = "Extensible memoizing collections and decorators" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, + {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, +] + +[[package]] +name = "cattrs" +version = "23.2.3" +description = "Composable complex class support for attrs and dataclasses." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cattrs-23.2.3-py3-none-any.whl", hash = "sha256:0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108"}, + {file = "cattrs-23.2.3.tar.gz", hash = "sha256:a934090d95abaa9e911dac357e3a8699e0b4b14f8529bcc7d2b1ad9d51672b9f"}, +] + +[package.dependencies] +attrs = ">=23.1.0" +exceptiongroup = {version = ">=1.1.1", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.1.0,<4.6.3 || >4.6.3", markers = "python_version < \"3.11\""} + +[package.extras] +bson = ["pymongo (>=4.4.0)"] +cbor2 = ["cbor2 (>=5.4.6)"] +msgpack = ["msgpack (>=1.0.5)"] +orjson = ["orjson (>=3.9.2)"] +pyyaml = ["pyyaml (>=6.0)"] +tomlkit = ["tomlkit (>=0.11.8)"] +ujson = ["ujson (>=5.7.0)"] + +[[package]] +name = "certifi" +version = "2024.2.2" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, +] + +[[package]] +name = "cffi" +version = "1.16.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "ci-credentials" +version = "1.1.0" +description = "CLI tooling to read and manage GSM secrets" +optional = false +python-versions = "^3.10" +files = [] +develop = false + +[package.dependencies] +click = "^8.1.3" +common_utils = {path = "../common_utils", develop = true} +pyyaml = "^6.0" +requests = "^2.28.2" + +[package.source] +type = "directory" +url = "../ci_credentials" + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "common-utils" +version = "0.0.0" +description = "Suite of all often used classes and common functions" +optional = false +python-versions = "^3.10" +files = [] +develop = true + +[package.dependencies] +cryptography = "^3.4.7" +pyjwt = "^2.1.0" +requests = "^2.28.2" + +[package.source] +type = "directory" +url = "../common_utils" + +[[package]] +name = "connector-ops" +version = "0.4.0" +description = "Packaged maintained by the connector operations team to perform CI for connectors" +optional = false +python-versions = "^3.10" +files = [] +develop = false + +[package.dependencies] +ci-credentials = {path = "../ci_credentials"} +click = "^8.1.3" +GitPython = "^3.1.29" +google-cloud-storage = "^2.8.0" +pandas = "^2.0.3" +pydantic = "^1.9" +pydash = "^6.0.2" +PyGithub = "^1.58.0" +PyYAML = "^6.0" +requests = "^2.28.2" +rich = "^13.0.0" +simpleeval = "^0.9.13" + +[package.source] +type = "directory" +url = "../connector_ops" + +[[package]] +name = "cryptography" +version = "3.4.8" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.6" +files = [ + {file = "cryptography-3.4.8-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:a00cf305f07b26c351d8d4e1af84ad7501eca8a342dedf24a7acb0e7b7406e14"}, + {file = "cryptography-3.4.8-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:f44d141b8c4ea5eb4dbc9b3ad992d45580c1d22bf5e24363f2fbf50c2d7ae8a7"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0a7dcbcd3f1913f664aca35d47c1331fce738d44ec34b7be8b9d332151b0b01e"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34dae04a0dce5730d8eb7894eab617d8a70d0c97da76b905de9efb7128ad7085"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eb7bb0df6f6f583dd8e054689def236255161ebbcf62b226454ab9ec663746b"}, + {file = "cryptography-3.4.8-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:9965c46c674ba8cc572bc09a03f4c649292ee73e1b683adb1ce81e82e9a6a0fb"}, + {file = "cryptography-3.4.8-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:3c4129fc3fdc0fa8e40861b5ac0c673315b3c902bbdc05fc176764815b43dd1d"}, + {file = "cryptography-3.4.8-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:695104a9223a7239d155d7627ad912953b540929ef97ae0c34c7b8bf30857e89"}, + {file = "cryptography-3.4.8-cp36-abi3-win32.whl", hash = "sha256:21ca464b3a4b8d8e86ba0ee5045e103a1fcfac3b39319727bc0fc58c09c6aff7"}, + {file = "cryptography-3.4.8-cp36-abi3-win_amd64.whl", hash = "sha256:3520667fda779eb788ea00080124875be18f2d8f0848ec00733c0ec3bb8219fc"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d2a6e5ef66503da51d2110edf6c403dc6b494cc0082f85db12f54e9c5d4c3ec5"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a305600e7a6b7b855cd798e00278161b681ad6e9b7eca94c721d5f588ab212af"}, + {file = "cryptography-3.4.8-pp36-pypy36_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:3fa3a7ccf96e826affdf1a0a9432be74dc73423125c8f96a909e3835a5ef194a"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:d9ec0e67a14f9d1d48dd87a2531009a9b251c02ea42851c060b25c782516ff06"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b0fbfae7ff7febdb74b574055c7466da334a5371f253732d7e2e7525d570498"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94fff993ee9bc1b2440d3b7243d488c6a3d9724cc2b09cdb297f6a886d040ef7"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:8695456444f277af73a4877db9fc979849cd3ee74c198d04fc0776ebc3db52b9"}, + {file = "cryptography-3.4.8-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:cd65b60cfe004790c795cc35f272e41a3df4631e2fb6b35aa7ac6ef2859d554e"}, + {file = "cryptography-3.4.8.tar.gz", hash = "sha256:94cc5ed4ceaefcbe5bf38c8fba6a21fc1d365bb8fb826ea1688e3370b2e24a1c"}, +] + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] +docstest = ["doc8", "pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] +sdist = ["setuptools-rust (>=0.11.4)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] + +[[package]] +name = "dagger-io" +version = "0.9.6" +description = "A client package for running Dagger pipelines in Python." +optional = false +python-versions = ">=3.10" +files = [ + {file = "dagger_io-0.9.6-py3-none-any.whl", hash = "sha256:e2f1e4bbc252071a314fa5b0bad11a910433a9ee043972b716f6fcc5f9fc8236"}, + {file = "dagger_io-0.9.6.tar.gz", hash = "sha256:147b5a33c44d17f602a4121679893655e91308beb8c46a466afed39cf40f789b"}, +] + +[package.dependencies] +anyio = ">=3.6.2" +beartype = ">=0.11.0" +cattrs = ">=22.2.0" +gql = ">=3.4.0" +graphql-core = ">=3.2.3" +httpx = ">=0.23.1" +platformdirs = ">=2.6.2" +rich = ">=10.11.0" +typing-extensions = ">=4.8.0" + +[[package]] +name = "deprecated" +version = "1.2.14" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, + {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, +] + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] + +[[package]] +name = "editor" +version = "1.6.6" +description = "🖋 Open the default text editor 🖋" +optional = false +python-versions = ">=3.8" +files = [ + {file = "editor-1.6.6-py3-none-any.whl", hash = "sha256:e818e6913f26c2a81eadef503a2741d7cca7f235d20e217274a009ecd5a74abf"}, + {file = "editor-1.6.6.tar.gz", hash = "sha256:bb6989e872638cd119db9a4fce284cd8e13c553886a1c044c6b8d8a160c871f8"}, +] + +[package.dependencies] +runs = "*" +xmod = "*" + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "future" +version = "0.18.3" +description = "Clean single-source support for Python 3 and 2" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "future-0.18.3.tar.gz", hash = "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307"}, +] + +[[package]] +name = "gax-google-logging-v2" +version = "0.8.3" +description = "GAX library for the Google Logging API" +optional = false +python-versions = "*" +files = [ + {file = "gax-google-logging-v2-0.8.3.tar.gz", hash = "sha256:c36cbb93e070b3b535e9fffff6879efe447e525dff75b62eb4564def515e1a18"}, +] + +[package.dependencies] +google-gax = ">=0.12.5,<0.13.0" +googleapis-common-protos = ">=1.1.0" +grpc-google-logging-v2 = ">=0.8.1,<0.9.0" +oauth2client = ">=1.4.11" + +[[package]] +name = "gax-google-pubsub-v1" +version = "0.8.3" +description = "DEPRECATED" +optional = false +python-versions = "*" +files = [ + {file = "gax-google-pubsub-v1-0.8.3.tar.gz", hash = "sha256:943df4aa05cf0302fa1616197d05e29adb62be2c0f55f80d8345439d72471526"}, +] + +[package.dependencies] +google-gax = ">=0.12.5,<0.13.0" +googleapis-common-protos = ">=1.1.0" +grpc-google-pubsub-v1 = ">=0.8.1,<0.9.0" +oauth2client = ">=1.4.11" + +[[package]] +name = "gcloud" +version = "0.18.3" +description = "API Client library for Google Cloud" +optional = false +python-versions = "*" +files = [ + {file = "gcloud-0.18.3.tar.gz", hash = "sha256:0af2dec59fce20561752f86e42d981c6a255e306a6c5e5d1fa3d358a8857e4fb"}, +] + +[package.dependencies] +gax-google-logging-v2 = ">=0.8.0,<0.9dev" +gax-google-pubsub-v1 = ">=0.8.0,<0.9dev" +google-gax = ">=0.12.3,<0.13dev" +googleapis-common-protos = "*" +grpc-google-logging-v2 = ">=0.8.0,<0.9dev" +grpc-google-pubsub-v1 = ">=0.8.0,<0.9dev" +grpcio = ">=1.0rc1" +httplib2 = ">=0.9.1" +oauth2client = ">=2.0.1" +protobuf = ">=3.0.0b2,<3.0.0.b2.post1 || >3.0.0.b2.post1" +six = "*" + +[package.extras] +grpc = ["gax-google-logging-v2 (>=0.8.0,<0.9dev)", "gax-google-pubsub-v1 (>=0.8.0,<0.9dev)", "google-gax (>=0.12.3,<0.13dev)", "grpc-google-logging-v2 (>=0.8.0,<0.9dev)", "grpc-google-pubsub-v1 (>=0.8.0,<0.9dev)", "grpcio (>=1.0rc1)"] + +[[package]] +name = "gitdb" +version = "4.0.11" +description = "Git Object Database" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, +] + +[package.dependencies] +smmap = ">=3.0.1,<6" + +[[package]] +name = "gitpython" +version = "3.1.41" +description = "GitPython is a Python library used to interact with Git repositories" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GitPython-3.1.41-py3-none-any.whl", hash = "sha256:c36b6634d069b3f719610175020a9aed919421c87552185b085e04fbbdb10b7c"}, + {file = "GitPython-3.1.41.tar.gz", hash = "sha256:ed66e624884f76df22c8e16066d567aaa5a37d5b5fa19db2c6df6f7156db9048"}, +] + +[package.dependencies] +gitdb = ">=4.0.1,<5" + +[package.extras] +test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "sumtypes"] + +[[package]] +name = "google" +version = "3.0.0" +description = "Python bindings to the Google search engine." +optional = false +python-versions = "*" +files = [ + {file = "google-3.0.0-py2.py3-none-any.whl", hash = "sha256:889cf695f84e4ae2c55fbc0cfdaf4c1e729417fa52ab1db0485202ba173e4935"}, + {file = "google-3.0.0.tar.gz", hash = "sha256:143530122ee5130509ad5e989f0512f7cb218b2d4eddbafbad40fd10e8d8ccbe"}, +] + +[package.dependencies] +beautifulsoup4 = "*" + +[[package]] +name = "google-api-core" +version = "2.17.0" +description = "Google API client core library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "google-api-core-2.17.0.tar.gz", hash = "sha256:de7ef0450faec7c75e0aea313f29ac870fdc44cfaec9d6499a9a17305980ef66"}, + {file = "google_api_core-2.17.0-py3-none-any.whl", hash = "sha256:08ed79ed8e93e329de5e3e7452746b734e6bf8438d8d64dd3319d21d3164890c"}, +] + +[package.dependencies] +google-auth = ">=2.14.1,<3.0.dev0" +googleapis-common-protos = ">=1.56.2,<2.0.dev0" +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +requests = ">=2.18.0,<3.0.0.dev0" + +[package.extras] +grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0)"] +grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] +grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] + +[[package]] +name = "google-auth" +version = "2.27.0" +description = "Google Authentication Library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "google-auth-2.27.0.tar.gz", hash = "sha256:e863a56ccc2d8efa83df7a80272601e43487fa9a728a376205c86c26aaefa821"}, + {file = "google_auth-2.27.0-py2.py3-none-any.whl", hash = "sha256:8e4bad367015430ff253fe49d500fdc3396c1a434db5740828c728e45bcce245"}, +] + +[package.dependencies] +cachetools = ">=2.0.0,<6.0" +pyasn1-modules = ">=0.2.1" +rsa = ">=3.1.4,<5" + +[package.extras] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] +enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] +pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +reauth = ["pyu2f (>=0.1.5)"] +requests = ["requests (>=2.20.0,<3.0.0.dev0)"] + +[[package]] +name = "google-cloud-core" +version = "2.4.1" +description = "Google Cloud API client core library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073"}, + {file = "google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61"}, +] + +[package.dependencies] +google-api-core = ">=1.31.6,<2.0.dev0 || >2.3.0,<3.0.0dev" +google-auth = ">=1.25.0,<3.0dev" + +[package.extras] +grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] + +[[package]] +name = "google-cloud-storage" +version = "2.14.0" +description = "Google Cloud Storage API client library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "google-cloud-storage-2.14.0.tar.gz", hash = "sha256:2d23fcf59b55e7b45336729c148bb1c464468c69d5efbaee30f7201dd90eb97e"}, + {file = "google_cloud_storage-2.14.0-py2.py3-none-any.whl", hash = "sha256:8641243bbf2a2042c16a6399551fbb13f062cbc9a2de38d6c0bb5426962e9dbd"}, +] + +[package.dependencies] +google-api-core = ">=1.31.5,<2.0.dev0 || >2.3.0,<3.0.0dev" +google-auth = ">=2.23.3,<3.0dev" +google-cloud-core = ">=2.3.0,<3.0dev" +google-crc32c = ">=1.0,<2.0dev" +google-resumable-media = ">=2.6.0" +requests = ">=2.18.0,<3.0.0dev" + +[package.extras] +protobuf = ["protobuf (<5.0.0dev)"] + +[[package]] +name = "google-crc32c" +version = "1.5.0" +description = "A python wrapper of the C library 'Google CRC32C'" +optional = false +python-versions = ">=3.7" +files = [ + {file = "google-crc32c-1.5.0.tar.gz", hash = "sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7"}, + {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13"}, + {file = "google_crc32c-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346"}, + {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65"}, + {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b"}, + {file = "google_crc32c-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02"}, + {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4"}, + {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e"}, + {file = "google_crc32c-1.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c"}, + {file = "google_crc32c-1.5.0-cp310-cp310-win32.whl", hash = "sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee"}, + {file = "google_crc32c-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289"}, + {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273"}, + {file = "google_crc32c-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298"}, + {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57"}, + {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438"}, + {file = "google_crc32c-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906"}, + {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183"}, + {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd"}, + {file = "google_crc32c-1.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c"}, + {file = "google_crc32c-1.5.0-cp311-cp311-win32.whl", hash = "sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709"}, + {file = "google_crc32c-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968"}, + {file = "google_crc32c-1.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae"}, + {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556"}, + {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f"}, + {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876"}, + {file = "google_crc32c-1.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc"}, + {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c"}, + {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a"}, + {file = "google_crc32c-1.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e"}, + {file = "google_crc32c-1.5.0-cp37-cp37m-win32.whl", hash = "sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94"}, + {file = "google_crc32c-1.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740"}, + {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8"}, + {file = "google_crc32c-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a"}, + {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946"}, + {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a"}, + {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d"}, + {file = "google_crc32c-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a"}, + {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37"}, + {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894"}, + {file = "google_crc32c-1.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a"}, + {file = "google_crc32c-1.5.0-cp38-cp38-win32.whl", hash = "sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4"}, + {file = "google_crc32c-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c"}, + {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7"}, + {file = "google_crc32c-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d"}, + {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100"}, + {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9"}, + {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57"}, + {file = "google_crc32c-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210"}, + {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd"}, + {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96"}, + {file = "google_crc32c-1.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61"}, + {file = "google_crc32c-1.5.0-cp39-cp39-win32.whl", hash = "sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c"}, + {file = "google_crc32c-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541"}, + {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325"}, + {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd"}, + {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091"}, + {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178"}, + {file = "google_crc32c-1.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2"}, + {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d"}, + {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2"}, + {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5"}, + {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462"}, + {file = "google_crc32c-1.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314"}, + {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728"}, + {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88"}, + {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb"}, + {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31"}, + {file = "google_crc32c-1.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93"}, +] + +[package.extras] +testing = ["pytest"] + +[[package]] +name = "google-gax" +version = "0.12.5" +description = "Google API Extensions" +optional = false +python-versions = "*" +files = [ + {file = "google-gax-0.12.5.tar.gz", hash = "sha256:63312a04cb87ca50e857245f05c582b2171807a30e61cef85006b983bf659cb9"}, +] + +[package.dependencies] +future = ">=0.15.2" +grpcio = ">=1.0rc1" +oauth2client = ">=1.5.2" +ply = "3.8" +protobuf = ">=3.0.0b3" + +[[package]] +name = "google-resumable-media" +version = "2.7.0" +description = "Utilities for Google Media Downloads and Resumable Uploads" +optional = false +python-versions = ">= 3.7" +files = [ + {file = "google-resumable-media-2.7.0.tar.gz", hash = "sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b"}, + {file = "google_resumable_media-2.7.0-py2.py3-none-any.whl", hash = "sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08"}, +] + +[package.dependencies] +google-crc32c = ">=1.0,<2.0dev" + +[package.extras] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)", "google-auth (>=1.22.0,<2.0dev)"] +requests = ["requests (>=2.18.0,<3.0.0dev)"] + +[[package]] +name = "googleapis-common-protos" +version = "1.62.0" +description = "Common protobufs used in Google APIs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, + {file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"}, +] + +[package.dependencies] +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" + +[package.extras] +grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] + +[[package]] +name = "gql" +version = "3.5.0" +description = "GraphQL client for Python" +optional = false +python-versions = "*" +files = [ + {file = "gql-3.5.0-py2.py3-none-any.whl", hash = "sha256:70dda5694a5b194a8441f077aa5fb70cc94e4ec08016117523f013680901ecb7"}, + {file = "gql-3.5.0.tar.gz", hash = "sha256:ccb9c5db543682b28f577069950488218ed65d4ac70bb03b6929aaadaf636de9"}, +] + +[package.dependencies] +anyio = ">=3.0,<5" +backoff = ">=1.11.1,<3.0" +graphql-core = ">=3.2,<3.3" +yarl = ">=1.6,<2.0" + +[package.extras] +aiohttp = ["aiohttp (>=3.8.0,<4)", "aiohttp (>=3.9.0b0,<4)"] +all = ["aiohttp (>=3.8.0,<4)", "aiohttp (>=3.9.0b0,<4)", "botocore (>=1.21,<2)", "httpx (>=0.23.1,<1)", "requests (>=2.26,<3)", "requests-toolbelt (>=1.0.0,<2)", "websockets (>=10,<12)"] +botocore = ["botocore (>=1.21,<2)"] +dev = ["aiofiles", "aiohttp (>=3.8.0,<4)", "aiohttp (>=3.9.0b0,<4)", "black (==22.3.0)", "botocore (>=1.21,<2)", "check-manifest (>=0.42,<1)", "flake8 (==3.8.1)", "httpx (>=0.23.1,<1)", "isort (==4.3.21)", "mock (==4.0.2)", "mypy (==0.910)", "parse (==1.15.0)", "pytest (==7.4.2)", "pytest-asyncio (==0.21.1)", "pytest-console-scripts (==1.3.1)", "pytest-cov (==3.0.0)", "requests (>=2.26,<3)", "requests-toolbelt (>=1.0.0,<2)", "sphinx (>=5.3.0,<6)", "sphinx-argparse (==0.2.5)", "sphinx-rtd-theme (>=0.4,<1)", "types-aiofiles", "types-mock", "types-requests", "vcrpy (==4.4.0)", "websockets (>=10,<12)"] +httpx = ["httpx (>=0.23.1,<1)"] +requests = ["requests (>=2.26,<3)", "requests-toolbelt (>=1.0.0,<2)"] +test = ["aiofiles", "aiohttp (>=3.8.0,<4)", "aiohttp (>=3.9.0b0,<4)", "botocore (>=1.21,<2)", "httpx (>=0.23.1,<1)", "mock (==4.0.2)", "parse (==1.15.0)", "pytest (==7.4.2)", "pytest-asyncio (==0.21.1)", "pytest-console-scripts (==1.3.1)", "pytest-cov (==3.0.0)", "requests (>=2.26,<3)", "requests-toolbelt (>=1.0.0,<2)", "vcrpy (==4.4.0)", "websockets (>=10,<12)"] +test-no-transport = ["aiofiles", "mock (==4.0.2)", "parse (==1.15.0)", "pytest (==7.4.2)", "pytest-asyncio (==0.21.1)", "pytest-console-scripts (==1.3.1)", "pytest-cov (==3.0.0)", "vcrpy (==4.4.0)"] +websockets = ["websockets (>=10,<12)"] + +[[package]] +name = "graphql-core" +version = "3.2.3" +description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"}, + {file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"}, +] + +[[package]] +name = "grpc-google-logging-v2" +version = "0.8.1" +description = "GRPC library for the google-logging-v2 service" +optional = false +python-versions = "*" +files = [ + {file = "grpc-google-logging-v2-0.8.1.tar.gz", hash = "sha256:4b6b4e603860b134b2cb8732bb4d1f2cec963d553497dcf70b3f5ecc99d7fb4f"}, +] + +[package.dependencies] +googleapis-common-protos = ">=1.1.0" +grpcio = ">=1.0rc1" +oauth2client = ">=1.4.11" + +[[package]] +name = "grpc-google-pubsub-v1" +version = "0.8.1" +description = "GRPC library for the google-pubsub-v1 service" +optional = false +python-versions = "*" +files = [ + {file = "grpc-google-pubsub-v1-0.8.1.tar.gz", hash = "sha256:ab5a3a239a9678012cdc00a9b9a8fe8c75fca9a0035da41da3078145e9d967b9"}, +] + +[package.dependencies] +googleapis-common-protos = ">=1.1.0" +grpcio = ">=1.0rc1" +oauth2client = ">=1.4.11" + +[[package]] +name = "grpcio" +version = "1.60.1" +description = "HTTP/2-based RPC framework" +optional = false +python-versions = ">=3.7" +files = [ + {file = "grpcio-1.60.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:14e8f2c84c0832773fb3958240c69def72357bc11392571f87b2d7b91e0bb092"}, + {file = "grpcio-1.60.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:33aed0a431f5befeffd9d346b0fa44b2c01aa4aeae5ea5b2c03d3e25e0071216"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:fead980fbc68512dfd4e0c7b1f5754c2a8e5015a04dea454b9cada54a8423525"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:082081e6a36b6eb5cf0fd9a897fe777dbb3802176ffd08e3ec6567edd85bc104"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55ccb7db5a665079d68b5c7c86359ebd5ebf31a19bc1a91c982fd622f1e31ff2"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9b54577032d4f235452f77a83169b6527bf4b77d73aeada97d45b2aaf1bf5ce0"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d142bcd604166417929b071cd396aa13c565749a4c840d6c702727a59d835eb"}, + {file = "grpcio-1.60.1-cp310-cp310-win32.whl", hash = "sha256:2a6087f234cb570008a6041c8ffd1b7d657b397fdd6d26e83d72283dae3527b1"}, + {file = "grpcio-1.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:f2212796593ad1d0235068c79836861f2201fc7137a99aa2fea7beeb3b101177"}, + {file = "grpcio-1.60.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:79ae0dc785504cb1e1788758c588c711f4e4a0195d70dff53db203c95a0bd303"}, + {file = "grpcio-1.60.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4eec8b8c1c2c9b7125508ff7c89d5701bf933c99d3910e446ed531cd16ad5d87"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:8c9554ca8e26241dabe7951aa1fa03a1ba0856688ecd7e7bdbdd286ebc272e4c"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91422ba785a8e7a18725b1dc40fbd88f08a5bb4c7f1b3e8739cab24b04fa8a03"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cba6209c96828711cb7c8fcb45ecef8c8859238baf15119daa1bef0f6c84bfe7"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c71be3f86d67d8d1311c6076a4ba3b75ba5703c0b856b4e691c9097f9b1e8bd2"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:af5ef6cfaf0d023c00002ba25d0751e5995fa0e4c9eec6cd263c30352662cbce"}, + {file = "grpcio-1.60.1-cp311-cp311-win32.whl", hash = "sha256:a09506eb48fa5493c58f946c46754ef22f3ec0df64f2b5149373ff31fb67f3dd"}, + {file = "grpcio-1.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:49c9b6a510e3ed8df5f6f4f3c34d7fbf2d2cae048ee90a45cd7415abab72912c"}, + {file = "grpcio-1.60.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:b58b855d0071575ea9c7bc0d84a06d2edfbfccec52e9657864386381a7ce1ae9"}, + {file = "grpcio-1.60.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:a731ac5cffc34dac62053e0da90f0c0b8560396a19f69d9703e88240c8f05858"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:cf77f8cf2a651fbd869fbdcb4a1931464189cd210abc4cfad357f1cacc8642a6"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c557e94e91a983e5b1e9c60076a8fd79fea1e7e06848eb2e48d0ccfb30f6e073"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:069fe2aeee02dfd2135d562d0663fe70fbb69d5eed6eb3389042a7e963b54de8"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb0af13433dbbd1c806e671d81ec75bd324af6ef75171fd7815ca3074fe32bfe"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2f44c32aef186bbba254129cea1df08a20be414144ac3bdf0e84b24e3f3b2e05"}, + {file = "grpcio-1.60.1-cp312-cp312-win32.whl", hash = "sha256:a212e5dea1a4182e40cd3e4067ee46be9d10418092ce3627475e995cca95de21"}, + {file = "grpcio-1.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:6e490fa5f7f5326222cb9f0b78f207a2b218a14edf39602e083d5f617354306f"}, + {file = "grpcio-1.60.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:4216e67ad9a4769117433814956031cb300f85edc855252a645a9a724b3b6594"}, + {file = "grpcio-1.60.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:73e14acd3d4247169955fae8fb103a2b900cfad21d0c35f0dcd0fdd54cd60367"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:6ecf21d20d02d1733e9c820fb5c114c749d888704a7ec824b545c12e78734d1c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33bdea30dcfd4f87b045d404388469eb48a48c33a6195a043d116ed1b9a0196c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b69e79d00f78c81eecfb38f4516080dc7f36a198b6b37b928f1c13b3c063e9"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:39aa848794b887120b1d35b1b994e445cc028ff602ef267f87c38122c1add50d"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:72153a0d2e425f45b884540a61c6639436ddafa1829a42056aa5764b84108b8e"}, + {file = "grpcio-1.60.1-cp37-cp37m-win_amd64.whl", hash = "sha256:50d56280b482875d1f9128ce596e59031a226a8b84bec88cb2bf76c289f5d0de"}, + {file = "grpcio-1.60.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:6d140bdeb26cad8b93c1455fa00573c05592793c32053d6e0016ce05ba267549"}, + {file = "grpcio-1.60.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:bc808924470643b82b14fe121923c30ec211d8c693e747eba8a7414bc4351a23"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:70c83bb530572917be20c21f3b6be92cd86b9aecb44b0c18b1d3b2cc3ae47df0"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b106bc52e7f28170e624ba61cc7dc6829566e535a6ec68528f8e1afbed1c41f"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e980cd6db1088c144b92fe376747328d5554bc7960ce583ec7b7d81cd47287"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0c5807e9152eff15f1d48f6b9ad3749196f79a4a050469d99eecb679be592acc"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1c3dc536b3ee124e8b24feb7533e5c70b9f2ef833e3b2e5513b2897fd46763a"}, + {file = "grpcio-1.60.1-cp38-cp38-win32.whl", hash = "sha256:d7404cebcdb11bb5bd40bf94131faf7e9a7c10a6c60358580fe83913f360f929"}, + {file = "grpcio-1.60.1-cp38-cp38-win_amd64.whl", hash = "sha256:c8754c75f55781515a3005063d9a05878b2cfb3cb7e41d5401ad0cf19de14872"}, + {file = "grpcio-1.60.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:0250a7a70b14000fa311de04b169cc7480be6c1a769b190769d347939d3232a8"}, + {file = "grpcio-1.60.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:660fc6b9c2a9ea3bb2a7e64ba878c98339abaf1811edca904ac85e9e662f1d73"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:76eaaba891083fcbe167aa0f03363311a9f12da975b025d30e94b93ac7a765fc"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d97c65ea7e097056f3d1ead77040ebc236feaf7f71489383d20f3b4c28412a"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb2a2911b028f01c8c64d126f6b632fcd8a9ac975aa1b3855766c94e4107180"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5a1ebbae7e2214f51b1f23b57bf98eeed2cf1ba84e4d523c48c36d5b2f8829ff"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a66f4d2a005bc78e61d805ed95dedfcb35efa84b7bba0403c6d60d13a3de2d6"}, + {file = "grpcio-1.60.1-cp39-cp39-win32.whl", hash = "sha256:8d488fbdbf04283f0d20742b64968d44825617aa6717b07c006168ed16488804"}, + {file = "grpcio-1.60.1-cp39-cp39-win_amd64.whl", hash = "sha256:61b7199cd2a55e62e45bfb629a35b71fc2c0cb88f686a047f25b1112d3810904"}, + {file = "grpcio-1.60.1.tar.gz", hash = "sha256:dd1d3a8d1d2e50ad9b59e10aa7f07c7d1be2b367f3f2d33c5fade96ed5460962"}, +] + +[package.extras] +protobuf = ["grpcio-tools (>=1.60.1)"] + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "1.0.2" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, + {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.23.0)"] + +[[package]] +name = "httplib2" +version = "0.22.0" +description = "A comprehensive HTTP client library." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "httplib2-0.22.0-py3-none-any.whl", hash = "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc"}, + {file = "httplib2-0.22.0.tar.gz", hash = "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81"}, +] + +[package.dependencies] +pyparsing = {version = ">=2.4.2,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.0.2 || >3.0.2,<3.0.3 || >3.0.3,<4", markers = "python_version > \"3.0\""} + +[[package]] +name = "httpx" +version = "0.26.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd"}, + {file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "idna" +version = "3.6" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "inquirer" +version = "3.2.3" +description = "Collection of common interactive command line user interfaces, based on Inquirer.js" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "inquirer-3.2.3-py3-none-any.whl", hash = "sha256:68fa2cfaa652212f035f73794aa1db2e6c0a9c8cef81ab6825b45120fa8ea345"}, + {file = "inquirer-3.2.3.tar.gz", hash = "sha256:0cba57d901b206dd597d8809b58c378c47fbc804a1fc9b33e2780ca2f9b43ac7"}, +] + +[package.dependencies] +blessed = ">=1.19.0" +editor = ">=1.6.0" +readchar = ">=3.0.6" + +[[package]] +name = "jinja2" +version = "3.1.3" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jinxed" +version = "1.2.1" +description = "Jinxed Terminal Library" +optional = false +python-versions = "*" +files = [ + {file = "jinxed-1.2.1-py2.py3-none-any.whl", hash = "sha256:37422659c4925969c66148c5e64979f553386a4226b9484d910d3094ced37d30"}, + {file = "jinxed-1.2.1.tar.gz", hash = "sha256:30c3f861b73279fea1ed928cfd4dfb1f273e16cd62c8a32acfac362da0f78f3f"}, +] + +[package.dependencies] +ansicon = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "metadata-service" +version = "0.3.3" +description = "" +optional = false +python-versions = "^3.9" +files = [] +develop = false + +[package.dependencies] +click = "^8.1.3" +gcloud = "^0.18.3" +google = "^3.0.0" +google-cloud-storage = "^2.8.0" +pydantic = "^1.10.6" +pydash = "^6.0.2" +pyyaml = "^6.0" +semver = "^3.0.1" + +[package.source] +type = "directory" +url = "../metadata_service/lib" + +[[package]] +name = "multidict" +version = "6.0.5" +description = "multidict implementation" +optional = false +python-versions = ">=3.7" +files = [ + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, + {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, + {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, + {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, + {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, + {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, + {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, + {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, + {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, + {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, + {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, + {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, + {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, + {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, + {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, + {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, +] + +[[package]] +name = "mypy" +version = "1.8.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, + {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, + {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, + {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, + {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, + {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, + {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, + {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, + {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, + {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, + {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, + {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, + {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, + {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, + {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, + {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, + {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, + {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, + {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.1.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "numpy" +version = "1.26.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, +] + +[[package]] +name = "oauth2client" +version = "4.1.3" +description = "OAuth 2.0 client library" +optional = false +python-versions = "*" +files = [ + {file = "oauth2client-4.1.3-py2.py3-none-any.whl", hash = "sha256:b8a81cc5d60e2d364f0b1b98f958dbd472887acaf1a5b05e21c28c31a2d6d3ac"}, + {file = "oauth2client-4.1.3.tar.gz", hash = "sha256:d486741e451287f69568a4d26d70d9acd73a2bbfa275746c535b4209891cccc6"}, +] + +[package.dependencies] +httplib2 = ">=0.9.1" +pyasn1 = ">=0.1.7" +pyasn1-modules = ">=0.0.5" +rsa = ">=3.1.4" +six = ">=1.6.1" + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pandas" +version = "2.2.0" +description = "Powerful data structures for data analysis, time series, and statistics" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pandas-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8108ee1712bb4fa2c16981fba7e68b3f6ea330277f5ca34fa8d557e986a11670"}, + {file = "pandas-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:736da9ad4033aeab51d067fc3bd69a0ba36f5a60f66a527b3d72e2030e63280a"}, + {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38e0b4fc3ddceb56ec8a287313bc22abe17ab0eb184069f08fc6a9352a769b18"}, + {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20404d2adefe92aed3b38da41d0847a143a09be982a31b85bc7dd565bdba0f4e"}, + {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ea3ee3f125032bfcade3a4cf85131ed064b4f8dd23e5ce6fa16473e48ebcaf5"}, + {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9670b3ac00a387620489dfc1bca66db47a787f4e55911f1293063a78b108df1"}, + {file = "pandas-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a946f210383c7e6d16312d30b238fd508d80d927014f3b33fb5b15c2f895430"}, + {file = "pandas-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a1b438fa26b208005c997e78672f1aa8138f67002e833312e6230f3e57fa87d5"}, + {file = "pandas-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ce2fbc8d9bf303ce54a476116165220a1fedf15985b09656b4b4275300e920b"}, + {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2707514a7bec41a4ab81f2ccce8b382961a29fbe9492eab1305bb075b2b1ff4f"}, + {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85793cbdc2d5bc32620dc8ffa715423f0c680dacacf55056ba13454a5be5de88"}, + {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cfd6c2491dc821b10c716ad6776e7ab311f7df5d16038d0b7458bc0b67dc10f3"}, + {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a146b9dcacc3123aa2b399df1a284de5f46287a4ab4fbfc237eac98a92ebcb71"}, + {file = "pandas-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbc1b53c0e1fdf16388c33c3cca160f798d38aea2978004dd3f4d3dec56454c9"}, + {file = "pandas-2.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a41d06f308a024981dcaa6c41f2f2be46a6b186b902c94c2674e8cb5c42985bc"}, + {file = "pandas-2.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:159205c99d7a5ce89ecfc37cb08ed179de7783737cea403b295b5eda8e9c56d1"}, + {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1e1f3861ea9132b32f2133788f3b14911b68102d562715d71bd0013bc45440"}, + {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:761cb99b42a69005dec2b08854fb1d4888fdf7b05db23a8c5a099e4b886a2106"}, + {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a20628faaf444da122b2a64b1e5360cde100ee6283ae8effa0d8745153809a2e"}, + {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f5be5d03ea2073627e7111f61b9f1f0d9625dc3c4d8dda72cc827b0c58a1d042"}, + {file = "pandas-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:a626795722d893ed6aacb64d2401d017ddc8a2341b49e0384ab9bf7112bdec30"}, + {file = "pandas-2.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9f66419d4a41132eb7e9a73dcec9486cf5019f52d90dd35547af11bc58f8637d"}, + {file = "pandas-2.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:57abcaeda83fb80d447f28ab0cc7b32b13978f6f733875ebd1ed14f8fbc0f4ab"}, + {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60f1f7dba3c2d5ca159e18c46a34e7ca7247a73b5dd1a22b6d59707ed6b899a"}, + {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb61dc8567b798b969bcc1fc964788f5a68214d333cade8319c7ab33e2b5d88a"}, + {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:52826b5f4ed658fa2b729264d63f6732b8b29949c7fd234510d57c61dbeadfcd"}, + {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bde2bc699dbd80d7bc7f9cab1e23a95c4375de615860ca089f34e7c64f4a8de7"}, + {file = "pandas-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:3de918a754bbf2da2381e8a3dcc45eede8cd7775b047b923f9006d5f876802ae"}, + {file = "pandas-2.2.0.tar.gz", hash = "sha256:30b83f7c3eb217fb4d1b494a57a2fda5444f17834f5df2de6b2ffff68dc3c8e2"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""}, +] +python-dateutil = ">=2.8.2" +pytz = ">=2020.1" +tzdata = ">=2022.7" + +[package.extras] +all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] +aws = ["s3fs (>=2022.11.0)"] +clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] +compression = ["zstandard (>=0.19.0)"] +computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] +feather = ["pyarrow (>=10.0.1)"] +fss = ["fsspec (>=2022.11.0)"] +gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] +hdf5 = ["tables (>=3.8.0)"] +html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] +mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] +parquet = ["pyarrow (>=10.0.1)"] +performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] +plot = ["matplotlib (>=3.6.3)"] +postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +spss = ["pyreadstat (>=1.2.0)"] +sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.9.2)"] + +[[package]] +name = "platformdirs" +version = "4.2.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] + +[[package]] +name = "pluggy" +version = "1.4.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "ply" +version = "3.8" +description = "Python Lex & Yacc" +optional = false +python-versions = "*" +files = [ + {file = "ply-3.8.tar.gz", hash = "sha256:e7d1bdff026beb159c9942f7a17e102c375638d9478a7ecd4cc0c76afd8de0b8"}, +] + +[[package]] +name = "protobuf" +version = "4.25.2" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "protobuf-4.25.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"}, + {file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"}, + {file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"}, + {file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"}, + {file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"}, + {file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"}, + {file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"}, + {file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"}, + {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, +] + +[[package]] +name = "pyasn1" +version = "0.5.1" +description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, + {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, +] + +[[package]] +name = "pyasn1-modules" +version = "0.3.0" +description = "A collection of ASN.1-based protocols modules" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, + {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, +] + +[package.dependencies] +pyasn1 = ">=0.4.6,<0.6.0" + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pydantic" +version = "1.10.14" +description = "Data validation and settings management using python type hints" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic-1.10.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7f4fcec873f90537c382840f330b90f4715eebc2bc9925f04cb92de593eae054"}, + {file = "pydantic-1.10.14-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e3a76f571970fcd3c43ad982daf936ae39b3e90b8a2e96c04113a369869dc87"}, + {file = "pydantic-1.10.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d886bd3c3fbeaa963692ef6b643159ccb4b4cefaf7ff1617720cbead04fd1d"}, + {file = "pydantic-1.10.14-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:798a3d05ee3b71967844a1164fd5bdb8c22c6d674f26274e78b9f29d81770c4e"}, + {file = "pydantic-1.10.14-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:23d47a4b57a38e8652bcab15a658fdb13c785b9ce217cc3a729504ab4e1d6bc9"}, + {file = "pydantic-1.10.14-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9f674b5c3bebc2eba401de64f29948ae1e646ba2735f884d1594c5f675d6f2a"}, + {file = "pydantic-1.10.14-cp310-cp310-win_amd64.whl", hash = "sha256:24a7679fab2e0eeedb5a8924fc4a694b3bcaac7d305aeeac72dd7d4e05ecbebf"}, + {file = "pydantic-1.10.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d578ac4bf7fdf10ce14caba6f734c178379bd35c486c6deb6f49006e1ba78a7"}, + {file = "pydantic-1.10.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa7790e94c60f809c95602a26d906eba01a0abee9cc24150e4ce2189352deb1b"}, + {file = "pydantic-1.10.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aad4e10efa5474ed1a611b6d7f0d130f4aafadceb73c11d9e72823e8f508e663"}, + {file = "pydantic-1.10.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1245f4f61f467cb3dfeced2b119afef3db386aec3d24a22a1de08c65038b255f"}, + {file = "pydantic-1.10.14-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:21efacc678a11114c765eb52ec0db62edffa89e9a562a94cbf8fa10b5db5c046"}, + {file = "pydantic-1.10.14-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:412ab4a3f6dbd2bf18aefa9f79c7cca23744846b31f1d6555c2ee2b05a2e14ca"}, + {file = "pydantic-1.10.14-cp311-cp311-win_amd64.whl", hash = "sha256:e897c9f35281f7889873a3e6d6b69aa1447ceb024e8495a5f0d02ecd17742a7f"}, + {file = "pydantic-1.10.14-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d604be0f0b44d473e54fdcb12302495fe0467c56509a2f80483476f3ba92b33c"}, + {file = "pydantic-1.10.14-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42c7d17706911199798d4c464b352e640cab4351efe69c2267823d619a937e5"}, + {file = "pydantic-1.10.14-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:596f12a1085e38dbda5cbb874d0973303e34227b400b6414782bf205cc14940c"}, + {file = "pydantic-1.10.14-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bfb113860e9288d0886e3b9e49d9cf4a9d48b441f52ded7d96db7819028514cc"}, + {file = "pydantic-1.10.14-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bc3ed06ab13660b565eed80887fcfbc0070f0aa0691fbb351657041d3e874efe"}, + {file = "pydantic-1.10.14-cp37-cp37m-win_amd64.whl", hash = "sha256:ad8c2bc677ae5f6dbd3cf92f2c7dc613507eafe8f71719727cbc0a7dec9a8c01"}, + {file = "pydantic-1.10.14-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c37c28449752bb1f47975d22ef2882d70513c546f8f37201e0fec3a97b816eee"}, + {file = "pydantic-1.10.14-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49a46a0994dd551ec051986806122767cf144b9702e31d47f6d493c336462597"}, + {file = "pydantic-1.10.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53e3819bd20a42470d6dd0fe7fc1c121c92247bca104ce608e609b59bc7a77ee"}, + {file = "pydantic-1.10.14-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbb503bbbbab0c588ed3cd21975a1d0d4163b87e360fec17a792f7d8c4ff29f"}, + {file = "pydantic-1.10.14-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:336709883c15c050b9c55a63d6c7ff09be883dbc17805d2b063395dd9d9d0022"}, + {file = "pydantic-1.10.14-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4ae57b4d8e3312d486e2498d42aed3ece7b51848336964e43abbf9671584e67f"}, + {file = "pydantic-1.10.14-cp38-cp38-win_amd64.whl", hash = "sha256:dba49d52500c35cfec0b28aa8b3ea5c37c9df183ffc7210b10ff2a415c125c4a"}, + {file = "pydantic-1.10.14-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c66609e138c31cba607d8e2a7b6a5dc38979a06c900815495b2d90ce6ded35b4"}, + {file = "pydantic-1.10.14-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d986e115e0b39604b9eee3507987368ff8148222da213cd38c359f6f57b3b347"}, + {file = "pydantic-1.10.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:646b2b12df4295b4c3148850c85bff29ef6d0d9621a8d091e98094871a62e5c7"}, + {file = "pydantic-1.10.14-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282613a5969c47c83a8710cc8bfd1e70c9223feb76566f74683af889faadc0ea"}, + {file = "pydantic-1.10.14-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:466669501d08ad8eb3c4fecd991c5e793c4e0bbd62299d05111d4f827cded64f"}, + {file = "pydantic-1.10.14-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:13e86a19dca96373dcf3190fcb8797d40a6f12f154a244a8d1e8e03b8f280593"}, + {file = "pydantic-1.10.14-cp39-cp39-win_amd64.whl", hash = "sha256:08b6ec0917c30861e3fe71a93be1648a2aa4f62f866142ba21670b24444d7fd8"}, + {file = "pydantic-1.10.14-py3-none-any.whl", hash = "sha256:8ee853cd12ac2ddbf0ecbac1c289f95882b2d4482258048079d13be700aa114c"}, + {file = "pydantic-1.10.14.tar.gz", hash = "sha256:46f17b832fe27de7850896f3afee50ea682220dd218f7e9c88d436788419dca6"}, +] + +[package.dependencies] +typing-extensions = ">=4.2.0" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "pydash" +version = "6.0.2" +description = "The kitchen sink of Python utility libraries for doing \"stuff\" in a functional way. Based on the Lo-Dash Javascript library." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydash-6.0.2-py3-none-any.whl", hash = "sha256:6d3ce5cbbc8ca3533c12782ac201c2ec756d1e1703ec3efc88f2b95d1ed2bb31"}, + {file = "pydash-6.0.2.tar.gz", hash = "sha256:35caa588e01d293713655e0870544d25128cd414c5e19477a0d63adc2b2ca03e"}, +] + +[package.extras] +dev = ["Sphinx", "black", "build", "coverage", "docformatter", "flake8", "flake8-black", "flake8-bugbear", "flake8-isort", "importlib-metadata (<5)", "invoke", "isort", "pylint", "pytest", "pytest-cov", "sphinx-rtd-theme", "tox", "twine", "wheel"] + +[[package]] +name = "pygithub" +version = "1.59.1" +description = "Use the full Github API v3" +optional = false +python-versions = ">=3.7" +files = [ + {file = "PyGithub-1.59.1-py3-none-any.whl", hash = "sha256:3d87a822e6c868142f0c2c4bf16cce4696b5a7a4d142a7bd160e1bdf75bc54a9"}, + {file = "PyGithub-1.59.1.tar.gz", hash = "sha256:c44e3a121c15bf9d3a5cc98d94c9a047a5132a9b01d22264627f58ade9ddc217"}, +] + +[package.dependencies] +deprecated = "*" +pyjwt = {version = ">=2.4.0", extras = ["crypto"]} +pynacl = ">=1.4.0" +requests = ">=2.14.0" + +[[package]] +name = "pygments" +version = "2.17.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, +] + +[package.extras] +plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pyjwt" +version = "2.8.0" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, + {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, +] + +[package.dependencies] +cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + +[[package]] +name = "pynacl" +version = "1.5.0" +description = "Python binding to the Networking and Cryptography (NaCl) library" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d"}, + {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b"}, + {file = "PyNaCl-1.5.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win32.whl", hash = "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"}, + {file = "PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93"}, + {file = "PyNaCl-1.5.0.tar.gz", hash = "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba"}, +] + +[package.dependencies] +cffi = ">=1.4.1" + +[package.extras] +docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] +tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] + +[[package]] +name = "pyparsing" +version = "3.1.1" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, + {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pytest" +version = "8.0.0" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.0.0-py3-none-any.whl", hash = "sha256:50fb9cbe836c3f20f0dfa99c565201fb75dc54c8d76373cd1bde06b06657bdb6"}, + {file = "pytest-8.0.0.tar.gz", hash = "sha256:249b1b0864530ba251b7438274c4d251c58d868edaaec8762893ad4a0d71c36c"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.3.0,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-mock" +version = "3.12.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.12.0.tar.gz", hash = "sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9"}, + {file = "pytest_mock-3.12.0-py3-none-any.whl", hash = "sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f"}, +] + +[package.dependencies] +pytest = ">=5.0" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2024.1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "readchar" +version = "4.0.5" +description = "Library to easily read single chars and key strokes" +optional = false +python-versions = ">=3.7" +files = [ + {file = "readchar-4.0.5-py3-none-any.whl", hash = "sha256:76ec784a5dd2afac3b7da8003329834cdd9824294c260027f8c8d2e4d0a78f43"}, + {file = "readchar-4.0.5.tar.gz", hash = "sha256:08a456c2d7c1888cde3f4688b542621b676eb38cd6cfed7eb6cb2e2905ddc826"}, +] + +[package.dependencies] +setuptools = ">=41.0" + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rich" +version = "13.7.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, + {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "rsa" +version = "4.9" +description = "Pure-Python RSA implementation" +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, + {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, +] + +[package.dependencies] +pyasn1 = ">=0.1.3" + +[[package]] +name = "ruff" +version = "0.2.1" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.2.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:dd81b911d28925e7e8b323e8d06951554655021df8dd4ac3045d7212ac4ba080"}, + {file = "ruff-0.2.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dc586724a95b7d980aa17f671e173df00f0a2eef23f8babbeee663229a938fec"}, + {file = "ruff-0.2.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c92db7101ef5bfc18e96777ed7bc7c822d545fa5977e90a585accac43d22f18a"}, + {file = "ruff-0.2.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:13471684694d41ae0f1e8e3a7497e14cd57ccb7dd72ae08d56a159d6c9c3e30e"}, + {file = "ruff-0.2.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a11567e20ea39d1f51aebd778685582d4c56ccb082c1161ffc10f79bebe6df35"}, + {file = "ruff-0.2.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:00a818e2db63659570403e44383ab03c529c2b9678ba4ba6c105af7854008105"}, + {file = "ruff-0.2.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be60592f9d218b52f03384d1325efa9d3b41e4c4d55ea022cd548547cc42cd2b"}, + {file = "ruff-0.2.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbd2288890b88e8aab4499e55148805b58ec711053588cc2f0196a44f6e3d855"}, + {file = "ruff-0.2.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ef052283da7dec1987bba8d8733051c2325654641dfe5877a4022108098683"}, + {file = "ruff-0.2.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7022d66366d6fded4ba3889f73cd791c2d5621b2ccf34befc752cb0df70f5fad"}, + {file = "ruff-0.2.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0a725823cb2a3f08ee743a534cb6935727d9e47409e4ad72c10a3faf042ad5ba"}, + {file = "ruff-0.2.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0034d5b6323e6e8fe91b2a1e55b02d92d0b582d2953a2b37a67a2d7dedbb7acc"}, + {file = "ruff-0.2.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e5cb5526d69bb9143c2e4d2a115d08ffca3d8e0fddc84925a7b54931c96f5c02"}, + {file = "ruff-0.2.1-py3-none-win32.whl", hash = "sha256:6b95ac9ce49b4fb390634d46d6ece32ace3acdd52814671ccaf20b7f60adb232"}, + {file = "ruff-0.2.1-py3-none-win_amd64.whl", hash = "sha256:e3affdcbc2afb6f5bd0eb3130139ceedc5e3f28d206fe49f63073cb9e65988e0"}, + {file = "ruff-0.2.1-py3-none-win_arm64.whl", hash = "sha256:efababa8e12330aa94a53e90a81eb6e2d55f348bc2e71adbf17d9cad23c03ee6"}, + {file = "ruff-0.2.1.tar.gz", hash = "sha256:3b42b5d8677cd0c72b99fcaf068ffc62abb5a19e71b4a3b9cfa50658a0af02f1"}, +] + +[[package]] +name = "runs" +version = "1.2.2" +description = "🏃 Run a block of text as a subprocess 🏃" +optional = false +python-versions = ">=3.8" +files = [ + {file = "runs-1.2.2-py3-none-any.whl", hash = "sha256:0980dcbc25aba1505f307ac4f0e9e92cbd0be2a15a1e983ee86c24c87b839dfd"}, + {file = "runs-1.2.2.tar.gz", hash = "sha256:9dc1815e2895cfb3a48317b173b9f1eac9ba5549b36a847b5cc60c3bf82ecef1"}, +] + +[package.dependencies] +xmod = "*" + +[[package]] +name = "semver" +version = "3.0.2" +description = "Python helper for Semantic Versioning (https://semver.org)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "semver-3.0.2-py3-none-any.whl", hash = "sha256:b1ea4686fe70b981f85359eda33199d60c53964284e0cfb4977d243e37cf4bf4"}, + {file = "semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc"}, +] + +[[package]] +name = "setuptools" +version = "69.1.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-69.1.0-py3-none-any.whl", hash = "sha256:c054629b81b946d63a9c6e732bc8b2513a7c3ea645f11d0139a2191d735c60c6"}, + {file = "setuptools-69.1.0.tar.gz", hash = "sha256:850894c4195f09c4ed30dba56213bf7c3f21d86ed6bdaafb5df5972593bfc401"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "simpleeval" +version = "0.9.13" +description = "A simple, safe single expression evaluator library." +optional = false +python-versions = "*" +files = [ + {file = "simpleeval-0.9.13-py2.py3-none-any.whl", hash = "sha256:22a2701a5006e4188d125d34accf2405c2c37c93f6b346f2484b6422415ae54a"}, + {file = "simpleeval-0.9.13.tar.gz", hash = "sha256:4a30f9cc01825fe4c719c785e3762623e350c4840d5e6855c2a8496baaa65fac"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "smmap" +version = "5.0.1" +description = "A pure Python implementation of a sliding window memory map manager" +optional = false +python-versions = ">=3.7" +files = [ + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, +] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "soupsieve" +version = "2.5" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.8" +files = [ + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, +] + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "types-toml" +version = "0.10.8.7" +description = "Typing stubs for toml" +optional = false +python-versions = "*" +files = [ + {file = "types-toml-0.10.8.7.tar.gz", hash = "sha256:58b0781c681e671ff0b5c0319309910689f4ab40e8a2431e205d70c94bb6efb1"}, + {file = "types_toml-0.10.8.7-py3-none-any.whl", hash = "sha256:61951da6ad410794c97bec035d59376ce1cbf4453dc9b6f90477e81e4442d631"}, +] + +[[package]] +name = "typing-extensions" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, +] + +[[package]] +name = "tzdata" +version = "2024.1" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, +] + +[[package]] +name = "urllib3" +version = "2.2.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, + {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + +[[package]] +name = "wrapt" +version = "1.16.0" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.6" +files = [ + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, +] + +[[package]] +name = "xmod" +version = "1.8.1" +description = "🌱 Turn any object into a module 🌱" +optional = false +python-versions = ">=3.8" +files = [ + {file = "xmod-1.8.1-py3-none-any.whl", hash = "sha256:a24e9458a4853489042522bdca9e50ee2eac5ab75c809a91150a8a7f40670d48"}, + {file = "xmod-1.8.1.tar.gz", hash = "sha256:38c76486b9d672c546d57d8035df0beb7f4a9b088bc3fb2de5431ae821444377"}, +] + +[[package]] +name = "yarl" +version = "1.9.4" +description = "Yet another URL library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, + {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, + {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, + {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, + {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, + {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, + {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, + {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, + {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, + {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, + {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, + {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, + {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, + {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, + {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, + {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "5390813cbcb5f02e211eeb58bf6c50c4521ea183fe0e3015328c337a464b962f" diff --git a/airbyte-ci/connectors/connectors_qa/pyproject.toml b/airbyte-ci/connectors/connectors_qa/pyproject.toml new file mode 100644 index 000000000000..dbc255530e80 --- /dev/null +++ b/airbyte-ci/connectors/connectors_qa/pyproject.toml @@ -0,0 +1,43 @@ +[tool.poetry] +name = "connectors-qa" +version = "1.0.0" +description = "A package to run QA checks on Airbyte connectors, generate reports and documentation." +authors = ["Airbyte "] +readme = "README.md" +packages = [ + { include = "connectors_qa", from = "src" }, +] +[tool.poetry.dependencies] +python = "^3.10" +airbyte-connectors-base-images = {path = "../base_images", develop = false} +connector-ops = {path = "../connector_ops", develop = false} +metadata-service = {path = "../metadata_service/lib", develop = false} +pydash = "^6.0.2" +jinja2 = "^3.1.3" +toml = "^0.10.2" +asyncclick = "^8.1.7.1" +asyncer = "^0.0.4" + +[tool.poetry.scripts] +connectors-qa = "connectors_qa.cli:connectors_qa" + +[tool.poetry.group.dev.dependencies] +ruff = "^0.2.1" +pytest = "^8.0.0" +pytest-mock = "^3.12.0" +mypy = "^1.8.0" +types-toml = "^0.10.8.7" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.poe.tasks] +test = "pytest tests" +type_check = "mypy src --disallow-untyped-defs" +lint = "ruff check src" + +[tool.airbyte_ci] +extra_poetry_groups = ["dev"] +poe_tasks = ["type_check", "lint", "test"] +required_environment_variables = ["DOCKER_HUB_USERNAME", "DOCKER_HUB_PASSWORD",] diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/__init__.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/__init__.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/__init__.py new file mode 100644 index 000000000000..285b881030e9 --- /dev/null +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/__init__.py @@ -0,0 +1,14 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. +from .assets import ENABLED_CHECKS as ASSETS_CHECKS +from .metadata import ENABLED_CHECKS as METADATA_CORRECTNESS_CHECKS +from .security import ENABLED_CHECKS as SECURITY_CHECKS +from .packaging import ENABLED_CHECKS as PACKAGING_CHECKS +from .documentation import ENABLED_CHECKS as DOCUMENTATION_CHECKS + +ENABLED_CHECKS = ( + DOCUMENTATION_CHECKS + + METADATA_CORRECTNESS_CHECKS + + PACKAGING_CHECKS + + ASSETS_CHECKS + + SECURITY_CHECKS +) diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/assets.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/assets.py new file mode 100644 index 000000000000..e4083a5ea4e8 --- /dev/null +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/assets.py @@ -0,0 +1,33 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + + +from connector_ops.utils import Connector # type: ignore +from connectors_qa.models import Check, CheckCategory, CheckResult + + +class AssetsCheck(Check): + category = CheckCategory.ASSETS + + +class CheckConnectorIconIsAvailable(AssetsCheck): + name = "Connectors must have an icon" + description = "Each connector must have an icon available in at the root of the connector code directory. It must be an SVG file named `icon.svg`." + requires_metadata = False + + def _run(self, connector: Connector) -> CheckResult: + if not connector.icon_path or not connector.icon_path.exists(): + return self.create_check_result( + connector=connector, + passed=False, + message="Icon file is missing. Please create an icon file at the root of the connector code directory.", + ) + if not connector.icon_path.name == "icon.svg": + return self.create_check_result( + connector=connector, + passed=False, + message="Icon file is not named 'icon.svg'", + ) + return self.create_check_result(connector=connector, passed=True, message="Icon file exists") + + +ENABLED_CHECKS = [CheckConnectorIconIsAvailable()] diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/documentation.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/documentation.py new file mode 100644 index 000000000000..7cf09b80c4dc --- /dev/null +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/documentation.py @@ -0,0 +1,206 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + +import textwrap +from typing import List + +from connector_ops.utils import Connector # type: ignore +from connectors_qa import consts +from connectors_qa.models import Check, CheckCategory, CheckResult +from pydash.objects import get # type: ignore + + +class DocumentationCheck(Check): + category = CheckCategory.DOCUMENTATION + + +class CheckMigrationGuide(DocumentationCheck): + name = "Breaking changes must be accompanied by a migration guide" + description = "When a breaking change is introduced we check that a migration guide is available. It should be stored under `./docs/integrations/s/-migrations.md`.\nThis document should contain a section for each breaking change, in order of the version descending. It must explain users which action to take to migrate to the new version." + + def _run(self, connector: Connector) -> CheckResult: + breaking_changes = get(connector.metadata, "releases.breakingChanges") + if not breaking_changes: + return self.create_check_result( + connector=connector, + passed=True, + message="No breaking changes found. A migration guide is not required", + ) + migration_guide_file_path = connector.migration_guide_file_path + migration_guide_exists = migration_guide_file_path is not None and migration_guide_file_path.exists() + if not migration_guide_exists: + return self.create_check_result( + connector=connector, + passed=False, + message=f"Migration guide file is missing for {connector.technical_name}. Please create a migration guide in ./docs/integrations/s/-migrations.md`", + ) + + expected_title = f"# {connector.name_from_metadata} Migration Guide" + expected_version_header_start = "## Upgrading to " + migration_guide_content = migration_guide_file_path.read_text() + try: + first_line = migration_guide_content.splitlines()[0] + except IndexError: + first_line = migration_guide_content + if not first_line == expected_title: + return self.create_check_result( + connector=connector, + passed=False, + message=f"Migration guide file for {connector.technical_name} does not start with the correct header. Expected '{expected_title}', got '{first_line}'", + ) + + # Check that the migration guide contains a section for each breaking change key ## Upgrading to {version} + # Note that breaking change is a dict where the version is the key + # Note that the migration guide must have the sections in order of the version descending + # 3.0.0, 2.0.0, 1.0.0, etc + # This means we have to record the headings in the migration guide and then check that they are in order + # We also have to check that the headings are in the breaking changes dict + ordered_breaking_changes = sorted(breaking_changes.keys(), reverse=True) + ordered_expected_headings = [f"{expected_version_header_start}{version}" for version in ordered_breaking_changes] + + ordered_heading_versions = [] + for line in migration_guide_content.splitlines(): + stripped_line = line.strip() + if stripped_line.startswith(expected_version_header_start): + version = stripped_line.replace(expected_version_header_start, "") + ordered_heading_versions.append(version) + + if ordered_breaking_changes != ordered_heading_versions: + return self.create_check_result( + connector=connector, + passed=False, + message=textwrap.dedent( + f""" + Migration guide file for {connector.name_from_metadata} has incorrect version headings. + Check for missing, extra, or misordered headings, or headers with typos. + Expected headings: {ordered_expected_headings} + """ + ), + ) + return self.create_check_result( + connector=connector, + passed=True, + message="The migration guide is correctly templated", + ) + + +class CheckDocumentationExists(DocumentationCheck): + name = "Connectors must have user facing documentation" + description = ( + "The user facing connector documentation should be stored under `./docs/integrations/s/.md`." + ) + + def _run(self, connector: Connector) -> CheckResult: + if not connector.documentation_file_path or not connector.documentation_file_path.exists(): + return self.fail( + connector=connector, + message="User facing documentation file is missing. Please create it under ./docs/integrations/s/.md", + ) + return self.pass_( + connector=connector, + message=f"User facing documentation file {connector.documentation_file_path} exists", + ) + + +class CheckDocumentationStructure(DocumentationCheck): + name = "Connectors documentation follows our guidelines" + description = f"The user facing connector documentation should follow the guidelines defined in the [documentation standards]({consts.DOCUMENTATION_STANDARDS_URL})." + + expected_sections = [ + "## Prerequisites", + "## Setup guide", + "## Supported sync modes", + "## Supported streams", + "## Changelog", + ] + + def check_main_header(self, connector: Connector, doc_lines: List[str]) -> List[str]: + errors = [] + if not doc_lines[0].lower().startswith(f"# {connector.metadata['name']}".lower()): + errors.append( + f"The connector name is not used as the main header in the documentation. Expected: '# {connector.metadata['name']}'" + ) + return errors + + def check_sections(self, doc_lines: List[str]) -> List[str]: + errors = [] + for expected_section in self.expected_sections: + if expected_section.lower() not in doc_lines: + errors.append(f"Connector documentation is missing a '{expected_section.replace('#', '').strip()}' section") + return errors + + def _run(self, connector: Connector) -> CheckResult: + if not connector.documentation_file_path or not connector.documentation_file_path.exists(): + return self.fail( + connector=connector, + message="Could not check documentation structure as the documentation file is missing.", + ) + + doc_lines = [line.lower() for line in connector.documentation_file_path.read_text().splitlines()] + + if not doc_lines: + return self.fail( + connector=connector, + message="Documentation file is empty", + ) + + errors = [] + errors.extend(self.check_main_header(connector, doc_lines)) + errors.extend(self.check_sections(doc_lines)) + + if errors: + return self.fail( + connector=connector, + message=f"Connector documentation does not follow the guidelines: {'. '.join(errors)}", + ) + return self.pass_( + connector=connector, + message="Documentation guidelines are followed", + ) + + +class CheckChangelogEntry(DocumentationCheck): + name = "Connectors must have a changelog entry for each version" + description = "Each new version of a connector must have a changelog entry defined in the user facing documentation in `./docs/integrations/s/.md`." + + def _run(self, connector: Connector) -> CheckResult: + if connector.documentation_file_path is None or not connector.documentation_file_path.exists(): + return self.fail( + connector=connector, + message="Could not check changelog entry as the documentation file is missing. Please create it.", + ) + + doc_lines = connector.documentation_file_path.read_text().splitlines() + if not doc_lines: + return self.fail( + connector=connector, + message="Documentation file is empty", + ) + + after_changelog = False + entry_found = False + for line in doc_lines: + if "# changelog" in line.lower(): + after_changelog = True + if after_changelog and connector.version in line: + entry_found = True + + if not after_changelog: + return self.fail( + connector=connector, + message="Connector documentation is missing a 'Changelog' section", + ) + if not entry_found: + return self.fail( + connector=connector, + message=f"Connectors must have a changelog entry for each version: changelog entry for version {connector.version} is missing in the documentation", + ) + + return self.pass_(connector=connector, message=f"Changelog entry found for version {connector.version}") + + +ENABLED_CHECKS = [ + CheckMigrationGuide(), + CheckDocumentationExists(), + CheckDocumentationStructure(), + CheckChangelogEntry(), +] diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/metadata.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/metadata.py new file mode 100644 index 000000000000..bb549f86d1cd --- /dev/null +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/metadata.py @@ -0,0 +1,99 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + + +import os + +from connector_ops.utils import Connector # type: ignore +from connectors_qa import consts +from connectors_qa.models import Check, CheckCategory, CheckResult +from metadata_service.validators.metadata_validator import PRE_UPLOAD_VALIDATORS, ValidatorOptions, validate_and_load # type: ignore + + +class MetadataCheck(Check): + category = CheckCategory.METADATA + + +class ValidateMetadata(MetadataCheck): + name = f"Connectors must have valid {consts.METADATA_FILE_NAME} file" + description = f"Connectors must have a `{consts.METADATA_FILE_NAME}` file at the root of their directory. This file is used to build our connector registry. Its structure must follow our metadata schema. Field values are also validated. This is to ensure that all connectors have the required metadata fields and that the metadata is valid. More details in this [documentation]({consts.METADATA_DOCUMENTATION_URL})." + # Metadata lib required the following env var to be set + # to check if the base image is on DockerHub + required_env_vars = { + consts.DOCKER_HUB_USERNAME_ENV_VAR_NAME, + consts.DOCKER_HUB_PASSWORD_ENV_VAR_NAME, + } + + def __init__(self) -> None: + for env_var in self.required_env_vars: + if env_var not in os.environ: + raise ValueError(f"Environment variable {env_var} is required for this check") + super().__init__() + + def _run(self, connector: Connector) -> CheckResult: + if not connector.documentation_file_path or not connector.documentation_file_path.exists(): + return self.fail( + connector=connector, + message="User facing documentation file is missing. Please create it", + ) + deserialized_metadata, error = validate_and_load( + connector.metadata_file_path, + PRE_UPLOAD_VALIDATORS, + ValidatorOptions(docs_path=str(connector.documentation_file_path)), + ) + if not deserialized_metadata: + return self.fail(connector=connector, message=f"Metadata file is invalid: {error}") + + return self.pass_( + connector=connector, + message="Metadata file valid.", + ) + + +class CheckConnectorLanguageTag(MetadataCheck): + name = "Connector must have a language tag in metadata" + description = f"Connectors must have a language tag in their metadata. It must be set in the `tags` field in {consts.METADATA_FILE_NAME}. The values can be `language:python` or `language:java`. This checks infers the correct language tag based on the presence of certain files in the connector directory." + + PYTHON_LANGUAGE_TAG = "language:python" + JAVA_LANGUAGE_TAG = "language:java" + + def _run(self, connector: Connector) -> CheckResult: + current_language_tags = [t for t in connector.metadata.get("tags", []) if t.startswith("language:")] + if not current_language_tags: + return self.fail( + connector=connector, + message="Language tag is missing in the metadata file", + ) + if len(current_language_tags) > 1: + return self.fail( + connector=connector, + message=f"Multiple language tags found in the metadata file: {current_language_tags}", + ) + current_language_tag = current_language_tags[0] + + if (connector.code_directory / consts.SETUP_PY_FILE_NAME).exists() or ( + connector.code_directory / consts.PYPROJECT_FILE_NAME + ).exists(): + expected_language = self.PYTHON_LANGUAGE_TAG + elif (connector.code_directory / consts.GRADLE_FILE_NAME).exists(): + expected_language = self.JAVA_LANGUAGE_TAG + else: + return self.fail( + connector=connector, + message="Could not infer the language tag from the connector directory", + ) + if current_language_tag != expected_language: + return self.fail( + connector=connector, + message=f"Expected language tag '{expected_language}' in the {consts.METADATA_FILE_NAME} file, but found '{current_language_tag}'", + ) + return self.pass_( + connector=connector, + message=f"Language tag {expected_language} is present in the metadata file", + ) + + +ENABLED_CHECKS = [ + ValidateMetadata(), + # Disabled until metadata are globally cleaned up + # CheckConnectorLanguageTag() +] diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py new file mode 100644 index 000000000000..24b125ce9b9e --- /dev/null +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py @@ -0,0 +1,219 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + + +import semver +import toml +from connector_ops.utils import Connector, ConnectorLanguage # type: ignore +from connectors_qa import consts +from connectors_qa.models import Check, CheckCategory, CheckResult +from pydash.objects import get # type: ignore + + +class PackagingCheck(Check): + category = CheckCategory.PACKAGING + + +class CheckConnectorUsesPoetry(PackagingCheck): + name = "Connectors must use Poetry for dependency management" + description = "Connectors must use [Poetry](https://python-poetry.org/) for dependency management. This is to ensure that all connectors use a dependency management tool which locks dependencies and ensures reproducible installs." + requires_metadata = False + applies_to_connector_languages = [ + ConnectorLanguage.PYTHON, + ConnectorLanguage.LOW_CODE, + ] + + def _run(self, connector: Connector) -> CheckResult: + if not (connector.code_directory / consts.PYPROJECT_FILE_NAME).exists(): + return self.create_check_result( + connector=connector, + passed=False, + message=f"{consts.PYPROJECT_FILE_NAME} file is missing", + ) + if not (connector.code_directory / consts.POETRY_LOCK_FILE_NAME).exists(): + return self.fail(connector=connector, message=f"{consts.POETRY_LOCK_FILE_NAME} file is missing") + if (connector.code_directory / consts.SETUP_PY_FILE_NAME).exists(): + return self.fail( + connector=connector, + message=f"{consts.SETUP_PY_FILE_NAME} file exists. Please remove it and use {consts.PYPROJECT_FILE_NAME} instead", + ) + return self.pass_( + connector=connector, + message="Poetry is used for dependency management", + ) + + +class CheckPublishToPyPiIsEnabled(PackagingCheck): + name = "Python connectors must have PyPi publishing enabled" + description = f"Python connectors must have [PyPi](https://pypi.org/) publishing enabled in their `{consts.METADATA_FILE_NAME}` file. This is declared by setting `remoteRegistries.pypi.enabled` to `true` in {consts.METADATA_FILE_NAME}. This is to ensure that all connectors can be published to PyPi and can be used in `airbyte-lib`." + applies_to_connector_languages = [ + ConnectorLanguage.PYTHON, + ConnectorLanguage.LOW_CODE, + ] + + def _run(self, connector: Connector) -> CheckResult: + publish_to_pypi_is_enabled = get(connector.metadata, "remoteRegistries.pypi.enabled", False) + if not publish_to_pypi_is_enabled: + return self.create_check_result( + connector=connector, + passed=False, + message=f"PyPi publishing is not enabled. Please enable it in the {consts.METADATA_FILE_NAME} file", + ) + return self.create_check_result(connector=connector, passed=True, message="PyPi publishing is enabled") + + +class CheckConnectorLicense(PackagingCheck): + name = "Connectors must be licensed under MIT or Elv2" + description = f"Connectors must be licensed under the MIT or Elv2 license. This is to ensure that all connectors are licensed under a permissive license. More details in our [License FAQ]({consts.LICENSE_FAQ_URL})." + + def _run(self, connector: Connector) -> CheckResult: + metadata_license = get(connector.metadata, "license") + if metadata_license is None: + return self.fail( + connector=connector, + message="License is missing in the metadata file", + ) + elif metadata_license.upper() not in consts.VALID_LICENSES: + return self.fail( + connector=connector, + message=f"Connector is not using a valid license. Please use any of: {', '.join(consts.VALID_LICENSES)}", + ) + else: + return self.pass_( + connector=connector, + message=f"Connector is licensed under {metadata_license}", + ) + + +class CheckConnectorLicenseMatchInPyproject(PackagingCheck): + name = f"Connector license in {consts.METADATA_FILE_NAME} and {consts.PYPROJECT_FILE_NAME} file must match" + description = f"Connectors license in {consts.METADATA_FILE_NAME} and {consts.PYPROJECT_FILE_NAME} file must match. This is to ensure that all connectors are consistently licensed" + applies_to_connector_languages = [ + ConnectorLanguage.PYTHON, + ConnectorLanguage.LOW_CODE, + ] + + def _run(self, connector: Connector) -> CheckResult: + metadata_license = get(connector.metadata, "license") + if metadata_license is None: + return self.fail( + connector=connector, + message=f"License is missing in the {consts.METADATA_FILE_NAME} file", + ) + if not (connector.code_directory / consts.PYPROJECT_FILE_NAME).exists(): + return self.fail( + connector=connector, + message=f"{consts.PYPROJECT_FILE_NAME} file is missing", + ) + try: + pyproject = toml.load((connector.code_directory / consts.PYPROJECT_FILE_NAME)) + except toml.TomlDecodeError: + return self.fail( + connector=connector, + message=f"{consts.PYPROJECT_FILE_NAME} is invalid toml file", + ) + + poetry_license = get(pyproject, "tool.poetry.license") + + if poetry_license is None: + return self.fail( + connector=connector, + message=f"Connector is missing license in {consts.PYPROJECT_FILE_NAME}. Please add it", + ) + + if poetry_license.lower() != metadata_license.lower(): + return self.fail( + connector=connector, + message=f"Connector is licensed under {poetry_license} in {consts.PYPROJECT_FILE_NAME}, but licensed under {metadata_license} in {consts.METADATA_FILE_NAME}. These two files have to be consistent", + ) + + return self.pass_( + connector=connector, + message=f"License in {consts.METADATA_FILE_NAME} and {consts.PYPROJECT_FILE_NAME} file match", + ) + + +# TODO if more metadata.yaml to pyproject.toml field matching has to be done then create a generic class for this type of checks +class CheckConnectorVersionMatchInPyproject(PackagingCheck): + name = f"Connector version in {consts.METADATA_FILE_NAME} and {consts.PYPROJECT_FILE_NAME} file must match" + description = f"Connector version in {consts.METADATA_FILE_NAME} and {consts.PYPROJECT_FILE_NAME} file must match. This is to ensure that connector release is consistent." + applies_to_connector_languages = [ + ConnectorLanguage.PYTHON, + ConnectorLanguage.LOW_CODE, + ] + + def _run(self, connector: Connector) -> CheckResult: + metadata_version = get(connector.metadata, "dockerImageTag") + if metadata_version is None: + return self.fail( + connector=connector, + message=f"dockerImageTag field is missing in the {consts.METADATA_FILE_NAME} file", + ) + + if not (connector.code_directory / consts.PYPROJECT_FILE_NAME).exists(): + return self.fail( + connector=connector, + message=f"{consts.PYPROJECT_FILE_NAME} file is missing", + ) + + try: + pyproject = toml.load((connector.code_directory / consts.PYPROJECT_FILE_NAME)) + except toml.TomlDecodeError: + return self.fail( + connector=connector, + message=f"{consts.PYPROJECT_FILE_NAME} is invalid toml file", + ) + + poetry_version = get(pyproject, "tool.poetry.version") + + if poetry_version is None: + return self.fail( + connector=connector, + message=f"Version field is missing in the {consts.PYPROJECT_FILE_NAME} file", + ) + + if poetry_version != metadata_version: + return self.fail( + connector=connector, + message=f"Version is {metadata_version} in {consts.METADATA_FILE_NAME}, but version is {poetry_version} in {consts.PYPROJECT_FILE_NAME}. These two files have to be consistent", + ) + + return self.pass_( + connector=connector, + message=f"Version in {consts.METADATA_FILE_NAME} and {consts.PYPROJECT_FILE_NAME} file match", + ) + + +class CheckVersionFollowsSemver(PackagingCheck): + name = "Connector version must follow Semantic Versioning" + description = f"Connector version must follow the Semantic Versioning scheme. This is to ensure that all connectors follow a consistent versioning scheme. Refer to our [Semantic Versioning for Connectors]({consts.SEMVER_FOR_CONNECTORS_DOC_URL}) for more details." + + def _run(self, connector: Connector) -> CheckResult: + if "dockerImageTag" not in connector.metadata: + return self.create_check_result( + connector=connector, + passed=False, + message=f"dockerImageTag is missing in {consts.METADATA_FILE_NAME}", + ) + try: + semver.Version.parse(str(connector.metadata["dockerImageTag"])) + except ValueError: + return self.create_check_result( + connector=connector, + passed=False, + message=f"Connector version {connector.metadata['dockerImageTag']} does not follow semantic versioning", + ) + return self.create_check_result( + connector=connector, + passed=True, + message="Connector version follows semantic versioning", + ) + + +ENABLED_CHECKS = [ + CheckConnectorUsesPoetry(), + CheckConnectorLicense(), + CheckConnectorLicenseMatchInPyproject(), + CheckVersionFollowsSemver(), + CheckConnectorVersionMatchInPyproject(), + CheckPublishToPyPiIsEnabled(), +] diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/security.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/security.py new file mode 100644 index 000000000000..d5e5f396cedd --- /dev/null +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/security.py @@ -0,0 +1,147 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + +from pathlib import Path +from typing import Iterable, Optional, Set, Tuple + +from connector_ops.utils import Connector, ConnectorLanguage # type: ignore +from connectors_qa import consts +from connectors_qa.models import Check, CheckCategory, CheckResult +from pydash.objects import get # type: ignore + + +class SecurityCheck(Check): + category = CheckCategory.SECURITY + + +class CheckConnectorUsesHTTPSOnly(SecurityCheck): + name = "Connectors must use HTTPS only" + description = "Connectors must use HTTPS only when making requests to external services." + requires_metadata = False + + ignore_comment = "# ignore-https-check" # Define the ignore comment pattern + + ignored_directories_for_https_checks = { + ".venv", + "tests", + "unit_tests", + "integration_tests", + "build", + "source-file", + ".pytest_cache", + "acceptance_tests_logs", + ".hypothesis", + ".ruff_cache", + } + + ignored_file_name_pattern_for_https_checks = { + "*Test.java", + "*.jar", + "*.pyc", + "*.gz", + "*.svg", + "expected_records.jsonl", + "expected_records.json", + } + + ignored_url_prefixes = { + "http://json-schema.org", + "http://localhost", + } + + @staticmethod + def _read_all_files_in_directory( + directory: Path, + ignored_directories: Optional[Set[str]] = None, + ignored_filename_patterns: Optional[Set[str]] = None, + ) -> Iterable[Tuple[Path, str]]: + ignored_directories = ignored_directories if ignored_directories is not None else set() + ignored_filename_patterns = ignored_filename_patterns if ignored_filename_patterns is not None else set() + + for path in directory.rglob("*"): + ignore_directory = any([ignored_directory in path.parts for ignored_directory in ignored_directories]) + ignore_filename = any([path.match(ignored_filename_pattern) for ignored_filename_pattern in ignored_filename_patterns]) + ignore = ignore_directory or ignore_filename + if path.is_file() and not ignore: + try: + for line in open(path, "r"): + yield path, line + except UnicodeDecodeError: + continue + + @staticmethod + def _line_is_comment(line: str, file_path: Path) -> bool: + language_comments = { + ".py": "#", + ".yml": "#", + ".yaml": "#", + ".java": "//", + ".md": " **For Airbyte Cloud:** @@ -164,71 +166,72 @@ Information about rate limits you may find [here](https://developer-docs.amazon. ## Changelog -| Version | Date | Pull Request | Subject | -|:---------|:-----------|:------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `3.4.0` | 2024-02-15 | [\#35273](https://github.com/airbytehq/airbyte/pull/35273) | Add `VendorOrders` stream | -| `3.3.2` | 2024-02-13 | [\#33996](https://github.com/airbytehq/airbyte/pull/33996) | Add integration tests | -| `3.3.1` | 2024-02-09 | [\#35106](https://github.com/airbytehq/airbyte/pull/35106) | Add logs for the failed check command | -| `3.3.0` | 2024-02-09 | [\#35062](https://github.com/airbytehq/airbyte/pull/35062) | Fix the check command for the `Vendor` account type | -| `3.2.2` | 2024-02-07 | [\#34914](https://github.com/airbytehq/airbyte/pull/34914) | Fix date formatting for ledger reports with aggregation by month | -| `3.2.1` | 2024-01-30 | [\#34654](https://github.com/airbytehq/airbyte/pull/34654) | Fix date format in state message for streams with custom dates formatting | -| `3.2.0` | 2024-01-26 | [\#34549](https://github.com/airbytehq/airbyte/pull/34549) | Update schemas for vendor analytics streams | -| `3.1.0` | 2024-01-17 | [\#34283](https://github.com/airbytehq/airbyte/pull/34283) | Delete deprecated streams | -| `3.0.1` | 2023-12-22 | [\#33741](https://github.com/airbytehq/airbyte/pull/33741) | Improve report streams performance | -| `3.0.0` | 2023-12-12 | [\#32977](https://github.com/airbytehq/airbyte/pull/32977) | Make all streams incremental | -| `2.5.0` | 2023-11-27 | [\#32505](https://github.com/airbytehq/airbyte/pull/32505) | Make report options configurable via UI | -| `2.4.0` | 2023-11-23 | [\#32738](https://github.com/airbytehq/airbyte/pull/32738) | Add `GET_VENDOR_NET_PURE_PRODUCT_MARGIN_REPORT`, `GET_VENDOR_REAL_TIME_INVENTORY_REPORT`, and `GET_VENDOR_TRAFFIC_REPORT` streams | -| `2.3.0` | 2023-11-22 | [\#32541](https://github.com/airbytehq/airbyte/pull/32541) | Make `GET_AFN_INVENTORY_DATA`, `GET_AFN_INVENTORY_DATA_BY_COUNTRY`, and `GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE` streams incremental | -| `2.2.0` | 2023-11-21 | [\#32639](https://github.com/airbytehq/airbyte/pull/32639) | Make start date optional, if start date is not provided, date 2 years ago from today will be used | -| `2.1.1` | 2023-11-21 | [\#32560](https://github.com/airbytehq/airbyte/pull/32560) | Silently exit sync if the retry attempts were unsuccessful | -| `2.1.0` | 2023-11-21 | [\#32591](https://github.com/airbytehq/airbyte/pull/32591) | Add new fields to GET_LEDGER_DETAIL_VIEW_DATA, GET_FBA_INVENTORY_PLANNING_DATA and Orders schemas | -| `2.0.2` | 2023-11-17 | [\#32462](https://github.com/airbytehq/airbyte/pull/32462) | Remove Max time option from specification; set default waiting time for reports to 1 hour | -| `2.0.1` | 2023-11-16 | [\#32550](https://github.com/airbytehq/airbyte/pull/32550) | Fix the OAuth flow | -| `2.0.0` | 2023-11-23 | [\#32355](https://github.com/airbytehq/airbyte/pull/32355) | Remove Brand Analytics from Airbyte Cloud, permanently remove deprecated FBA reports | -| `1.6.2` | 2023-11-14 | [\#32508](https://github.com/airbytehq/airbyte/pull/32508) | Do not use AWS signature as it is no longer required by the Amazon API | -| `1.6.1` | 2023-11-13 | [\#32457](https://github.com/airbytehq/airbyte/pull/32457) | Fix report decompression | -| `1.6.0` | 2023-11-09 | [\#32259](https://github.com/airbytehq/airbyte/pull/32259) | mark "aws_secret_key" and "aws_access_key" as required in specification; update schema for stream `Orders` | -| `1.5.1` | 2023-08-18 | [\#29255](https://github.com/airbytehq/airbyte/pull/29255) | role_arn is optional on UI but not really on the backend blocking connector set up using oauth | -| `1.5.0` | 2023-08-08 | [\#29054](https://github.com/airbytehq/airbyte/pull/29054) | Add new stream `OrderItems` | -| `1.4.1` | 2023-07-25 | [\#27050](https://github.com/airbytehq/airbyte/pull/27050) | Fix - non vendor accounts connector create/check issue | -| `1.4.0` | 2023-07-21 | [\#27110](https://github.com/airbytehq/airbyte/pull/27110) | Add `GET_FLAT_FILE_ACTIONABLE_ORDER_DATA_SHIPPING` and `GET_ORDER_REPORT_DATA_SHIPPING` streams | -| `1.3.0` | 2023-06-09 | [\#27110](https://github.com/airbytehq/airbyte/pull/27110) | Removed `app_id` from `InputConfiguration`, refactored `spec` | -| `1.2.0` | 2023-05-23 | [\#22503](https://github.com/airbytehq/airbyte/pull/22503) | Enabled stream attribute customization from Source configuration | -| `1.1.0` | 2023-04-21 | [\#23605](https://github.com/airbytehq/airbyte/pull/23605) | Add FBA Reimbursement Report stream | -| `1.0.1` | 2023-03-15 | [\#24098](https://github.com/airbytehq/airbyte/pull/24098) | Add Belgium Marketplace | -| `1.0.0` | 2023-03-13 | [\#23980](https://github.com/airbytehq/airbyte/pull/23980) | Make `app_id` required. Increase `end_date` gap up to 5 minutes from now for Finance streams. Fix connection check failure when trying to connect to Amazon Vendor Central accounts | -| `0.2.33` | 2023-03-01 | [\#23606](https://github.com/airbytehq/airbyte/pull/23606) | Implement reportOptions for all missing reports and refactor | -| `0.2.32` | 2022-02-21 | [\#23300](https://github.com/airbytehq/airbyte/pull/23300) | Make AWS Access Key, AWS Secret Access and Role ARN optional | -| `0.2.31` | 2022-01-10 | [\#16430](https://github.com/airbytehq/airbyte/pull/16430) | Implement slicing for report streams | -| `0.2.30` | 2022-12-28 | [\#20896](https://github.com/airbytehq/airbyte/pull/20896) | Validate connections without orders data | -| `0.2.29` | 2022-11-18 | [\#19581](https://github.com/airbytehq/airbyte/pull/19581) | Use user provided end date for GET_SALES_AND_TRAFFIC_REPORT | -| `0.2.28` | 2022-10-20 | [\#18283](https://github.com/airbytehq/airbyte/pull/18283) | Added multiple (22) report types | -| `0.2.26` | 2022-09-24 | [\#16629](https://github.com/airbytehq/airbyte/pull/16629) | Report API version to 2021-06-30, added multiple (5) report types | -| `0.2.25` | 2022-07-27 | [\#15063](https://github.com/airbytehq/airbyte/pull/15063) | Add Restock Inventory Report | -| `0.2.24` | 2022-07-12 | [\#14625](https://github.com/airbytehq/airbyte/pull/14625) | Add FBA Storage Fees Report | -| `0.2.23` | 2022-06-08 | [\#13604](https://github.com/airbytehq/airbyte/pull/13604) | Add new streams: Fullfiments returns and Settlement reports | -| `0.2.22` | 2022-06-15 | [\#13633](https://github.com/airbytehq/airbyte/pull/13633) | Fix - handle start date for financial stream | -| `0.2.21` | 2022-06-01 | [\#13364](https://github.com/airbytehq/airbyte/pull/13364) | Add financial streams | -| `0.2.20` | 2022-05-30 | [\#13059](https://github.com/airbytehq/airbyte/pull/13059) | Add replication end date to config | -| `0.2.19` | 2022-05-24 | [\#13119](https://github.com/airbytehq/airbyte/pull/13119) | Add OAuth2.0 support | -| `0.2.18` | 2022-05-06 | [\#12663](https://github.com/airbytehq/airbyte/pull/12663) | Add GET_XML_BROWSE_TREE_DATA report | -| `0.2.17` | 2022-05-19 | [\#12946](https://github.com/airbytehq/airbyte/pull/12946) | Add throttling exception managing in Orders streams | -| `0.2.16` | 2022-05-04 | [\#12523](https://github.com/airbytehq/airbyte/pull/12523) | allow to use IAM user arn or IAM role | -| `0.2.15` | 2022-01-25 | [\#9789](https://github.com/airbytehq/airbyte/pull/9789) | Add stream FbaReplacementsReports | -| `0.2.14` | 2022-01-19 | [\#9621](https://github.com/airbytehq/airbyte/pull/9621) | Add GET_FLAT_FILE_ALL_ORDERS_DATA_BY_LAST_UPDATE_GENERAL report | -| `0.2.13` | 2022-01-18 | [\#9581](https://github.com/airbytehq/airbyte/pull/9581) | Change createdSince parameter to dataStartTime | -| `0.2.12` | 2022-01-05 | [\#9312](https://github.com/airbytehq/airbyte/pull/9312) | Add all remaining brand analytics report streams | -| `0.2.11` | 2022-01-05 | [\#9115](https://github.com/airbytehq/airbyte/pull/9115) | Fix reading only 100 orders | -| `0.2.10` | 2021-12-31 | [\#9236](https://github.com/airbytehq/airbyte/pull/9236) | Fix NoAuth deprecation warning | -| `0.2.9` | 2021-12-30 | [\#9212](https://github.com/airbytehq/airbyte/pull/9212) | Normalize GET_SELLER_FEEDBACK_DATA header field names | -| `0.2.8` | 2021-12-22 | [\#8810](https://github.com/airbytehq/airbyte/pull/8810) | Fix GET_SELLER_FEEDBACK_DATA Date cursor field format | -| `0.2.7` | 2021-12-21 | [\#9002](https://github.com/airbytehq/airbyte/pull/9002) | Extract REPORTS_MAX_WAIT_SECONDS to configurable parameter | -| `0.2.6` | 2021-12-10 | [\#8179](https://github.com/airbytehq/airbyte/pull/8179) | Add GET_BRAND_ANALYTICS_SEARCH_TERMS_REPORT report | -| `0.2.5` | 2021-12-06 | [\#8425](https://github.com/airbytehq/airbyte/pull/8425) | Update title, description fields in spec | -| `0.2.4` | 2021-11-08 | [\#8021](https://github.com/airbytehq/airbyte/pull/8021) | Added GET_SELLER_FEEDBACK_DATA report with incremental sync capability | -| `0.2.3` | 2021-11-08 | [\#7828](https://github.com/airbytehq/airbyte/pull/7828) | Remove datetime format from all streams | -| `0.2.2` | 2021-11-08 | [\#7752](https://github.com/airbytehq/airbyte/pull/7752) | Change `check_connection` function to use stream Orders | -| `0.2.1` | 2021-09-17 | [\#5248](https://github.com/airbytehq/airbyte/pull/5248) | Added `extra stream` support. Updated `reports streams` logics | -| `0.2.0` | 2021-08-06 | [\#4863](https://github.com/airbytehq/airbyte/pull/4863) | Rebuild source with `airbyte-cdk` | -| `0.1.3` | 2021-06-23 | [\#4288](https://github.com/airbytehq/airbyte/pull/4288) | Bugfix failing `connection check` | -| `0.1.2` | 2021-06-15 | [\#4108](https://github.com/airbytehq/airbyte/pull/4108) | Fixed: Sync fails with timeout when create report is CANCELLED` | +| Version | Date | Pull Request | Subject | +|:---------|:-----------|:------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `3.5.0` | 2024-02-09 | [\#35331](https://github.com/airbytehq/airbyte/pull/35331) | Fix check for Vendor accounts. Add failed report result message | +| `3.4.0` | 2024-02-15 | [\#35273](https://github.com/airbytehq/airbyte/pull/35273) | Add `VendorOrders` stream | +| `3.3.2` | 2024-02-13 | [\#33996](https://github.com/airbytehq/airbyte/pull/33996) | Add integration tests | +| `3.3.1` | 2024-02-09 | [\#35106](https://github.com/airbytehq/airbyte/pull/35106) | Add logs for the failed check command | +| `3.3.0` | 2024-02-09 | [\#35062](https://github.com/airbytehq/airbyte/pull/35062) | Fix the check command for the `Vendor` account type | +| `3.2.2` | 2024-02-07 | [\#34914](https://github.com/airbytehq/airbyte/pull/34914) | Fix date formatting for ledger reports with aggregation by month | +| `3.2.1` | 2024-01-30 | [\#34654](https://github.com/airbytehq/airbyte/pull/34654) | Fix date format in state message for streams with custom dates formatting | +| `3.2.0` | 2024-01-26 | [\#34549](https://github.com/airbytehq/airbyte/pull/34549) | Update schemas for vendor analytics streams | +| `3.1.0` | 2024-01-17 | [\#34283](https://github.com/airbytehq/airbyte/pull/34283) | Delete deprecated streams | +| `3.0.1` | 2023-12-22 | [\#33741](https://github.com/airbytehq/airbyte/pull/33741) | Improve report streams performance | +| `3.0.0` | 2023-12-12 | [\#32977](https://github.com/airbytehq/airbyte/pull/32977) | Make all streams incremental | +| `2.5.0` | 2023-11-27 | [\#32505](https://github.com/airbytehq/airbyte/pull/32505) | Make report options configurable via UI | +| `2.4.0` | 2023-11-23 | [\#32738](https://github.com/airbytehq/airbyte/pull/32738) | Add `GET_VENDOR_NET_PURE_PRODUCT_MARGIN_REPORT`, `GET_VENDOR_REAL_TIME_INVENTORY_REPORT`, and `GET_VENDOR_TRAFFIC_REPORT` streams | +| `2.3.0` | 2023-11-22 | [\#32541](https://github.com/airbytehq/airbyte/pull/32541) | Make `GET_AFN_INVENTORY_DATA`, `GET_AFN_INVENTORY_DATA_BY_COUNTRY`, and `GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE` streams incremental | +| `2.2.0` | 2023-11-21 | [\#32639](https://github.com/airbytehq/airbyte/pull/32639) | Make start date optional, if start date is not provided, date 2 years ago from today will be used | +| `2.1.1` | 2023-11-21 | [\#32560](https://github.com/airbytehq/airbyte/pull/32560) | Silently exit sync if the retry attempts were unsuccessful | +| `2.1.0` | 2023-11-21 | [\#32591](https://github.com/airbytehq/airbyte/pull/32591) | Add new fields to GET_LEDGER_DETAIL_VIEW_DATA, GET_FBA_INVENTORY_PLANNING_DATA and Orders schemas | +| `2.0.2` | 2023-11-17 | [\#32462](https://github.com/airbytehq/airbyte/pull/32462) | Remove Max time option from specification; set default waiting time for reports to 1 hour | +| `2.0.1` | 2023-11-16 | [\#32550](https://github.com/airbytehq/airbyte/pull/32550) | Fix the OAuth flow | +| `2.0.0` | 2023-11-23 | [\#32355](https://github.com/airbytehq/airbyte/pull/32355) | Remove Brand Analytics from Airbyte Cloud, permanently remove deprecated FBA reports | +| `1.6.2` | 2023-11-14 | [\#32508](https://github.com/airbytehq/airbyte/pull/32508) | Do not use AWS signature as it is no longer required by the Amazon API | +| `1.6.1` | 2023-11-13 | [\#32457](https://github.com/airbytehq/airbyte/pull/32457) | Fix report decompression | +| `1.6.0` | 2023-11-09 | [\#32259](https://github.com/airbytehq/airbyte/pull/32259) | mark "aws_secret_key" and "aws_access_key" as required in specification; update schema for stream `Orders` | +| `1.5.1` | 2023-08-18 | [\#29255](https://github.com/airbytehq/airbyte/pull/29255) | role_arn is optional on UI but not really on the backend blocking connector set up using oauth | +| `1.5.0` | 2023-08-08 | [\#29054](https://github.com/airbytehq/airbyte/pull/29054) | Add new stream `OrderItems` | +| `1.4.1` | 2023-07-25 | [\#27050](https://github.com/airbytehq/airbyte/pull/27050) | Fix - non vendor accounts connector create/check issue | +| `1.4.0` | 2023-07-21 | [\#27110](https://github.com/airbytehq/airbyte/pull/27110) | Add `GET_FLAT_FILE_ACTIONABLE_ORDER_DATA_SHIPPING` and `GET_ORDER_REPORT_DATA_SHIPPING` streams | +| `1.3.0` | 2023-06-09 | [\#27110](https://github.com/airbytehq/airbyte/pull/27110) | Removed `app_id` from `InputConfiguration`, refactored `spec` | +| `1.2.0` | 2023-05-23 | [\#22503](https://github.com/airbytehq/airbyte/pull/22503) | Enabled stream attribute customization from Source configuration | +| `1.1.0` | 2023-04-21 | [\#23605](https://github.com/airbytehq/airbyte/pull/23605) | Add FBA Reimbursement Report stream | +| `1.0.1` | 2023-03-15 | [\#24098](https://github.com/airbytehq/airbyte/pull/24098) | Add Belgium Marketplace | +| `1.0.0` | 2023-03-13 | [\#23980](https://github.com/airbytehq/airbyte/pull/23980) | Make `app_id` required. Increase `end_date` gap up to 5 minutes from now for Finance streams. Fix connection check failure when trying to connect to Amazon Vendor Central accounts | +| `0.2.33` | 2023-03-01 | [\#23606](https://github.com/airbytehq/airbyte/pull/23606) | Implement reportOptions for all missing reports and refactor | +| `0.2.32` | 2022-02-21 | [\#23300](https://github.com/airbytehq/airbyte/pull/23300) | Make AWS Access Key, AWS Secret Access and Role ARN optional | +| `0.2.31` | 2022-01-10 | [\#16430](https://github.com/airbytehq/airbyte/pull/16430) | Implement slicing for report streams | +| `0.2.30` | 2022-12-28 | [\#20896](https://github.com/airbytehq/airbyte/pull/20896) | Validate connections without orders data | +| `0.2.29` | 2022-11-18 | [\#19581](https://github.com/airbytehq/airbyte/pull/19581) | Use user provided end date for GET_SALES_AND_TRAFFIC_REPORT | +| `0.2.28` | 2022-10-20 | [\#18283](https://github.com/airbytehq/airbyte/pull/18283) | Added multiple (22) report types | +| `0.2.26` | 2022-09-24 | [\#16629](https://github.com/airbytehq/airbyte/pull/16629) | Report API version to 2021-06-30, added multiple (5) report types | +| `0.2.25` | 2022-07-27 | [\#15063](https://github.com/airbytehq/airbyte/pull/15063) | Add Restock Inventory Report | +| `0.2.24` | 2022-07-12 | [\#14625](https://github.com/airbytehq/airbyte/pull/14625) | Add FBA Storage Fees Report | +| `0.2.23` | 2022-06-08 | [\#13604](https://github.com/airbytehq/airbyte/pull/13604) | Add new streams: Fullfiments returns and Settlement reports | +| `0.2.22` | 2022-06-15 | [\#13633](https://github.com/airbytehq/airbyte/pull/13633) | Fix - handle start date for financial stream | +| `0.2.21` | 2022-06-01 | [\#13364](https://github.com/airbytehq/airbyte/pull/13364) | Add financial streams | +| `0.2.20` | 2022-05-30 | [\#13059](https://github.com/airbytehq/airbyte/pull/13059) | Add replication end date to config | +| `0.2.19` | 2022-05-24 | [\#13119](https://github.com/airbytehq/airbyte/pull/13119) | Add OAuth2.0 support | +| `0.2.18` | 2022-05-06 | [\#12663](https://github.com/airbytehq/airbyte/pull/12663) | Add GET_XML_BROWSE_TREE_DATA report | +| `0.2.17` | 2022-05-19 | [\#12946](https://github.com/airbytehq/airbyte/pull/12946) | Add throttling exception managing in Orders streams | +| `0.2.16` | 2022-05-04 | [\#12523](https://github.com/airbytehq/airbyte/pull/12523) | allow to use IAM user arn or IAM role | +| `0.2.15` | 2022-01-25 | [\#9789](https://github.com/airbytehq/airbyte/pull/9789) | Add stream FbaReplacementsReports | +| `0.2.14` | 2022-01-19 | [\#9621](https://github.com/airbytehq/airbyte/pull/9621) | Add GET_FLAT_FILE_ALL_ORDERS_DATA_BY_LAST_UPDATE_GENERAL report | +| `0.2.13` | 2022-01-18 | [\#9581](https://github.com/airbytehq/airbyte/pull/9581) | Change createdSince parameter to dataStartTime | +| `0.2.12` | 2022-01-05 | [\#9312](https://github.com/airbytehq/airbyte/pull/9312) | Add all remaining brand analytics report streams | +| `0.2.11` | 2022-01-05 | [\#9115](https://github.com/airbytehq/airbyte/pull/9115) | Fix reading only 100 orders | +| `0.2.10` | 2021-12-31 | [\#9236](https://github.com/airbytehq/airbyte/pull/9236) | Fix NoAuth deprecation warning | +| `0.2.9` | 2021-12-30 | [\#9212](https://github.com/airbytehq/airbyte/pull/9212) | Normalize GET_SELLER_FEEDBACK_DATA header field names | +| `0.2.8` | 2021-12-22 | [\#8810](https://github.com/airbytehq/airbyte/pull/8810) | Fix GET_SELLER_FEEDBACK_DATA Date cursor field format | +| `0.2.7` | 2021-12-21 | [\#9002](https://github.com/airbytehq/airbyte/pull/9002) | Extract REPORTS_MAX_WAIT_SECONDS to configurable parameter | +| `0.2.6` | 2021-12-10 | [\#8179](https://github.com/airbytehq/airbyte/pull/8179) | Add GET_BRAND_ANALYTICS_SEARCH_TERMS_REPORT report | +| `0.2.5` | 2021-12-06 | [\#8425](https://github.com/airbytehq/airbyte/pull/8425) | Update title, description fields in spec | +| `0.2.4` | 2021-11-08 | [\#8021](https://github.com/airbytehq/airbyte/pull/8021) | Added GET_SELLER_FEEDBACK_DATA report with incremental sync capability | +| `0.2.3` | 2021-11-08 | [\#7828](https://github.com/airbytehq/airbyte/pull/7828) | Remove datetime format from all streams | +| `0.2.2` | 2021-11-08 | [\#7752](https://github.com/airbytehq/airbyte/pull/7752) | Change `check_connection` function to use stream Orders | +| `0.2.1` | 2021-09-17 | [\#5248](https://github.com/airbytehq/airbyte/pull/5248) | Added `extra stream` support. Updated `reports streams` logics | +| `0.2.0` | 2021-08-06 | [\#4863](https://github.com/airbytehq/airbyte/pull/4863) | Rebuild source with `airbyte-cdk` | +| `0.1.3` | 2021-06-23 | [\#4288](https://github.com/airbytehq/airbyte/pull/4288) | Bugfix failing `connection check` | +| `0.1.2` | 2021-06-15 | [\#4108](https://github.com/airbytehq/airbyte/pull/4108) | Fixed: Sync fails with timeout when create report is CANCELLED` | From 87d792e980f3a7129a36544269d5b2ee6ce966ba Mon Sep 17 00:00:00 2001 From: Augustin Date: Mon, 19 Feb 2024 18:06:37 +0100 Subject: [PATCH 29/43] doc: Document our connectors QA checks (#35324) --- airbyte-ci/connectors/connectors_qa/README.md | 6 +- .../connectors/connectors_qa/poetry.lock | 128 ++++++++++-------- .../connectors/connectors_qa/pyproject.toml | 2 + .../src/connectors_qa/checks/assets.py | 3 +- .../src/connectors_qa/checks/documentation.py | 2 +- .../src/connectors_qa/checks/packaging.py | 2 +- .../connectors_qa/templates/qa_checks.md.j2 | 2 +- .../tests/integration_tests/__init__.py | 0 .../integration_tests/test_documentation.py | 28 ++++ .../change-cdk-connector.md | 4 +- .../resources/qa-checks.md | 81 +++++++++++ .../submit-new-connector.md | 1 + docusaurus/sidebars.js | 1 + 13 files changed, 198 insertions(+), 62 deletions(-) create mode 100644 airbyte-ci/connectors/connectors_qa/tests/integration_tests/__init__.py create mode 100644 airbyte-ci/connectors/connectors_qa/tests/integration_tests/test_documentation.py create mode 100644 docs/contributing-to-airbyte/resources/qa-checks.md diff --git a/airbyte-ci/connectors/connectors_qa/README.md b/airbyte-ci/connectors/connectors_qa/README.md index a646fb8dcc85..2e570d96dd98 100644 --- a/airbyte-ci/connectors/connectors_qa/README.md +++ b/airbyte-ci/connectors/connectors_qa/README.md @@ -75,7 +75,11 @@ This package uses two local dependencies: To add a new QA check, you have to create add new class in one of the `checks` module. This class must inherit from `models.Check` and implement the `_run` method. Then, you need to add an instance of this class to the `ENABLED_CHECKS` list of the module. -**Please run the `generate-doumentation` command to update the documentation with the new check and commit it in your PR.** +**Please run the `generate-documentation` command to update the documentation with the new check and commit it in your PR.**: +```bash +# From airbyte repo root +connectors-qa generate-documentation docs/contributing-to-airbyte/resources/qa-checks.md +``` ### Running tests diff --git a/airbyte-ci/connectors/connectors_qa/poetry.lock b/airbyte-ci/connectors/connectors_qa/poetry.lock index 8b772f849f2e..1d13efbb0bae 100644 --- a/airbyte-ci/connectors/connectors_qa/poetry.lock +++ b/airbyte-ci/connectors/connectors_qa/poetry.lock @@ -35,13 +35,13 @@ files = [ [[package]] name = "anyio" -version = "4.2.0" +version = "4.3.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, - {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, + {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, + {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, ] [package.dependencies] @@ -443,7 +443,7 @@ url = "../common_utils" [[package]] name = "connector-ops" -version = "0.4.0" +version = "0.3.3" description = "Packaged maintained by the connector operations team to perform CI for connectors" optional = false python-versions = "^3.10" @@ -659,20 +659,20 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.41" +version = "3.1.42" description = "GitPython is a Python library used to interact with Git repositories" optional = false python-versions = ">=3.7" files = [ - {file = "GitPython-3.1.41-py3-none-any.whl", hash = "sha256:c36b6634d069b3f719610175020a9aed919421c87552185b085e04fbbdb10b7c"}, - {file = "GitPython-3.1.41.tar.gz", hash = "sha256:ed66e624884f76df22c8e16066d567aaa5a37d5b5fa19db2c6df6f7156db9048"}, + {file = "GitPython-3.1.42-py3-none-any.whl", hash = "sha256:1bf9cd7c9e7255f77778ea54359e54ac22a72a5b51288c457c881057b7bb9ecd"}, + {file = "GitPython-3.1.42.tar.gz", hash = "sha256:2d99869e0fef71a73cbd242528105af1d6c1b108c60dfabd994bf292f76c3ceb"}, ] [package.dependencies] gitdb = ">=4.0.1,<5" [package.extras] -test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "sumtypes"] +test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar"] [[package]] name = "google" @@ -690,13 +690,13 @@ beautifulsoup4 = "*" [[package]] name = "google-api-core" -version = "2.17.0" +version = "2.17.1" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.17.0.tar.gz", hash = "sha256:de7ef0450faec7c75e0aea313f29ac870fdc44cfaec9d6499a9a17305980ef66"}, - {file = "google_api_core-2.17.0-py3-none-any.whl", hash = "sha256:08ed79ed8e93e329de5e3e7452746b734e6bf8438d8d64dd3319d21d3164890c"}, + {file = "google-api-core-2.17.1.tar.gz", hash = "sha256:9df18a1f87ee0df0bc4eea2770ebc4228392d8cc4066655b320e2cfccb15db95"}, + {file = "google_api_core-2.17.1-py3-none-any.whl", hash = "sha256:610c5b90092c360736baccf17bd3efbcb30dd380e7a6dc28a71059edb8bd0d8e"}, ] [package.dependencies] @@ -712,13 +712,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.27.0" +version = "2.28.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.27.0.tar.gz", hash = "sha256:e863a56ccc2d8efa83df7a80272601e43487fa9a728a376205c86c26aaefa821"}, - {file = "google_auth-2.27.0-py2.py3-none-any.whl", hash = "sha256:8e4bad367015430ff253fe49d500fdc3396c1a434db5740828c728e45bcce245"}, + {file = "google-auth-2.28.0.tar.gz", hash = "sha256:3cfc1b6e4e64797584fb53fc9bd0b7afa9b7c0dba2004fa7dcc9349e58cc3195"}, + {file = "google_auth-2.28.0-py2.py3-none-any.whl", hash = "sha256:7634d29dcd1e101f5226a23cbc4a0c6cda6394253bf80e281d9c5c6797869c53"}, ] [package.dependencies] @@ -1053,13 +1053,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.2" +version = "1.0.3" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, - {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, + {file = "httpcore-1.0.3-py3-none-any.whl", hash = "sha256:9a6a501c3099307d9fd76ac244e08503427679b1e81ceb1d922485e2f2462ad2"}, + {file = "httpcore-1.0.3.tar.gz", hash = "sha256:5c0f9546ad17dac4d0772b0808856eb616eb8b48ce94f49ed819fd6982a8a544"}, ] [package.dependencies] @@ -1070,7 +1070,7 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.23.0)"] +trio = ["trio (>=0.22.0,<0.24.0)"] [[package]] name = "httplib2" @@ -1651,22 +1651,22 @@ files = [ [[package]] name = "protobuf" -version = "4.25.2" +version = "4.25.3" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"}, - {file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"}, - {file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"}, - {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"}, - {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"}, - {file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"}, - {file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"}, - {file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"}, - {file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"}, - {file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"}, - {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, + {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, + {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, + {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, + {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, + {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, + {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, + {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, + {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, + {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, + {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, ] [[package]] @@ -1865,13 +1865,13 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "8.0.0" +version = "8.0.1" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.0.0-py3-none-any.whl", hash = "sha256:50fb9cbe836c3f20f0dfa99c565201fb75dc54c8d76373cd1bde06b06657bdb6"}, - {file = "pytest-8.0.0.tar.gz", hash = "sha256:249b1b0864530ba251b7438274c4d251c58d868edaaec8762893ad4a0d71c36c"}, + {file = "pytest-8.0.1-py3-none-any.whl", hash = "sha256:3e4f16fe1c0a9dc9d9389161c127c3edc5d810c38d6793042fb81d9f48a59fca"}, + {file = "pytest-8.0.1.tar.gz", hash = "sha256:267f6563751877d772019b13aacbe4e860d73fe8f651f28112e9ac37de7513ae"}, ] [package.dependencies] @@ -1885,6 +1885,24 @@ tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-asyncio" +version = "0.23.5" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-asyncio-0.23.5.tar.gz", hash = "sha256:3a048872a9c4ba14c3e90cc1aa20cbc2def7d01c7c8db3777ec281ba9c057675"}, + {file = "pytest_asyncio-0.23.5-py3-none-any.whl", hash = "sha256:4e7093259ba018d58ede7d5315131d21923a60f8a6e9ee266ce1589685c89eac"}, +] + +[package.dependencies] +pytest = ">=7.0.0,<9" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] + [[package]] name = "pytest-mock" version = "3.12.0" @@ -2055,28 +2073,28 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.2.1" +version = "0.2.2" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.2.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:dd81b911d28925e7e8b323e8d06951554655021df8dd4ac3045d7212ac4ba080"}, - {file = "ruff-0.2.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dc586724a95b7d980aa17f671e173df00f0a2eef23f8babbeee663229a938fec"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c92db7101ef5bfc18e96777ed7bc7c822d545fa5977e90a585accac43d22f18a"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:13471684694d41ae0f1e8e3a7497e14cd57ccb7dd72ae08d56a159d6c9c3e30e"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a11567e20ea39d1f51aebd778685582d4c56ccb082c1161ffc10f79bebe6df35"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:00a818e2db63659570403e44383ab03c529c2b9678ba4ba6c105af7854008105"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be60592f9d218b52f03384d1325efa9d3b41e4c4d55ea022cd548547cc42cd2b"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbd2288890b88e8aab4499e55148805b58ec711053588cc2f0196a44f6e3d855"}, - {file = "ruff-0.2.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ef052283da7dec1987bba8d8733051c2325654641dfe5877a4022108098683"}, - {file = "ruff-0.2.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7022d66366d6fded4ba3889f73cd791c2d5621b2ccf34befc752cb0df70f5fad"}, - {file = "ruff-0.2.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0a725823cb2a3f08ee743a534cb6935727d9e47409e4ad72c10a3faf042ad5ba"}, - {file = "ruff-0.2.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0034d5b6323e6e8fe91b2a1e55b02d92d0b582d2953a2b37a67a2d7dedbb7acc"}, - {file = "ruff-0.2.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e5cb5526d69bb9143c2e4d2a115d08ffca3d8e0fddc84925a7b54931c96f5c02"}, - {file = "ruff-0.2.1-py3-none-win32.whl", hash = "sha256:6b95ac9ce49b4fb390634d46d6ece32ace3acdd52814671ccaf20b7f60adb232"}, - {file = "ruff-0.2.1-py3-none-win_amd64.whl", hash = "sha256:e3affdcbc2afb6f5bd0eb3130139ceedc5e3f28d206fe49f63073cb9e65988e0"}, - {file = "ruff-0.2.1-py3-none-win_arm64.whl", hash = "sha256:efababa8e12330aa94a53e90a81eb6e2d55f348bc2e71adbf17d9cad23c03ee6"}, - {file = "ruff-0.2.1.tar.gz", hash = "sha256:3b42b5d8677cd0c72b99fcaf068ffc62abb5a19e71b4a3b9cfa50658a0af02f1"}, + {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"}, + {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"}, + {file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"}, + {file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"}, + {file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"}, + {file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"}, ] [[package]] @@ -2232,13 +2250,13 @@ files = [ [[package]] name = "urllib3" -version = "2.2.0" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, - {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] [package.extras] @@ -2454,4 +2472,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "5390813cbcb5f02e211eeb58bf6c50c4521ea183fe0e3015328c337a464b962f" +content-hash = "cc999d31f1c5111833dc2d09a6c66a25e50b3179193d011ff3141e992f4846d8" diff --git a/airbyte-ci/connectors/connectors_qa/pyproject.toml b/airbyte-ci/connectors/connectors_qa/pyproject.toml index dbc255530e80..0b418a689705 100644 --- a/airbyte-ci/connectors/connectors_qa/pyproject.toml +++ b/airbyte-ci/connectors/connectors_qa/pyproject.toml @@ -27,6 +27,8 @@ pytest = "^8.0.0" pytest-mock = "^3.12.0" mypy = "^1.8.0" types-toml = "^0.10.8.7" +pytest-asyncio = "^0.23.5" +gitpython = "^3.1.42" [build-system] requires = ["poetry-core"] diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/assets.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/assets.py index e4083a5ea4e8..643f3728a57e 100644 --- a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/assets.py +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/assets.py @@ -11,7 +11,7 @@ class AssetsCheck(Check): class CheckConnectorIconIsAvailable(AssetsCheck): name = "Connectors must have an icon" - description = "Each connector must have an icon available in at the root of the connector code directory. It must be an SVG file named `icon.svg`." + description = "Each connector must have an icon available in at the root of the connector code directory. It must be an SVG file named `icon.svg` and must be a square." requires_metadata = False def _run(self, connector: Connector) -> CheckResult: @@ -27,6 +27,7 @@ def _run(self, connector: Connector) -> CheckResult: passed=False, message="Icon file is not named 'icon.svg'", ) + # TODO check that the icon is a square return self.create_check_result(connector=connector, passed=True, message="Icon file exists") diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/documentation.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/documentation.py index 7cf09b80c4dc..bdd4b6eaaca2 100644 --- a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/documentation.py +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/documentation.py @@ -15,7 +15,7 @@ class DocumentationCheck(Check): class CheckMigrationGuide(DocumentationCheck): name = "Breaking changes must be accompanied by a migration guide" - description = "When a breaking change is introduced we check that a migration guide is available. It should be stored under `./docs/integrations/s/-migrations.md`.\nThis document should contain a section for each breaking change, in order of the version descending. It must explain users which action to take to migrate to the new version." + description = "When a breaking change is introduced, we check that a migration guide is available. It should be stored under `./docs/integrations/s/-migrations.md`.\nThis document should contain a section for each breaking change, in order of the version descending. It must explain users which action to take to migrate to the new version." def _run(self, connector: Connector) -> CheckResult: breaking_changes = get(connector.metadata, "releases.breakingChanges") diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py index 24b125ce9b9e..aa5e50bfefdf 100644 --- a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py @@ -86,7 +86,7 @@ def _run(self, connector: Connector) -> CheckResult: class CheckConnectorLicenseMatchInPyproject(PackagingCheck): name = f"Connector license in {consts.METADATA_FILE_NAME} and {consts.PYPROJECT_FILE_NAME} file must match" - description = f"Connectors license in {consts.METADATA_FILE_NAME} and {consts.PYPROJECT_FILE_NAME} file must match. This is to ensure that all connectors are consistently licensed" + description = f"Connectors license in {consts.METADATA_FILE_NAME} and {consts.PYPROJECT_FILE_NAME} file must match. This is to ensure that all connectors are consistently licensed." applies_to_connector_languages = [ ConnectorLanguage.PYTHON, ConnectorLanguage.LOW_CODE, diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/templates/qa_checks.md.j2 b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/templates/qa_checks.md.j2 index f3da36148a75..a40d8aa31e6a 100644 --- a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/templates/qa_checks.md.j2 +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/templates/qa_checks.md.j2 @@ -13,5 +13,5 @@ They are by no mean replacing the need for a manual review of the connector code *Applies to the following connector languages: {{ ', '.join(check.applies_to_connector_languages) }}* {{ check.description }} -{% endfor %} {%- endfor %} +{% endfor %} diff --git a/airbyte-ci/connectors/connectors_qa/tests/integration_tests/__init__.py b/airbyte-ci/connectors/connectors_qa/tests/integration_tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/airbyte-ci/connectors/connectors_qa/tests/integration_tests/test_documentation.py b/airbyte-ci/connectors/connectors_qa/tests/integration_tests/test_documentation.py new file mode 100644 index 000000000000..afe74946cb10 --- /dev/null +++ b/airbyte-ci/connectors/connectors_qa/tests/integration_tests/test_documentation.py @@ -0,0 +1,28 @@ +# Copyright (c) 2023 Airbyte, Inc., all rights reserved. + + +from pathlib import Path + +import git +import pytest +from asyncclick.testing import CliRunner +from connectors_qa.cli import generate_documentation + +DOCUMENTATION_FILE_PATH_IN_AIRBYTE_REPO = Path("docs/contributing-to-airbyte/resources/qa-checks.md") + +@pytest.fixture +def airbyte_repo(): + return git.Repo(search_parent_directories=True) + +@pytest.mark.asyncio +async def test_generated_qa_checks_documentation_is_up_to_date(airbyte_repo, tmp_path): + # Arrange + current_doc = (airbyte_repo.working_dir / DOCUMENTATION_FILE_PATH_IN_AIRBYTE_REPO).read_text() + newly_generated_doc_path = tmp_path / "qa-checks.md" + + # Act + await CliRunner().invoke(generate_documentation, [str(tmp_path / "qa-checks.md")], catch_exceptions=False) + + # Assert + suggested_command = f"connectors-qa generate-documentation {DOCUMENTATION_FILE_PATH_IN_AIRBYTE_REPO}" + assert newly_generated_doc_path.read_text() == current_doc, f"The generated documentation is not up to date. Please run `{suggested_command}` and commit the changes." diff --git a/docs/contributing-to-airbyte/change-cdk-connector.md b/docs/contributing-to-airbyte/change-cdk-connector.md index ffb3c5151983..81fcd8a291c0 100644 --- a/docs/contributing-to-airbyte/change-cdk-connector.md +++ b/docs/contributing-to-airbyte/change-cdk-connector.md @@ -21,10 +21,10 @@ Make sure you're working on an issue had been already triaged to not have your c 3. Code the change 4. Write a unit test for each custom function you added or changed 5. Ensure all tests, including connector acceptance tests, pass -6. Update the `metadata.yaml` and `Dockerfile` version following the [guidelines](./resources/pull-requests-handbook.md#semantic-versioning-for-connectors) +6. Update the `metadata.yaml` following the [guidelines](./resources/pull-requests-handbook.md#semantic-versioning-for-connectors) 7. Update the changelog entry in documentation in `docs/integrations/.md` +8. Make sure your contribution passes our [QA checks](./resources/qa-checks.md) -A comment will automatically be added to your PR with a checklist containing the necessary steps to complete your contribution and get it merged. :::info There is a README file inside each connector folder containing instructions to run that connector's tests locally. diff --git a/docs/contributing-to-airbyte/resources/qa-checks.md b/docs/contributing-to-airbyte/resources/qa-checks.md new file mode 100644 index 000000000000..5eac5b345d2b --- /dev/null +++ b/docs/contributing-to-airbyte/resources/qa-checks.md @@ -0,0 +1,81 @@ +# Airbyte connectors QA checks + +This document is listing all the static-analysis checks that are performed on the Airbyte connectors. +These checks are running in our CI/CD pipeline and are used to ensure a connector is following the best practices and is respecting the Airbyte standards. +Meeting these standards means that the connector will be able to be safely integrated into the Airbyte platform and released to registries (DockerHub, Pypi etc.). +You can consider these checks as a set of guidelines to follow when developing a connector. +They are by no mean replacing the need for a manual review of the connector codebase and the implementation of good test suites. + + +## 📄 Documentation + +### Breaking changes must be accompanied by a migration guide +*Applies to the following connector languages: java, low-code, python* + +When a breaking change is introduced, we check that a migration guide is available. It should be stored under `./docs/integrations/s/-migrations.md`. +This document should contain a section for each breaking change, in order of the version descending. It must explain users which action to take to migrate to the new version. +### Connectors must have user facing documentation +*Applies to the following connector languages: java, low-code, python* + +The user facing connector documentation should be stored under `./docs/integrations/s/.md`. +### Connectors documentation follows our guidelines +*Applies to the following connector languages: java, low-code, python* + +The user facing connector documentation should follow the guidelines defined in the [documentation standards](https://hackmd.io/Bz75cgATSbm7DjrAqgl4rw). +### Connectors must have a changelog entry for each version +*Applies to the following connector languages: java, low-code, python* + +Each new version of a connector must have a changelog entry defined in the user facing documentation in `./docs/integrations/s/.md`. + +## 📝 Metadata + +### Connectors must have valid metadata.yaml file +*Applies to the following connector languages: java, low-code, python* + +Connectors must have a `metadata.yaml` file at the root of their directory. This file is used to build our connector registry. Its structure must follow our metadata schema. Field values are also validated. This is to ensure that all connectors have the required metadata fields and that the metadata is valid. More details in this [documentation](https://docs.airbyte.com/connector-development/connector-metadata-file). + +## 📦 Packaging + +### Connectors must use Poetry for dependency management +*Applies to the following connector languages: python, low-code* + +Connectors must use [Poetry](https://python-poetry.org/) for dependency management. This is to ensure that all connectors use a dependency management tool which locks dependencies and ensures reproducible installs. +### Connectors must be licensed under MIT or Elv2 +*Applies to the following connector languages: java, low-code, python* + +Connectors must be licensed under the MIT or Elv2 license. This is to ensure that all connectors are licensed under a permissive license. More details in our [License FAQ](https://docs.airbyte.com/developer-guides/licenses/license-faq). +### Connector license in metadata.yaml and pyproject.toml file must match +*Applies to the following connector languages: python, low-code* + +Connectors license in metadata.yaml and pyproject.toml file must match. This is to ensure that all connectors are consistently licensed. +### Connector version must follow Semantic Versioning +*Applies to the following connector languages: java, low-code, python* + +Connector version must follow the Semantic Versioning scheme. This is to ensure that all connectors follow a consistent versioning scheme. Refer to our [Semantic Versioning for Connectors](https://docs.airbyte.com/contributing-to-airbyte/#semantic-versioning-for-connectors) for more details. +### Connector version in metadata.yaml and pyproject.toml file must match +*Applies to the following connector languages: python, low-code* + +Connector version in metadata.yaml and pyproject.toml file must match. This is to ensure that connector release is consistent. +### Python connectors must have PyPi publishing enabled +*Applies to the following connector languages: python, low-code* + +Python connectors must have [PyPi](https://pypi.org/) publishing enabled in their `metadata.yaml` file. This is declared by setting `remoteRegistries.pypi.enabled` to `true` in metadata.yaml. This is to ensure that all connectors can be published to PyPi and can be used in `airbyte-lib`. + +## 💼 Assets + +### Connectors must have an icon +*Applies to the following connector languages: java, low-code, python* + +Each connector must have an icon available in at the root of the connector code directory. It must be an SVG file named `icon.svg` and must be a square. + +## 🔒 Security + +### Connectors must use HTTPS only +*Applies to the following connector languages: java, low-code, python* + +Connectors must use HTTPS only when making requests to external services. +### Python connectors must not use a Dockerfile and must declare their base image in metadata.yaml file +*Applies to the following connector languages: python, low-code* + +Connectors must use our Python connector base image (`docker.io/airbyte/python-connector-base`), declared through the `connectorBuildOptions.baseImage` in their `metadata.yaml`. +This is to ensure that all connectors use a base image which is maintained and has security updates. diff --git a/docs/contributing-to-airbyte/submit-new-connector.md b/docs/contributing-to-airbyte/submit-new-connector.md index 82cbb25fbf66..664064d4cd13 100644 --- a/docs/contributing-to-airbyte/submit-new-connector.md +++ b/docs/contributing-to-airbyte/submit-new-connector.md @@ -19,6 +19,7 @@ This will enable our team to make sure your contribution does not overlap with e 3. Code the change 4. Ensure all tests pass. For connectors, this includes acceptance tests as well. 5. Update documentation in `docs/integrations/.md` +6. Make sure your contribution passes our [QA checks](./resources/qa-checks.md) #### Open a pull request diff --git a/docusaurus/sidebars.js b/docusaurus/sidebars.js index 2be5469c7aba..138790ac2deb 100644 --- a/docusaurus/sidebars.js +++ b/docusaurus/sidebars.js @@ -312,6 +312,7 @@ const contributeToAirbyte = { "contributing-to-airbyte/resources/pull-requests-handbook", "contributing-to-airbyte/resources/code-style", "contributing-to-airbyte/resources/code-formatting", + "contributing-to-airbyte/resources/qa-checks", "contributing-to-airbyte/resources/developing-locally", "contributing-to-airbyte/resources/developing-on-docker", ], From 95257930878bfec48edbdee587a5dfe8233fbbb9 Mon Sep 17 00:00:00 2001 From: Augustin Date: Mon, 19 Feb 2024 18:58:09 +0100 Subject: [PATCH 30/43] airbyte-ci: use connectors-qa instead of connector_ops.qa_check (#35325) --- airbyte-ci/connectors/pipelines/README.md | 3 +- .../airbyte_ci/connectors/publish/pipeline.py | 11 +- .../airbyte_ci/connectors/test/pipeline.py | 5 +- .../connectors/test/steps/common.py | 156 ++++-------------- .../test/steps/python_connectors.py | 9 +- .../connectors/pipelines/pipelines/consts.py | 1 + .../connectors/pipelines/pyproject.toml | 2 +- .../pipelines/tests/test_publish.py | 38 ++--- .../pipelines/tests/test_tests/test_common.py | 113 ------------- 9 files changed, 63 insertions(+), 275 deletions(-) diff --git a/airbyte-ci/connectors/pipelines/README.md b/airbyte-ci/connectors/pipelines/README.md index 039062963b08..2a15062dcdcd 100644 --- a/airbyte-ci/connectors/pipelines/README.md +++ b/airbyte-ci/connectors/pipelines/README.md @@ -640,7 +640,8 @@ E.G.: running Poe tasks on the modified internal packages of the current branch: | Version | PR | Description | | ------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| 4.2.3 | [#35322](https://github.com/airbytehq/airbyte/pull/35322) | Declare `connectors_qa` as an internal package for testing. | +| 4.2.4 | [#35325](https://github.com/airbytehq/airbyte/pull/35325) | Use `connectors_qa` for QA checks and remove redundant checks. | +| 4.2.3 | [#35322](https://github.com/airbytehq/airbyte/pull/35322) | Declare `connectors_qa` as an internal package for testing. | | 4.2.2 | [#35364](https://github.com/airbytehq/airbyte/pull/35364) | Fix connector tests following gradle changes in #35307. | | 4.2.1 | [#35204](https://github.com/airbytehq/airbyte/pull/35204) | Run `poetry check` before `poetry install` on poetry package install. | | 4.2.0 | [#35103](https://github.com/airbytehq/airbyte/pull/35103) | Java 21 support. | diff --git a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/pipeline.py b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/pipeline.py index 849a9348f115..fb97c7e157bb 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/pipeline.py +++ b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/publish/pipeline.py @@ -13,7 +13,8 @@ from pipelines.airbyte_ci.connectors.build_image import steps from pipelines.airbyte_ci.connectors.publish.context import PublishConnectorContext from pipelines.airbyte_ci.connectors.reports import ConnectorReport -from pipelines.airbyte_ci.metadata.pipeline import MetadataUpload, MetadataValidation +from pipelines.airbyte_ci.connectors.test.steps.common import QaChecks +from pipelines.airbyte_ci.metadata.pipeline import MetadataUpload from pipelines.airbyte_ci.steps.python_registry import PublishToPythonRegistry, PythonRegistryPublishContext from pipelines.dagger.actions.remote_storage import upload_to_gcs from pipelines.dagger.actions.system import docker @@ -273,11 +274,11 @@ def create_connector_report(results: List[StepResult]) -> ConnectorReport: results = [] - metadata_validation_results = await MetadataValidation(context).run() - results.append(metadata_validation_results) + qa_check_results = await QaChecks(context).run() + results.append(qa_check_results) - # Exit early if the metadata file is invalid. - if metadata_validation_results.status is not StepStatus.SUCCESS: + # Exit early if the qa checks do not pass + if qa_check_results.status is not StepStatus.SUCCESS: return create_connector_report(results) check_connector_image_results = await CheckConnectorImageDoesNotExist(context).run() diff --git a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/pipeline.py b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/pipeline.py index d1b875a1c180..98af38978d70 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/pipeline.py +++ b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/pipeline.py @@ -13,8 +13,7 @@ from pipelines.airbyte_ci.connectors.context import ConnectorContext from pipelines.airbyte_ci.connectors.reports import ConnectorReport from pipelines.airbyte_ci.connectors.test.steps import java_connectors, python_connectors -from pipelines.airbyte_ci.connectors.test.steps.common import QaChecks, VersionFollowsSemverCheck, VersionIncrementCheck -from pipelines.airbyte_ci.metadata.pipeline import MetadataValidation +from pipelines.airbyte_ci.connectors.test.steps.common import QaChecks, VersionIncrementCheck from pipelines.helpers.execution.run_steps import StepToRun, run_steps if TYPE_CHECKING: @@ -57,8 +56,6 @@ async def run_connector_test_pipeline(context: ConnectorContext, semaphore: anyi if not context.code_tests_only: static_analysis_steps_to_run = [ [ - StepToRun(id=CONNECTOR_TEST_STEP_ID.METADATA_VALIDATION, step=MetadataValidation(context)), - StepToRun(id=CONNECTOR_TEST_STEP_ID.VERSION_FOLLOW_CHECK, step=VersionFollowsSemverCheck(context)), StepToRun(id=CONNECTOR_TEST_STEP_ID.VERSION_INC_CHECK, step=VersionIncrementCheck(context)), StepToRun(id=CONNECTOR_TEST_STEP_ID.QA_CHECKS, step=QaChecks(context)), ] diff --git a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/common.py b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/common.py index 426ae273d1a4..313bb09d69e6 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/common.py +++ b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/common.py @@ -8,20 +8,19 @@ import os from abc import ABC, abstractmethod from functools import cached_property -from typing import Any, ClassVar, List, Optional +from typing import ClassVar, List, Optional import requests # type: ignore import semver import yaml # type: ignore -from connector_ops.utils import Connector # type: ignore from dagger import Container, Directory from pipelines import hacks from pipelines.airbyte_ci.connectors.context import ConnectorContext -from pipelines.consts import CIContext +from pipelines.airbyte_ci.steps.docker import SimpleDockerStep +from pipelines.consts import INTERNAL_TOOL_PATHS, CIContext from pipelines.dagger.actions import secrets -from pipelines.dagger.containers import internal_tools from pipelines.helpers.utils import METADATA_FILE_NAME -from pipelines.models.steps import STEP_PARAMS, Step, StepResult, StepStatus +from pipelines.models.steps import STEP_PARAMS, MountPath, Step, StepResult, StepStatus class VersionCheck(Step, ABC): @@ -119,71 +118,37 @@ def validate(self) -> StepResult: return self.success_result -class VersionFollowsSemverCheck(VersionCheck): - context: ConnectorContext - title = "Connector version semver check" - - @property - def failure_message(self) -> str: - return f"The dockerImageTag in {METADATA_FILE_NAME} is not following semantic versioning or was decremented. Master version is {self.master_connector_version}, current version is {self.current_connector_version}" - - def validate(self) -> StepResult: - try: - if not self.current_connector_version >= self.master_connector_version: - return self.failure_result - except ValueError: - return self.failure_result - return self.success_result - - -class QaChecks(Step): - """A step to run QA checks for a connector.""" - - context: ConnectorContext - title = "QA checks" - - async def _run(self) -> StepResult: - """Run QA checks on a connector. - - The QA checks are defined in this module: - https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connector_ops/connector_ops/qa_checks.py - - Args: - context (ConnectorContext): The current test context, providing a connector object, a dagger client and a repository directory. - Returns: - StepResult: Failure or success of the QA checks with stdout and stderr. - """ - connector_ops = await internal_tools.with_connector_ops(self.context) - include = [ - str(self.context.connector.code_directory), - str(self.context.connector.documentation_file_path), - str(self.context.connector.migration_guide_file_path), - str(self.context.connector.icon_path), - ] - if ( - self.context.connector.technical_name.endswith("strict-encrypt") - or self.context.connector.technical_name == "source-file-secure" - ): - original_connector = Connector(self.context.connector.technical_name.replace("-strict-encrypt", "").replace("-secure", "")) - include += [ - str(original_connector.code_directory), - str(original_connector.documentation_file_path), - str(original_connector.icon_path), - str(original_connector.migration_guide_file_path), - ] - - filtered_repo = self.context.get_repo_dir( - include=include, +class QaChecks(SimpleDockerStep): + """A step to run QA checks for a connectors. + More details in https://github.com/airbytehq/airbyte/blob/main/airbyte-ci/connectors/connectors_qa/README.md + """ + + def __init__(self, context: ConnectorContext) -> None: + super().__init__( + title=f"Run QA checks for {context.connector.technical_name}", + context=context, + paths_to_mount=[ + MountPath(context.connector.code_directory), + # These paths are optional + # But their absence might make the QA check fail + MountPath(context.connector.documentation_file_path, optional=True), + MountPath(context.connector.migration_guide_file_path, optional=True), + MountPath(context.connector.icon_path, optional=True), + ], + internal_tools=[ + MountPath(INTERNAL_TOOL_PATHS.CONNECTORS_QA.value), + ], + secrets={ + k: v + for k, v in { + "DOCKER_HUB_USERNAME": context.docker_hub_username_secret, + "DOCKER_HUB_PASSWORD": context.docker_hub_password_secret, + }.items() + if v + }, + command=["connectors-qa", "run", f"--name={context.connector.technical_name}"], ) - qa_checks = ( - connector_ops.with_mounted_directory("/airbyte", filtered_repo) - .with_workdir("/airbyte") - .with_exec(["run-qa-checks", f"connectors/{self.context.connector.technical_name}"]) - ) - - return await self.get_step_result(qa_checks) - class AcceptanceTests(Step): """A step to run acceptance tests for a connector if it has an acceptance test config file.""" @@ -318,58 +283,3 @@ async def _build_connector_acceptance_test(self, connector_under_test_container: ) return cat_container.with_unix_socket("/var/run/docker.sock", self.context.dagger_client.host().unix_socket("/var/run/docker.sock")) - - -class CheckBaseImageIsUsed(Step): - context: ConnectorContext - title = "Check our base image is used" - - async def _run(self, *args: Any, **kwargs: Any) -> StepResult: - is_certified = self.context.connector.metadata.get("supportLevel") == "certified" - if not is_certified: - return self.skip("Connector is not certified, it does not require the use of our base image.") - - is_using_base_image = self.context.connector.metadata.get("connectorBuildOptions", {}).get("baseImage") is not None - migration_hint = f"Please run 'airbyte-ci connectors --name={self.context.connector.technical_name} migrate_to_base_image ' and commit the changes." - if not is_using_base_image: - return StepResult( - step=self, - status=StepStatus.FAILURE, - stdout=f"Connector is certified but does not use our base image. {migration_hint}", - ) - has_dockerfile = "Dockerfile" in await (await self.context.get_connector_dir(include=["Dockerfile"])).entries() - if has_dockerfile: - return StepResult( - step=self, - status=StepStatus.FAILURE, - stdout=f"Connector is certified but is still using a Dockerfile. {migration_hint}", - ) - return StepResult(step=self, status=StepStatus.SUCCESS, stdout="Connector is certified and uses our base image.") - - -class CheckPythonRegistryPublishConfiguration(Step): - context: ConnectorContext - title = "Check connector is published to python registry if it's a certified python connector" - - async def _run(self, *args: Any, **kwargs: Any) -> StepResult: - is_python_registry_published = self.context.connector.metadata.get("remoteRegistries", {}).get("pypi", {}).get("enabled", False) - if is_python_registry_published: - return StepResult(step=self, status=StepStatus.SUCCESS, stdout="Connector is published to PyPI.") - - tags = self.context.connector.metadata.get("tags", []) - is_python_registry_compatible = ("language:python" in tags or "language:low-code" in tags) and "language:java" not in tags - is_certified = self.context.connector.metadata.get("supportLevel") == "certified" - is_source = self.context.connector.metadata.get("connectorType") == "source" - if not is_source or not is_certified or not is_python_registry_compatible: - return self.skip( - "Connector is not a certified python source connector, it does not require to be published to python registry." - ) - - migration_hint = "Check the airbyte-ci readme under https://github.com/airbytehq/airbyte/tree/master/airbyte-ci/connectors/pipelines#python-registry-publishing for how to configure publishing." - if not is_python_registry_published: - return StepResult( - step=self, - status=StepStatus.FAILURE, - stdout=f"Connector is a certified python source but publication to PyPI is not enabled. {migration_hint}", - ) - return StepResult(step=self, status=StepStatus.SUCCESS, stdout="Connector is a certified python source and is published to PyPI.") diff --git a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/python_connectors.py b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/python_connectors.py index 286d93be657a..c19c807fcea0 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/python_connectors.py +++ b/airbyte-ci/connectors/pipelines/pipelines/airbyte_ci/connectors/test/steps/python_connectors.py @@ -15,7 +15,7 @@ from pipelines.airbyte_ci.connectors.build_image.steps.python_connectors import BuildConnectorImages from pipelines.airbyte_ci.connectors.consts import CONNECTOR_TEST_STEP_ID from pipelines.airbyte_ci.connectors.context import ConnectorContext -from pipelines.airbyte_ci.connectors.test.steps.common import AcceptanceTests, CheckBaseImageIsUsed, CheckPythonRegistryPublishConfiguration +from pipelines.airbyte_ci.connectors.test.steps.common import AcceptanceTests from pipelines.consts import LOCAL_BUILD_PLATFORM from pipelines.dagger.actions import secrets from pipelines.dagger.actions.python.poetry import with_poetry @@ -278,12 +278,5 @@ def get_test_steps(context: ConnectorContext) -> STEP_TREE: }, depends_on=[CONNECTOR_TEST_STEP_ID.BUILD], ), - StepToRun( - id=CONNECTOR_TEST_STEP_ID.CHECK_BASE_IMAGE, step=CheckBaseImageIsUsed(context), depends_on=[CONNECTOR_TEST_STEP_ID.BUILD] - ), - StepToRun( - id=CONNECTOR_TEST_STEP_ID.CHECK_PYTHON_REGISTRY_PUBLISH_CONFIGURATION, - step=CheckPythonRegistryPublishConfiguration(context), - ), ], ] diff --git a/airbyte-ci/connectors/pipelines/pipelines/consts.py b/airbyte-ci/connectors/pipelines/pipelines/consts.py index 74dce55e7c76..06bec50a19bb 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/consts.py +++ b/airbyte-ci/connectors/pipelines/pipelines/consts.py @@ -88,6 +88,7 @@ class ContextState(Enum): class INTERNAL_TOOL_PATHS(str, Enum): CI_CREDENTIALS = "airbyte-ci/connectors/ci_credentials" CONNECTOR_OPS = "airbyte-ci/connectors/connector_ops" + CONNECTORS_QA = "airbyte-ci/connectors/connectors_qa" METADATA_SERVICE = "airbyte-ci/connectors/metadata_service/lib" diff --git a/airbyte-ci/connectors/pipelines/pyproject.toml b/airbyte-ci/connectors/pipelines/pyproject.toml index e1613efd6ceb..6f77c50066f9 100644 --- a/airbyte-ci/connectors/pipelines/pyproject.toml +++ b/airbyte-ci/connectors/pipelines/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "pipelines" -version = "4.2.3" +version = "4.2.4" description = "Packaged maintained by the connector operations team to perform CI for connectors' pipelines" authors = ["Airbyte "] diff --git a/airbyte-ci/connectors/pipelines/tests/test_publish.py b/airbyte-ci/connectors/pipelines/tests/test_publish.py index 471c89ae6ece..79430b9ea282 100644 --- a/airbyte-ci/connectors/pipelines/tests/test_publish.py +++ b/airbyte-ci/connectors/pipelines/tests/test_publish.py @@ -147,7 +147,7 @@ def test_parse_spec_output_no_spec(self, publish_context): STEPS_TO_PATCH = [ - (publish_pipeline, "MetadataValidation"), + (publish_pipeline, "QaChecks"), (publish_pipeline, "MetadataUpload"), (publish_pipeline, "CheckConnectorImageDoesNotExist"), (publish_pipeline, "UploadSpecToCache"), @@ -159,29 +159,29 @@ def test_parse_spec_output_no_spec(self, publish_context): @pytest.mark.parametrize("pre_release", [True, False]) -async def test_run_connector_publish_pipeline_when_failed_validation(mocker, pre_release): - """We validate that no other steps are called if the metadata validation step fails.""" +async def test_run_connector_publish_pipeline_when_failed_qa_checks(mocker, pre_release): + """We validate that no other steps are called if the qa checks step fails.""" for module, to_mock in STEPS_TO_PATCH: mocker.patch.object(module, to_mock, return_value=mocker.AsyncMock()) - run_metadata_validation = publish_pipeline.MetadataValidation.return_value.run - run_metadata_validation.return_value = mocker.Mock(status=StepStatus.FAILURE) + run_qa_checks = publish_pipeline.QaChecks.return_value.run + run_qa_checks.return_value = mocker.Mock(status=StepStatus.FAILURE) context = mocker.MagicMock(pre_release=pre_release) semaphore = anyio.Semaphore(1) report = await publish_pipeline.run_connector_publish_pipeline(context, semaphore) - run_metadata_validation.assert_called_once() + run_qa_checks.assert_called_once() # Check that nothing else is called for module, to_mock in STEPS_TO_PATCH: - if to_mock != "MetadataValidation": + if to_mock != "QaChecks": getattr(module, to_mock).return_value.run.assert_not_called() assert ( report.steps_results == context.report.steps_results == [ - run_metadata_validation.return_value, + run_qa_checks.return_value, ] ) @@ -200,8 +200,8 @@ async def test_run_connector_publish_pipeline_when_image_exists_or_failed(mocker for module, to_mock in STEPS_TO_PATCH: mocker.patch.object(module, to_mock, return_value=mocker.AsyncMock()) - run_metadata_validation = publish_pipeline.MetadataValidation.return_value.run - run_metadata_validation.return_value = mocker.Mock(status=StepStatus.SUCCESS) + run_qa_checks = publish_pipeline.QaChecks.return_value.run + run_qa_checks.return_value = mocker.Mock(status=StepStatus.SUCCESS) # ensure spec always succeeds run_upload_spec_to_cache = publish_pipeline.UploadSpecToCache.return_value.run @@ -214,12 +214,12 @@ async def test_run_connector_publish_pipeline_when_image_exists_or_failed(mocker semaphore = anyio.Semaphore(1) report = await publish_pipeline.run_connector_publish_pipeline(publish_context, semaphore) - run_metadata_validation.assert_called_once() + run_qa_checks.assert_called_once() run_check_connector_image_does_not_exist.assert_called_once() # Check that nothing else is called for module, to_mock in STEPS_TO_PATCH: - if to_mock not in ["MetadataValidation", "MetadataUpload", "CheckConnectorImageDoesNotExist", "UploadSpecToCache"]: + if to_mock not in ["QaChecks", "MetadataUpload", "CheckConnectorImageDoesNotExist", "UploadSpecToCache"]: getattr(module, to_mock).return_value.run.assert_not_called() if check_image_exists_status is StepStatus.SKIPPED: @@ -228,7 +228,7 @@ async def test_run_connector_publish_pipeline_when_image_exists_or_failed(mocker report.steps_results == publish_context.report.steps_results == [ - run_metadata_validation.return_value, + run_qa_checks.return_value, run_check_connector_image_does_not_exist.return_value, run_upload_spec_to_cache.return_value, run_metadata_upload.return_value, @@ -241,7 +241,7 @@ async def test_run_connector_publish_pipeline_when_image_exists_or_failed(mocker report.steps_results == publish_context.report.steps_results == [ - run_metadata_validation.return_value, + run_qa_checks.return_value, run_check_connector_image_does_not_exist.return_value, ] ) @@ -268,12 +268,10 @@ async def test_run_connector_publish_pipeline_when_image_does_not_exist( upload_to_spec_cache_step_status, metadata_upload_step_status, ): - """We check that the full pipeline is executed as expected when the connector image does not exist and the metadata validation passed.""" + """We check that the full pipeline is executed as expected when the connector image does not exist and the qa checks passed.""" for module, to_mock in STEPS_TO_PATCH: mocker.patch.object(module, to_mock, return_value=mocker.AsyncMock()) - publish_pipeline.MetadataValidation.return_value.run.return_value = mocker.Mock( - name="metadata_validation_result", status=StepStatus.SUCCESS - ) + publish_pipeline.QaChecks.return_value.run.return_value = mocker.Mock(name="qa_checks_result", status=StepStatus.SUCCESS) publish_pipeline.CheckConnectorImageDoesNotExist.return_value.run.return_value = mocker.Mock( name="check_connector_image_does_not_exist_result", status=StepStatus.SUCCESS ) @@ -308,7 +306,7 @@ async def test_run_connector_publish_pipeline_when_image_does_not_exist( report = await publish_pipeline.run_connector_publish_pipeline(context, semaphore) steps_to_run = [ - publish_pipeline.MetadataValidation.return_value.run, + publish_pipeline.QaChecks.return_value.run, publish_pipeline.CheckConnectorImageDoesNotExist.return_value.run, publish_pipeline.steps.run_connector_build, publish_pipeline.PushConnectorImageToRegistry.return_value.run, @@ -366,7 +364,7 @@ async def test_run_connector_python_registry_publish_pipeline( ) for step in [ - publish_pipeline.MetadataValidation, + publish_pipeline.QaChecks, publish_pipeline.CheckConnectorImageDoesNotExist, publish_pipeline.UploadSpecToCache, publish_pipeline.MetadataUpload, diff --git a/airbyte-ci/connectors/pipelines/tests/test_tests/test_common.py b/airbyte-ci/connectors/pipelines/tests/test_tests/test_common.py index 79b7ba853e7b..8cc58cb470b5 100644 --- a/airbyte-ci/connectors/pipelines/tests/test_tests/test_common.py +++ b/airbyte-ci/connectors/pipelines/tests/test_tests/test_common.py @@ -243,116 +243,3 @@ async def test_params(self, dagger_client, mocker, test_context_ci, test_input_d assert set(acceptance_test_step.params_as_cli_options) == {"-ra", "--disable-warnings", "--durations=3"} acceptance_test_step.extra_params = {"--durations": ["5"], "--collect-only": []} assert set(acceptance_test_step.params_as_cli_options) == {"-ra", "--disable-warnings", "--durations=5", "--collect-only"} - - -class TestCheckBaseImageIsUsed: - @pytest.fixture - def certified_connector_no_base_image(self, all_connectors): - for connector in all_connectors: - if connector.metadata.get("supportLevel") == "certified": - if connector.metadata.get("connectorBuildOptions", {}).get("baseImage") is None: - return connector - pytest.skip("No certified connector without base image found") - - @pytest.fixture - def certified_connector_with_base_image(self, all_connectors): - for connector in all_connectors: - if connector.metadata.get("supportLevel") == "certified": - if connector.metadata.get("connectorBuildOptions", {}).get("baseImage") is not None: - return connector - pytest.skip("No certified connector with base image found") - - @pytest.fixture - def community_connector_no_base_image(self, all_connectors): - for connector in all_connectors: - if connector.metadata.get("supportLevel") == "community": - if connector.metadata.get("connectorBuildOptions", {}).get("baseImage") is None: - return connector - pytest.skip("No certified connector without base image found") - - @pytest.fixture - def test_context(self, mocker, dagger_client): - return mocker.MagicMock(dagger_client=dagger_client) - - async def test_pass_on_community_connector_no_base_image(self, mocker, dagger_client, community_connector_no_base_image): - test_context = mocker.MagicMock(dagger_client=dagger_client, connector=community_connector_no_base_image) - check_base_image_is_used_step = common.CheckBaseImageIsUsed(test_context) - step_result = await check_base_image_is_used_step.run() - assert step_result.status == StepStatus.SKIPPED - - async def test_pass_on_certified_connector_with_base_image(self, mocker, dagger_client, certified_connector_with_base_image): - dagger_connector_dir = dagger_client.host().directory(str(certified_connector_with_base_image.code_directory)) - test_context = mocker.MagicMock( - dagger_client=dagger_client, - connector=certified_connector_with_base_image, - get_connector_dir=mocker.AsyncMock(return_value=dagger_connector_dir), - ) - check_base_image_is_used_step = common.CheckBaseImageIsUsed(test_context) - step_result = await check_base_image_is_used_step.run() - assert step_result.status == StepStatus.SUCCESS - - async def test_fail_on_certified_connector_no_base_image(self, mocker, dagger_client, certified_connector_no_base_image): - test_context = mocker.MagicMock(dagger_client=dagger_client, connector=certified_connector_no_base_image) - check_base_image_is_used_step = common.CheckBaseImageIsUsed(test_context) - step_result = await check_base_image_is_used_step.run() - assert step_result.status == StepStatus.FAILURE - - -class TestCheckPythonRegistryPublishConfiguration: - @pytest.fixture - def test_context(self, mocker, dagger_client): - return mocker.MagicMock(dagger_client=dagger_client) - - def _get_connector_with_metadata(self, mocker, tags, support_level, pypi=None): - connector = mocker.MagicMock() - connector.metadata = { - "supportLevel": support_level, - "tags": tags, - "connectorType": "source", - } - if pypi: - connector.metadata["remoteRegistries"] = {"pypi": pypi} - return connector - - async def test_pass_on_community_connector_not_published(self, mocker, dagger_client): - test_context = mocker.MagicMock( - dagger_client=dagger_client, connector=self._get_connector_with_metadata(mocker, ["language:python"], "community") - ) - check_python_registry_config = common.CheckPythonRegistryPublishConfiguration(test_context) - step_result = await check_python_registry_config.run() - assert step_result.status == StepStatus.SKIPPED - - async def test_pass_on_java_connector_not_published(self, mocker, dagger_client): - test_context = mocker.MagicMock( - dagger_client=dagger_client, connector=self._get_connector_with_metadata(mocker, ["language:java"], "certified") - ) - check_python_registry_config = common.CheckPythonRegistryPublishConfiguration(test_context) - step_result = await check_python_registry_config.run() - assert step_result.status == StepStatus.SKIPPED - - async def test_pass_on_certified_connector_published(self, mocker, dagger_client): - test_context = mocker.MagicMock( - dagger_client=dagger_client, - connector=self._get_connector_with_metadata(mocker, ["language:python"], "certified", {"enabled": True}), - ) - check_python_registry_config = common.CheckPythonRegistryPublishConfiguration(test_context) - step_result = await check_python_registry_config.run() - assert step_result.status == StepStatus.SUCCESS - - async def test_pass_on_community_connector_published(self, mocker, dagger_client): - test_context = mocker.MagicMock( - dagger_client=dagger_client, - connector=self._get_connector_with_metadata(mocker, ["language:python"], "community", {"enabled": True}), - ) - check_python_registry_config = common.CheckPythonRegistryPublishConfiguration(test_context) - step_result = await check_python_registry_config.run() - assert step_result.status == StepStatus.SUCCESS - - async def test_fail_on_certified_connector_not_published(self, mocker, dagger_client): - test_context = mocker.MagicMock( - dagger_client=dagger_client, - connector=self._get_connector_with_metadata(mocker, ["language:python"], "certified", {"enabled": False}), - ) - check_python_registry_config = common.CheckPythonRegistryPublishConfiguration(test_context) - step_result = await check_python_registry_config.run() - assert step_result.status == StepStatus.FAILURE From fbbf8fe21a97d3fb83a834444fa933392fad9318 Mon Sep 17 00:00:00 2001 From: Evan Tahler Date: Mon, 19 Feb 2024 10:13:04 -0800 Subject: [PATCH 31/43] Update `metadata-service` to latest version + docs (#35419) --- .../metadata_service/lib/pyproject.toml | 2 +- .../metadata_service/orchestrator/README.md | 92 ++++++++++++++----- .../metadata_service/orchestrator/poetry.lock | 25 ++++- 3 files changed, 91 insertions(+), 28 deletions(-) diff --git a/airbyte-ci/connectors/metadata_service/lib/pyproject.toml b/airbyte-ci/connectors/metadata_service/lib/pyproject.toml index 079ca51f3f54..b4f0389e433b 100644 --- a/airbyte-ci/connectors/metadata_service/lib/pyproject.toml +++ b/airbyte-ci/connectors/metadata_service/lib/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "metadata-service" -version = "0.3.3" +version = "0.3.4" description = "" authors = ["Ben Church "] readme = "README.md" diff --git a/airbyte-ci/connectors/metadata_service/orchestrator/README.md b/airbyte-ci/connectors/metadata_service/orchestrator/README.md index bea709c3007f..ed1c3b44ade9 100644 --- a/airbyte-ci/connectors/metadata_service/orchestrator/README.md +++ b/airbyte-ci/connectors/metadata_service/orchestrator/README.md @@ -1,6 +1,6 @@ # Connector Orchestrator -This is the Orchestrator for Airbyte metadata built on Dagster. +This is the Orchestrator for Airbyte metadata built on Dagster. # Setup @@ -8,7 +8,8 @@ This is the Orchestrator for Airbyte metadata built on Dagster. #### Poetry -Before you can start working on this project, you will need to have Poetry installed on your system. Please follow the instructions below to install Poetry: +Before you can start working on this project, you will need to have Poetry installed on your system. +Please follow the instructions below to install Poetry: 1. Open your terminal or command prompt. 2. Install Poetry using the recommended installation method: @@ -23,125 +24,165 @@ Alternatively, you can use `pip` to install Poetry: pip install --user poetry ``` -3. After the installation is complete, close and reopen your terminal to ensure the newly installed `poetry` command is available in your system's PATH. +3. After the installation is complete, close and reopen your terminal to ensure the newly installed + `poetry` command is available in your system's PATH. -For more detailed instructions and alternative installation methods, please refer to the official Poetry documentation: https://python-poetry.org/docs/#installation +For more detailed instructions and alternative installation methods, please refer to the official +Poetry documentation: https://python-poetry.org/docs/#installation ### Using Poetry in the Project -Once Poetry is installed, you can use it to manage the project's dependencies and virtual environment. To get started, navigate to the project's root directory in your terminal and follow these steps: - +Once Poetry is installed, you can use it to manage the project's dependencies and virtual +environment. To get started, navigate to the project's root directory in your terminal and follow +these steps: ## Installation + ```bash poetry install cp .env.template .env ``` ## Create a GCP Service Account and Dev Bucket + Developing against the orchestrator requires a development bucket in GCP. The orchestrator will use this bucket to: + - store important output files. (e.g. Reports) - watch for changes to the `registry` directory in the bucket. However all tmp files will be stored in a local directory. To create a development bucket: + 1. Create a GCP Service Account with the following permissions: - - Storage Admin - - Storage Object Admin - - Storage Object Creator - - Storage Object Viewer + - Storage Admin + - Storage Object Admin + - Storage Object Creator + - Storage Object Viewer 2. Create a PUBLIC GCS bucket 3. Add the service account as a member of the bucket with the following permissions: - - Storage Admin - - Storage Object Admin - - Storage Object Creator - - Storage Object Viewer + + - Storage Admin + - Storage Object Admin + - Storage Object Creator + - Storage Object Viewer 4. Add the following environment variables to your `.env` file: - - `METADATA_BUCKET` - - `GCS_CREDENTIALS` + - `METADATA_BUCKET` + - `GCS_CREDENTIALS` Note that the `GCS_CREDENTIALS` should be the raw json string of the service account credentials. Here is an example of how to import the service account credentials into your environment: + ```bash export GCS_CREDENTIALS=`cat /path/to/credentials.json` ``` ## The Orchestrator -The orchestrator (built using Dagster) is responsible for orchestrating various the metadata processes. +The orchestrator (built using Dagster) is responsible for orchestrating various the metadata +processes. + +Dagster has a number of concepts that are important to understand before working on the +orchestrator. -Dagster has a number of concepts that are important to understand before working on the orchestrator. 1. Assets 2. Resources 3. Schedules 4. Sensors 5. Ops -Refer to the [Dagster documentation](https://docs.dagster.io/concepts) for more information on these concepts. +Refer to the [Dagster documentation](https://docs.dagster.io/concepts) for more information on these +concepts. ### Starting the Dagster Daemons + Start the orchestrator with the following command: + ```bash poetry run dagster dev ``` Then you can access the Dagster UI at http://localhost:3000 -Note its important to use `dagster dev` instead of `dagit` because `dagster dev` start additional services that are required for the orchestrator to run. Namely the sensor service. +Note its important to use `dagster dev` instead of `dagit` because `dagster dev` start additional +services that are required for the orchestrator to run. Namely the sensor service. ### Materializing Assets with the UI -When you navigate to the orchestrator in the UI, you will see a list of assets that are available to be materialized. + +When you navigate to the orchestrator in the UI, you will see a list of assets that are available to +be materialized. From here you have the following options + 1. Materialize all assets 2. Select a subset of assets to materialize 3. Enable a sensor to automatically materialize assets ### Materializing Assets without the UI -In some cases you may want to run the orchestrator without the UI. To learn more about Dagster's CLI commands, see the [Dagster CLI documentation](https://docs.dagster.io/_apidocs/cli). +In some cases you may want to run the orchestrator without the UI. To learn more about Dagster's CLI +commands, see the [Dagster CLI documentation](https://docs.dagster.io/_apidocs/cli). ## Running Tests + ```bash poetry run pytest ``` +## Deploying to Dagster Automatically + +GitHub Actions is used to automatically deploy the orchestrator to Dagster Cloud +([Github Action](https://github.com/airbytehq/airbyte/blob/master/.github/workflows/metadata_service_deploy_orchestrator_dagger.yml)). + +1. Update the version of your code (`../lib`) and update the version of the package in + `pyproject.toml` +1. In this project (`../orchestrator`) Run `poetry lock --no-update` to bump the version of the + requirements you may have changed in + `airbyte-ci/connectors/metadata_service/orchestrator/poetry.lock` +1. Push your changes to the `master` branch and the orchestrator will be automatically deployed to + Dagster Cloud. + ## Deploying to Dagster Cloud manually -Note: This is a temporary solution until we have a CI/CD pipeline setup. -Getting the CICD setup is currently blocked until we hear back from Dagster on a better way to use relative imports in a Dagster Cloud Deployment. +This should only be needed if the above (automatic deployment) fails. ### Installing the dagster-cloud cli + ```bash pip install dagster-cloud dagster-cloud config ``` ### Deploying the orchestrator + ```bash cd orchestrator DAGSTER_CLOUD_API_TOKEN= airbyte-ci metadata deploy orchestrator ``` # Using the Orchestrator to create a Connector Registry for Development + The orchestrator can be used to create a connector registry for development purposes. ## Setup + First you will need to setup the orchestrator as described above. Then you will want to do the following ### 1. Mirror the production bucket -Use the Google Cloud Console to mirror the production bucket (prod-airbyte-cloud-connector-metadata-service) to your development bucket. + +Use the Google Cloud Console to mirror the production bucket +(prod-airbyte-cloud-connector-metadata-service) to your development bucket. [Docs](https://cloud.google.com/storage-transfer/docs/cloud-storage-to-cloud-storage) ### 2. Upload any local metadata files you want to test changes with + ```bash # assuming your terminal is in the same location as this readme cd ../lib @@ -150,6 +191,7 @@ poetry run metadata_service upload ``` ### 3. Generate the registry + ```bash poetry run dagster dev open http://localhost:3000 diff --git a/airbyte-ci/connectors/metadata_service/orchestrator/poetry.lock b/airbyte-ci/connectors/metadata_service/orchestrator/poetry.lock index d350d91b4064..8b4130bb6cc1 100644 --- a/airbyte-ci/connectors/metadata_service/orchestrator/poetry.lock +++ b/airbyte-ci/connectors/metadata_service/orchestrator/poetry.lock @@ -1914,6 +1914,16 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -1970,7 +1980,7 @@ files = [ [[package]] name = "metadata-service" -version = "0.3.3" +version = "0.3.4" description = "" optional = false python-versions = "^3.9" @@ -3013,6 +3023,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -3020,8 +3031,16 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -3038,6 +3057,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -3045,6 +3065,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -4250,4 +4271,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9, <3.13" -content-hash = "bb5bbfdca5cf2dd2c8040275e5ae8ff9ec78719f2aad3bdddb0f652b9f2bd893" +content-hash = "122eb321956cdeea7fd94d3d6ef5fd0d2b8153d2d5fb136a9644fc83a1f56419" From 15f1d999e5f909b905f35e60733378522f046007 Mon Sep 17 00:00:00 2001 From: Evan Tahler Date: Mon, 19 Feb 2024 10:40:44 -0800 Subject: [PATCH 32/43] Bump destination-kvdb again to test metadata for archival (#35422) --- airbyte-integrations/connectors/destination-kvdb/Dockerfile | 2 +- airbyte-integrations/connectors/destination-kvdb/metadata.yaml | 2 +- docs/integrations/destinations/kvdb.md | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/airbyte-integrations/connectors/destination-kvdb/Dockerfile b/airbyte-integrations/connectors/destination-kvdb/Dockerfile index 0fb6a071dc8f..31fd4d41eefb 100644 --- a/airbyte-integrations/connectors/destination-kvdb/Dockerfile +++ b/airbyte-integrations/connectors/destination-kvdb/Dockerfile @@ -34,5 +34,5 @@ COPY destination_kvdb ./destination_kvdb ENV AIRBYTE_ENTRYPOINT "python /airbyte/integration_code/main.py" ENTRYPOINT ["python", "/airbyte/integration_code/main.py"] -LABEL io.airbyte.version=0.1.1 +LABEL io.airbyte.version=0.1.2 LABEL io.airbyte.name=airbyte/destination-kvdb diff --git a/airbyte-integrations/connectors/destination-kvdb/metadata.yaml b/airbyte-integrations/connectors/destination-kvdb/metadata.yaml index d700e915c1fd..9c553db1318b 100644 --- a/airbyte-integrations/connectors/destination-kvdb/metadata.yaml +++ b/airbyte-integrations/connectors/destination-kvdb/metadata.yaml @@ -7,7 +7,7 @@ data: connectorSubtype: api connectorType: destination definitionId: f2e549cd-8e2a-48f8-822d-cc13630eb42d - dockerImageTag: 0.1.1 + dockerImageTag: 0.1.2 dockerRepository: airbyte/destination-kvdb githubIssueLabel: destination-kvdb icon: kvdb.svg diff --git a/docs/integrations/destinations/kvdb.md b/docs/integrations/destinations/kvdb.md index 587b428d3a83..2574237a92e0 100644 --- a/docs/integrations/destinations/kvdb.md +++ b/docs/integrations/destinations/kvdb.md @@ -6,5 +6,6 @@ The KVDB destination for Airbyte | Version | Date | Pull Request | Subject | | :------ | :--------- | :------------------------------------------------------- | :-------------------------------- | +| 0.1.2 | 2024-02-19 | [35422](https://github.com/airbytehq/airbyte/pull/35422) | bump connector version to publish | | 0.1.1 | 2024-02-16 | [35370](https://github.com/airbytehq/airbyte/pull/35370) | bump connector version to publish | | 0.1.0 | 2021-07-19 | [4786](https://github.com/airbytehq/airbyte/pull/4786) | Python Demo Destination: KVDB | From a54b3103687dee94ed63935baf152b715cd42670 Mon Sep 17 00:00:00 2001 From: Augustin Date: Mon, 19 Feb 2024 21:06:24 +0100 Subject: [PATCH 33/43] connectors_qa: make `CheckPublishToPyPiIsEnabled` only run on source connectors (#35426) --- airbyte-ci/connectors/connectors_qa/README.md | 11 ++++++++++- .../connectors/connectors_qa/pyproject.toml | 2 +- .../src/connectors_qa/checks/packaging.py | 1 + .../connectors_qa/src/connectors_qa/models.py | 16 ++++++++++++++++ .../src/connectors_qa/templates/qa_checks.md.j2 | 1 + .../tests/unit_tests/test_models.py | 13 +++++++++++++ .../resources/qa-checks.md | 14 ++++++++++++++ 7 files changed, 56 insertions(+), 2 deletions(-) diff --git a/airbyte-ci/connectors/connectors_qa/README.md b/airbyte-ci/connectors/connectors_qa/README.md index 2e570d96dd98..cb1e79cd2c9f 100644 --- a/airbyte-ci/connectors/connectors_qa/README.md +++ b/airbyte-ci/connectors/connectors_qa/README.md @@ -97,4 +97,13 @@ poe type_check ```bash poe lint -``` \ No newline at end of file +``` + +## Changelog + +### 1.0.1 +* Add `applies_to_connector_types` attribute to `Check` class to specify the connector types that the check applies to. +* Make `CheckPublishToPyPiIsEnabled` run on source connectors only. + +### 1.0.0 +Initial release of `connectors-qa` package. \ No newline at end of file diff --git a/airbyte-ci/connectors/connectors_qa/pyproject.toml b/airbyte-ci/connectors/connectors_qa/pyproject.toml index 0b418a689705..8e9068045e32 100644 --- a/airbyte-ci/connectors/connectors_qa/pyproject.toml +++ b/airbyte-ci/connectors/connectors_qa/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "connectors-qa" -version = "1.0.0" +version = "1.0.1" description = "A package to run QA checks on Airbyte connectors, generate reports and documentation." authors = ["Airbyte "] readme = "README.md" diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py index aa5e50bfefdf..539e56b9cb56 100644 --- a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/checks/packaging.py @@ -49,6 +49,7 @@ class CheckPublishToPyPiIsEnabled(PackagingCheck): ConnectorLanguage.PYTHON, ConnectorLanguage.LOW_CODE, ] + applies_to_connector_types = ["source"] def _run(self, connector: Connector) -> CheckResult: publish_to_pypi_is_enabled = get(connector.metadata, "remoteRegistries.pypi.enabled", False) diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/models.py b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/models.py index 4df2f027d6c8..3f1086869adb 100644 --- a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/models.py +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/models.py @@ -19,6 +19,8 @@ ConnectorLanguage.PYTHON, ] +ALL_TYPES = ["source", "destination"] + class CheckCategory(Enum): """The category of a QA check""" @@ -110,6 +112,15 @@ def applies_to_connector_languages(self) -> List[ConnectorLanguage]: """ return ALL_LANGUAGES + @property + def applies_to_connector_types(self) -> List[str]: + """The connector types that the QA check applies to + + Returns: + List[str]: The connector types that the QA check applies to + """ + return ALL_TYPES + @property @abstractmethod def category(self) -> CheckCategory: @@ -136,6 +147,11 @@ def run(self, connector: Connector) -> CheckResult: connector, f"Check does not apply to {connector.language.value} connectors", ) + if connector.type not in self.applies_to_connector_types: + return self.skip( + connector, + f"Check does not apply to {connector.type} connectors", + ) return self._run(connector) def _run(self, connector: Connector) -> CheckResult: diff --git a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/templates/qa_checks.md.j2 b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/templates/qa_checks.md.j2 index a40d8aa31e6a..7ce3fdaf437c 100644 --- a/airbyte-ci/connectors/connectors_qa/src/connectors_qa/templates/qa_checks.md.j2 +++ b/airbyte-ci/connectors/connectors_qa/src/connectors_qa/templates/qa_checks.md.j2 @@ -10,6 +10,7 @@ They are by no mean replacing the need for a manual review of the connector code ## {{ category.value }} {% for check in checks %} ### {{ check.name }} +*Applies to the following connector types: {{ ', '.join(check.applies_to_connector_types) }}* *Applies to the following connector languages: {{ ', '.join(check.applies_to_connector_languages) }}* {{ check.description }} diff --git a/airbyte-ci/connectors/connectors_qa/tests/unit_tests/test_models.py b/airbyte-ci/connectors/connectors_qa/tests/unit_tests/test_models.py index a0ea1d24b250..c9f274fa8ba8 100644 --- a/airbyte-ci/connectors/connectors_qa/tests/unit_tests/test_models.py +++ b/airbyte-ci/connectors/connectors_qa/tests/unit_tests/test_models.py @@ -50,3 +50,16 @@ def test_skip_when_language_does_not_apply(self, mocker): # Assert assert all(result.status == CheckStatus.SKIPPED for result in results) + + def test_skip_when_type_does_not_apply(self, mocker): + # Arrange + connector = mocker.MagicMock(type="destination") + + # Act + results = [] + for check in ENABLED_CHECKS: + if connector.type not in check.applies_to_connector_types: + results.append(check.run(connector)) + + # Assert + assert all(result.status == CheckStatus.SKIPPED for result in results) diff --git a/docs/contributing-to-airbyte/resources/qa-checks.md b/docs/contributing-to-airbyte/resources/qa-checks.md index 5eac5b345d2b..4647e6c59c78 100644 --- a/docs/contributing-to-airbyte/resources/qa-checks.md +++ b/docs/contributing-to-airbyte/resources/qa-checks.md @@ -10,19 +10,23 @@ They are by no mean replacing the need for a manual review of the connector code ## 📄 Documentation ### Breaking changes must be accompanied by a migration guide +*Applies to the following connector types: source, destination* *Applies to the following connector languages: java, low-code, python* When a breaking change is introduced, we check that a migration guide is available. It should be stored under `./docs/integrations/s/-migrations.md`. This document should contain a section for each breaking change, in order of the version descending. It must explain users which action to take to migrate to the new version. ### Connectors must have user facing documentation +*Applies to the following connector types: source, destination* *Applies to the following connector languages: java, low-code, python* The user facing connector documentation should be stored under `./docs/integrations/s/.md`. ### Connectors documentation follows our guidelines +*Applies to the following connector types: source, destination* *Applies to the following connector languages: java, low-code, python* The user facing connector documentation should follow the guidelines defined in the [documentation standards](https://hackmd.io/Bz75cgATSbm7DjrAqgl4rw). ### Connectors must have a changelog entry for each version +*Applies to the following connector types: source, destination* *Applies to the following connector languages: java, low-code, python* Each new version of a connector must have a changelog entry defined in the user facing documentation in `./docs/integrations/s/.md`. @@ -30,6 +34,7 @@ Each new version of a connector must have a changelog entry defined in the user ## 📝 Metadata ### Connectors must have valid metadata.yaml file +*Applies to the following connector types: source, destination* *Applies to the following connector languages: java, low-code, python* Connectors must have a `metadata.yaml` file at the root of their directory. This file is used to build our connector registry. Its structure must follow our metadata schema. Field values are also validated. This is to ensure that all connectors have the required metadata fields and that the metadata is valid. More details in this [documentation](https://docs.airbyte.com/connector-development/connector-metadata-file). @@ -37,26 +42,32 @@ Connectors must have a `metadata.yaml` file at the root of their directory. This ## 📦 Packaging ### Connectors must use Poetry for dependency management +*Applies to the following connector types: source, destination* *Applies to the following connector languages: python, low-code* Connectors must use [Poetry](https://python-poetry.org/) for dependency management. This is to ensure that all connectors use a dependency management tool which locks dependencies and ensures reproducible installs. ### Connectors must be licensed under MIT or Elv2 +*Applies to the following connector types: source, destination* *Applies to the following connector languages: java, low-code, python* Connectors must be licensed under the MIT or Elv2 license. This is to ensure that all connectors are licensed under a permissive license. More details in our [License FAQ](https://docs.airbyte.com/developer-guides/licenses/license-faq). ### Connector license in metadata.yaml and pyproject.toml file must match +*Applies to the following connector types: source, destination* *Applies to the following connector languages: python, low-code* Connectors license in metadata.yaml and pyproject.toml file must match. This is to ensure that all connectors are consistently licensed. ### Connector version must follow Semantic Versioning +*Applies to the following connector types: source, destination* *Applies to the following connector languages: java, low-code, python* Connector version must follow the Semantic Versioning scheme. This is to ensure that all connectors follow a consistent versioning scheme. Refer to our [Semantic Versioning for Connectors](https://docs.airbyte.com/contributing-to-airbyte/#semantic-versioning-for-connectors) for more details. ### Connector version in metadata.yaml and pyproject.toml file must match +*Applies to the following connector types: source, destination* *Applies to the following connector languages: python, low-code* Connector version in metadata.yaml and pyproject.toml file must match. This is to ensure that connector release is consistent. ### Python connectors must have PyPi publishing enabled +*Applies to the following connector types: source* *Applies to the following connector languages: python, low-code* Python connectors must have [PyPi](https://pypi.org/) publishing enabled in their `metadata.yaml` file. This is declared by setting `remoteRegistries.pypi.enabled` to `true` in metadata.yaml. This is to ensure that all connectors can be published to PyPi and can be used in `airbyte-lib`. @@ -64,6 +75,7 @@ Python connectors must have [PyPi](https://pypi.org/) publishing enabled in thei ## 💼 Assets ### Connectors must have an icon +*Applies to the following connector types: source, destination* *Applies to the following connector languages: java, low-code, python* Each connector must have an icon available in at the root of the connector code directory. It must be an SVG file named `icon.svg` and must be a square. @@ -71,10 +83,12 @@ Each connector must have an icon available in at the root of the connector code ## 🔒 Security ### Connectors must use HTTPS only +*Applies to the following connector types: source, destination* *Applies to the following connector languages: java, low-code, python* Connectors must use HTTPS only when making requests to external services. ### Python connectors must not use a Dockerfile and must declare their base image in metadata.yaml file +*Applies to the following connector types: source, destination* *Applies to the following connector languages: python, low-code* Connectors must use our Python connector base image (`docker.io/airbyte/python-connector-base`), declared through the `connectorBuildOptions.baseImage` in their `metadata.yaml`. From b339aafabf0c4be059170184b64e67e1f73508e6 Mon Sep 17 00:00:00 2001 From: Marius Posta Date: Mon, 19 Feb 2024 13:56:03 -0800 Subject: [PATCH 34/43] gradle: remove archived connectors (#35423) --- settings.gradle | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/settings.gradle b/settings.gradle index 17f8450c9a95..c373a535e49c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -155,9 +155,21 @@ cdkPath.eachDir { dir -> def integrationsPath = rootDir.toPath().resolve('airbyte-integrations/connectors') integrationsPath.eachDir { dir -> def buildFiles = file(dir).list { file, name -> name == "build.gradle" } - if (buildFiles.length == 1) { - include ":airbyte-integrations:connectors:${dir.getFileName()}" + if (buildFiles.length != 1) { + // Ignore python and other non-gradle connectors. + return + } + File metadataFile = dir.resolve("metadata.yaml").toFile() + if (!metadataFile.exists()) { + // Don't support connectors without metadata. + return + } + String metadataYaml = metadataFile.getText("UTF-8") + if (metadataYaml =~ /(?m)^\s+supportLevel:\s*["']?archived["']?\s*$/) { + // Ignore archived connectors. + return } + include ":airbyte-integrations:connectors:${dir.getFileName()}" } // Include miscellaneous modules. From d108b9d56bec2d1b19aa78867c2c26ebfe392562 Mon Sep 17 00:00:00 2001 From: Anton Karpets Date: Tue, 20 Feb 2024 09:16:45 +0200 Subject: [PATCH 35/43] =?UTF-8?q?=E2=9C=A8Source=20Facebook=20Marketing:?= =?UTF-8?q?=20add=20integration=20tests=20(#35061)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../acceptance-test-config.yml | 4 +- .../integration_tests/expected_records.jsonl | 50 +- .../source-facebook-marketing/metadata.yaml | 2 +- .../source-facebook-marketing/poetry.lock | 10 +- .../source-facebook-marketing/pyproject.toml | 4 +- .../source_facebook_marketing/api.py | 5 +- .../source_facebook_marketing/source.py | 1 - .../streams/async_job_manager.py | 4 +- .../streams/base_insight_streams.py | 9 +- .../streams/common.py | 4 +- .../streams/streams.py | 6 +- .../source_facebook_marketing/utils.py | 2 +- .../unit_tests/integration/__init__.py | 0 .../unit_tests/integration/config.py | 55 ++ .../unit_tests/integration/pagination.py | 24 + .../unit_tests/integration/request_builder.py | 83 +++ .../integration/response_builder.py | 33 ++ .../test_ads_insights_action_product_id.py | 533 ++++++++++++++++++ .../unit_tests/integration/test_videos.py | 348 ++++++++++++ .../unit_tests/integration/utils.py | 44 ++ .../ads_insights_action_product_id.json | 203 +++++++ .../resource/http/response/videos.json | 111 ++++ .../sources/facebook-marketing.md | 3 +- 23 files changed, 1485 insertions(+), 53 deletions(-) create mode 100644 airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/__init__.py create mode 100644 airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/config.py create mode 100644 airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/pagination.py create mode 100644 airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/request_builder.py create mode 100644 airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/response_builder.py create mode 100644 airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/test_ads_insights_action_product_id.py create mode 100644 airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/test_videos.py create mode 100644 airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/utils.py create mode 100644 airbyte-integrations/connectors/source-facebook-marketing/unit_tests/resource/http/response/ads_insights_action_product_id.json create mode 100644 airbyte-integrations/connectors/source-facebook-marketing/unit_tests/resource/http/response/videos.json diff --git a/airbyte-integrations/connectors/source-facebook-marketing/acceptance-test-config.yml b/airbyte-integrations/connectors/source-facebook-marketing/acceptance-test-config.yml index 5afdc8dfa797..b4ec84009b78 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/acceptance-test-config.yml +++ b/airbyte-integrations/connectors/source-facebook-marketing/acceptance-test-config.yml @@ -83,9 +83,9 @@ acceptance_tests: bypass_reason: is changeable empty_streams: - name: "ads_insights_action_product_id" - bypass_reason: "Data not permanent" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" - name: "videos" - bypass_reason: "Cannot populate" + bypass_reason: "Data cannot be seeded in the test account, integration tests added for the stream instead" timeout_seconds: 4800 expect_records: path: "integration_tests/expected_records.jsonl" diff --git a/airbyte-integrations/connectors/source-facebook-marketing/integration_tests/expected_records.jsonl b/airbyte-integrations/connectors/source-facebook-marketing/integration_tests/expected_records.jsonl index 370321935410..324435dbda63 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/integration_tests/expected_records.jsonl +++ b/airbyte-integrations/connectors/source-facebook-marketing/integration_tests/expected_records.jsonl @@ -1,29 +1,29 @@ -{"stream": "ad_account", "data": {"id": "act_212551616838260", "account_id": "212551616838260", "account_status": 1, "age": 1392.454224537, "amount_spent": "39125", "balance": "0", "business": {"id": "1506473679510495", "name": "Airbyte"}, "business_city": "", "business_country_code": "US", "business_name": "", "business_street": "", "business_street2": "", "can_create_brand_lift_study": false, "capabilities": ["CAN_CREATE_CALL_ADS", "CAN_SEE_GROWTH_OPPORTUNITY_DATA", "ENABLE_IA_RECIRC_AD_DISPLAY_FORMAT", "CAN_USE_MOBILE_EXTERNAL_PAGE_TYPE", "CAN_USE_FB_FEED_POSITION_IN_VIDEO_VIEW_15S", "ENABLE_BIZ_DISCO_ADS", "ENABLE_BRAND_OBJECTIVES_FOR_BIZ_DISCO_ADS", "ENABLE_DIRECT_REACH_FOR_BIZ_DISCO_ADS", "ENABLE_DYNAMIC_ADS_ON_IG_STORIES_ADS", "ENABLE_IG_STORIES_ADS_PPE_OBJECTIVE", "ENABLE_IG_STORIES_ADS_MESSENGER_DESTINATION", "ENABLE_PAC_FOR_BIZ_DISCO_ADS", "CAN_USE_FB_INSTREAM_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_FB_STORY_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_AN_INSTREAM_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_IG_STORY_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_FB_IA_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_FB_SUG_VIDEO_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_FB_MKT_PLACE_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_IG_FEED_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_IG_EXPLORE_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_AN_CLASSIC_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_AN_REWARD_VIDEO_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_REACH_AND_FREQUENCY", "CAN_USE_RECURRING_BUDGET", "HAS_VALID_PAYMENT_METHODS", "CAN_USE_LINK_CLICK_BILLING_EVENT", "CAN_USE_CPA_BILLING_EVENT", "CAN_SEE_NEW_CONVERSION_WINDOW_NUX", "ADS_INSTREAM_INTERFACE_INTEGRITY", "ADS_INSTREAM_LINK_CLICK", "ADS_INSTREAM_LINK_CLICK_IMAGE", "ADS_IN_OBJECTIVES_DEPRECATION", "MESSENGER_INBOX_ADS_PRODUCT_CATALOG_SALES", "CAN_SHOW_MESSENGER_DUPLICSTION_UPSELL", "ALLOW_INSTREAM_ONLY_FOR_REACH", "ADS_INSTREAM_VIDEO_PLACEMENT_CONVERSIONS", "CAN_CREATE_INSTAGRAM_EXPLORE_ADS", "ALLOW_INSTREAM_VIDEOS_PLACEMENT_ONLY", "ALLOW_INSTREAM_NON_INTERRUPTIVE_LEADGEN", "INSTREAM_VIDEO_AD_DESKTOP_CONVERSION_AD_PREVIEW", "ALLOW_INSTREAM_ONLY_FOR_BRAND_AWARENESS_AUCTION", "ALLOW_SUGGESTED_VIDEOS_PLACEMENT_ONLY", "WHATSAPP_DESTINATION_ADS", "CTM_ADS_CREATION_CLICK_TO_DIRECT", "CTW_ADS_ENABLE_IG_FEED_PLACEMENT", "CTW_ADS_FOR_NON_MESSAGES_OBJECTIVE", "CTW_ADS_TRUSTED_TIER_2_PLUS_ADVERTISER", "CTW_ADS_TRUSTED_TIER_ADVERTISER", "ADS_PLACEMENT_MARKETPLACE", "ADNW_DISABLE_INSTREAM_AND_WEB_PLACEMENT", "CAN_CHANGE_BILLING_THRESHOLD", "CAN_USE_APP_EVENT_AVERAGE_COST_BIDDING", "CAN_USE_LEAD_GEN_AVERAGE_COST_BIDDING", "ADS_VALUE_OPTIMIZATION_DYNAMIC_ADS_1D", "ADS_DELIVERY_INSIGHTS_IN_BIDDING_PRESET_EXPERIMENT", "ADS_DELIVERY_INSIGHTS_OPTIMIZATION_PRESET", "CAN_SEE_APP_AD_EVENTS", "CAN_SEE_NEW_STANDARD_EVENTS_BETA", "CAN_SEE_VCK_HOLIDAY_TEMPLATES", "ENABLE_DCO_FOR_FB_STORY_ADS", "CAN_USE_IG_EXPLORE_GRID_HOME_PLACEMENT", "CAN_USE_IG_EXPLORE_HOME_IN_REACH_AND_FREQUENCY", "CAN_USE_IG_EXPLORE_HOME_POST_ENGAGEMENT_MESSAGES", "CAN_USE_IG_SEARCH_PLACEMENT", "CAN_USE_IG_SEARCH_RESULTS_AUTO_PLACEMENT", "CAN_USE_IG_REELS_PAC_CAROUSEL", "CAN_USE_IG_REELS_POSITION", "CAN_SEE_CONVERSION_LIFT_SUMMARY", "CAN_USE_IG_PROFILE_FEED_POSITION", "CAN_USE_IG_REELS_REACH_AND_FREQUENCY", "CAN_USE_IG_REELS_OVERLAY_POSITION", "CAN_USE_IG_REELS_OVERLAY_PAC", "CAN_USE_IG_SHOP_TAB_PAC", "CAN_SEE_LEARNING_STAGE", "ENABLE_WEBSITE_CONVERSIONS_FOR_FB_STORY_ADS", "ENABLE_MESSENGER_INBOX_VIDEO_ADS", "ENABLE_VIDEO_VIEWS_FOR_FB_STORY_ADS", "ENABLE_LINK_CLICKS_FOR_FB_STORY_ADS", "ENABLE_REACH_FOR_FB_STORY_ADS", "CAN_USE_CALL_TO_ACTION_LINK_IMPORT_EXPORT", "ADS_INSTREAM_VIDEO_ENABLE_SLIDE_SHOW", "ALLOW_INSTREAM_VIDEOS_PLACEMENT_ONLY_IN_VV_REACH_AND_FREQUENCY", "ENABLE_MOBILE_APP_INSTALLS_FOR_FB_STORY_ADS", "ENABLE_LEAD_GEN_FOR_FB_STORY_ADS", "CAN_USE_FB_MKT_PLACE_POSITION_IN_REACH", "CAN_USE_FB_MKT_PLACE_POSITION_IN_VIDEO_VIEW", "CAN_USE_FB_MKT_PLACE_POSITION_IN_STORE_VISIT", "ENABLE_MOBILE_APP_ENGAGEMENT_FOR_FB_STORY_ADS", "CAN_USE_FB_MKT_PLACE_POSITION_IN_BRAND_AWARENESS", "CAN_USE_FB_MKT_PLACE_POSITION_IN_APP_INSTALLS", "CAN_USE_FB_MKT_PLACE_POSITION_IN_LEAD_GENERATION", "CAN_USE_FB_MKT_PLACE_POSITION_IN_MESSAGE", "CAN_USE_FB_MKT_PLACE_POSITION_IN_PAGE_LIKE", "CAN_USE_FB_MKT_PLACE_POSITION_IN_POST_ENGAGEMENT", "RF_ALLOW_MARKETPLACE_ACCOUNT", "RF_ALLOW_SEARCH_ACCOUNT", "VERTICAL_VIDEO_PAC_INSTREAM_UPSELL", "IX_COLLECTION_ENABLED_FOR_BAO_AND_REACH", "ADS_BM_REQUIREMENTS_OCT_15_RELEASE", "ENABLE_POST_ENGAGEMENT_FOR_FB_STORY", "ENBABLE_CATALOG_SALES_FOR_FB_STORY", "CAN_USE_WHATSAPP_DESTINATION_ON_LINK_CLICKS_AND_CONVERSIONS", "CAN_USE_WHATSAPP_DESTINATION_ON_CONVERSIONS", "IS_NON_TAIL_AD_ACCOUNT", "IS_IN_IG_EXISTING_POST_CTA_DEFAULTING_EXPERIMENT", "IS_IN_SHORT_WA_LINK_CTWA_UNCONV_TRAFFIC_EXPERIMENT", "IS_IN_ODAX_EXPERIENCE", "IS_IN_REACH_BRAND_AWARENESS_WHATSAPP_L1_DESTINATION_EXPERIMENT", "IS_IN_VIDEO_VIEWS_WHATSAPP_L1_DESTINATION_EXPERIMENT", "IS_IN_WHATSAPP_DESTINATION_DEFAULTING_EXPERIMENT", "CAN_USE_MARKETPLACE_DESKTOP", "ADS_MERCHANT_OVERLAYS_DEPRECATION", "CONNECTIONS_DEPRECATION_V2", "CAN_USE_LIVE_VIDEO_FOR_THRUPLAY", "CAN_SEE_HEC_AM_FLOW", "CAN_SEE_POLITICAL_FLOW", "ADS_INSTREAM_PLACEMENT_CATALOG_SALES", "ENABLE_CONVERSIONS_FOR_FB_GROUP_TAB_ADS", "ENABLE_LINK_CLICK_FOR_FB_GROUP_TAB_ADS", "ENABLE_REACH_FOR_FB_GROUP_TAB_ADS", "CAN_USE_CONVERSATIONS_OPTIMIZATION", "ENABLE_THRUPLAY_OPTIMIZATION_MESSENGER_STORY_ADS", "CAN_USE_IG_STORY_POLLS_PAC_CREATION", "IOS14_CEO_CAMPAIGN_CREATION", "ENABLE_VIDEO_CHANNEL_PLACEMENT_FOR_RSVP_ADS", "DIGITAL_CIRCULAR_ADS", "CAN_SEE_SAFR_V3_FLOW", "CAN_USE_FB_REELS_POSITION", "CAN_USE_ADS_ON_FB_REELS_POSITION", "CAN_USE_FB_REELS_AUTO_PLACEMENT", "ENABLE_FB_REELS_CREATION_PAC_ADS", "ENABLE_FB_REELS_CREATION_DCO_ADS", "ENABLE_FB_REELS_POSTLOOP_CREATION_DCO_ADS", "ENABLE_FB_REELS_POSTLOOP_CREATION_PAC_ADS", "RF_CPA_BILLING_DEPRECATION_PHASE_2", "ENABLE_APP_INSTALL_CUSTOM_PRODUCT_PAGES", "ENABLE_ADS_ON_FB_REELS_PLACEMENT_UNIFICATION", "ENABLE_ADS_ON_IG_SHOP_TAB_DEPRECATION_L2_NUX", "ADS_RF_FB_REELS_PLACEMENT", "REELS_DM_ADS_ENABLE_REACH_AND_FREQUENCY", "ADS_AEMV2_HAS_LAUNCHED", "ELIGIBLE_FOR_TEXT_GEN"], "created_time": "2020-04-13T18:04:59-0700", "currency": "USD", "disable_reason": 0.0, "end_advertiser": 1506473679510495.0, "end_advertiser_name": "Airbyte", "fb_entity": 85.0, "funding_source": 2825262454257003.0, "funding_source_details": {"id": "2825262454257003", "type": 1}, "has_migrated_permissions": true, "is_attribution_spec_system_default": true, "is_direct_deals_enabled": false, "is_in_3ds_authorization_enabled_market": false, "is_notifications_enabled": true, "is_personal": 0.0, "is_prepay_account": false, "is_tax_id_required": false, "min_campaign_group_spend_cap": 10000.0, "min_daily_budget": 100.0, "name": "Airbyte", "offsite_pixels_tos_accepted": true, "owner": 1506473679510495.0, "rf_spec": {"min_reach_limits": {"US": 200000, "CA": 200000, "GB": 200000, "AR": 200000, "AU": 200000, "AT": 200000, "BE": 200000, "BR": 200000, "CL": 200000, "CN": 200000, "CO": 200000, "HR": 200000, "DK": 200000, "DO": 200000, "EG": 200000, "FI": 200000, "FR": 200000, "DE": 200000, "GR": 200000, "HK": 200000, "IN": 200000, "ID": 200000, "IE": 200000, "IL": 200000, "IT": 200000, "JP": 200000, "JO": 200000, "KW": 200000, "LB": 200000, "MY": 200000, "MX": 200000, "NL": 200000, "NZ": 200000, "NG": 200000, "NO": 200000, "PK": 200000, "PA": 200000, "PE": 200000, "PH": 200000, "PL": 200000, "RU": 200000, "SA": 200000, "RS": 200000, "SG": 200000, "ZA": 200000, "KR": 200000, "ES": 200000, "SE": 200000, "CH": 200000, "TW": 200000, "TH": 200000, "TR": 200000, "AE": 200000, "VE": 200000, "PT": 200000, "LU": 200000, "BG": 200000, "CZ": 200000, "SI": 200000, "IS": 200000, "SK": 200000, "LT": 200000, "TT": 200000, "BD": 200000, "LK": 200000, "KE": 200000, "HU": 200000, "MA": 200000, "CY": 200000, "JM": 200000, "EC": 200000, "RO": 200000, "BO": 200000, "GT": 200000, "CR": 200000, "QA": 200000, "SV": 200000, "HN": 200000, "NI": 200000, "PY": 200000, "UY": 200000, "PR": 200000, "BA": 200000, "PS": 200000, "TN": 200000, "BH": 200000, "VN": 200000, "GH": 200000, "MU": 200000, "UA": 200000, "MT": 200000, "BS": 200000, "MV": 200000, "OM": 200000, "MK": 200000, "LV": 200000, "EE": 200000, "IQ": 200000, "DZ": 200000, "AL": 200000, "NP": 200000, "MO": 200000, "ME": 200000, "SN": 200000, "GE": 200000, "BN": 200000, "UG": 200000, "GP": 200000, "BB": 200000, "AZ": 200000, "TZ": 200000, "LY": 200000, "MQ": 200000, "CM": 200000, "BW": 200000, "ET": 200000, "KZ": 200000, "NA": 200000, "MG": 200000, "NC": 200000, "MD": 200000, "FJ": 200000, "BY": 200000, "JE": 200000, "GU": 200000, "YE": 200000, "ZM": 200000, "IM": 200000, "HT": 200000, "KH": 200000, "AW": 200000, "PF": 200000, "AF": 200000, "BM": 200000, "GY": 200000, "AM": 200000, "MW": 200000, "AG": 200000, "RW": 200000, "GG": 200000, "GM": 200000, "FO": 200000, "LC": 200000, "KY": 200000, "BJ": 200000, "AD": 200000, "GD": 200000, "VI": 200000, "BZ": 200000, "VC": 200000, "MN": 200000, "MZ": 200000, "ML": 200000, "AO": 200000, "GF": 200000, "UZ": 200000, "DJ": 200000, "BF": 200000, "MC": 200000, "TG": 200000, "GL": 200000, "GA": 200000, "GI": 200000, "CD": 200000, "KG": 200000, "PG": 200000, "BT": 200000, "KN": 200000, "SZ": 200000, "LS": 200000, "LA": 200000, "LI": 200000, "MP": 200000, "SR": 200000, "SC": 200000, "VG": 200000, "TC": 200000, "DM": 200000, "MR": 200000, "AX": 200000, "SM": 200000, "SL": 200000, "NE": 200000, "CG": 200000, "AI": 200000, "YT": 200000, "CV": 200000, "GN": 200000, "TM": 200000, "BI": 200000, "TJ": 200000, "VU": 200000, "SB": 200000, "ER": 200000, "WS": 200000, "AS": 200000, "FK": 200000, "GQ": 200000, "TO": 200000, "KM": 200000, "PW": 200000, "FM": 200000, "CF": 200000, "SO": 200000, "MH": 200000, "VA": 200000, "TD": 200000, "KI": 200000, "ST": 200000, "TV": 200000, "NR": 200000, "RE": 200000, "LR": 200000, "ZW": 200000, "CI": 200000, "MM": 200000, "AN": 200000, "AQ": 200000, "BQ": 200000, "BV": 200000, "IO": 200000, "CX": 200000, "CC": 200000, "CK": 200000, "CW": 200000, "TF": 200000, "GW": 200000, "HM": 200000, "XK": 200000, "MS": 200000, "NU": 200000, "NF": 200000, "PN": 200000, "BL": 200000, "SH": 200000, "MF": 200000, "PM": 200000, "SX": 200000, "GS": 200000, "SD": 200000, "SS": 200000, "SJ": 200000, "TL": 200000, "TK": 200000, "UM": 200000, "WF": 200000, "EH": 200000}, "countries": ["US", "CA", "GB", "AR", "AU", "AT", "BE", "BR", "CL", "CN", "CO", "HR", "DK", "DO", "EG", "FI", "FR", "DE", "GR", "HK", "IN", "ID", "IE", "IL", "IT", "JP", "JO", "KW", "LB", "MY", "MX", "NL", "NZ", "NG", "NO", "PK", "PA", "PE", "PH", "PL", "RU", "SA", "RS", "SG", "ZA", "KR", "ES", "SE", "CH", "TW", "TH", "TR", "AE", "VE", "PT", "LU", "BG", "CZ", "SI", "IS", "SK", "LT", "TT", "BD", "LK", "KE", "HU", "MA", "CY", "JM", "EC", "RO", "BO", "GT", "CR", "QA", "SV", "HN", "NI", "PY", "UY", "PR", "BA", "PS", "TN", "BH", "VN", "GH", "MU", "UA", "MT", "BS", "MV", "OM", "MK", "EE", "LV", "IQ", "DZ", "AL", "NP", "MO", "SD", "ME", "SN", "GE", "BN", "UG", "GP", "BB", "ZW", "CI", "AZ", "TZ", "LY", "MQ", "MM", "CM", "BW", "ET", "KZ", "NA", "MG", "NC", "MD", "FJ", "BY", "JE", "GU", "YE", "ZM", "IM", "HT", "KH", "AW", "PF", "AF", "BM", "GY", "AM", "MW", "AG", "RW", "GG", "GM", "FO", "LC", "KY", "BJ", "AD", "GD", "VI", "BZ", "VC", "MN", "MZ", "ML", "AO", "GF", "UZ", "DJ", "BF", "MC", "TG", "GL", "GA", "GI", "CD", "KG", "PG", "BT", "KN", "SZ", "LS", "LA", "LI", "MP", "SR", "SC", "VG", "TC", "DM", "MR", "AX", "SM", "SL", "NE", "CG", "AI", "YT", "LR", "CV", "GN", "TM", "BI", "TJ", "VU", "SB", "ER", "WS", "AS", "FK", "GQ", "TO", "KM", "PW", "FM", "CF", "SO", "MH", "VA", "TD", "KI", "ST", "TV", "NR", "RE", "AN", "AQ", "BQ", "BV", "IO", "CX", "CC", "CK", "CW", "TF", "GW", "HM", "XK", "MS", "NU", "NF", "PN", "BL", "SH", "MF", "PM", "SX", "GS", "SS", "SJ", "TL", "TK", "UM", "WF", "EH"], "min_campaign_duration": {"US": 1, "CA": 1, "GB": 1, "AR": 1, "AU": 1, "AT": 1, "BE": 1, "BR": 1, "CL": 1, "CN": 1, "CO": 1, "HR": 1, "DK": 1, "DO": 1, "EG": 1, "FI": 1, "FR": 1, "DE": 1, "GR": 1, "HK": 1, "IN": 1, "ID": 1, "IE": 1, "IL": 1, "IT": 1, "JP": 1, "JO": 1, "KW": 1, "LB": 1, "MY": 1, "MX": 1, "NL": 1, "NZ": 1, "NG": 1, "NO": 1, "PK": 1, "PA": 1, "PE": 1, "PH": 1, "PL": 1, "RU": 1, "SA": 1, "RS": 1, "SG": 1, "ZA": 1, "KR": 1, "ES": 1, "SE": 1, "CH": 1, "TW": 1, "TH": 1, "TR": 1, "AE": 1, "VE": 1, "PT": 1, "LU": 1, "BG": 1, "CZ": 1, "SI": 1, "IS": 1, "SK": 1, "LT": 1, "TT": 1, "BD": 1, "LK": 1, "KE": 1, "HU": 1, "MA": 1, "CY": 1, "JM": 1, "EC": 1, "RO": 1, "BO": 1, "GT": 1, "CR": 1, "QA": 1, "SV": 1, "HN": 1, "NI": 1, "PY": 1, "UY": 1, "PR": 1, "BA": 1, "PS": 1, "TN": 1, "BH": 1, "VN": 1, "GH": 1, "MU": 1, "UA": 1, "MT": 1, "BS": 1, "MV": 1, "OM": 1, "MK": 1, "LV": 1, "EE": 1, "IQ": 1, "DZ": 1, "AL": 1, "NP": 1, "MO": 1, "ME": 1, "SN": 1, "GE": 1, "BN": 1, "UG": 1, "GP": 1, "BB": 1, "AZ": 1, "TZ": 1, "LY": 1, "MQ": 1, "CM": 1, "BW": 1, "ET": 1, "KZ": 1, "NA": 1, "MG": 1, "NC": 1, "MD": 1, "FJ": 1, "BY": 1, "JE": 1, "GU": 1, "YE": 1, "ZM": 1, "IM": 1, "HT": 1, "KH": 1, "AW": 1, "PF": 1, "AF": 1, "BM": 1, "GY": 1, "AM": 1, "MW": 1, "AG": 1, "RW": 1, "GG": 1, "GM": 1, "FO": 1, "LC": 1, "KY": 1, "BJ": 1, "AD": 1, "GD": 1, "VI": 1, "BZ": 1, "VC": 1, "MN": 1, "MZ": 1, "ML": 1, "AO": 1, "GF": 1, "UZ": 1, "DJ": 1, "BF": 1, "MC": 1, "TG": 1, "GL": 1, "GA": 1, "GI": 1, "CD": 1, "KG": 1, "PG": 1, "BT": 1, "KN": 1, "SZ": 1, "LS": 1, "LA": 1, "LI": 1, "MP": 1, "SR": 1, "SC": 1, "VG": 1, "TC": 1, "DM": 1, "MR": 1, "AX": 1, "SM": 1, "SL": 1, "NE": 1, "CG": 1, "AI": 1, "YT": 1, "CV": 1, "GN": 1, "TM": 1, "BI": 1, "TJ": 1, "VU": 1, "SB": 1, "ER": 1, "WS": 1, "AS": 1, "FK": 1, "GQ": 1, "TO": 1, "KM": 1, "PW": 1, "FM": 1, "CF": 1, "SO": 1, "MH": 1, "VA": 1, "TD": 1, "KI": 1, "ST": 1, "TV": 1, "NR": 1, "RE": 1, "LR": 1, "ZW": 1, "CI": 1, "MM": 1, "AN": 1, "AQ": 1, "BQ": 1, "BV": 1, "IO": 1, "CX": 1, "CC": 1, "CK": 1, "CW": 1, "TF": 1, "GW": 1, "HM": 1, "XK": 1, "MS": 1, "NU": 1, "NF": 1, "PN": 1, "BL": 1, "SH": 1, "MF": 1, "PM": 1, "SX": 1, "GS": 1, "SD": 1, "SS": 1, "SJ": 1, "TL": 1, "TK": 1, "UM": 1, "WF": 1, "EH": 1}, "max_campaign_duration": {"US": 90, "CA": 90, "GB": 90, "AR": 90, "AU": 90, "AT": 90, "BE": 90, "BR": 90, "CL": 90, "CN": 90, "CO": 90, "HR": 90, "DK": 90, "DO": 90, "EG": 90, "FI": 90, "FR": 90, "DE": 90, "GR": 90, "HK": 90, "IN": 90, "ID": 90, "IE": 90, "IL": 90, "IT": 90, "JP": 90, "JO": 90, "KW": 90, "LB": 90, "MY": 90, "MX": 90, "NL": 90, "NZ": 90, "NG": 90, "NO": 90, "PK": 90, "PA": 90, "PE": 90, "PH": 90, "PL": 90, "RU": 90, "SA": 90, "RS": 90, "SG": 90, "ZA": 90, "KR": 90, "ES": 90, "SE": 90, "CH": 90, "TW": 90, "TH": 90, "TR": 90, "AE": 90, "VE": 90, "PT": 90, "LU": 90, "BG": 90, "CZ": 90, "SI": 90, "IS": 90, "SK": 90, "LT": 90, "TT": 90, "BD": 90, "LK": 90, "KE": 90, "HU": 90, "MA": 90, "CY": 90, "JM": 90, "EC": 90, "RO": 90, "BO": 90, "GT": 90, "CR": 90, "QA": 90, "SV": 90, "HN": 90, "NI": 90, "PY": 90, "UY": 90, "PR": 90, "BA": 90, "PS": 90, "TN": 90, "BH": 90, "VN": 90, "GH": 90, "MU": 90, "UA": 90, "MT": 90, "BS": 90, "MV": 90, "OM": 90, "MK": 90, "LV": 90, "EE": 90, "IQ": 90, "DZ": 90, "AL": 90, "NP": 90, "MO": 90, "ME": 90, "SN": 90, "GE": 90, "BN": 90, "UG": 90, "GP": 90, "BB": 90, "AZ": 90, "TZ": 90, "LY": 90, "MQ": 90, "CM": 90, "BW": 90, "ET": 90, "KZ": 90, "NA": 90, "MG": 90, "NC": 90, "MD": 90, "FJ": 90, "BY": 90, "JE": 90, "GU": 90, "YE": 90, "ZM": 90, "IM": 90, "HT": 90, "KH": 90, "AW": 90, "PF": 90, "AF": 90, "BM": 90, "GY": 90, "AM": 90, "MW": 90, "AG": 90, "RW": 90, "GG": 90, "GM": 90, "FO": 90, "LC": 90, "KY": 90, "BJ": 90, "AD": 90, "GD": 90, "VI": 90, "BZ": 90, "VC": 90, "MN": 90, "MZ": 90, "ML": 90, "AO": 90, "GF": 90, "UZ": 90, "DJ": 90, "BF": 90, "MC": 90, "TG": 90, "GL": 90, "GA": 90, "GI": 90, "CD": 90, "KG": 90, "PG": 90, "BT": 90, "KN": 90, "SZ": 90, "LS": 90, "LA": 90, "LI": 90, "MP": 90, "SR": 90, "SC": 90, "VG": 90, "TC": 90, "DM": 90, "MR": 90, "AX": 90, "SM": 90, "SL": 90, "NE": 90, "CG": 90, "AI": 90, "YT": 90, "CV": 90, "GN": 90, "TM": 90, "BI": 90, "TJ": 90, "VU": 90, "SB": 90, "ER": 90, "WS": 90, "AS": 90, "FK": 90, "GQ": 90, "TO": 90, "KM": 90, "PW": 90, "FM": 90, "CF": 90, "SO": 90, "MH": 90, "VA": 90, "TD": 90, "KI": 90, "ST": 90, "TV": 90, "NR": 90, "RE": 90, "LR": 90, "ZW": 90, "CI": 90, "MM": 90, "AN": 90, "AQ": 90, "BQ": 90, "BV": 90, "IO": 90, "CX": 90, "CC": 90, "CK": 90, "CW": 90, "TF": 90, "GW": 90, "HM": 90, "XK": 90, "MS": 90, "NU": 90, "NF": 90, "PN": 90, "BL": 90, "SH": 90, "MF": 90, "PM": 90, "SX": 90, "GS": 90, "SD": 90, "SS": 90, "SJ": 90, "TL": 90, "TK": 90, "UM": 90, "WF": 90, "EH": 90}, "max_days_to_finish": {"US": 180, "CA": 180, "GB": 180, "AR": 180, "AU": 180, "AT": 180, "BE": 180, "BR": 180, "CL": 180, "CN": 180, "CO": 180, "HR": 180, "DK": 180, "DO": 180, "EG": 180, "FI": 180, "FR": 180, "DE": 180, "GR": 180, "HK": 180, "IN": 180, "ID": 180, "IE": 180, "IL": 180, "IT": 180, "JP": 180, "JO": 180, "KW": 180, "LB": 180, "MY": 180, "MX": 180, "NL": 180, "NZ": 180, "NG": 180, "NO": 180, "PK": 180, "PA": 180, "PE": 180, "PH": 180, "PL": 180, "RU": 180, "SA": 180, "RS": 180, "SG": 180, "ZA": 180, "KR": 180, "ES": 180, "SE": 180, "CH": 180, "TW": 180, "TH": 180, "TR": 180, "AE": 180, "VE": 180, "PT": 180, "LU": 180, "BG": 180, "CZ": 180, "SI": 180, "IS": 180, "SK": 180, "LT": 180, "TT": 180, "BD": 180, "LK": 180, "KE": 180, "HU": 180, "MA": 180, "CY": 180, "JM": 180, "EC": 180, "RO": 180, "BO": 180, "GT": 180, "CR": 180, "QA": 180, "SV": 180, "HN": 180, "NI": 180, "PY": 180, "UY": 180, "PR": 180, "BA": 180, "PS": 180, "TN": 180, "BH": 180, "VN": 180, "GH": 180, "MU": 180, "UA": 180, "MT": 180, "BS": 180, "MV": 180, "OM": 180, "MK": 180, "LV": 180, "EE": 180, "IQ": 180, "DZ": 180, "AL": 180, "NP": 180, "MO": 180, "ME": 180, "SN": 180, "GE": 180, "BN": 180, "UG": 180, "GP": 180, "BB": 180, "AZ": 180, "TZ": 180, "LY": 180, "MQ": 180, "CM": 180, "BW": 180, "ET": 180, "KZ": 180, "NA": 180, "MG": 180, "NC": 180, "MD": 180, "FJ": 180, "BY": 180, "JE": 180, "GU": 180, "YE": 180, "ZM": 180, "IM": 180, "HT": 180, "KH": 180, "AW": 180, "PF": 180, "AF": 180, "BM": 180, "GY": 180, "AM": 180, "MW": 180, "AG": 180, "RW": 180, "GG": 180, "GM": 180, "FO": 180, "LC": 180, "KY": 180, "BJ": 180, "AD": 180, "GD": 180, "VI": 180, "BZ": 180, "VC": 180, "MN": 180, "MZ": 180, "ML": 180, "AO": 180, "GF": 180, "UZ": 180, "DJ": 180, "BF": 180, "MC": 180, "TG": 180, "GL": 180, "GA": 180, "GI": 180, "CD": 180, "KG": 180, "PG": 180, "BT": 180, "KN": 180, "SZ": 180, "LS": 180, "LA": 180, "LI": 180, "MP": 180, "SR": 180, "SC": 180, "VG": 180, "TC": 180, "DM": 180, "MR": 180, "AX": 180, "SM": 180, "SL": 180, "NE": 180, "CG": 180, "AI": 180, "YT": 180, "CV": 180, "GN": 180, "TM": 180, "BI": 180, "TJ": 180, "VU": 180, "SB": 180, "ER": 180, "WS": 180, "AS": 180, "FK": 180, "GQ": 180, "TO": 180, "KM": 180, "PW": 180, "FM": 180, "CF": 180, "SO": 180, "MH": 180, "VA": 180, "TD": 180, "KI": 180, "ST": 180, "TV": 180, "NR": 180, "RE": 180, "LR": 180, "ZW": 180, "CI": 180, "MM": 180, "AN": 180, "AQ": 180, "BQ": 180, "BV": 180, "IO": 180, "CX": 180, "CC": 180, "CK": 180, "CW": 180, "TF": 180, "GW": 180, "HM": 180, "XK": 180, "MS": 180, "NU": 180, "NF": 180, "PN": 180, "BL": 180, "SH": 180, "MF": 180, "PM": 180, "SX": 180, "GS": 180, "SD": 180, "SS": 180, "SJ": 180, "TL": 180, "TK": 180, "UM": 180, "WF": 180, "EH": 180}, "global_io_max_campaign_duration": 100}, "spend_cap": "0", "tax_id_status": 0.0, "tax_id_type": "0", "timezone_id": 1.0, "timezone_name": "America/Los_Angeles", "timezone_offset_hours_utc": -8.0, "tos_accepted": {"web_custom_audience_tos": 1}, "user_tasks": ["DRAFT", "ANALYZE", "ADVERTISE", "MANAGE"]}, "emitted_at": 1707135364182} +{"stream": "ad_account", "data": {"id": "act_212551616838260", "account_id": "212551616838260", "account_status": 1, "age": 1406.5197337963, "amount_spent": "39125", "balance": "0", "business": {"id": "1506473679510495", "name": "Airbyte"}, "business_city": "", "business_country_code": "US", "business_name": "", "business_street": "", "business_street2": "", "can_create_brand_lift_study": false, "capabilities": ["CAN_CREATE_CALL_ADS", "CAN_SEE_GROWTH_OPPORTUNITY_DATA", "ENABLE_IA_RECIRC_AD_DISPLAY_FORMAT", "CAN_USE_MOBILE_EXTERNAL_PAGE_TYPE", "CAN_USE_FB_FEED_POSITION_IN_VIDEO_VIEW_15S", "ENABLE_BIZ_DISCO_ADS", "ENABLE_BRAND_OBJECTIVES_FOR_BIZ_DISCO_ADS", "ENABLE_DIRECT_REACH_FOR_BIZ_DISCO_ADS", "ENABLE_DYNAMIC_ADS_ON_IG_STORIES_ADS", "ENABLE_IG_STORIES_ADS_PPE_OBJECTIVE", "ENABLE_IG_STORIES_ADS_MESSENGER_DESTINATION", "ENABLE_PAC_FOR_BIZ_DISCO_ADS", "CAN_USE_FB_INSTREAM_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_FB_STORY_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_AN_INSTREAM_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_IG_STORY_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_FB_IA_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_FB_SUG_VIDEO_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_FB_MKT_PLACE_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_IG_FEED_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_IG_EXPLORE_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_AN_CLASSIC_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_AN_REWARD_VIDEO_POSITION_IN_VIDEO_VIEW_15S", "CAN_USE_REACH_AND_FREQUENCY", "CAN_USE_RECURRING_BUDGET", "HAS_VALID_PAYMENT_METHODS", "CAN_USE_LINK_CLICK_BILLING_EVENT", "CAN_USE_CPA_BILLING_EVENT", "CAN_SEE_NEW_CONVERSION_WINDOW_NUX", "ADS_INSTREAM_INTERFACE_INTEGRITY", "ADS_INSTREAM_LINK_CLICK", "ADS_INSTREAM_LINK_CLICK_IMAGE", "ADS_IN_OBJECTIVES_DEPRECATION", "MESSENGER_INBOX_ADS_PRODUCT_CATALOG_SALES", "CAN_SHOW_MESSENGER_DUPLICSTION_UPSELL", "ALLOW_INSTREAM_ONLY_FOR_REACH", "ADS_INSTREAM_VIDEO_PLACEMENT_CONVERSIONS", "CAN_CREATE_INSTAGRAM_EXPLORE_ADS", "ALLOW_INSTREAM_VIDEOS_PLACEMENT_ONLY", "ALLOW_INSTREAM_NON_INTERRUPTIVE_LEADGEN", "INSTREAM_VIDEO_AD_DESKTOP_CONVERSION_AD_PREVIEW", "ALLOW_INSTREAM_ONLY_FOR_BRAND_AWARENESS_AUCTION", "ALLOW_SUGGESTED_VIDEOS_PLACEMENT_ONLY", "WHATSAPP_DESTINATION_ADS", "CTM_ADS_CREATION_CLICK_TO_DIRECT", "CTW_ADS_ENABLE_IG_FEED_PLACEMENT", "CTW_ADS_FOR_NON_MESSAGES_OBJECTIVE", "CTW_ADS_TRUSTED_TIER_2_PLUS_ADVERTISER", "CTW_ADS_TRUSTED_TIER_ADVERTISER", "ADS_PLACEMENT_MARKETPLACE", "ADNW_DISABLE_INSTREAM_AND_WEB_PLACEMENT", "CAN_CHANGE_BILLING_THRESHOLD", "CAN_USE_APP_EVENT_AVERAGE_COST_BIDDING", "CAN_USE_LEAD_GEN_AVERAGE_COST_BIDDING", "ADS_VALUE_OPTIMIZATION_DYNAMIC_ADS_1D", "ADS_DELIVERY_INSIGHTS_IN_BIDDING_PRESET_EXPERIMENT", "ADS_DELIVERY_INSIGHTS_OPTIMIZATION_PRESET", "CAN_SEE_APP_AD_EVENTS", "CAN_SEE_NEW_STANDARD_EVENTS_BETA", "CAN_SEE_VCK_HOLIDAY_TEMPLATES", "ENABLE_DCO_FOR_FB_STORY_ADS", "CAN_USE_IG_EXPLORE_GRID_HOME_PLACEMENT", "CAN_USE_IG_EXPLORE_HOME_IN_REACH_AND_FREQUENCY", "CAN_USE_IG_EXPLORE_HOME_POST_ENGAGEMENT_MESSAGES", "CAN_USE_IG_SEARCH_PLACEMENT", "CAN_USE_IG_SEARCH_RESULTS_AUTO_PLACEMENT", "CAN_USE_IG_REELS_PAC_CAROUSEL", "CAN_USE_IG_REELS_POSITION", "CAN_SEE_CONVERSION_LIFT_SUMMARY", "CAN_USE_IG_PROFILE_FEED_POSITION", "CAN_USE_IG_REELS_REACH_AND_FREQUENCY", "CAN_USE_IG_REELS_OVERLAY_POSITION", "CAN_USE_IG_REELS_OVERLAY_PAC", "CAN_USE_IG_SHOP_TAB_PAC", "CAN_SEE_LEARNING_STAGE", "ENABLE_WEBSITE_CONVERSIONS_FOR_FB_STORY_ADS", "ENABLE_MESSENGER_INBOX_VIDEO_ADS", "ENABLE_VIDEO_VIEWS_FOR_FB_STORY_ADS", "ENABLE_LINK_CLICKS_FOR_FB_STORY_ADS", "ENABLE_REACH_FOR_FB_STORY_ADS", "CAN_USE_CALL_TO_ACTION_LINK_IMPORT_EXPORT", "ADS_INSTREAM_VIDEO_ENABLE_SLIDE_SHOW", "ALLOW_INSTREAM_VIDEOS_PLACEMENT_ONLY_IN_VV_REACH_AND_FREQUENCY", "ENABLE_MOBILE_APP_INSTALLS_FOR_FB_STORY_ADS", "ENABLE_LEAD_GEN_FOR_FB_STORY_ADS", "CAN_USE_FB_MKT_PLACE_POSITION_IN_REACH", "CAN_USE_FB_MKT_PLACE_POSITION_IN_VIDEO_VIEW", "CAN_USE_FB_MKT_PLACE_POSITION_IN_STORE_VISIT", "ENABLE_MOBILE_APP_ENGAGEMENT_FOR_FB_STORY_ADS", "CAN_USE_FB_MKT_PLACE_POSITION_IN_BRAND_AWARENESS", "CAN_USE_FB_MKT_PLACE_POSITION_IN_APP_INSTALLS", "CAN_USE_FB_MKT_PLACE_POSITION_IN_LEAD_GENERATION", "CAN_USE_FB_MKT_PLACE_POSITION_IN_MESSAGE", "CAN_USE_FB_MKT_PLACE_POSITION_IN_PAGE_LIKE", "CAN_USE_FB_MKT_PLACE_POSITION_IN_POST_ENGAGEMENT", "RF_ALLOW_MARKETPLACE_ACCOUNT", "RF_ALLOW_SEARCH_ACCOUNT", "VERTICAL_VIDEO_PAC_INSTREAM_UPSELL", "IX_COLLECTION_ENABLED_FOR_BAO_AND_REACH", "ADS_BM_REQUIREMENTS_OCT_15_RELEASE", "ENABLE_POST_ENGAGEMENT_FOR_FB_STORY", "ENBABLE_CATALOG_SALES_FOR_FB_STORY", "CAN_USE_WHATSAPP_DESTINATION_ON_LINK_CLICKS_AND_CONVERSIONS", "CAN_USE_WHATSAPP_DESTINATION_ON_CONVERSIONS", "IS_NON_TAIL_AD_ACCOUNT", "IS_IN_IG_EXISTING_POST_CTA_DEFAULTING_EXPERIMENT", "IS_IN_SHORT_WA_LINK_CTWA_UNCONV_TRAFFIC_EXPERIMENT", "IS_IN_ODAX_EXPERIENCE", "IS_IN_REACH_BRAND_AWARENESS_WHATSAPP_L1_DESTINATION_EXPERIMENT", "IS_IN_VIDEO_VIEWS_WHATSAPP_L1_DESTINATION_EXPERIMENT", "IS_IN_WHATSAPP_DESTINATION_DEFAULTING_EXPERIMENT", "CAN_USE_MARKETPLACE_DESKTOP", "ADS_MERCHANT_OVERLAYS_DEPRECATION", "CONNECTIONS_DEPRECATION_V2", "CAN_USE_LIVE_VIDEO_FOR_THRUPLAY", "CAN_SEE_HEC_AM_FLOW", "CAN_SEE_POLITICAL_FLOW", "ADS_INSTREAM_PLACEMENT_CATALOG_SALES", "ENABLE_CONVERSIONS_FOR_FB_GROUP_TAB_ADS", "ENABLE_LINK_CLICK_FOR_FB_GROUP_TAB_ADS", "ENABLE_REACH_FOR_FB_GROUP_TAB_ADS", "CAN_USE_CONVERSATIONS_OPTIMIZATION", "ENABLE_THRUPLAY_OPTIMIZATION_MESSENGER_STORY_ADS", "CAN_USE_IG_STORY_POLLS_PAC_CREATION", "IOS14_CEO_CAMPAIGN_CREATION", "ENABLE_VIDEO_CHANNEL_PLACEMENT_FOR_RSVP_ADS", "DIGITAL_CIRCULAR_ADS", "CAN_SEE_SAFR_V3_FLOW", "CAN_USE_FB_REELS_POSITION", "CAN_USE_ADS_ON_FB_REELS_POSITION", "CAN_USE_FB_REELS_AUTO_PLACEMENT", "ENABLE_FB_REELS_CREATION_PAC_ADS", "ENABLE_FB_REELS_CREATION_DCO_ADS", "ENABLE_FB_REELS_POSTLOOP_CREATION_DCO_ADS", "ENABLE_FB_REELS_POSTLOOP_CREATION_PAC_ADS", "RF_CPA_BILLING_DEPRECATION_PHASE_2", "ENABLE_APP_INSTALL_CUSTOM_PRODUCT_PAGES", "ENABLE_ADS_ON_FB_REELS_PLACEMENT_UNIFICATION", "ADS_RF_FB_REELS_PLACEMENT", "REELS_DM_ADS_ENABLE_REACH_AND_FREQUENCY", "ELIGIBLE_FOR_TEXT_GEN", "CAN_USE_BUDGET_SCHEDULING_API", "ADS_AEMV2_HAS_LAUNCHED"], "created_time": "2020-04-13T18:04:59-0700", "currency": "USD", "disable_reason": 0.0, "end_advertiser": 1506473679510495.0, "end_advertiser_name": "Airbyte", "fb_entity": 85.0, "funding_source": 2825262454257003.0, "funding_source_details": {"id": "2825262454257003", "type": 1}, "has_migrated_permissions": true, "is_attribution_spec_system_default": true, "is_direct_deals_enabled": false, "is_in_3ds_authorization_enabled_market": false, "is_notifications_enabled": true, "is_personal": 0.0, "is_prepay_account": false, "is_tax_id_required": false, "min_campaign_group_spend_cap": 10000.0, "min_daily_budget": 100.0, "name": "Airbyte", "offsite_pixels_tos_accepted": true, "owner": 1506473679510495.0, "rf_spec": {"min_reach_limits": {"US": 200000, "CA": 200000, "GB": 200000, "AR": 200000, "AU": 200000, "AT": 200000, "BE": 200000, "BR": 200000, "CL": 200000, "CN": 200000, "CO": 200000, "HR": 200000, "DK": 200000, "DO": 200000, "EG": 200000, "FI": 200000, "FR": 200000, "DE": 200000, "GR": 200000, "HK": 200000, "IN": 200000, "ID": 200000, "IE": 200000, "IL": 200000, "IT": 200000, "JP": 200000, "JO": 200000, "KW": 200000, "LB": 200000, "MY": 200000, "MX": 200000, "NL": 200000, "NZ": 200000, "NG": 200000, "NO": 200000, "PK": 200000, "PA": 200000, "PE": 200000, "PH": 200000, "PL": 200000, "RU": 200000, "SA": 200000, "RS": 200000, "SG": 200000, "ZA": 200000, "KR": 200000, "ES": 200000, "SE": 200000, "CH": 200000, "TW": 200000, "TH": 200000, "TR": 200000, "AE": 200000, "VE": 200000, "PT": 200000, "LU": 200000, "BG": 200000, "CZ": 200000, "SI": 200000, "IS": 200000, "SK": 200000, "LT": 200000, "TT": 200000, "BD": 200000, "LK": 200000, "KE": 200000, "HU": 200000, "MA": 200000, "CY": 200000, "JM": 200000, "EC": 200000, "RO": 200000, "BO": 200000, "GT": 200000, "CR": 200000, "QA": 200000, "SV": 200000, "HN": 200000, "NI": 200000, "PY": 200000, "UY": 200000, "PR": 200000, "BA": 200000, "PS": 200000, "TN": 200000, "BH": 200000, "VN": 200000, "GH": 200000, "MU": 200000, "UA": 200000, "MT": 200000, "BS": 200000, "MV": 200000, "OM": 200000, "MK": 200000, "LV": 200000, "EE": 200000, "IQ": 200000, "DZ": 200000, "AL": 200000, "NP": 200000, "MO": 200000, "ME": 200000, "SN": 200000, "GE": 200000, "BN": 200000, "UG": 200000, "GP": 200000, "BB": 200000, "AZ": 200000, "TZ": 200000, "LY": 200000, "MQ": 200000, "CM": 200000, "BW": 200000, "ET": 200000, "KZ": 200000, "NA": 200000, "MG": 200000, "NC": 200000, "MD": 200000, "FJ": 200000, "BY": 200000, "JE": 200000, "GU": 200000, "YE": 200000, "ZM": 200000, "IM": 200000, "HT": 200000, "KH": 200000, "AW": 200000, "PF": 200000, "AF": 200000, "BM": 200000, "GY": 200000, "AM": 200000, "MW": 200000, "AG": 200000, "RW": 200000, "GG": 200000, "GM": 200000, "FO": 200000, "LC": 200000, "KY": 200000, "BJ": 200000, "AD": 200000, "GD": 200000, "VI": 200000, "BZ": 200000, "VC": 200000, "MN": 200000, "MZ": 200000, "ML": 200000, "AO": 200000, "GF": 200000, "UZ": 200000, "DJ": 200000, "BF": 200000, "MC": 200000, "TG": 200000, "GL": 200000, "GA": 200000, "GI": 200000, "CD": 200000, "KG": 200000, "PG": 200000, "BT": 200000, "KN": 200000, "SZ": 200000, "LS": 200000, "LA": 200000, "LI": 200000, "MP": 200000, "SR": 200000, "SC": 200000, "VG": 200000, "TC": 200000, "DM": 200000, "MR": 200000, "AX": 200000, "SM": 200000, "SL": 200000, "NE": 200000, "CG": 200000, "AI": 200000, "YT": 200000, "CV": 200000, "GN": 200000, "TM": 200000, "BI": 200000, "TJ": 200000, "VU": 200000, "SB": 200000, "ER": 200000, "WS": 200000, "AS": 200000, "FK": 200000, "GQ": 200000, "TO": 200000, "KM": 200000, "PW": 200000, "FM": 200000, "CF": 200000, "SO": 200000, "MH": 200000, "VA": 200000, "TD": 200000, "KI": 200000, "ST": 200000, "TV": 200000, "NR": 200000, "RE": 200000, "LR": 200000, "ZW": 200000, "CI": 200000, "MM": 200000, "AN": 200000, "AQ": 200000, "BQ": 200000, "BV": 200000, "IO": 200000, "CX": 200000, "CC": 200000, "CK": 200000, "CW": 200000, "TF": 200000, "GW": 200000, "HM": 200000, "XK": 200000, "MS": 200000, "NU": 200000, "NF": 200000, "PN": 200000, "BL": 200000, "SH": 200000, "MF": 200000, "PM": 200000, "SX": 200000, "GS": 200000, "SS": 200000, "SJ": 200000, "TL": 200000, "TK": 200000, "UM": 200000, "WF": 200000, "EH": 200000}, "countries": ["US", "CA", "GB", "AR", "AU", "AT", "BE", "BR", "CL", "CN", "CO", "HR", "DK", "DO", "EG", "FI", "FR", "DE", "GR", "HK", "IN", "ID", "IE", "IL", "IT", "JP", "JO", "KW", "LB", "MY", "MX", "NL", "NZ", "NG", "NO", "PK", "PA", "PE", "PH", "PL", "RU", "SA", "RS", "SG", "ZA", "KR", "ES", "SE", "CH", "TW", "TH", "TR", "AE", "VE", "PT", "LU", "BG", "CZ", "SI", "IS", "SK", "LT", "TT", "BD", "LK", "KE", "HU", "MA", "CY", "JM", "EC", "RO", "BO", "GT", "CR", "QA", "SV", "HN", "NI", "PY", "UY", "PR", "BA", "PS", "TN", "BH", "VN", "GH", "MU", "UA", "MT", "BS", "MV", "OM", "MK", "EE", "LV", "IQ", "DZ", "AL", "NP", "MO", "ME", "SN", "GE", "BN", "UG", "GP", "BB", "ZW", "CI", "AZ", "TZ", "LY", "MQ", "MM", "CM", "BW", "ET", "KZ", "NA", "MG", "NC", "MD", "FJ", "BY", "JE", "GU", "YE", "ZM", "IM", "HT", "KH", "AW", "PF", "AF", "BM", "GY", "AM", "MW", "AG", "RW", "GG", "GM", "FO", "LC", "KY", "BJ", "AD", "GD", "VI", "BZ", "VC", "MN", "MZ", "ML", "AO", "GF", "UZ", "DJ", "BF", "MC", "TG", "GL", "GA", "GI", "CD", "KG", "PG", "BT", "KN", "SZ", "LS", "LA", "LI", "MP", "SR", "SC", "VG", "TC", "DM", "MR", "AX", "SM", "SL", "NE", "CG", "AI", "YT", "LR", "CV", "GN", "TM", "BI", "TJ", "VU", "SB", "ER", "WS", "AS", "FK", "GQ", "TO", "KM", "PW", "FM", "CF", "SO", "MH", "VA", "TD", "KI", "ST", "TV", "NR", "RE", "AN", "AQ", "BQ", "BV", "IO", "CX", "CC", "CK", "CW", "TF", "GW", "HM", "XK", "MS", "NU", "NF", "PN", "BL", "SH", "MF", "PM", "SX", "GS", "SS", "SJ", "TL", "TK", "UM", "WF", "EH"], "min_campaign_duration": {"US": 1, "CA": 1, "GB": 1, "AR": 1, "AU": 1, "AT": 1, "BE": 1, "BR": 1, "CL": 1, "CN": 1, "CO": 1, "HR": 1, "DK": 1, "DO": 1, "EG": 1, "FI": 1, "FR": 1, "DE": 1, "GR": 1, "HK": 1, "IN": 1, "ID": 1, "IE": 1, "IL": 1, "IT": 1, "JP": 1, "JO": 1, "KW": 1, "LB": 1, "MY": 1, "MX": 1, "NL": 1, "NZ": 1, "NG": 1, "NO": 1, "PK": 1, "PA": 1, "PE": 1, "PH": 1, "PL": 1, "RU": 1, "SA": 1, "RS": 1, "SG": 1, "ZA": 1, "KR": 1, "ES": 1, "SE": 1, "CH": 1, "TW": 1, "TH": 1, "TR": 1, "AE": 1, "VE": 1, "PT": 1, "LU": 1, "BG": 1, "CZ": 1, "SI": 1, "IS": 1, "SK": 1, "LT": 1, "TT": 1, "BD": 1, "LK": 1, "KE": 1, "HU": 1, "MA": 1, "CY": 1, "JM": 1, "EC": 1, "RO": 1, "BO": 1, "GT": 1, "CR": 1, "QA": 1, "SV": 1, "HN": 1, "NI": 1, "PY": 1, "UY": 1, "PR": 1, "BA": 1, "PS": 1, "TN": 1, "BH": 1, "VN": 1, "GH": 1, "MU": 1, "UA": 1, "MT": 1, "BS": 1, "MV": 1, "OM": 1, "MK": 1, "LV": 1, "EE": 1, "IQ": 1, "DZ": 1, "AL": 1, "NP": 1, "MO": 1, "ME": 1, "SN": 1, "GE": 1, "BN": 1, "UG": 1, "GP": 1, "BB": 1, "AZ": 1, "TZ": 1, "LY": 1, "MQ": 1, "CM": 1, "BW": 1, "ET": 1, "KZ": 1, "NA": 1, "MG": 1, "NC": 1, "MD": 1, "FJ": 1, "BY": 1, "JE": 1, "GU": 1, "YE": 1, "ZM": 1, "IM": 1, "HT": 1, "KH": 1, "AW": 1, "PF": 1, "AF": 1, "BM": 1, "GY": 1, "AM": 1, "MW": 1, "AG": 1, "RW": 1, "GG": 1, "GM": 1, "FO": 1, "LC": 1, "KY": 1, "BJ": 1, "AD": 1, "GD": 1, "VI": 1, "BZ": 1, "VC": 1, "MN": 1, "MZ": 1, "ML": 1, "AO": 1, "GF": 1, "UZ": 1, "DJ": 1, "BF": 1, "MC": 1, "TG": 1, "GL": 1, "GA": 1, "GI": 1, "CD": 1, "KG": 1, "PG": 1, "BT": 1, "KN": 1, "SZ": 1, "LS": 1, "LA": 1, "LI": 1, "MP": 1, "SR": 1, "SC": 1, "VG": 1, "TC": 1, "DM": 1, "MR": 1, "AX": 1, "SM": 1, "SL": 1, "NE": 1, "CG": 1, "AI": 1, "YT": 1, "CV": 1, "GN": 1, "TM": 1, "BI": 1, "TJ": 1, "VU": 1, "SB": 1, "ER": 1, "WS": 1, "AS": 1, "FK": 1, "GQ": 1, "TO": 1, "KM": 1, "PW": 1, "FM": 1, "CF": 1, "SO": 1, "MH": 1, "VA": 1, "TD": 1, "KI": 1, "ST": 1, "TV": 1, "NR": 1, "RE": 1, "LR": 1, "ZW": 1, "CI": 1, "MM": 1, "AN": 1, "AQ": 1, "BQ": 1, "BV": 1, "IO": 1, "CX": 1, "CC": 1, "CK": 1, "CW": 1, "TF": 1, "GW": 1, "HM": 1, "XK": 1, "MS": 1, "NU": 1, "NF": 1, "PN": 1, "BL": 1, "SH": 1, "MF": 1, "PM": 1, "SX": 1, "GS": 1, "SS": 1, "SJ": 1, "TL": 1, "TK": 1, "UM": 1, "WF": 1, "EH": 1}, "max_campaign_duration": {"US": 90, "CA": 90, "GB": 90, "AR": 90, "AU": 90, "AT": 90, "BE": 90, "BR": 90, "CL": 90, "CN": 90, "CO": 90, "HR": 90, "DK": 90, "DO": 90, "EG": 90, "FI": 90, "FR": 90, "DE": 90, "GR": 90, "HK": 90, "IN": 90, "ID": 90, "IE": 90, "IL": 90, "IT": 90, "JP": 90, "JO": 90, "KW": 90, "LB": 90, "MY": 90, "MX": 90, "NL": 90, "NZ": 90, "NG": 90, "NO": 90, "PK": 90, "PA": 90, "PE": 90, "PH": 90, "PL": 90, "RU": 90, "SA": 90, "RS": 90, "SG": 90, "ZA": 90, "KR": 90, "ES": 90, "SE": 90, "CH": 90, "TW": 90, "TH": 90, "TR": 90, "AE": 90, "VE": 90, "PT": 90, "LU": 90, "BG": 90, "CZ": 90, "SI": 90, "IS": 90, "SK": 90, "LT": 90, "TT": 90, "BD": 90, "LK": 90, "KE": 90, "HU": 90, "MA": 90, "CY": 90, "JM": 90, "EC": 90, "RO": 90, "BO": 90, "GT": 90, "CR": 90, "QA": 90, "SV": 90, "HN": 90, "NI": 90, "PY": 90, "UY": 90, "PR": 90, "BA": 90, "PS": 90, "TN": 90, "BH": 90, "VN": 90, "GH": 90, "MU": 90, "UA": 90, "MT": 90, "BS": 90, "MV": 90, "OM": 90, "MK": 90, "LV": 90, "EE": 90, "IQ": 90, "DZ": 90, "AL": 90, "NP": 90, "MO": 90, "ME": 90, "SN": 90, "GE": 90, "BN": 90, "UG": 90, "GP": 90, "BB": 90, "AZ": 90, "TZ": 90, "LY": 90, "MQ": 90, "CM": 90, "BW": 90, "ET": 90, "KZ": 90, "NA": 90, "MG": 90, "NC": 90, "MD": 90, "FJ": 90, "BY": 90, "JE": 90, "GU": 90, "YE": 90, "ZM": 90, "IM": 90, "HT": 90, "KH": 90, "AW": 90, "PF": 90, "AF": 90, "BM": 90, "GY": 90, "AM": 90, "MW": 90, "AG": 90, "RW": 90, "GG": 90, "GM": 90, "FO": 90, "LC": 90, "KY": 90, "BJ": 90, "AD": 90, "GD": 90, "VI": 90, "BZ": 90, "VC": 90, "MN": 90, "MZ": 90, "ML": 90, "AO": 90, "GF": 90, "UZ": 90, "DJ": 90, "BF": 90, "MC": 90, "TG": 90, "GL": 90, "GA": 90, "GI": 90, "CD": 90, "KG": 90, "PG": 90, "BT": 90, "KN": 90, "SZ": 90, "LS": 90, "LA": 90, "LI": 90, "MP": 90, "SR": 90, "SC": 90, "VG": 90, "TC": 90, "DM": 90, "MR": 90, "AX": 90, "SM": 90, "SL": 90, "NE": 90, "CG": 90, "AI": 90, "YT": 90, "CV": 90, "GN": 90, "TM": 90, "BI": 90, "TJ": 90, "VU": 90, "SB": 90, "ER": 90, "WS": 90, "AS": 90, "FK": 90, "GQ": 90, "TO": 90, "KM": 90, "PW": 90, "FM": 90, "CF": 90, "SO": 90, "MH": 90, "VA": 90, "TD": 90, "KI": 90, "ST": 90, "TV": 90, "NR": 90, "RE": 90, "LR": 90, "ZW": 90, "CI": 90, "MM": 90, "AN": 90, "AQ": 90, "BQ": 90, "BV": 90, "IO": 90, "CX": 90, "CC": 90, "CK": 90, "CW": 90, "TF": 90, "GW": 90, "HM": 90, "XK": 90, "MS": 90, "NU": 90, "NF": 90, "PN": 90, "BL": 90, "SH": 90, "MF": 90, "PM": 90, "SX": 90, "GS": 90, "SS": 90, "SJ": 90, "TL": 90, "TK": 90, "UM": 90, "WF": 90, "EH": 90}, "max_days_to_finish": {"US": 180, "CA": 180, "GB": 180, "AR": 180, "AU": 180, "AT": 180, "BE": 180, "BR": 180, "CL": 180, "CN": 180, "CO": 180, "HR": 180, "DK": 180, "DO": 180, "EG": 180, "FI": 180, "FR": 180, "DE": 180, "GR": 180, "HK": 180, "IN": 180, "ID": 180, "IE": 180, "IL": 180, "IT": 180, "JP": 180, "JO": 180, "KW": 180, "LB": 180, "MY": 180, "MX": 180, "NL": 180, "NZ": 180, "NG": 180, "NO": 180, "PK": 180, "PA": 180, "PE": 180, "PH": 180, "PL": 180, "RU": 180, "SA": 180, "RS": 180, "SG": 180, "ZA": 180, "KR": 180, "ES": 180, "SE": 180, "CH": 180, "TW": 180, "TH": 180, "TR": 180, "AE": 180, "VE": 180, "PT": 180, "LU": 180, "BG": 180, "CZ": 180, "SI": 180, "IS": 180, "SK": 180, "LT": 180, "TT": 180, "BD": 180, "LK": 180, "KE": 180, "HU": 180, "MA": 180, "CY": 180, "JM": 180, "EC": 180, "RO": 180, "BO": 180, "GT": 180, "CR": 180, "QA": 180, "SV": 180, "HN": 180, "NI": 180, "PY": 180, "UY": 180, "PR": 180, "BA": 180, "PS": 180, "TN": 180, "BH": 180, "VN": 180, "GH": 180, "MU": 180, "UA": 180, "MT": 180, "BS": 180, "MV": 180, "OM": 180, "MK": 180, "LV": 180, "EE": 180, "IQ": 180, "DZ": 180, "AL": 180, "NP": 180, "MO": 180, "ME": 180, "SN": 180, "GE": 180, "BN": 180, "UG": 180, "GP": 180, "BB": 180, "AZ": 180, "TZ": 180, "LY": 180, "MQ": 180, "CM": 180, "BW": 180, "ET": 180, "KZ": 180, "NA": 180, "MG": 180, "NC": 180, "MD": 180, "FJ": 180, "BY": 180, "JE": 180, "GU": 180, "YE": 180, "ZM": 180, "IM": 180, "HT": 180, "KH": 180, "AW": 180, "PF": 180, "AF": 180, "BM": 180, "GY": 180, "AM": 180, "MW": 180, "AG": 180, "RW": 180, "GG": 180, "GM": 180, "FO": 180, "LC": 180, "KY": 180, "BJ": 180, "AD": 180, "GD": 180, "VI": 180, "BZ": 180, "VC": 180, "MN": 180, "MZ": 180, "ML": 180, "AO": 180, "GF": 180, "UZ": 180, "DJ": 180, "BF": 180, "MC": 180, "TG": 180, "GL": 180, "GA": 180, "GI": 180, "CD": 180, "KG": 180, "PG": 180, "BT": 180, "KN": 180, "SZ": 180, "LS": 180, "LA": 180, "LI": 180, "MP": 180, "SR": 180, "SC": 180, "VG": 180, "TC": 180, "DM": 180, "MR": 180, "AX": 180, "SM": 180, "SL": 180, "NE": 180, "CG": 180, "AI": 180, "YT": 180, "CV": 180, "GN": 180, "TM": 180, "BI": 180, "TJ": 180, "VU": 180, "SB": 180, "ER": 180, "WS": 180, "AS": 180, "FK": 180, "GQ": 180, "TO": 180, "KM": 180, "PW": 180, "FM": 180, "CF": 180, "SO": 180, "MH": 180, "VA": 180, "TD": 180, "KI": 180, "ST": 180, "TV": 180, "NR": 180, "RE": 180, "LR": 180, "ZW": 180, "CI": 180, "MM": 180, "AN": 180, "AQ": 180, "BQ": 180, "BV": 180, "IO": 180, "CX": 180, "CC": 180, "CK": 180, "CW": 180, "TF": 180, "GW": 180, "HM": 180, "XK": 180, "MS": 180, "NU": 180, "NF": 180, "PN": 180, "BL": 180, "SH": 180, "MF": 180, "PM": 180, "SX": 180, "GS": 180, "SS": 180, "SJ": 180, "TL": 180, "TK": 180, "UM": 180, "WF": 180, "EH": 180}, "global_io_max_campaign_duration": 100}, "spend_cap": "0", "tax_id_status": 0.0, "tax_id_type": "0", "timezone_id": 1.0, "timezone_name": "America/Los_Angeles", "timezone_offset_hours_utc": -8.0, "tos_accepted": {"web_custom_audience_tos": 1}, "user_tasks": ["DRAFT", "ANALYZE", "ADVERTISE", "MANAGE"]}, "emitted_at": 1708350623793} {"stream": "ads", "data": {"id": "23853620229650398", "bid_type": "ABSOLUTE_OCPM", "account_id": "212551616838260", "campaign_id": "23853619670350398", "adset_id": "23853619670380398", "status": "ACTIVE", "creative": {"id": "23853666124230398"}, "updated_time": "2023-03-21T22:41:46-0700", "created_time": "2023-03-17T08:04:31-0700", "name": "With The Highest Standard for Reliability", "targeting": {"age_max": 60, "age_min": 18, "custom_audiences": [{"id": "23853630753300398", "name": "Lookalike (US, 10%) - Airbyte Cloud Users"}, {"id": "23853683587660398", "name": "Web Traffic [ALL] - _copy"}], "geo_locations": {"countries": ["US"], "location_types": ["home", "recent"]}, "brand_safety_content_filter_levels": ["FACEBOOK_STANDARD", "AN_STANDARD"], "targeting_relaxation_types": {"lookalike": 1, "custom_audience": 1}, "publisher_platforms": ["facebook", "instagram", "audience_network", "messenger"], "facebook_positions": ["feed", "biz_disco_feed", "facebook_reels", "facebook_reels_overlay", "right_hand_column", "video_feeds", "instant_article", "instream_video", "marketplace", "story", "search"], "instagram_positions": ["stream", "story", "explore", "reels", "shop", "explore_home", "profile_feed"], "device_platforms": ["mobile", "desktop"], "messenger_positions": ["story"], "audience_network_positions": ["classic", "instream_video", "rewarded_video"]}, "effective_status": "ACTIVE", "last_updated_by_app_id": "119211728144504", "source_ad_id": "0", "tracking_specs": [{"action.type": ["offsite_conversion"], "fb_pixel": ["917042523049733"]}, {"action.type": ["link_click"], "post": ["662226902575095"], "post.wall": ["112704783733939"]}, {"action.type": ["post_engagement"], "page": ["112704783733939"], "post": ["662226902575095"]}], "conversion_specs": [{"action.type": ["offsite_conversion"], "conversion_id": ["6015304265216283"]}]}, "emitted_at": 1707135365030} {"stream": "ad_sets", "data": {"id": "23853619670380398", "name": "Lookalike audience_Free Connector Program", "promoted_object": {"pixel_id": "917042523049733", "custom_event_type": "COMPLETE_REGISTRATION"}, "account_id": "212551616838260", "updated_time": "2023-03-21T14:20:51-0700", "daily_budget": 2000.0, "budget_remaining": 2000.0, "effective_status": "ACTIVE", "campaign_id": "23853619670350398", "created_time": "2023-03-17T08:04:28-0700", "start_time": "2023-03-17T08:04:28-0700", "lifetime_budget": 0.0, "targeting": {"age_max": 60, "age_min": 18, "custom_audiences": [{"id": "23853630753300398", "name": "Lookalike (US, 10%) - Airbyte Cloud Users"}, {"id": "23853683587660398", "name": "Web Traffic [ALL] - _copy"}], "geo_locations": {"countries": ["US"], "location_types": ["home", "recent"]}, "brand_safety_content_filter_levels": ["FACEBOOK_STANDARD", "AN_STANDARD"], "targeting_relaxation_types": {"lookalike": 1, "custom_audience": 1}, "publisher_platforms": ["facebook", "instagram", "audience_network", "messenger"], "facebook_positions": ["feed", "biz_disco_feed", "facebook_reels", "facebook_reels_overlay", "right_hand_column", "video_feeds", "instant_article", "instream_video", "marketplace", "story", "search"], "instagram_positions": ["stream", "story", "explore", "reels", "shop", "explore_home", "profile_feed"], "device_platforms": ["mobile", "desktop"], "messenger_positions": ["story"], "audience_network_positions": ["classic", "instream_video", "rewarded_video"]}, "bid_strategy": "LOWEST_COST_WITHOUT_CAP"}, "emitted_at": 1707135364623} -{"stream":"campaigns","data":{"id":"23846542053890398","account_id":"212551616838260","budget_rebalance_flag":false,"budget_remaining":0.0,"buying_type":"AUCTION","created_time":"2021-01-18T21:36:42-0800","configured_status":"PAUSED","effective_status":"PAUSED","name":"Fake Campaign 0","objective":"MESSAGES","smart_promotion_type":"GUIDED_CREATION","source_campaign_id":0.0,"special_ad_category":"NONE","start_time":"1969-12-31T15:59:59-0800","status":"PAUSED","updated_time":"2021-02-18T01:00:02-0800"},"emitted_at":1694795155769} +{"stream": "campaigns", "data": {"id": "23846542053890398", "account_id": "212551616838260", "budget_rebalance_flag": false, "budget_remaining": 0.0,"buying_type": "AUCTION", "created_time": "2021-01-18T21:36:42-0800", "configured_status": "PAUSED", "effective_status": "PAUSED", "name": "Fake Campaign 0", "objective": "MESSAGES", "smart_promotion_type": "GUIDED_CREATION", "source_campaign_id": 0.0, "special_ad_category": "NONE", "start_time": "1969-12-31T15:59:59-0800", "status": "PAUSED", "updated_time": "2021-02-18T01:00:02-0800"}, "emitted_at": 1694795155769} {"stream": "custom_audiences", "data": {"id": "23853683587660398", "account_id": "212551616838260", "approximate_count_lower_bound": 4700, "approximate_count_upper_bound": 5500, "customer_file_source": "PARTNER_PROVIDED_ONLY", "data_source": {"type": "UNKNOWN", "sub_type": "ANYTHING", "creation_params": "[]"}, "delivery_status": {"code": 200, "description": "This audience is ready for use."}, "description": "Custom Audience-Web Traffic [ALL] - _copy", "is_value_based": false, "name": "Web Traffic [ALL] - _copy", "operation_status": {"code": 200, "description": "Normal"}, "permission_for_actions": {"can_edit": true, "can_see_insight": "True", "can_share": "True", "subtype_supports_lookalike": "True", "supports_recipient_lookalike": "False"}, "retention_days": 0, "subtype": "CUSTOM", "time_content_updated": 1679433484, "time_created": 1679433479, "time_updated": 1679433484}, "emitted_at": 1698925454024} {"stream": "ad_creatives", "data": {"id": "23853630774830398", "body": "Until a connector meets our GA reliability standards, you don't pay for it.", "image_url": "https://scontent.fiev6-1.fna.fbcdn.net/v/t45.1600-4/333773383_23853620180320398_4214441850420455541_n.png?_nc_cat=109&ccb=1-7&_nc_sid=c0a1f7&_nc_ohc=qbTWMi-gWi8AX8hFZLQ&_nc_ht=scontent.fiev6-1.fna&edm=ALjApogEAAAA&oh=00_AfC9KndALRjbR5Z4Xz_ZytJTb9rsS_S4_SDvmiegih69vQ&oe=65C8B50F", "account_id": "212551616838260", "actor_id": "112704783733939", "asset_feed_spec": {"bodies": [{"text": "Until a connector meets our GA reliability standards, you don't pay for it."}, {"text": "Reliability is the cornerstone of having an ELT tool you trust."}, {"text": "Don't compromise between cost and connector reliability."}, {"text": "Limitless data movement with free Alpha and Beta connectors"}], "descriptions": [{"text": "Until a connector meets our GA reliability standards, you don't pay for it. "}], "titles": [{"text": "Introducing: our free connector program"}], "optimization_type": "DEGREES_OF_FREEDOM"}, "call_to_action_type": "SIGN_UP", "effective_instagram_story_id": "5605802859523550", "effective_object_story_id": "112704783733939_660115876119531", "title": "Introducing: our free connector program", "name": "Introducing: our free connector program 2023-03-17-ccf7ed52a98e5e699299861a8a323194", "instagram_actor_id": "2185696824778148", "instagram_permalink_url": "https://www.instagram.com/p/Cp5PgWrjU8V/", "object_story_spec": {"page_id": "112704783733939", "instagram_actor_id": "2185696824778148", "link_data": {"link": "https://airbyte.com/free-connector-program?utm_medium=paid_social&utm_source=facebook&utm_campaign=q1_freeconnectorprogram_t", "image_hash": "970937d2f16de20c0a99e598aa876ac0", "call_to_action": {"type": "SIGN_UP"}}}, "object_type": "SHARE", "status": "ACTIVE", "thumbnail_url": "https://external.fiev6-1.fna.fbcdn.net/emg1/v/t13/8568826884261823966?url=https%3A%2F%2Fwww.facebook.com%2Fads%2Fimage%2F%3Fd%3DAQL3nBsTZ0CoQ_uD_vAVwqZKjwi7X3zsqa8EbE4S1aY7w8cjJ7x6BihYqZkQTgC3BzwY5Y_dxv11UvkOL0cMER5tPch9x6_Q2p3xtHYED2DHLT6v9o9CnYB8S5FMSQ91vMBQCbLFVHh_bSr0OT_4bW4V&fb_obo=1&utld=facebook.com&stp=c0.5000x0.5000f_dst-emg0_p64x64_q75&ccb=13-1&oh=06_AbE-j6xf-dGVCh9dJcOJdFM5v4Sydw74rDQJWynPZayneA&oe=65C511DE&_nc_sid=58080a", "image_hash": "970937d2f16de20c0a99e598aa876ac0"}, "emitted_at": 1707288372517} -{"stream":"activities","data":{"account_id":"212551616838260","actor_id":"122043039268043192","actor_name":"Payments RTU Processor","application_id":"0","date_time_in_timezone":"03/13/2023 at 6:30 AM","event_time":"2023-03-13T13:30:47+0000","event_type":"ad_account_billing_charge","extra_data":"{\"currency\":\"USD\",\"new_value\":1188,\"transaction_id\":\"5885578541558696-11785530\",\"action\":67,\"type\":\"payment_amount\"}","object_id":"212551616838260","object_name":"Airbyte","object_type":"ACCOUNT","translated_event_type":"Account billed"},"emitted_at":1696931251153} -{"stream":"custom_conversions","data":{"id":"694166388077667","account_id":"212551616838260","creation_time":"2020-04-22T01:36:00+0000","custom_event_type":"CONTACT","data_sources":[{"id":"2667253716886462","source_type":"PIXEL","name":"Dataline's Pixel"}],"default_conversion_value":0,"event_source_type":"pixel","is_archived":true,"is_unavailable":false,"name":"SubscribedButtonClick","retention_days":0,"rule":"{\"and\":[{\"event\":{\"eq\":\"PageView\"}},{\"or\":[{\"URL\":{\"i_contains\":\"SubscribedButtonClick\"}}]}]}"},"emitted_at":1692180839174} -{"stream":"images","data":{"id":"212551616838260:c1e94a8768a405f0f212d71fe8336647","account_id":"212551616838260","name":"Audience_1_Ad_3_1200x1200_blue_CTA_arrow.png_105","creatives":["23853630775340398","23853630871360398","23853666124200398"],"original_height":1200,"original_width":1200,"permalink_url":"https://www.facebook.com/ads/image/?d=AQIDNjjLb7VzVJ26jXb_HpudCEUJqbV_lLF2JVsdruDcBxnXQEKfzzd21VVJnkm0B-JLosUXNNg1BH78y7FxnK3AH-0D_lnk7kn39_bIcOMK7Z9HYyFInfsVY__adup3A5zGTIcHC9Y98Je5qK-yD8F6","status":"ACTIVE","url":"https://scontent-dus1-1.xx.fbcdn.net/v/t45.1600-4/335907140_23853620220420398_4375584095210967511_n.png?_nc_cat=104&ccb=1-7&_nc_sid=2aac32&_nc_ohc=xdjrPpbRGNAAX8Dck01&_nc_ht=scontent-dus1-1.xx&edm=AJcBmwoEAAAA&oh=00_AfDCqQ6viqrgLcfbO3O5-n030Usq7Zyt2c1TmsatqnYf7Q&oe=64E2779A","created_time":"2023-03-16T13:13:17-0700","hash":"c1e94a8768a405f0f212d71fe8336647","url_128":"https://scontent-dus1-1.xx.fbcdn.net/v/t45.1600-4/335907140_23853620220420398_4375584095210967511_n.png?stp=dst-png_s128x128&_nc_cat=104&ccb=1-7&_nc_sid=2aac32&_nc_ohc=xdjrPpbRGNAAX8Dck01&_nc_ht=scontent-dus1-1.xx&edm=AJcBmwoEAAAA&oh=00_AfAY50CMpox2s4w_f18IVx7sZuXlg4quF6YNIJJ8D4PZew&oe=64E2779A","is_associated_creatives_in_adgroups":true,"updated_time":"2023-03-17T08:09:56-0700","height":1200,"width":1200},"emitted_at":1692180839582} -{"stream":"ads_insights","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","actions":[{"action_destination":"244953057175777","action_target_id":"244953057175777","action_type":"page_engagement","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0},{"action_destination":"244953057175777","action_target_id":"244953057175777","action_type":"post_engagement","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0},{"action_destination":"244953057175777","action_target_id":"244953057175777","action_type":"link_click","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0}],"ad_id":"23846765228310398","ad_name":"Airbyte Ad","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":3,"conversion_rate_ranking":"UNKNOWN","cost_per_estimated_ad_recallers":0.007,"cost_per_inline_link_click":0.396667,"cost_per_inline_post_engagement":0.396667,"cost_per_unique_click":0.396667,"cost_per_unique_inline_link_click":0.396667,"cpc":0.396667,"cpm":0.902199,"cpp":0.948207,"created_time":"2021-02-09","ctr":0.227445,"date_start":"2021-02-15","date_stop":"2021-02-15","engagement_rate_ranking":"UNKNOWN","estimated_ad_recall_rate":13.545817,"estimated_ad_recallers":170.0,"frequency":1.050996,"impressions":1319,"inline_link_click_ctr":0.227445,"inline_link_clicks":3,"inline_post_engagement":3,"instant_experience_clicks_to_open":1.0,"instant_experience_clicks_to_start":1.0,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","outbound_clicks":[{"action_destination":"244953057175777","action_target_id":"244953057175777","action_type":"outbound_click","value":3.0}],"quality_ranking":"UNKNOWN","reach":1255,"social_spend":0.0,"spend":1.19,"unique_actions":[{"action_destination":"244953057175777","action_target_id":"244953057175777","action_type":"page_engagement","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0},{"action_destination":"244953057175777","action_target_id":"244953057175777","action_type":"post_engagement","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0},{"action_destination":"244953057175777","action_target_id":"244953057175777","action_type":"link_click","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0}],"unique_clicks":3,"unique_ctr":0.239044,"unique_inline_link_click_ctr":0.239044,"unique_inline_link_clicks":3,"unique_link_clicks_ctr":0.239044,"unique_outbound_clicks":[{"action_destination":"244953057175777","action_target_id":"244953057175777","action_type":"outbound_click","value":3.0}],"updated_time":"2021-08-27","video_play_curve_actions":[{"action_type":"video_view"}],"website_ctr":[{"action_type":"link_click","value":0.227445}],"wish_bid":0.0},"emitted_at":1682686057366} -{"stream":"ads_insights_action_carousel_card","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846765228310398","ad_name":"Airbyte Ad","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":3,"conversion_rate_ranking":"UNKNOWN","cost_per_estimated_ad_recallers":0.007,"cost_per_inline_link_click":0.396667,"cost_per_inline_post_engagement":0.396667,"cost_per_unique_click":0.396667,"cost_per_unique_inline_link_click":0.396667,"cpc":0.396667,"cpm":0.902199,"cpp":0.948207,"created_time":"2021-02-09","ctr":0.227445,"date_start":"2021-02-15","date_stop":"2021-02-15","engagement_rate_ranking":"UNKNOWN","estimated_ad_recall_rate":13.545817,"estimated_ad_recallers":170.0,"frequency":1.050996,"impressions":1319,"inline_link_click_ctr":0.227445,"inline_post_engagement":3,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","quality_ranking":"UNKNOWN","reach":1255,"social_spend":0.0,"spend":1.19,"unique_actions":[{"action_type":"page_engagement","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0},{"action_type":"post_engagement","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0},{"action_type":"link_click","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0}],"unique_clicks":3,"unique_ctr":0.239044,"unique_inline_link_click_ctr":0.239044,"unique_inline_link_clicks":3,"updated_time":"2021-08-27","video_play_curve_actions":[{"action_type":"video_view"}],"website_ctr":[{"action_type":"link_click","value":0.227445}],"wish_bid":0.0},"emitted_at":1692180857757} -{"stream":"ads_insights_action_conversion_device","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":0,"cost_per_estimated_ad_recallers":0.004,"cpm":0.754717,"cpp":0.784314,"created_time":"2021-02-11","ctr":0.0,"date_start":"2021-02-15","date_stop":"2021-02-15","estimated_ad_recall_rate":19.607843,"estimated_ad_recallers":10.0,"frequency":1.039216,"impressions":53,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":51,"spend":0.04,"unique_clicks":0,"updated_time":"2021-08-27","device_platform":"desktop"},"emitted_at":1696936270620} -{"stream":"ads_insights_action_reaction","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":1,"conversion_rate_ranking":"UNKNOWN","cost_per_estimated_ad_recallers":0.008889,"cost_per_unique_click":0.8,"cpc":0.8,"cpm":1.255887,"cpp":1.296596,"created_time":"2021-02-11","ctr":0.156986,"date_start":"2021-02-14","date_stop":"2021-02-14","engagement_rate_ranking":"UNKNOWN","estimated_ad_recall_rate":14.58671,"estimated_ad_recallers":90.0,"frequency":1.032415,"impressions":637,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","quality_ranking":"UNKNOWN","reach":617,"social_spend":0.0,"spend":0.8,"unique_clicks":1,"unique_ctr":0.162075,"updated_time":"2021-08-27","video_play_curve_actions":[{"action_type":"video_view"}],"wish_bid":0.0},"emitted_at":1696936287351} -{"stream":"ads_insights_action_type","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":1,"conversion_rate_ranking":"UNKNOWN","cost_per_estimated_ad_recallers":0.008889,"cost_per_unique_click":0.8,"cpc":0.8,"cpm":1.255887,"cpp":1.296596,"created_time":"2021-02-11","ctr":0.156986,"date_start":"2021-02-14","date_stop":"2021-02-14","engagement_rate_ranking":"UNKNOWN","estimated_ad_recall_rate":14.58671,"estimated_ad_recallers":90.0,"frequency":1.032415,"impressions":637,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","quality_ranking":"UNKNOWN","reach":617,"social_spend":0.0,"spend":0.8,"unique_clicks":1,"unique_ctr":0.162075,"updated_time":"2021-08-27","video_play_curve_actions":[{"action_type":"video_view"}],"wish_bid":0.0},"emitted_at":1696936315908} -{"stream":"ads_insights_action_video_sound","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":1,"conversion_rate_ranking":"UNKNOWN","cost_per_estimated_ad_recallers":0.008889,"cost_per_unique_click":0.8,"cpc":0.8,"cpm":1.255887,"cpp":1.296596,"created_time":"2021-02-11","ctr":0.156986,"date_start":"2021-02-14","date_stop":"2021-02-14","engagement_rate_ranking":"UNKNOWN","estimated_ad_recall_rate":14.58671,"estimated_ad_recallers":90.0,"frequency":1.032415,"impressions":637,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","quality_ranking":"UNKNOWN","reach":617,"social_spend":0.0,"spend":0.8,"unique_clicks":1,"unique_ctr":0.162075,"updated_time":"2021-08-27","video_play_curve_actions": [{"action_type": "video_view"}],"wish_bid":0.0},"emitted_at":1696936296894} -{"stream":"ads_insights_action_video_type","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":1,"conversion_rate_ranking":"UNKNOWN","cost_per_estimated_ad_recallers":0.008889,"cost_per_unique_click":0.8,"cpc":0.8,"cpm":1.255887,"cpp":1.296596,"created_time":"2021-02-11","ctr":0.156986,"date_start":"2021-02-14","date_stop":"2021-02-14","engagement_rate_ranking":"UNKNOWN","estimated_ad_recall_rate":14.58671,"estimated_ad_recallers":90.0,"frequency":1.032415,"impressions":637,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","quality_ranking":"UNKNOWN","reach":617,"social_spend":0.0,"spend":0.8,"unique_clicks":1,"unique_ctr":0.162075,"updated_time":"2021-08-27","video_play_curve_actions":[{"action_type":"video_view"}],"wish_bid":0.0},"emitted_at":1696936306631} -{"stream":"ads_insights_age_and_gender","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":0,"cost_per_estimated_ad_recallers":0.02,"cpm":0.869565,"cpp":0.952381,"created_time":"2021-02-11","ctr":0.0,"date_start":"2021-02-15","date_stop":"2021-02-15","estimated_ad_recall_rate":4.761905,"estimated_ad_recallers":1.0,"frequency":1.095238,"gender_targeting":"female","impressions":23,"instant_experience_clicks_to_open":1.0,"instant_experience_clicks_to_start":1.0,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":21,"spend":0.02,"unique_clicks":0,"updated_time":"2021-08-27","age":"55-64","gender":"female"},"emitted_at":1696939548058} -{"stream":"ads_insights_country","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":1,"cost_per_estimated_ad_recallers":0.008889,"cost_per_unique_click":0.8,"cpc":0.8,"cpm":1.255887,"cpp":1.296596,"created_time":"2021-02-11","ctr":0.156986,"date_start":"2021-02-14","date_stop":"2021-02-14","estimated_ad_recall_rate":14.58671,"estimated_ad_recallers":90.0,"frequency":1.032415,"impressions":637,"instant_experience_clicks_to_open":1.0,"instant_experience_clicks_to_start":1.0,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":617,"spend":0.8,"unique_clicks":1,"unique_ctr":0.162075,"updated_time":"2021-08-27","country":"US"},"emitted_at":1696936565587} -{"stream":"ads_insights_delivery_device","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846765228310398","ad_name":"Airbyte Ad","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":0,"cost_per_estimated_ad_recallers":0.0075,"cpm":1.630435,"cpp":1.744186,"created_time":"2021-02-09","ctr":0.0,"date_start":"2021-02-15","date_stop":"2021-02-15","estimated_ad_recall_rate":23.255814,"estimated_ad_recallers":20.0,"frequency":1.069767,"impressions":92,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":86,"spend":0.15,"unique_clicks":0,"updated_time":"2021-08-27","device_platform":"desktop"},"emitted_at":1696936327621} -{"stream":"ads_insights_delivery_platform","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","actions":[{"action_type":"page_engagement","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0},{"action_type":"post_engagement","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0},{"action_type":"link_click","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0}],"ad_id":"23846765228310398","ad_name":"Airbyte Ad","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":3,"cost_per_action_type":[{"action_type":"post_engagement","value":0.39,"1d_click":0.39,"7d_click":0.39,"28d_click":0.39},{"action_type":"page_engagement","value":0.39,"1d_click":0.39,"7d_click":0.39,"28d_click":0.39},{"action_type":"link_click","value":0.39,"1d_click":0.39,"7d_click":0.39,"28d_click":0.39}],"cost_per_estimated_ad_recallers":0.006882,"cost_per_inline_link_click":0.39,"cost_per_inline_post_engagement":0.39,"cost_per_outbound_click":[{"action_type":"outbound_click","value":0.39}],"cost_per_unique_action_type":[{"action_type":"post_engagement","value":0.39,"1d_click":0.39,"7d_click":0.39,"28d_click":0.39},{"action_type":"page_engagement","value":0.39,"1d_click":0.39,"7d_click":0.39,"28d_click":0.39},{"action_type":"link_click","value":0.39,"1d_click":0.39,"7d_click":0.39,"28d_click":0.39}],"cost_per_unique_click":0.39,"cost_per_unique_inline_link_click":0.39,"cost_per_unique_outbound_click":[{"action_type":"outbound_click","value":0.39}],"cpc":0.39,"cpm":0.922713,"cpp":0.971761,"created_time":"2021-02-09","ctr":0.236593,"date_start":"2021-02-15","date_stop":"2021-02-15","estimated_ad_recall_rate":14.119601,"estimated_ad_recallers":170.0,"frequency":1.053156,"impressions":1268,"inline_link_click_ctr":0.236593,"inline_link_clicks":3,"inline_post_engagement":3,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","outbound_clicks":[{"action_type":"outbound_click","value":3.0}],"outbound_clicks_ctr":[{"action_type":"outbound_click","value":0.236593}],"reach":1204,"spend":1.17,"unique_actions":[{"action_type":"page_engagement","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0},{"action_type":"post_engagement","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0},{"action_type":"link_click","value":3.0,"1d_click":3.0,"7d_click":3.0,"28d_click":3.0}],"unique_clicks":3,"unique_ctr":0.249169,"unique_inline_link_click_ctr":0.249169,"unique_inline_link_clicks":3,"unique_link_clicks_ctr":0.249169,"unique_outbound_clicks":[{"action_type":"outbound_click","value":3.0}],"unique_outbound_clicks_ctr":[{"action_type":"outbound_click","value":0.249169}],"updated_time":"2021-08-27","website_ctr":[{"action_type":"link_click","value":0.236593}],"publisher_platform":"facebook"},"emitted_at":1696936337306} -{"stream":"ads_insights_delivery_platform_and_device_platform","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846765228310398","ad_name":"Airbyte Ad","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":0,"cost_per_estimated_ad_recallers":0.002,"cpm":0.392157,"cpp":0.392157,"created_time":"2021-02-09","ctr":0.0,"date_start":"2021-02-15","date_stop":"2021-02-15","estimated_ad_recall_rate":19.607843,"estimated_ad_recallers":10.0,"frequency":1.0,"impressions":51,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":51,"spend":0.02,"unique_clicks":0,"updated_time":"2021-08-27","publisher_platform":"instagram","device_platform":"mobile_app"},"emitted_at":1696967644628} -{"stream":"ads_insights_demographics_age","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":0,"cost_per_estimated_ad_recallers":0.0085,"cpm":1.14094,"cpp":1.188811,"created_time":"2021-02-11","ctr":0.0,"date_start":"2021-02-15","date_stop":"2021-02-15","estimated_ad_recall_rate":13.986014,"estimated_ad_recallers":20.0,"frequency":1.041958,"impressions":149,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":143,"spend":0.17,"unique_clicks":0,"updated_time":"2021-08-27","age":"25-34"},"emitted_at":1696936389857} -{"stream":"ads_insights_demographics_country","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":1,"cost_per_estimated_ad_recallers":0.008889,"cost_per_unique_click":0.8,"cpc":0.8,"cpm":1.255887,"cpp":1.296596,"created_time":"2021-02-11","ctr":0.156986,"date_start":"2021-02-14","date_stop":"2021-02-14","estimated_ad_recall_rate":14.58671,"estimated_ad_recallers":90.0,"frequency":1.032415,"impressions":637,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":617,"spend":0.8,"unique_clicks":1,"unique_ctr":0.162075,"updated_time":"2021-08-27","country":"US"},"emitted_at":1696936440731} -{"stream":"ads_insights_demographics_dma_region","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":0,"cost_per_estimated_ad_recallers":0.0,"cpm":0.0,"created_time":"2021-02-11","ctr":0.0,"date_start":"2021-02-15","date_stop":"2021-02-15","estimated_ad_recallers":1.0,"frequency":1.0,"impressions":1,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":1,"spend":0.0,"unique_clicks":0,"updated_time":"2021-08-27","dma":"Anchorage"},"emitted_at":1696936491393} -{"stream":"ads_insights_demographics_gender","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":0,"cost_per_estimated_ad_recallers":0.0085,"cpm":1.268657,"cpp":1.338583,"created_time":"2021-02-11","ctr":0.0,"date_start":"2021-02-14","date_stop":"2021-02-14","estimated_ad_recall_rate":15.748032,"estimated_ad_recallers":20.0,"frequency":1.055118,"gender_targeting":"female","impressions":134,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":127,"spend":0.17,"unique_clicks":0,"updated_time":"2021-08-27","gender":"female"},"emitted_at":1696967753477} -{"stream":"ads_insights_dma","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":0,"cost_per_estimated_ad_recallers":0.0,"cpm":0.0,"created_time":"2021-02-11","ctr":0.0,"date_start":"2021-02-15","date_stop":"2021-02-15","estimated_ad_recallers":1.0,"frequency":1.0,"impressions":1,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":1,"spend":0.0,"unique_clicks":0,"updated_time":"2021-08-27","dma":"West Palm Beach-Ft. Pierce"},"emitted_at":1696936556045} -{"stream":"ads_insights_platform_and_device","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":0,"cost_per_estimated_ad_recallers":0.0,"cpm":0.0,"cpp":0.0,"created_time":"2021-02-11","ctr":0.0,"date_start":"2021-02-15","date_stop":"2021-02-15","estimated_ad_recall_rate":12.5,"estimated_ad_recallers":1.0,"frequency":1.0,"impressions":8,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":8,"spend":0.0,"unique_clicks":0,"updated_time":"2021-08-27","publisher_platform":"instagram","platform_position":"feed","impression_device":"android_smartphone"},"emitted_at":1696936579028} -{"stream":"ads_insights_region","data":{"account_currency":"USD","account_id":"212551616838260","account_name":"Airbyte","ad_id":"23846784938030398","ad_name":"Stock photo ad 2","adset_id":"23846765228280398","adset_name":"Vanilla awareness ad set","buying_type":"AUCTION","campaign_id":"23846765228240398","campaign_name":"Airbyte Awareness Campaign 1 (sherif)","clicks":0,"cost_per_estimated_ad_recallers":0.02,"cpm":1.111111,"cpp":1.111111,"created_time":"2021-02-11","ctr":0.0,"date_start":"2021-02-15","date_stop":"2021-02-15","estimated_ad_recall_rate":5.555556,"estimated_ad_recallers":1.0,"frequency":1.0,"impressions":18,"instant_experience_clicks_to_open":1.0,"instant_experience_clicks_to_start":1.0,"objective":"BRAND_AWARENESS","optimization_goal":"AD_RECALL_LIFT","reach":18,"spend":0.02,"unique_clicks":0,"updated_time":"2021-08-27","region":"New York"},"emitted_at":1696936621899} -{"stream":"customcustom_insight_stream","data":{"account_id":"212551616838260","cpc":0.27,"ad_id":"23846765228310398","clicks":1,"account_name":"Airbyte","date_start":"2021-02-15","date_stop":"2021-02-15","gender":"female"},"emitted_at":1695385890508} +{"stream": "activities", "data": {"account_id": "212551616838260", "actor_id": "122043039268043192", "actor_name": "Payments RTU Processor", "application_id": "0", "date_time_in_timezone": "03/13/2023 at 6:30 AM", "event_time": "2023-03-13T13:30:47+0000", "event_type": "ad_account_billing_charge", "extra_data": "{\"currency\":\"USD\",\"new_value\":1188,\"transaction_id\":\"5885578541558696-11785530\",\"action\":67,\"type\":\"payment_amount\"}", "object_id": "212551616838260", "object_name": "Airbyte", "object_type": "ACCOUNT", "translated_event_type": "Account billed"}, "emitted_at": 1696931251153} +{"stream": "custom_conversions", "data": {"id": "694166388077667", "account_id": "212551616838260", "creation_time": "2020-04-22T01:36:00+0000", "custom_event_type": "CONTACT", "data_sources": [{"id": "2667253716886462", "source_type": "PIXEL", "name": "Dataline's Pixel"}], "default_conversion_value": 0, "event_source_type": "pixel", "is_archived": true, "is_unavailable": false, "name": "SubscribedButtonClick", "retention_days": 0, "rule": "{\"and\":[{\"event\":{\"eq\":\"PageView\"}},{\"or\":[{\"URL\":{\"i_contains\":\"SubscribedButtonClick\"}}]}]}"}, "emitted_at": 1692180839174} +{"stream": "images", "data": {"id": "212551616838260:c1e94a8768a405f0f212d71fe8336647", "account_id": "212551616838260", "name": "Audience_1_Ad_3_1200x1200_blue_CTA_arrow.png_105", "creatives": ["23853630775340398", "23853630871360398", "23853666124200398"], "original_height": 1200, "original_width": 1200, "permalink_url": "https://www.facebook.com/ads/image/?d=AQIDNjjLb7VzVJ26jXb_HpudCEUJqbV_lLF2JVsdruDcBxnXQEKfzzd21VVJnkm0B-JLosUXNNg1BH78y7FxnK3AH-0D_lnk7kn39_bIcOMK7Z9HYyFInfsVY__adup3A5zGTIcHC9Y98Je5qK-yD8F6", "status": "ACTIVE", "url": "https://scontent-dus1-1.xx.fbcdn.net/v/t45.1600-4/335907140_23853620220420398_4375584095210967511_n.png?_nc_cat=104&ccb=1-7&_nc_sid=2aac32&_nc_ohc=xdjrPpbRGNAAX8Dck01&_nc_ht=scontent-dus1-1.xx&edm=AJcBmwoEAAAA&oh=00_AfDCqQ6viqrgLcfbO3O5-n030Usq7Zyt2c1TmsatqnYf7Q&oe=64E2779A", "created_time": "2023-03-16T13:13:17-0700", "hash": "c1e94a8768a405f0f212d71fe8336647", "url_128": "https://scontent-dus1-1.xx.fbcdn.net/v/t45.1600-4/335907140_23853620220420398_4375584095210967511_n.png?stp=dst-png_s128x128&_nc_cat=104&ccb=1-7&_nc_sid=2aac32&_nc_ohc=xdjrPpbRGNAAX8Dck01&_nc_ht=scontent-dus1-1.xx&edm=AJcBmwoEAAAA&oh=00_AfAY50CMpox2s4w_f18IVx7sZuXlg4quF6YNIJJ8D4PZew&oe=64E2779A", "is_associated_creatives_in_adgroups": true, "updated_time": "2023-03-17T08:09:56-0700", "height": 1200, "width": 1200}, "emitted_at": 1692180839582} +{"stream": "ads_insights", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "actions": [{"action_destination": "244953057175777", "action_target_id": "244953057175777", "action_type": "page_engagement", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}, {"action_destination": "244953057175777", "action_target_id": "244953057175777", "action_type": "post_engagement", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}, {"action_destination": "244953057175777", "action_target_id": "244953057175777", "action_type": "link_click", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}], "ad_id": "23846765228310398", "ad_name": "Airbyte Ad", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 3, "conversion_rate_ranking": "UNKNOWN", "cost_per_estimated_ad_recallers": 0.007, "cost_per_inline_link_click": 0.396667, "cost_per_inline_post_engagement": 0.396667, "cost_per_unique_click": 0.396667, "cost_per_unique_inline_link_click": 0.396667, "cpc": 0.396667, "cpm": 0.902199, "cpp": 0.948207, "created_time": "2021-02-09", "ctr": 0.227445, "date_start": "2021-02-15", "date_stop": "2021-02-15", "engagement_rate_ranking": "UNKNOWN", "estimated_ad_recall_rate": 13.545817, "estimated_ad_recallers": 170.0, "frequency": 1.050996, "impressions": 1319, "inline_link_click_ctr": 0.227445, "inline_link_clicks": 3, "inline_post_engagement": 3, "instant_experience_clicks_to_open": 1.0, "instant_experience_clicks_to_start": 1.0, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "outbound_clicks": [{"action_destination": "244953057175777", "action_target_id": "244953057175777", "action_type": "outbound_click", "value": 3.0}], "quality_ranking": "UNKNOWN", "reach": 1255, "social_spend": 0.0, "spend": 1.19, "unique_actions": [{"action_destination": "244953057175777", "action_target_id": "244953057175777", "action_type": "page_engagement", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}, {"action_destination": "244953057175777", "action_target_id": "244953057175777", "action_type": "post_engagement", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}, {"action_destination": "244953057175777", "action_target_id": "244953057175777", "action_type": "link_click", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}], "unique_clicks": 3, "unique_ctr": 0.239044, "unique_inline_link_click_ctr": 0.239044, "unique_inline_link_clicks": 3, "unique_link_clicks_ctr": 0.239044, "unique_outbound_clicks": [{"action_destination": "244953057175777", "action_target_id": "244953057175777", "action_type": "outbound_click", "value": 3.0}], "updated_time": "2021-08-27", "video_play_curve_actions": [{"action_type": "video_view"}], "website_ctr": [{"action_type": "link_click", "value": 0.227445}], "wish_bid": 0.0}, "emitted_at": 1682686057366} +{"stream": "ads_insights_action_carousel_card", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846765228310398", "ad_name": "Airbyte Ad", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 3, "conversion_rate_ranking": "UNKNOWN", "cost_per_estimated_ad_recallers": 0.007, "cost_per_inline_link_click": 0.396667, "cost_per_inline_post_engagement": 0.396667, "cost_per_unique_click": 0.396667, "cost_per_unique_inline_link_click": 0.396667, "cpc": 0.396667, "cpm": 0.902199, "cpp": 0.948207, "created_time": "2021-02-09", "ctr": 0.227445, "date_start": "2021-02-15", "date_stop": "2021-02-15", "engagement_rate_ranking": "UNKNOWN", "estimated_ad_recall_rate": 13.545817, "estimated_ad_recallers": 170.0, "frequency": 1.050996, "impressions": 1319, "inline_link_click_ctr": 0.227445, "inline_post_engagement": 3, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "quality_ranking": "UNKNOWN", "reach": 1255, "social_spend": 0.0, "spend": 1.19, "unique_actions": [{"action_type": "page_engagement", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}, {"action_type": "post_engagement", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}, {"action_type": "link_click", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}], "unique_clicks": 3, "unique_ctr": 0.239044, "unique_inline_link_click_ctr": 0.239044, "unique_inline_link_clicks": 3, "updated_time": "2021-08-27", "video_play_curve_actions": [{"action_type": "video_view"}], "website_ctr": [{"action_type": "link_click", "value": 0.227445}], "wish_bid": 0.0}, "emitted_at": 1692180857757} +{"stream": "ads_insights_action_conversion_device", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 0, "cost_per_estimated_ad_recallers": 0.004, "cpm": 0.754717, "cpp": 0.784314, "created_time": "2021-02-11", "ctr": 0.0, "date_start": "2021-02-15", "date_stop": "2021-02-15", "estimated_ad_recall_rate": 19.607843, "estimated_ad_recallers": 10.0, "frequency": 1.039216, "impressions": 53, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 51, "spend": 0.04, "unique_clicks": 0, "updated_time": "2021-08-27", "device_platform": "desktop"}, "emitted_at": 1696936270620} +{"stream": "ads_insights_action_reaction", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 1, "conversion_rate_ranking": "UNKNOWN", "cost_per_estimated_ad_recallers": 0.008889, "cost_per_unique_click": 0.8, "cpc": 0.8, "cpm": 1.255887, "cpp": 1.296596, "created_time": "2021-02-11", "ctr": 0.156986, "date_start": "2021-02-14", "date_stop": "2021-02-14", "engagement_rate_ranking": "UNKNOWN", "estimated_ad_recall_rate": 14.58671, "estimated_ad_recallers": 90.0, "frequency": 1.032415, "impressions": 637, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "quality_ranking": "UNKNOWN", "reach": 617, "social_spend": 0.0, "spend": 0.8, "unique_clicks": 1, "unique_ctr": 0.162075, "updated_time": "2021-08-27", "video_play_curve_actions": [{"action_type": "video_view"}], "wish_bid": 0.0}, "emitted_at": 1696936287351} +{"stream": "ads_insights_action_type", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 1, "conversion_rate_ranking": "UNKNOWN", "cost_per_estimated_ad_recallers": 0.008889, "cost_per_unique_click": 0.8, "cpc": 0.8, "cpm": 1.255887, "cpp": 1.296596, "created_time": "2021-02-11", "ctr": 0.156986, "date_start": "2021-02-14", "date_stop": "2021-02-14", "engagement_rate_ranking": "UNKNOWN", "estimated_ad_recall_rate": 14.58671, "estimated_ad_recallers": 90.0, "frequency": 1.032415, "impressions": 637, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "quality_ranking": "UNKNOWN", "reach": 617, "social_spend": 0.0, "spend": 0.8, "unique_clicks": 1, "unique_ctr": 0.162075, "updated_time": "2021-08-27", "video_play_curve_actions": [{"action_type": "video_view"}], "wish_bid": 0.0}, "emitted_at": 1696936315908} +{"stream": "ads_insights_action_video_sound", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 1, "conversion_rate_ranking": "UNKNOWN", "cost_per_estimated_ad_recallers": 0.008889, "cost_per_unique_click": 0.8, "cpc": 0.8, "cpm": 1.255887, "cpp": 1.296596, "created_time": "2021-02-11", "ctr": 0.156986, "date_start": "2021-02-14", "date_stop": "2021-02-14", "engagement_rate_ranking": "UNKNOWN", "estimated_ad_recall_rate": 14.58671, "estimated_ad_recallers": 90.0, "frequency": 1.032415, "impressions": 637, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "quality_ranking": "UNKNOWN", "reach": 617, "social_spend": 0.0, "spend": 0.8, "unique_clicks": 1, "unique_ctr": 0.162075, "updated_time": "2021-08-27", "video_play_curve_actions": [{"action_type": "video_view"}], "wish_bid": 0.0}, "emitted_at": 1696936296894} +{"stream": "ads_insights_action_video_type", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 1, "conversion_rate_ranking": "UNKNOWN", "cost_per_estimated_ad_recallers": 0.008889, "cost_per_unique_click": 0.8, "cpc": 0.8, "cpm": 1.255887, "cpp": 1.296596, "created_time": "2021-02-11", "ctr": 0.156986, "date_start": "2021-02-14", "date_stop": "2021-02-14", "engagement_rate_ranking": "UNKNOWN", "estimated_ad_recall_rate": 14.58671, "estimated_ad_recallers": 90.0, "frequency": 1.032415, "impressions": 637, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "quality_ranking": "UNKNOWN", "reach": 617, "social_spend": 0.0, "spend": 0.8, "unique_clicks": 1, "unique_ctr": 0.162075, "updated_time": "2021-08-27", "video_play_curve_actions": [{"action_type": "video_view"}], "wish_bid": 0.0}, "emitted_at": 1696936306631} +{"stream": "ads_insights_age_and_gender", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 0, "cost_per_estimated_ad_recallers": 0.02, "cpm": 0.869565, "cpp": 0.952381, "created_time": "2021-02-11", "ctr": 0.0, "date_start": "2021-02-15", "date_stop": "2021-02-15", "estimated_ad_recall_rate": 4.761905, "estimated_ad_recallers": 1.0, "frequency": 1.095238, "gender_targeting": "female", "impressions": 23, "instant_experience_clicks_to_open": 1.0, "instant_experience_clicks_to_start": 1.0, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 21, "spend": 0.02, "unique_clicks": 0, "updated_time": "2021-08-27", "age": "55-64", "gender": "female"}, "emitted_at": 1696939548058} +{"stream": "ads_insights_country", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 1, "cost_per_estimated_ad_recallers": 0.008889, "cost_per_unique_click": 0.8, "cpc": 0.8, "cpm": 1.255887, "cpp": 1.296596, "created_time": "2021-02-11", "ctr": 0.156986, "date_start": "2021-02-14", "date_stop": "2021-02-14", "estimated_ad_recall_rate": 14.58671, "estimated_ad_recallers": 90.0, "frequency": 1.032415, "impressions": 637, "instant_experience_clicks_to_open": 1.0, "instant_experience_clicks_to_start": 1.0, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 617, "spend": 0.8, "unique_clicks": 1, "unique_ctr": 0.162075, "updated_time": "2021-08-27", "country": "US"}, "emitted_at": 1696936565587} +{"stream": "ads_insights_delivery_device", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846765228310398", "ad_name": "Airbyte Ad", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 0, "cost_per_estimated_ad_recallers": 0.0075, "cpm": 1.630435, "cpp": 1.744186, "created_time": "2021-02-09", "ctr": 0.0, "date_start": "2021-02-15", "date_stop": "2021-02-15", "estimated_ad_recall_rate": 23.255814, "estimated_ad_recallers": 20.0, "frequency": 1.069767, "impressions": 92, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 86, "spend": 0.15, "unique_clicks": 0, "updated_time": "2021-08-27", "device_platform": "desktop"}, "emitted_at": 1696936327621} +{"stream": "ads_insights_delivery_platform", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "actions": [{"action_type": "page_engagement", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}, {"action_type": "post_engagement", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}, {"action_type": "link_click", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}], "ad_id": "23846765228310398", "ad_name": "Airbyte Ad", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 3, "cost_per_action_type": [{"action_type": "post_engagement", "value": 0.39, "1d_click": 0.39, "7d_click": 0.39, "28d_click": 0.39}, {"action_type": "page_engagement", "value": 0.39, "1d_click": 0.39, "7d_click": 0.39, "28d_click": 0.39}, {"action_type": "link_click", "value": 0.39, "1d_click": 0.39, "7d_click": 0.39, "28d_click": 0.39}], "cost_per_estimated_ad_recallers": 0.006882, "cost_per_inline_link_click": 0.39, "cost_per_inline_post_engagement": 0.39, "cost_per_outbound_click": [{"action_type": "outbound_click", "value": 0.39}], "cost_per_unique_action_type": [{"action_type": "post_engagement", "value": 0.39, "1d_click": 0.39, "7d_click": 0.39, "28d_click": 0.39}, {"action_type": "page_engagement", "value": 0.39, "1d_click": 0.39, "7d_click": 0.39, "28d_click": 0.39}, {"action_type": "link_click", "value": 0.39, "1d_click": 0.39, "7d_click": 0.39, "28d_click": 0.39}], "cost_per_unique_click": 0.39, "cost_per_unique_inline_link_click": 0.39, "cost_per_unique_outbound_click": [{"action_type": "outbound_click", "value": 0.39}], "cpc": 0.39, "cpm": 0.922713, "cpp": 0.971761, "created_time": "2021-02-09", "ctr": 0.236593, "date_start": "2021-02-15", "date_stop": "2021-02-15", "estimated_ad_recall_rate": 14.119601, "estimated_ad_recallers": 170.0, "frequency": 1.053156, "impressions": 1268, "inline_link_click_ctr": 0.236593, "inline_link_clicks": 3, "inline_post_engagement": 3, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "outbound_clicks": [{"action_type": "outbound_click", "value": 3.0}], "outbound_clicks_ctr": [{"action_type": "outbound_click", "value": 0.236593}], "reach": 1204, "spend": 1.17, "unique_actions": [{"action_type": "page_engagement", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}, {"action_type": "post_engagement", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}, {"action_type": "link_click", "value": 3.0, "1d_click": 3.0, "7d_click": 3.0, "28d_click": 3.0}], "unique_clicks": 3, "unique_ctr": 0.249169, "unique_inline_link_click_ctr": 0.249169, "unique_inline_link_clicks": 3, "unique_link_clicks_ctr": 0.249169, "unique_outbound_clicks": [{"action_type": "outbound_click", "value": 3.0}], "unique_outbound_clicks_ctr": [{"action_type": "outbound_click", "value": 0.249169}], "updated_time": "2021-08-27", "website_ctr": [{"action_type": "link_click", "value": 0.236593}], "publisher_platform": "facebook"}, "emitted_at": 1696936337306} +{"stream": "ads_insights_delivery_platform_and_device_platform", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846765228310398", "ad_name": "Airbyte Ad", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 0, "cost_per_estimated_ad_recallers": 0.002, "cpm": 0.392157, "cpp": 0.392157, "created_time": "2021-02-09", "ctr": 0.0, "date_start": "2021-02-15", "date_stop": "2021-02-15", "estimated_ad_recall_rate": 19.607843, "estimated_ad_recallers": 10.0, "frequency": 1.0, "impressions": 51, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 51, "spend": 0.02, "unique_clicks": 0, "updated_time": "2021-08-27", "publisher_platform": "instagram", "device_platform": "mobile_app"}, "emitted_at": 1696967644628} +{"stream": "ads_insights_demographics_age", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 0, "cost_per_estimated_ad_recallers": 0.0085, "cpm": 1.14094, "cpp": 1.188811, "created_time": "2021-02-11", "ctr": 0.0, "date_start": "2021-02-15", "date_stop": "2021-02-15", "estimated_ad_recall_rate": 13.986014, "estimated_ad_recallers": 20.0, "frequency": 1.041958, "impressions": 149, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 143, "spend": 0.17, "unique_clicks": 0, "updated_time": "2021-08-27", "age": "25-34"}, "emitted_at": 1696936389857} +{"stream": "ads_insights_demographics_country", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 1, "cost_per_estimated_ad_recallers": 0.008889, "cost_per_unique_click": 0.8, "cpc": 0.8, "cpm": 1.255887, "cpp": 1.296596, "created_time": "2021-02-11", "ctr": 0.156986, "date_start": "2021-02-14", "date_stop": "2021-02-14", "estimated_ad_recall_rate": 14.58671, "estimated_ad_recallers": 90.0, "frequency": 1.032415, "impressions": 637, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 617, "spend": 0.8, "unique_clicks": 1, "unique_ctr": 0.162075, "updated_time": "2021-08-27", "country": "US"}, "emitted_at": 1696936440731} +{"stream": "ads_insights_demographics_dma_region", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 0, "cost_per_estimated_ad_recallers": 0.0, "cpm": 0.0, "created_time": "2021-02-11", "ctr": 0.0, "date_start": "2021-02-15", "date_stop": "2021-02-15", "estimated_ad_recallers": 1.0, "frequency": 1.0, "impressions": 1, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 1, "spend": 0.0, "unique_clicks": 0, "updated_time": "2021-08-27", "dma": "Anchorage"}, "emitted_at": 1696936491393} +{"stream": "ads_insights_demographics_gender", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 0, "cost_per_estimated_ad_recallers": 0.0085, "cpm": 1.268657, "cpp": 1.338583, "created_time": "2021-02-11", "ctr": 0.0, "date_start": "2021-02-14", "date_stop": "2021-02-14", "estimated_ad_recall_rate": 15.748032, "estimated_ad_recallers": 20.0, "frequency": 1.055118, "gender_targeting": "female", "impressions": 134, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 127, "spend": 0.17, "unique_clicks": 0, "updated_time": "2021-08-27", "gender": "female"}, "emitted_at": 1696967753477} +{"stream": "ads_insights_dma", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 0, "cost_per_estimated_ad_recallers": 0.0, "cpm": 0.0, "created_time": "2021-02-11", "ctr": 0.0, "date_start": "2021-02-15", "date_stop": "2021-02-15", "estimated_ad_recallers": 1.0, "frequency": 1.0, "impressions": 1, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 1, "spend": 0.0, "unique_clicks": 0, "updated_time": "2021-08-27", "dma": "West Palm Beach-Ft. Pierce"}, "emitted_at": 1696936556045} +{"stream": "ads_insights_platform_and_device", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 0, "cost_per_estimated_ad_recallers": 0.0, "cpm": 0.0, "cpp": 0.0, "created_time": "2021-02-11", "ctr": 0.0, "date_start": "2021-02-15", "date_stop": "2021-02-15", "estimated_ad_recall_rate": 12.5, "estimated_ad_recallers": 1.0, "frequency": 1.0, "impressions": 8, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 8, "spend": 0.0, "unique_clicks": 0, "updated_time": "2021-08-27", "publisher_platform": "instagram", "platform_position": "feed", "impression_device": "android_smartphone"}, "emitted_at": 1696936579028} +{"stream": "ads_insights_region", "data": {"account_currency": "USD", "account_id": "212551616838260", "account_name": "Airbyte", "ad_id": "23846784938030398", "ad_name": "Stock photo ad 2", "adset_id": "23846765228280398", "adset_name": "Vanilla awareness ad set", "buying_type": "AUCTION", "campaign_id": "23846765228240398", "campaign_name": "Airbyte Awareness Campaign 1 (sherif)", "clicks": 0, "cost_per_estimated_ad_recallers": 0.02, "cpm": 1.111111, "cpp": 1.111111, "created_time": "2021-02-11", "ctr": 0.0, "date_start": "2021-02-15", "date_stop": "2021-02-15", "estimated_ad_recall_rate": 5.555556, "estimated_ad_recallers": 1.0, "frequency": 1.0, "impressions": 18, "instant_experience_clicks_to_open": 1.0, "instant_experience_clicks_to_start": 1.0, "objective": "BRAND_AWARENESS", "optimization_goal": "AD_RECALL_LIFT", "reach": 18, "spend": 0.02, "unique_clicks": 0, "updated_time": "2021-08-27", "region": "New York"}, "emitted_at": 1696936621899} +{"stream": "customcustom_insight_stream", "data": {"account_id": "212551616838260", "cpc": 0.27, "ad_id": "23846765228310398", "clicks": 1, "account_name": "Airbyte", "date_start": "2021-02-15", "date_stop": "2021-02-15", "gender": "female"}, "emitted_at": 1695385890508} diff --git a/airbyte-integrations/connectors/source-facebook-marketing/metadata.yaml b/airbyte-integrations/connectors/source-facebook-marketing/metadata.yaml index ecbb99f6755f..ae15d5dd7b85 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/metadata.yaml +++ b/airbyte-integrations/connectors/source-facebook-marketing/metadata.yaml @@ -10,7 +10,7 @@ data: connectorSubtype: api connectorType: source definitionId: e7778cfc-e97c-4458-9ecb-b4f2bba8946c - dockerImageTag: 1.3.2 + dockerImageTag: 1.3.3 dockerRepository: airbyte/source-facebook-marketing documentationUrl: https://docs.airbyte.com/integrations/sources/facebook-marketing githubIssueLabel: source-facebook-marketing diff --git a/airbyte-integrations/connectors/source-facebook-marketing/poetry.lock b/airbyte-integrations/connectors/source-facebook-marketing/poetry.lock index 6cae856d6501..3cfd31f7261a 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/poetry.lock +++ b/airbyte-integrations/connectors/source-facebook-marketing/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiohttp" @@ -112,13 +112,13 @@ frozenlist = ">=1.1.0" [[package]] name = "airbyte-cdk" -version = "0.61.0" +version = "0.62.1" description = "A framework for writing Airbyte Connectors." optional = false python-versions = ">=3.8" files = [ - {file = "airbyte-cdk-0.61.0.tar.gz", hash = "sha256:8beda008c5a177041ac02860a431ce7b1ecd00062a4a8f31fe6ac446cbed3e70"}, - {file = "airbyte_cdk-0.61.0-py3-none-any.whl", hash = "sha256:3f989bfe692c9519d61f9120ddb744ab82c432c2caf25374d4d6f5cdc374a1e9"}, + {file = "airbyte-cdk-0.62.1.tar.gz", hash = "sha256:3c934dd8b045079a9c807f699ca2012eaa5df755606e3f5b8b16247cbbd7e8c6"}, + {file = "airbyte_cdk-0.62.1-py3-none-any.whl", hash = "sha256:792399a602b7f5c3cd4ed2a5fce5910cfe3676b9b9199b9208f2d5236f5f42d3"}, ] [package.dependencies] @@ -1507,4 +1507,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.9,<3.12" -content-hash = "3e81a26b7b125e532293d350044a1353fbc2a6b856890e5fd9f9f0bf70fe3a47" +content-hash = "5753d144dc008fabd12b18d9e28d148ee96976d7b83cdcf0a82b3ea22f8f315f" diff --git a/airbyte-integrations/connectors/source-facebook-marketing/pyproject.toml b/airbyte-integrations/connectors/source-facebook-marketing/pyproject.toml index 2465930f5ced..5a37a64ce856 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/pyproject.toml +++ b/airbyte-integrations/connectors/source-facebook-marketing/pyproject.toml @@ -3,7 +3,7 @@ requires = [ "poetry-core>=1.0.0",] build-backend = "poetry.core.masonry.api" [tool.poetry] -version = "1.3.2" +version = "1.3.3" name = "source-facebook-marketing" description = "Source implementation for Facebook Marketing." authors = [ "Airbyte ",] @@ -17,7 +17,7 @@ include = "source_facebook_marketing" [tool.poetry.dependencies] python = "^3.9,<3.12" -airbyte-cdk = "==0.61.0" +airbyte-cdk = "==0.62.1" facebook-business = "==17.0.0" cached-property = "==1.5.2" pendulum = "==2.1.2" diff --git a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/api.py b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/api.py index 61a171b9659d..edfd6195602e 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/api.py +++ b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/api.py @@ -6,7 +6,6 @@ import logging from dataclasses import dataclass from time import sleep -from typing import List import backoff import pendulum @@ -35,7 +34,7 @@ class MyFacebookAdsApi(FacebookAdsApi): # see `_should_restore_page_size` method docstring for more info. # attribute to handle the reduced request limit request_record_limit_is_reduced: bool = False - # attribute to save the status of last successfull call + # attribute to save the status of the last successful call last_api_call_is_successful: bool = False @dataclass @@ -144,7 +143,7 @@ def _update_insights_throttle_limit(self, response: FacebookResponse): def _should_restore_default_page_size(self, params): """ - Track the state of the `request_record_limit_is_reduced` and `last_api_call_is_successfull`, + Track the state of the `request_record_limit_is_reduced` and `last_api_call_is_successful`, based on the logic from `@backoff_policy` (common.py > `reduce_request_record_limit` and `revert_request_record_limit`) """ params = True if params else False diff --git a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/source.py b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/source.py index 65e8c057852a..18cc0840526a 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/source.py +++ b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/source.py @@ -14,7 +14,6 @@ DestinationSyncMode, FailureType, OAuthConfigSpecification, - SyncMode, ) from airbyte_cdk.sources import AbstractSource from airbyte_cdk.sources.streams import Stream diff --git a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/async_job_manager.py b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/async_job_manager.py index 738507e4408b..f486fb314784 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/async_job_manager.py +++ b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/async_job_manager.py @@ -134,7 +134,7 @@ def _get_current_throttle_value(self) -> float: """ Get current ads insights throttle value based on app id and account id. It evaluated as minimum of those numbers cause when account id throttle - hit 100 it cool down very slowly (i.e. it still says 100 despite no jobs + hit 100 it cools down very slowly (i.e. it still says 100 despite no jobs running and it capable serve new requests). Because of this behaviour facebook throttle limit is not reliable metric to estimate async workload. """ @@ -144,7 +144,7 @@ def _get_current_throttle_value(self) -> float: def _update_api_throttle_limit(self): """ - Sends /insights GET request with no parameters so it would + Sends /insights GET request with no parameters, so it would respond with empty list of data so api use "x-fb-ads-insights-throttle" header to update current insights throttle limit. """ diff --git a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/base_insight_streams.py b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/base_insight_streams.py index c671a4b9b917..169ef7875405 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/base_insight_streams.py +++ b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/base_insight_streams.py @@ -44,8 +44,7 @@ class AdsInsights(FBMarketingIncrementalStream): ] # Facebook store metrics maximum of 37 months old. Any time range that - # older that 37 months from current date would result in 400 Bad request - # HTTP response. + # older than 37 months from current date would result in 400 Bad request HTTP response. # https://developers.facebook.com/docs/marketing-api/reference/ad-account/insights/#overview INSIGHTS_RETENTION_PERIOD = pendulum.duration(months=37) @@ -106,8 +105,8 @@ def insights_lookback_period(self): """ Facebook freezes insight data 28 days after it was generated, which means that all data from the past 28 days may have changed since we last emitted it, so we retrieve it again. - But in some cases users my have define their own lookback window, thats - why the value for `insights_lookback_window` is set throught config. + But in some cases users my have define their own lookback window, that's + why the value for `insights_lookback_window` is set through the config. """ return pendulum.duration(days=self._insights_lookback_window) @@ -174,7 +173,7 @@ def state(self) -> MutableMapping[str, Any]: def state(self, value: Mapping[str, Any]): """State setter, will ignore saved state if time_increment is different from previous.""" # if the time increment configured for this stream is different from the one in the previous state - # then the previous state object is invalid and we should start replicating data from scratch + # then the previous state object is invalid, and we should start replicating data from scratch # to achieve this, we skip setting the state transformed_state = self._transform_state_from_old_format(value, ["time_increment"]) if transformed_state.get("time_increment", 1) != self.time_increment: diff --git a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/common.py b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/common.py index 3947689761b3..a5776d8f7c32 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/common.py +++ b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/common.py @@ -61,12 +61,12 @@ def reduce_request_record_limit(details): def revert_request_record_limit(details): """ - This method is triggered `on_success` after successfull retry, + This method is triggered `on_success` after successful retry, sets the internal class flags to provide the logic to restore the previously reduced `limit` param. """ # reference issue: https://github.com/airbytehq/airbyte/issues/25383 - # set the flag to the api class that the last api call was ssuccessfull + # set the flag to the api class that the last api call was successful details.get("args")[0].last_api_call_is_successfull = True # set the flag to the api class that the `limit` param is restored details.get("args")[0].request_record_limit_is_reduced = False diff --git a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/streams.py b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/streams.py index c7fd0237963b..fec7d321a1ed 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/streams.py +++ b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/streams/streams.py @@ -36,7 +36,7 @@ def fetch_thumbnail_data_url(url: str) -> Optional[str]: class AdCreatives(FBMarketingStream): - """AdCreative is append only stream + """AdCreative is append-only stream doc: https://developers.facebook.com/docs/marketing-api/reference/ad-creative """ @@ -48,7 +48,7 @@ def __init__(self, fetch_thumbnail_images: bool = False, **kwargs): self._fetch_thumbnail_images = fetch_thumbnail_images def fields(self, **kwargs) -> List[str]: - """Remove "thumbnail_data_url" field because it is computed field and it's not a field that we can request from Facebook""" + """Remove "thumbnail_data_url" field because it is a computed field, and it's not a field that we can request from Facebook""" if self._fields: return self._fields @@ -231,7 +231,7 @@ def list_objects(self, params: Mapping[str, Any], account_id: str) -> Iterable: return [FBAdAccount(self._api.get_account(account_id=account_id).get_id()).api_get(fields=fields)] except FacebookRequestError as e: # This is a workaround for cases when account seem to have all the required permissions - # but despite of that is not allowed to get `owner` field. See (https://github.com/airbytehq/oncall/issues/3167) + # but despite that is not allowed to get `owner` field. See (https://github.com/airbytehq/oncall/issues/3167) if e.api_error_code() == 200 and e.api_error_message() == "(#200) Requires business_management permission to manage the object": fields.remove("owner") return [FBAdAccount(self._api.get_account(account_id=account_id).get_id()).api_get(fields=fields)] diff --git a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/utils.py b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/utils.py index d3550ae6d1c8..f7e54467f1e1 100644 --- a/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/utils.py +++ b/airbyte-integrations/connectors/source-facebook-marketing/source_facebook_marketing/utils.py @@ -11,7 +11,7 @@ logger = logging.getLogger("airbyte") # Facebook store metrics maximum of 37 months old. Any time range that -# older that 37 months from current date would result in 400 Bad request +# older than 37 months from current date would result in 400 Bad request # HTTP response. # https://developers.facebook.com/docs/marketing-api/reference/ad-account/insights/#overview DATA_RETENTION_PERIOD = 37 diff --git a/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/__init__.py b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/config.py b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/config.py new file mode 100644 index 000000000000..ef0591147cc7 --- /dev/null +++ b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/config.py @@ -0,0 +1,55 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +from __future__ import annotations + +from datetime import datetime +from typing import Any, List, MutableMapping + +import pendulum + +ACCESS_TOKEN = "test_access_token" +ACCOUNT_ID = "111111111111111" +CLIENT_ID = "test_client_id" +CLIENT_SECRET = "test_client_secret" +DATE_FORMAT = "%Y-%m-%d" +DATE_TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" +END_DATE = "2023-01-01T23:59:59Z" +NOW = pendulum.now(tz="utc") +START_DATE = "2023-01-01T00:00:00Z" + + +class ConfigBuilder: + def __init__(self) -> None: + self._config: MutableMapping[str, Any] = { + "account_ids": [ACCOUNT_ID], + "access_token": ACCESS_TOKEN, + "start_date": START_DATE, + "end_date": END_DATE, + "include_deleted": True, + "fetch_thumbnail_images": True, + "custom_insights": [], + "page_size": 100, + "insights_lookback_window": 28, + "insights_job_timeout": 60, + "action_breakdowns_allow_empty": True, + "client_id": CLIENT_ID, + "client_secret": CLIENT_SECRET, + } + + def with_account_ids(self, account_ids: List[str]) -> ConfigBuilder: + self._config["account_ids"] = account_ids + return self + + def with_start_date(self, start_date: datetime) -> ConfigBuilder: + self._config["start_date"] = start_date.strftime(DATE_TIME_FORMAT) + return self + + def with_end_date(self, end_date: datetime) -> ConfigBuilder: + self._config["end_date"] = end_date.strftime(DATE_TIME_FORMAT) + return self + + def build(self) -> MutableMapping[str, Any]: + return self._config diff --git a/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/pagination.py b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/pagination.py new file mode 100644 index 000000000000..69b284d6d308 --- /dev/null +++ b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/pagination.py @@ -0,0 +1,24 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +from typing import Any, Dict +from urllib.parse import urlunparse + +from airbyte_cdk.test.mock_http.request import HttpRequest +from airbyte_cdk.test.mock_http.response_builder import PaginationStrategy + +NEXT_PAGE_TOKEN = "QVFIUlhOX3Rnbm5Y" + + +class FacebookMarketingPaginationStrategy(PaginationStrategy): + def __init__(self, request: HttpRequest, next_page_token: str) -> None: + self._next_page_token = next_page_token + self._next_page_url = f"{urlunparse(request._parsed_url)}&after={self._next_page_token}" + + def update(self, response: Dict[str, Any]) -> None: + # set a constant value for paging.cursors.after so we know how the 'next' link is built + # https://developers.facebook.com/docs/graph-api/results + response["paging"]["cursors"]["after"] = self._next_page_token + response["paging"]["next"] = self._next_page_url diff --git a/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/request_builder.py b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/request_builder.py new file mode 100644 index 000000000000..a07c81b13448 --- /dev/null +++ b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/request_builder.py @@ -0,0 +1,83 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +from __future__ import annotations + +from typing import Any, List, Mapping, Optional, Union + +from airbyte_cdk.test.mock_http.request import HttpRequest + +from .config import ACCESS_TOKEN, ACCOUNT_ID + + +def get_account_request(account_id: Optional[str] = ACCOUNT_ID) -> RequestBuilder: + return RequestBuilder.get_account_endpoint(access_token=ACCESS_TOKEN, account_id=account_id) + + +class RequestBuilder: + + @classmethod + def get_account_endpoint(cls, access_token: str, account_id: str) -> RequestBuilder: + return cls(access_token=access_token).with_account_id(account_id) + + @classmethod + def get_videos_endpoint(cls, access_token: str, account_id: str) -> RequestBuilder: + return cls(access_token=access_token, resource="advideos").with_account_id(account_id) + + @classmethod + def get_insights_endpoint(cls, access_token: str, account_id: str) -> RequestBuilder: + return cls(access_token=access_token, resource="insights").with_account_id(account_id) + + @classmethod + def get_execute_batch_endpoint(cls, access_token: str) -> RequestBuilder: + return cls(access_token=access_token) + + @classmethod + def get_insights_download_endpoint(cls, access_token: str, job_id: str) -> RequestBuilder: + return cls(access_token=access_token, resource=f"{job_id}/insights") + + def __init__(self, access_token: str, resource: Optional[str] = "") -> None: + self._account_id = None + self._resource = resource + self._query_params = {"access_token": access_token} + self._body = None + + def with_account_id(self, account_id: str) -> RequestBuilder: + self._account_id = account_id + return self + + def with_limit(self, limit: int) -> RequestBuilder: + self._query_params["limit"] = limit + return self + + def with_summary(self) -> RequestBuilder: + self._query_params["summary"] = "true" + return self + + def with_fields(self, fields: List[str]) -> RequestBuilder: + self._query_params["fields"] = self._get_formatted_fields(fields) + return self + + def with_next_page_token(self, next_page_token: str) -> RequestBuilder: + self._query_params["after"] = next_page_token + return self + + def with_body(self, body: Union[str, bytes, Mapping[str, Any]]) -> RequestBuilder: + self._body = body + return self + + def build(self) -> HttpRequest: + return HttpRequest( + url=f"https://graph.facebook.com/v17.0/{self._account_sub_path()}{self._resource}", + query_params=self._query_params, + body=self._body, + ) + + def _account_sub_path(self) -> str: + return f"act_{self._account_id}/" if self._account_id else "" + + @staticmethod + def _get_formatted_fields(fields: List[str]) -> str: + return ",".join(fields) diff --git a/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/response_builder.py b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/response_builder.py new file mode 100644 index 000000000000..836ab1a41e3a --- /dev/null +++ b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/response_builder.py @@ -0,0 +1,33 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +import json +from http import HTTPStatus +from typing import Any, List, Mapping, Optional, Union + +from airbyte_cdk.test.mock_http import HttpResponse + +from .config import ACCOUNT_ID + + +def build_response( + body: Union[Mapping[str, Any], List[Mapping[str, Any]]], + status_code: HTTPStatus, + headers: Optional[Mapping[str, str]] = None, +) -> HttpResponse: + headers = headers or {} + return HttpResponse(body=json.dumps(body), status_code=status_code.value, headers=headers) + + +def get_account_response(account_id: Optional[str] = ACCOUNT_ID) -> HttpResponse: + response = {"account_id": account_id, "id": f"act_{account_id}"} + return build_response(body=response, status_code=HTTPStatus.OK) + + +def error_reduce_amount_of_data_response() -> HttpResponse: + response = { + "error": {"code": 1, "message": "Please reduce the amount of data you're asking for, then retry your request"}, + } + return build_response(body=response, status_code=HTTPStatus.INTERNAL_SERVER_ERROR) diff --git a/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/test_ads_insights_action_product_id.py b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/test_ads_insights_action_product_id.py new file mode 100644 index 000000000000..2fe71e37f271 --- /dev/null +++ b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/test_ads_insights_action_product_id.py @@ -0,0 +1,533 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +import json +from datetime import datetime, timedelta +from http import HTTPStatus +from typing import List, Optional, Union +from unittest import TestCase + +import freezegun +import pendulum +from airbyte_cdk.test.entrypoint_wrapper import EntrypointOutput +from airbyte_cdk.test.mock_http import HttpMocker +from airbyte_cdk.test.mock_http.response_builder import ( + FieldPath, + HttpResponse, + HttpResponseBuilder, + RecordBuilder, + create_record_builder, + create_response_builder, + find_template, +) +from airbyte_protocol.models import AirbyteStateMessage, SyncMode +from source_facebook_marketing.streams.async_job import Status + +from .config import ACCESS_TOKEN, ACCOUNT_ID, DATE_FORMAT, END_DATE, NOW, START_DATE, ConfigBuilder +from .pagination import NEXT_PAGE_TOKEN, FacebookMarketingPaginationStrategy +from .request_builder import RequestBuilder, get_account_request +from .response_builder import build_response, error_reduce_amount_of_data_response, get_account_response +from .utils import config, encode_request_body, read_output + +_STREAM_NAME = "ads_insights_action_product_id" +_CURSOR_FIELD = "date_start" +_REPORT_RUN_ID = "1571860060019548" +_JOB_ID = "1049937379601625" + + +def _update_api_throttle_limit_request(account_id: Optional[str] = ACCOUNT_ID) -> RequestBuilder: + return RequestBuilder.get_insights_endpoint(access_token=ACCESS_TOKEN, account_id=account_id) + + +def _job_start_request( + account_id: Optional[str] = ACCOUNT_ID, since: Optional[datetime] = None, until: Optional[datetime] = None +) -> RequestBuilder: + since = since.strftime(DATE_FORMAT) if since else START_DATE[:10] + until = until.strftime(DATE_FORMAT) if until else END_DATE[:10] + body = { + "level": "ad", + "action_breakdowns": [], + "action_report_time": "mixed", + "breakdowns": ["product_id"], + "fields": [ + "account_currency", + "account_id", + "account_name", + "action_values", + "actions", + "ad_click_actions", + "ad_id", + "ad_impression_actions", + "ad_name", + "adset_id", + "adset_name", + "age_targeting", + "attribution_setting", + "auction_bid", + "auction_competitiveness", + "auction_max_competitor_bid", + "buying_type", + "campaign_id", + "campaign_name", + "canvas_avg_view_percent", + "canvas_avg_view_time", + "catalog_segment_actions", + "catalog_segment_value", + "catalog_segment_value_mobile_purchase_roas", + "catalog_segment_value_omni_purchase_roas", + "catalog_segment_value_website_purchase_roas", + "clicks", + "conversion_rate_ranking", + "conversion_values", + "conversions", + "converted_product_quantity", + "converted_product_value", + "cost_per_15_sec_video_view", + "cost_per_2_sec_continuous_video_view", + "cost_per_action_type", + "cost_per_ad_click", + "cost_per_conversion", + "cost_per_estimated_ad_recallers", + "cost_per_inline_link_click", + "cost_per_inline_post_engagement", + "cost_per_outbound_click", + "cost_per_thruplay", + "cost_per_unique_action_type", + "cost_per_unique_click", + "cost_per_unique_inline_link_click", + "cost_per_unique_outbound_click", + "cpc", + "cpm", + "cpp", + "created_time", + "ctr", + "date_start", + "date_stop", + "engagement_rate_ranking", + "estimated_ad_recall_rate", + "estimated_ad_recall_rate_lower_bound", + "estimated_ad_recall_rate_upper_bound", + "estimated_ad_recallers", + "estimated_ad_recallers_lower_bound", + "estimated_ad_recallers_upper_bound", + "frequency", + "full_view_impressions", + "full_view_reach", + "gender_targeting", + "impressions", + "inline_link_click_ctr", + "inline_link_clicks", + "inline_post_engagement", + "instant_experience_clicks_to_open", + "instant_experience_clicks_to_start", + "instant_experience_outbound_clicks", + "labels", + "location", + "mobile_app_purchase_roas", + "objective", + "optimization_goal", + "outbound_clicks", + "outbound_clicks_ctr", + "purchase_roas", + "qualifying_question_qualify_answer_rate", + "quality_ranking", + "reach", + "social_spend", + "spend", + "unique_actions", + "unique_clicks", + "unique_ctr", + "unique_inline_link_click_ctr", + "unique_inline_link_clicks", + "unique_link_clicks_ctr", + "unique_outbound_clicks", + "unique_outbound_clicks_ctr", + "updated_time", + "video_15_sec_watched_actions", + "video_30_sec_watched_actions", + "video_avg_time_watched_actions", + "video_continuous_2_sec_watched_actions", + "video_p100_watched_actions", + "video_p25_watched_actions", + "video_p50_watched_actions", + "video_p75_watched_actions", + "video_p95_watched_actions", + "video_play_actions", + "video_play_curve_actions", + "video_play_retention_0_to_15s_actions", + "video_play_retention_20_to_60s_actions", + "video_play_retention_graph_actions", + "video_time_watched_actions", + "website_ctr", + "website_purchase_roas", + "wish_bid", + ], + "time_increment": 1, + "action_attribution_windows": ["1d_click", "7d_click", "28d_click", "1d_view", "7d_view", "28d_view"], + "time_range": {"since": since, "until": until}, + } + return RequestBuilder.get_insights_endpoint(access_token=ACCESS_TOKEN, account_id=account_id).with_body( + encode_request_body(body) + ) + + +def _job_status_request(report_run_ids: Union[str, List[str]]) -> RequestBuilder: + if isinstance(report_run_ids, str): + report_run_ids = [report_run_ids] + body = {"batch": [{"method": "GET", "relative_url": f"{report_run_id}/"} for report_run_id in report_run_ids]} + return RequestBuilder.get_execute_batch_endpoint(access_token=ACCESS_TOKEN).with_body(encode_request_body(body)) + + +def _get_insights_request(job_id: str) -> RequestBuilder: + return RequestBuilder.get_insights_download_endpoint(access_token=ACCESS_TOKEN, job_id=job_id).with_limit(100) + + +def _update_api_throttle_limit_response(api_throttle: Optional[int] = 0) -> HttpResponse: + body = {} + headers = { + "x-fb-ads-insights-throttle": json.dumps( + {"app_id_util_pct": api_throttle, "acc_id_util_pct": api_throttle, "ads_api_access_tier": "standard_access"} + ), + } + return build_response(body=body, status_code=HTTPStatus.OK, headers=headers) + + +def _job_start_response(report_run_id: str) -> HttpResponse: + body = {"report_run_id": report_run_id} + return build_response(body=body, status_code=HTTPStatus.OK) + + +def _job_status_response( + job_ids: Union[str, List[str]], status: Optional[Status] = Status.COMPLETED, account_id: Optional[str] = ACCOUNT_ID +) -> HttpResponse: + if isinstance(job_ids, str): + job_ids = [job_ids] + body = [ + { + "body": json.dumps( + { + "id": job_id, "account_id": account_id, "async_status": status, "async_percent_completion": 100 + } + ), + } for job_id in job_ids + ] + return build_response(body=body, status_code=HTTPStatus.OK) + + +def _insights_response() -> HttpResponseBuilder: + return create_response_builder( + response_template=find_template(_STREAM_NAME, __file__), + records_path=FieldPath("data"), + pagination_strategy=FacebookMarketingPaginationStrategy( + request=_get_insights_request(_JOB_ID).with_limit(100).build(), next_page_token=NEXT_PAGE_TOKEN + ), + ) + + +def _ads_insights_action_product_id_record() -> RecordBuilder: + return create_record_builder( + response_template=find_template(_STREAM_NAME, __file__), + records_path=FieldPath("data"), + record_cursor_path=FieldPath(_CURSOR_FIELD), + ) + + +@freezegun.freeze_time(NOW.isoformat()) +class TestFullRefresh(TestCase): + + @staticmethod + def _read(config_: ConfigBuilder, expecting_exception: bool = False) -> EntrypointOutput: + return read_output( + config_builder=config_, + stream_name=_STREAM_NAME, + sync_mode=SyncMode.full_refresh, + expecting_exception=expecting_exception, + ) + + @HttpMocker() + def test_given_one_page_when_read_then_return_records(self, http_mocker: HttpMocker) -> None: + client_side_account_id = "123123123" + server_side_account_id = "321321321" + + start_date = pendulum.parse(START_DATE) + end_date = start_date + timedelta(hours=23) + + http_mocker.get( + get_account_request(account_id=client_side_account_id).build(), + get_account_response(account_id=server_side_account_id), + ) + http_mocker.get( + _update_api_throttle_limit_request(account_id=server_side_account_id).build(), + _update_api_throttle_limit_response(), + ) + http_mocker.post( + _job_start_request(account_id=server_side_account_id, since=start_date, until=end_date).build(), + _job_start_response(_REPORT_RUN_ID), + ) + http_mocker.post(_job_status_request(_REPORT_RUN_ID).build(), _job_status_response(_JOB_ID)) + http_mocker.get( + _get_insights_request(_JOB_ID).build(), + _insights_response().with_record(_ads_insights_action_product_id_record()).build(), + ) + + output = self._read( + config().with_account_ids([client_side_account_id]).with_start_date(start_date).with_end_date(end_date) + ) + assert len(output.records) == 1 + + @HttpMocker() + def test_given_multiple_pages_when_read_then_return_records(self, http_mocker: HttpMocker) -> None: + http_mocker.get(get_account_request().build(), get_account_response()) + http_mocker.get(_update_api_throttle_limit_request().build(), _update_api_throttle_limit_response()) + http_mocker.post(_job_start_request().build(), _job_start_response(_REPORT_RUN_ID)) + http_mocker.post(_job_status_request(_REPORT_RUN_ID).build(), _job_status_response(_JOB_ID)) + http_mocker.get( + _get_insights_request(_JOB_ID).build(), + _insights_response().with_pagination().with_record(_ads_insights_action_product_id_record()).build(), + ) + http_mocker.get( + _get_insights_request(_JOB_ID).with_next_page_token(NEXT_PAGE_TOKEN).build(), + _insights_response().with_record(_ads_insights_action_product_id_record()).with_record( + _ads_insights_action_product_id_record() + ).build(), + ) + + output = self._read(config()) + assert len(output.records) == 3 + + @HttpMocker() + def test_given_api_throttle_exceeds_limit_on_first_check_when_read_then_wait_throttle_down_and_return_records( + self, http_mocker: HttpMocker + ) -> None: + http_mocker.get(get_account_request().build(), get_account_response()) + http_mocker.get( + _update_api_throttle_limit_request().build(), + [ + _update_api_throttle_limit_response(api_throttle=100), + _update_api_throttle_limit_response(api_throttle=0), + ], + ) + http_mocker.post(_job_start_request().build(), _job_start_response(_REPORT_RUN_ID)) + http_mocker.post(_job_status_request(_REPORT_RUN_ID).build(), _job_status_response(_JOB_ID)) + http_mocker.get( + _get_insights_request(_JOB_ID).build(), + _insights_response().with_record(_ads_insights_action_product_id_record()).build(), + ) + + output = self._read(config()) + assert len(output.records) == 1 + + @HttpMocker() + def test_given_multiple_days_when_read_then_return_records(self, http_mocker: HttpMocker) -> None: + start_date = NOW.subtract(days=1) + end_date = NOW + report_run_id_1 = "1571860060019500" + report_run_id_2 = "4571860060019599" + job_id_1 = "1049937379601600" + job_id_2 = "1049937379601699" + + http_mocker.get(get_account_request().build(), get_account_response()) + http_mocker.get(_update_api_throttle_limit_request().build(), _update_api_throttle_limit_response()) + http_mocker.post( + _job_start_request(since=start_date, until=start_date).build(), _job_start_response(report_run_id_1) + ) + http_mocker.post( + _job_start_request(since=end_date, until=end_date).build(), _job_start_response(report_run_id_2) + ) + http_mocker.post( + _job_status_request([report_run_id_1, report_run_id_2]).build(), _job_status_response([job_id_1, job_id_2]) + ) + http_mocker.get( + _get_insights_request(job_id_1).build(), + _insights_response().with_record(_ads_insights_action_product_id_record()).build(), + ) + http_mocker.get( + _get_insights_request(job_id_2).build(), + _insights_response().with_record(_ads_insights_action_product_id_record()).build(), + ) + + output = self._read(config().with_start_date(start_date).with_end_date(end_date)) + assert len(output.records) == 2 + + @HttpMocker() + def test_given_multiple_account_ids_when_read_then_return_records_from_all_accounts( + self, http_mocker: HttpMocker + ) -> None: + account_id_1 = "123123123" + account_id_2 = "321321321" + report_run_id_1 = "1571860060019500" + report_run_id_2 = "4571860060019599" + job_id_1 = "1049937379601600" + job_id_2 = "1049937379601699" + + api_throttle_limit_response = _update_api_throttle_limit_response() + + http_mocker.get( + get_account_request().with_account_id(account_id_1).build(), get_account_response(account_id=account_id_1) + ) + http_mocker.get( + _update_api_throttle_limit_request().with_account_id(account_id_1).build(), api_throttle_limit_response + ) + http_mocker.post( + _job_start_request().with_account_id(account_id_1).build(), _job_start_response(report_run_id_1) + ) + http_mocker.post( + _job_status_request(report_run_id_1).build(), _job_status_response(job_id_1, account_id=account_id_1) + ) + http_mocker.get( + _get_insights_request(job_id_1).build(), + _insights_response().with_record(_ads_insights_action_product_id_record()).build(), + ) + + http_mocker.get( + get_account_request().with_account_id(account_id_2).build(), get_account_response(account_id=account_id_2) + ) + http_mocker.get( + _update_api_throttle_limit_request().with_account_id(account_id_2).build(), api_throttle_limit_response + ) + http_mocker.post( + _job_start_request().with_account_id(account_id_2).build(), _job_start_response(report_run_id_2) + ) + http_mocker.post( + _job_status_request(report_run_id_2).build(), _job_status_response(job_id_2, account_id=account_id_2) + ) + http_mocker.get( + _get_insights_request(job_id_2).build(), + _insights_response().with_record(_ads_insights_action_product_id_record()).build(), + ) + + output = self._read(config().with_account_ids([account_id_1, account_id_2])) + assert len(output.records) == 2 + + @HttpMocker() + def test_given_status_500_reduce_amount_of_data_when_read_then_limit_reduced(self, http_mocker: HttpMocker) -> None: + limit = 100 + + http_mocker.get(get_account_request().build(), get_account_response()) + http_mocker.get(_update_api_throttle_limit_request().build(), _update_api_throttle_limit_response()) + http_mocker.post(_job_start_request().build(), _job_start_response(_REPORT_RUN_ID)) + http_mocker.post(_job_status_request(_REPORT_RUN_ID).build(), _job_status_response(_JOB_ID)) + http_mocker.get( + _get_insights_request(_JOB_ID).with_limit(limit).build(), + error_reduce_amount_of_data_response(), + ) + http_mocker.get( + _get_insights_request(_JOB_ID).with_limit(int(limit / 2)).build(), + _insights_response().with_record(_ads_insights_action_product_id_record()).build(), + ) + + self._read(config()) + + +@freezegun.freeze_time(NOW.isoformat()) +class TestIncremental(TestCase): + @staticmethod + def _read( + config_: ConfigBuilder, state: Optional[List[AirbyteStateMessage]] = None, expecting_exception: bool = False + ) -> EntrypointOutput: + return read_output( + config_builder=config_, + stream_name=_STREAM_NAME, + sync_mode=SyncMode.incremental, + state=state, + expecting_exception=expecting_exception, + ) + + @HttpMocker() + def test_when_read_then_state_message_produced_and_state_match_start_interval( + self, http_mocker: HttpMocker + ) -> None: + account_id = "123123123" + start_date = NOW.set(hour=0, minute=0, second=0) + end_date = NOW.set(hour=23, minute=59, second=59) + + http_mocker.get( + get_account_request().with_account_id(account_id).build(), get_account_response(account_id=account_id) + ) + http_mocker.get( + _update_api_throttle_limit_request().with_account_id(account_id).build(), + _update_api_throttle_limit_response(), + ) + http_mocker.post( + _job_start_request(since=start_date, until=end_date).with_account_id(account_id).build(), + _job_start_response(_REPORT_RUN_ID), + ) + http_mocker.post( + _job_status_request(_REPORT_RUN_ID).build(), _job_status_response(_JOB_ID, account_id=account_id) + ) + http_mocker.get( + _get_insights_request(_JOB_ID).build(), + _insights_response().with_record(_ads_insights_action_product_id_record()).build(), + ) + + output = self._read(config().with_account_ids([account_id]).with_start_date(start_date).with_end_date(end_date)) + cursor_value_from_state_message = output.most_recent_state.get(_STREAM_NAME, {}).get(account_id, {}).get( + _CURSOR_FIELD + ) + assert cursor_value_from_state_message == start_date.strftime(DATE_FORMAT) + + @HttpMocker() + def test_given_multiple_account_ids_when_read_then_state_produced_by_account_id_and_state_match_start_interval( + self, http_mocker: HttpMocker + ) -> None: + account_id_1 = "123123123" + account_id_2 = "321321321" + start_date = NOW.set(hour=0, minute=0, second=0) + end_date = NOW.set(hour=23, minute=59, second=59) + report_run_id_1 = "1571860060019500" + report_run_id_2 = "4571860060019599" + job_id_1 = "1049937379601600" + job_id_2 = "1049937379601699" + + api_throttle_limit_response = _update_api_throttle_limit_response() + + http_mocker.get( + get_account_request().with_account_id(account_id_1).build(), get_account_response(account_id=account_id_1) + ) + http_mocker.get( + _update_api_throttle_limit_request().with_account_id(account_id_1).build(), api_throttle_limit_response + ) + http_mocker.post( + _job_start_request(since=start_date, until=end_date).with_account_id(account_id_1).build(), + _job_start_response(report_run_id_1), + ) + http_mocker.post( + _job_status_request(report_run_id_1).build(), _job_status_response(job_id_1, account_id=account_id_1) + ) + http_mocker.get( + _get_insights_request(job_id_1).build(), + _insights_response().with_record(_ads_insights_action_product_id_record()).build(), + ) + + http_mocker.get( + get_account_request().with_account_id(account_id_2).build(), get_account_response(account_id=account_id_2) + ) + http_mocker.get( + _update_api_throttle_limit_request().with_account_id(account_id_2).build(), api_throttle_limit_response + ) + http_mocker.post( + _job_start_request(since=start_date, until=end_date).with_account_id(account_id_2).build(), + _job_start_response(report_run_id_2), + ) + http_mocker.post( + _job_status_request(report_run_id_2).build(), _job_status_response(job_id_2, account_id=account_id_2) + ) + http_mocker.get( + _get_insights_request(job_id_2).build(), + _insights_response().with_record(_ads_insights_action_product_id_record()).build(), + ) + + output = self._read( + config().with_account_ids([account_id_1, account_id_2]).with_start_date(start_date).with_end_date(end_date) + ) + cursor_value_from_state_account_1 = output.most_recent_state.get(_STREAM_NAME, {}).get(account_id_1, {}).get( + _CURSOR_FIELD + ) + cursor_value_from_state_account_2 = output.most_recent_state.get(_STREAM_NAME, {}).get(account_id_2, {}).get( + _CURSOR_FIELD + ) + expected_cursor_value = start_date.strftime(DATE_FORMAT) + assert cursor_value_from_state_account_1 == expected_cursor_value + assert cursor_value_from_state_account_2 == expected_cursor_value diff --git a/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/test_videos.py b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/test_videos.py new file mode 100644 index 000000000000..f2aa2990f3fb --- /dev/null +++ b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/test_videos.py @@ -0,0 +1,348 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +from typing import List, Optional +from unittest import TestCase + +import freezegun +from airbyte_cdk.test.entrypoint_wrapper import EntrypointOutput +from airbyte_cdk.test.mock_http import HttpMocker +from airbyte_cdk.test.mock_http.response_builder import ( + FieldPath, + HttpResponseBuilder, + RecordBuilder, + create_record_builder, + create_response_builder, + find_template, +) +from airbyte_cdk.test.state_builder import StateBuilder +from airbyte_protocol.models import AirbyteStateMessage, SyncMode + +from .config import ACCESS_TOKEN, ACCOUNT_ID, NOW, ConfigBuilder +from .pagination import NEXT_PAGE_TOKEN, FacebookMarketingPaginationStrategy +from .request_builder import RequestBuilder, get_account_request +from .response_builder import error_reduce_amount_of_data_response, get_account_response +from .utils import config, read_output + +_STREAM_NAME = "videos" +_CURSOR_FIELD = "updated_time" +_FIELDS = [ + "id", + "ad_breaks", + "backdated_time", + "backdated_time_granularity", + "content_category", + "content_tags", + "created_time", + "custom_labels", + "description", + "embed_html", + "embeddable", + "format", + "icon", + "is_crosspost_video", + "is_crossposting_eligible", + "is_episode", + "is_instagram_eligible", + "length", + "live_status", + "permalink_url", + "post_views", + "premiere_living_room_status", + "published", + "scheduled_publish_time", + "source", + "title", + "universal_video_id", + "updated_time", + "views", +] + + +def _get_videos_request(account_id: Optional[str] = ACCOUNT_ID) -> RequestBuilder: + return RequestBuilder.get_videos_endpoint( + access_token=ACCESS_TOKEN, account_id=account_id + ).with_limit(100).with_fields(_FIELDS).with_summary() + + +def _get_videos_response() -> HttpResponseBuilder: + return create_response_builder( + response_template=find_template(_STREAM_NAME, __file__), + records_path=FieldPath("data"), + pagination_strategy=FacebookMarketingPaginationStrategy( + request=_get_videos_request().build(), next_page_token=NEXT_PAGE_TOKEN + ), + ) + + +def _video_record() -> RecordBuilder: + return create_record_builder( + response_template=find_template(_STREAM_NAME, __file__), + records_path=FieldPath("data"), + record_id_path=FieldPath("id"), + record_cursor_path=FieldPath(_CURSOR_FIELD), + ) + + +@freezegun.freeze_time(NOW.isoformat()) +class TestFullRefresh(TestCase): + + @staticmethod + def _read(config_: ConfigBuilder, expecting_exception: bool = False) -> EntrypointOutput: + return read_output( + config_builder=config_, + stream_name=_STREAM_NAME, + sync_mode=SyncMode.full_refresh, + expecting_exception=expecting_exception, + ) + + @HttpMocker() + def test_given_one_page_when_read_then_return_records(self, http_mocker: HttpMocker) -> None: + client_side_account_id = ACCOUNT_ID + server_side_account_id = ACCOUNT_ID + + http_mocker.get( + get_account_request(account_id=client_side_account_id).build(), + get_account_response(account_id=server_side_account_id), + ) + http_mocker.get( + _get_videos_request(account_id=server_side_account_id).build(), + _get_videos_response().with_record(_video_record()).build(), + ) + + output = self._read(config().with_account_ids([client_side_account_id])) + assert len(output.records) == 1 + + @HttpMocker() + def test_given_multiple_pages_when_read_then_return_records(self, http_mocker: HttpMocker) -> None: + http_mocker.get(get_account_request().build(), get_account_response()) + http_mocker.get( + _get_videos_request().build(), + _get_videos_response().with_pagination().with_record(_video_record()).build(), + ) + http_mocker.get( + _get_videos_request().with_next_page_token(NEXT_PAGE_TOKEN).build(), + _get_videos_response().with_record(_video_record()).with_record(_video_record()).build(), + ) + + output = self._read(config()) + assert len(output.records) == 3 + + @HttpMocker() + def test_given_multiple_account_ids_when_read_then_return_records_from_all_accounts( + self, http_mocker: HttpMocker + ) -> None: + account_id_1 = "123123123" + account_id_2 = "321321321" + + http_mocker.get( + get_account_request().with_account_id(account_id_1).build(), get_account_response(account_id=account_id_1) + ) + http_mocker.get( + _get_videos_request().with_account_id(account_id_1).build(), + _get_videos_response().with_record(_video_record()).build(), + ) + http_mocker.get( + get_account_request().with_account_id(account_id_2).build(), get_account_response(account_id=account_id_2) + ) + http_mocker.get( + _get_videos_request().with_account_id(account_id_2).build(), + _get_videos_response().with_record(_video_record()).build(), + ) + + output = self._read(config().with_account_ids([account_id_1, account_id_2])) + assert len(output.records) == 2 + + @HttpMocker() + def test_when_read_then_add_account_id_field(self, http_mocker: HttpMocker) -> None: + account_id = "123123123" + + http_mocker.get( + get_account_request().with_account_id(account_id).build(), get_account_response(account_id=account_id) + ) + http_mocker.get( + _get_videos_request().with_account_id(account_id).build(), + _get_videos_response().with_record(_video_record()).build(), + ) + + output = self._read(config().with_account_ids([account_id])) + assert output.records[0].record.data["account_id"] == account_id + + @HttpMocker() + def test_when_read_then_datetime_fields_transformed(self, http_mocker: HttpMocker) -> None: + created_time_field = "created_time" + input_datetime_value = "2024-01-01t00:00:00 0000" + expected_datetime_value = "2024-01-01T00:00:00+0000" + + http_mocker.get(get_account_request().build(), get_account_response()) + http_mocker.get( + _get_videos_request().with_fields(_FIELDS).with_summary().build(), + _get_videos_response().with_record( + _video_record().with_field(FieldPath(created_time_field), input_datetime_value) + ).build(), + ) + + output = self._read(config()) + assert output.records[0].record.data[created_time_field] == expected_datetime_value + + @HttpMocker() + def test_given_status_500_reduce_amount_of_data_when_read_then_limit_reduced(self, http_mocker: HttpMocker) -> None: + limit = 100 + + http_mocker.get(get_account_request().build(), get_account_response()) + http_mocker.get( + _get_videos_request().with_limit(limit).with_fields(_FIELDS).with_summary().build(), + error_reduce_amount_of_data_response(), + ) + http_mocker.get( + _get_videos_request().with_limit(int(limit / 2)).with_fields(_FIELDS).with_summary().build(), + _get_videos_response().with_record(_video_record()).build(), + ) + + self._read(config()) + + +@freezegun.freeze_time(NOW.isoformat()) +class TestIncremental(TestCase): + @staticmethod + def _read( + config_: ConfigBuilder, state: Optional[List[AirbyteStateMessage]] = None, expecting_exception: bool = False + ) -> EntrypointOutput: + return read_output( + config_builder=config_, + stream_name=_STREAM_NAME, + sync_mode=SyncMode.incremental, + state=state, + expecting_exception=expecting_exception, + ) + + @HttpMocker() + def test_when_read_then_state_message_produced_and_state_match_latest_record(self, http_mocker: HttpMocker) -> None: + min_cursor_value = "2024-01-01T00:00:00+00:00" + max_cursor_value = "2024-02-01T00:00:00+00:00" + account_id = "123123123" + + http_mocker.get( + get_account_request().with_account_id(account_id).build(), get_account_response(account_id=account_id) + ) + http_mocker.get( + _get_videos_request().with_account_id(account_id).build(), + _get_videos_response().with_record(_video_record().with_cursor(max_cursor_value)).with_record( + _video_record().with_cursor(min_cursor_value) + ).build(), + ) + + output = self._read(config().with_account_ids([account_id])) + cursor_value_from_state_message = output.most_recent_state.get(_STREAM_NAME, {}).get(account_id, {}).get( + _CURSOR_FIELD + ) + assert cursor_value_from_state_message == max_cursor_value + + @HttpMocker() + def test_given_multiple_account_ids_when_read_then_state_produced_by_account_id_and_state_match_latest_record( + self, http_mocker: HttpMocker + ) -> None: + account_id_1 = "123123123" + account_id_2 = "321321321" + min_cursor_value_account_id_1 = "2024-01-01T00:00:00+00:00" + max_cursor_value_account_id_1 = "2024-02-01T00:00:00+00:00" + min_cursor_value_account_id_2 = "2024-03-01T00:00:00+00:00" + max_cursor_value_account_id_2 = "2024-04-01T00:00:00+00:00" + + http_mocker.get( + get_account_request().with_account_id(account_id_1).build(), get_account_response(account_id=account_id_1) + ) + http_mocker.get( + _get_videos_request().with_account_id(account_id_1).build(), + _get_videos_response().with_record(_video_record().with_cursor(max_cursor_value_account_id_1)).with_record( + _video_record().with_cursor(min_cursor_value_account_id_1) + ).build(), + ) + http_mocker.get( + get_account_request().with_account_id(account_id_2).build(), get_account_response(account_id=account_id_2) + ) + http_mocker.get( + _get_videos_request().with_account_id(account_id_2).build(), + _get_videos_response().with_record(_video_record().with_cursor(max_cursor_value_account_id_2)).with_record( + _video_record().with_cursor(min_cursor_value_account_id_2) + ).build(), + ) + + output = self._read(config().with_account_ids([account_id_1, account_id_2])) + cursor_value_from_state_account_1 = output.most_recent_state.get(_STREAM_NAME, {}).get(account_id_1, {}).get( + _CURSOR_FIELD + ) + cursor_value_from_state_account_2 = output.most_recent_state.get(_STREAM_NAME, {}).get(account_id_2, {}).get( + _CURSOR_FIELD + ) + assert cursor_value_from_state_account_1 == max_cursor_value_account_id_1 + assert cursor_value_from_state_account_2 == max_cursor_value_account_id_2 + + @HttpMocker() + def test_given_state_when_read_then_records_with_cursor_value_less_than_state_filtered( + self, http_mocker: HttpMocker + ) -> None: + account_id = "123123123" + cursor_value_1 = "2024-01-01T00:00:00+00:00" + cursor_value_2 = "2024-01-02T00:00:00+00:00" + cursor_value_3 = "2024-01-03T00:00:00+00:00" + + http_mocker.get( + get_account_request().with_account_id(account_id).build(), get_account_response(account_id=account_id) + ) + http_mocker.get( + _get_videos_request().with_account_id(account_id).build(), + _get_videos_response().with_record(_video_record().with_cursor(cursor_value_3)).with_record( + _video_record().with_cursor(cursor_value_2) + ).with_record( + _video_record().with_cursor(cursor_value_1) + ).build(), + ) + + output = self._read( + config().with_account_ids([account_id]), + state=StateBuilder().with_stream_state(_STREAM_NAME, {account_id: {_CURSOR_FIELD: cursor_value_2}}).build(), + ) + assert len(output.records) == 2 + + @HttpMocker() + def test_given_state_and_multiple_account_ids_when_read_then_records_with_cursor_value_less_than_state_filtered( + self, http_mocker: HttpMocker + ) -> None: + account_id_1 = "123123123" + account_id_2 = "321321321" + cursor_value_1 = "2024-01-01T00:00:00+00:00" + cursor_value_2 = "2024-01-02T00:00:00+00:00" + cursor_value_3 = "2024-01-03T00:00:00+00:00" + + http_mocker.get( + get_account_request().with_account_id(account_id_1).build(), get_account_response(account_id=account_id_1) + ) + http_mocker.get( + _get_videos_request().with_account_id(account_id_1).build(), + _get_videos_response().with_record(_video_record().with_cursor(cursor_value_3)).with_record( + _video_record().with_cursor(cursor_value_2) + ).with_record( + _video_record().with_cursor(cursor_value_1) + ).build(), + ) + http_mocker.get( + get_account_request().with_account_id(account_id_2).build(), get_account_response(account_id=account_id_2) + ) + http_mocker.get( + _get_videos_request().with_account_id(account_id_2).build(), + _get_videos_response().with_record(_video_record().with_cursor(cursor_value_3)).with_record( + _video_record().with_cursor(cursor_value_2) + ).with_record( + _video_record().with_cursor(cursor_value_1) + ).build(), + ) + + stream_state = {account_id_1: {_CURSOR_FIELD: cursor_value_2}, account_id_2: {_CURSOR_FIELD: cursor_value_2}} + output = self._read( + config().with_account_ids([account_id_1, account_id_2]), + state=StateBuilder().with_stream_state(_STREAM_NAME, stream_state).build(), + ) + assert len(output.records) == 4 diff --git a/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/utils.py b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/utils.py new file mode 100644 index 000000000000..14d184412d9f --- /dev/null +++ b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/integration/utils.py @@ -0,0 +1,44 @@ +# +# Copyright (c) 2024 Airbyte, Inc., all rights reserved. +# + + +from typing import Any, Dict, List, Optional +from urllib.parse import urlencode + +from airbyte_cdk.test.catalog_builder import CatalogBuilder +from airbyte_cdk.test.entrypoint_wrapper import EntrypointOutput, read +from airbyte_protocol.models import AirbyteStateMessage, ConfiguredAirbyteCatalog, SyncMode +from facebook_business.api import _top_level_param_json_encode +from source_facebook_marketing import SourceFacebookMarketing + +from .config import ConfigBuilder + + +def config() -> ConfigBuilder: + return ConfigBuilder() + + +def catalog(stream_name: str, sync_mode: SyncMode) -> ConfiguredAirbyteCatalog: + return CatalogBuilder().with_stream(stream_name, sync_mode).build() + + +def source() -> SourceFacebookMarketing: + return SourceFacebookMarketing() + + +def read_output( + config_builder: ConfigBuilder, + stream_name: str, + sync_mode: SyncMode, + state: Optional[List[AirbyteStateMessage]] = None, + expecting_exception: Optional[bool] = False, +) -> EntrypointOutput: + _catalog = catalog(stream_name, sync_mode) + _config = config_builder.build() + return read(source(), _config, _catalog, state, expecting_exception) + + +def encode_request_body(body: Dict[str, Any]) -> str: + body = body.copy() + return urlencode(_top_level_param_json_encode(body)) diff --git a/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/resource/http/response/ads_insights_action_product_id.json b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/resource/http/response/ads_insights_action_product_id.json new file mode 100644 index 000000000000..2645a16c4eec --- /dev/null +++ b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/resource/http/response/ads_insights_action_product_id.json @@ -0,0 +1,203 @@ +{ + "data": [ + { + "account_currency": "USD", + "account_id": "798085168510957", + "account_name": "Porsche Riverside", + "actions": [ + { + "action_type": "page_engagement", + "value": "10", + "1d_click": "10", + "7d_click": "10", + "28d_click": "10" + }, + { + "action_type": "post_engagement", + "value": "10", + "1d_click": "10", + "7d_click": "10", + "28d_click": "10" + } + ], + "ad_id": "23854695759200548", + "ad_name": "New - AIA - Advertised Offers - Cayenne", + "adset_id": "23854404706320548", + "adset_name": "New Cayenne", + "buying_type": "AUCTION", + "campaign_id": "23854404676180548", + "campaign_name": "zzzzzNew - AIA - Advertised Offers", + "clicks": "9", + "cost_per_action_type": [ + { + "action_type": "link_click", + "value": "1.594444", + "1d_click": "1.594444", + "7d_click": "1.594444", + "28d_click": "1.594444" + }, + { + "action_type": "post_engagement", + "value": "1.435", + "1d_click": "1.435", + "7d_click": "1.435", + "28d_click": "1.435" + }, + { + "action_type": "page_engagement", + "value": "1.435", + "1d_click": "1.435", + "7d_click": "1.435", + "28d_click": "1.435" + } + ], + "cost_per_inline_link_click": "1.594444", + "cost_per_inline_post_engagement": "1.435", + "cost_per_outbound_click": [ + { + "action_type": "outbound_click", + "value": "1.594444" + } + ], + "cpc": "1.594444", + "cpm": "77.567568", + "created_time": "2023-06-01", + "ctr": "4.864865", + "date_start": "2023-06-01", + "date_stop": "2023-06-01", + "impressions": "185", + "inline_link_click_ctr": "4.864865", + "inline_link_clicks": "9", + "inline_post_engagement": "10", + "objective": "PRODUCT_CATALOG_SALES", + "optimization_goal": "OFFSITE_CONVERSIONS", + "outbound_clicks": [ + { + "action_type": "outbound_click", + "value": "9" + } + ], + "outbound_clicks_ctr": [ + { + "action_type": "outbound_click", + "value": "4.864865" + } + ], + "spend": "14.35", + "updated_time": "2023-06-01", + "website_ctr": [ + { + "action_type": "link_click", + "value": "4.864865" + } + ], + "product_id": "5983858725075630" + }, + { + "account_currency": "USD", + "account_id": "798085168510957", + "account_name": "Porsche Riverside", + "actions": [ + { + "action_type": "page_engagement", + "value": "4", + "1d_click": "4", + "7d_click": "4", + "28d_click": "4" + }, + { + "action_type": "post_engagement", + "value": "4", + "1d_click": "4", + "7d_click": "4", + "28d_click": "4" + }, + { + "action_type": "link_click", + "value": "4", + "1d_click": "4", + "7d_click": "4", + "28d_click": "4" + } + ], + "ad_id": "23854695759200548", + "ad_name": "New - AIA - Advertised Offers - Cayenne", + "adset_id": "23854404706320548", + "adset_name": "New Cayenne", + "buying_type": "AUCTION", + "campaign_id": "23854404676180548", + "campaign_name": "zzzzzNew - AIA - Advertised Offers", + "clicks": "7", + "cost_per_action_type": [ + { + "action_type": "link_click", + "value": "2.1325", + "1d_click": "2.1325", + "7d_click": "2.1325", + "28d_click": "2.1325" + }, + { + "action_type": "post_engagement", + "value": "2.1325", + "1d_click": "2.1325", + "7d_click": "2.1325", + "28d_click": "2.1325" + }, + { + "action_type": "page_engagement", + "value": "2.1325", + "1d_click": "2.1325", + "7d_click": "2.1325", + "28d_click": "2.1325" + } + ], + "cost_per_inline_link_click": "2.1325", + "cost_per_inline_post_engagement": "2.1325", + "cost_per_outbound_click": [ + { + "action_type": "outbound_click", + "value": "2.1325" + } + ], + "cpc": "1.218571", + "cpm": "49.883041", + "created_time": "2023-06-01", + "ctr": "4.093567", + "date_start": "2023-06-01", + "date_stop": "2023-06-01", + "impressions": "171", + "inline_link_click_ctr": "2.339181", + "inline_link_clicks": "4", + "inline_post_engagement": "4", + "objective": "PRODUCT_CATALOG_SALES", + "optimization_goal": "OFFSITE_CONVERSIONS", + "outbound_clicks": [ + { + "action_type": "outbound_click", + "value": "4" + } + ], + "outbound_clicks_ctr": [ + { + "action_type": "outbound_click", + "value": "2.339181" + } + ], + "spend": "8.53", + "updated_time": "2023-06-01", + "website_ctr": [ + { + "action_type": "link_click", + "value": "2.339181" + } + ], + "product_id": "6023934044385671" + } + ], + "paging": { + "cursors": { + "before": "MAZDZD", + "after": "NzIZD" + } + } +} diff --git a/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/resource/http/response/videos.json b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/resource/http/response/videos.json new file mode 100644 index 000000000000..b939df637bbc --- /dev/null +++ b/airbyte-integrations/connectors/source-facebook-marketing/unit_tests/resource/http/response/videos.json @@ -0,0 +1,111 @@ +{ + "data": [ + { + "id": "925443935443492", + "content_category": "OTHER", + "created_time": "2024-02-01T21:40:03+0000", + "embed_html": "\u003Ciframe allow=\"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share\" allowfullscreen=\"true\" frameborder=\"0\" height=\"1080\" scrolling=\"no\" src=\"https://www.facebook.com/plugins/video.php?href=https\u00253A\u00252F\u00252Fwww.facebook.com\u00252F23854402720800548\u00252Fvideos\u00252F925443935443492\u00252F\u00253Fidorvanity\u00253D23854402720800548&width=1080\" style=\"border:none;overflow:hidden\" width=\"1080\">\u003C/iframe>", + "embeddable": true, + "format": [ + { + "embed_html": "\u003Ciframe allow=\"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share\" allowfullscreen=\"true\" frameborder=\"0\" height=\"130\" scrolling=\"no\" src=\"https://www.facebook.com/plugins/video.php?href=https\u00253A\u00252F\u00252Fwww.facebook.com\u00252F23854402720800548\u00252Fvideos\u00252F925443935443492\u00252F\u00253Fidorvanity\u00253D23854402720800548&width=130\" style=\"border:none;overflow:hidden\" width=\"130\">\u003C/iframe>", + "filter": "130x130", + "height": 130, + "picture": "https://scontent.fiev6-1.fna.fbcdn.net/v/t15.13418-10/423069644_877218477743074_5429676119391867799_n.jpg?stp=dst-jpg_p130x130&_nc_cat=100&ccb=1-7&_nc_sid=1a7029&_nc_ohc=NA4oxYdIA_cAX-0Bvx_&_nc_ht=scontent.fiev6-1.fna&edm=AM_bLsMEAAAA&oh=00_AfBwNsaOjVl78jAV6jaMdmkBp54ZV6stgb8BBf5spWzRVw&oe=65CA7A97", + "width": 130 + }, + { + "embed_html": "\u003Ciframe allow=\"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share\" allowfullscreen=\"true\" frameborder=\"0\" height=\"480\" scrolling=\"no\" src=\"https://www.facebook.com/plugins/video.php?href=https\u00253A\u00252F\u00252Fwww.facebook.com\u00252F23854402720800548\u00252Fvideos\u00252F925443935443492\u00252F\u00253Fidorvanity\u00253D23854402720800548&width=480\" style=\"border:none;overflow:hidden\" width=\"480\">\u003C/iframe>", + "filter": "480x480", + "height": 480, + "picture": "https://scontent.fiev6-1.fna.fbcdn.net/v/t15.13418-10/423069644_877218477743074_5429676119391867799_n.jpg?stp=dst-jpg_p480x480&_nc_cat=100&ccb=1-7&_nc_sid=1a7029&_nc_ohc=NA4oxYdIA_cAX-0Bvx_&_nc_ht=scontent.fiev6-1.fna&edm=AM_bLsMEAAAA&oh=00_AfCSSRmwbclnqnKAlmrAMK8Q8T6covE1azUyk-YQ7DGfAA&oe=65CA7A97", + "width": 480 + }, + { + "embed_html": "\u003Ciframe allow=\"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share\" allowfullscreen=\"true\" frameborder=\"0\" height=\"720\" scrolling=\"no\" src=\"https://www.facebook.com/plugins/video.php?href=https\u00253A\u00252F\u00252Fwww.facebook.com\u00252F23854402720800548\u00252Fvideos\u00252F925443935443492\u00252F\u00253Fidorvanity\u00253D23854402720800548&width=720\" style=\"border:none;overflow:hidden\" width=\"720\">\u003C/iframe>", + "filter": "720x720", + "height": 720, + "picture": "https://scontent.fiev6-1.fna.fbcdn.net/v/t15.13418-10/423069644_877218477743074_5429676119391867799_n.jpg?stp=dst-jpg_p720x720&_nc_cat=100&ccb=1-7&_nc_sid=1a7029&_nc_ohc=NA4oxYdIA_cAX-0Bvx_&_nc_ht=scontent.fiev6-1.fna&edm=AM_bLsMEAAAA&oh=00_AfCiwt-R1NWb4qQaxws6AD0Sk1sp99cfyDzKdRPWII1ZRw&oe=65CA7A97", + "width": 720 + }, + { + "embed_html": "\u003Ciframe allow=\"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share\" allowfullscreen=\"true\" frameborder=\"0\" height=\"1080\" scrolling=\"no\" src=\"https://www.facebook.com/plugins/video.php?href=https\u00253A\u00252F\u00252Fwww.facebook.com\u00252F23854402720800548\u00252Fvideos\u00252F925443935443492\u00252F\u00253Fidorvanity\u00253D23854402720800548&width=1080\" style=\"border:none;overflow:hidden\" width=\"1080\">\u003C/iframe>", + "filter": "native", + "height": 1080, + "picture": "https://scontent.fiev6-1.fna.fbcdn.net/v/t15.13418-10/423069644_877218477743074_5429676119391867799_n.jpg?stp=dst-jpg&_nc_cat=100&ccb=1-7&_nc_sid=1a7029&_nc_ohc=NA4oxYdIA_cAX-0Bvx_&_nc_ht=scontent.fiev6-1.fna&edm=AM_bLsMEAAAA&oh=00_AfDcziC4hL0U904kPv8GBKuhH4CP6gDqGagDX2xWVTvTnQ&oe=65CA7A97", + "width": 1080 + } + ], + "icon": "https://static.xx.fbcdn.net/rsrc.php/v3/yD/r/DggDhA4z4tO.gif", + "is_crosspost_video": false, + "is_crossposting_eligible": false, + "is_episode": false, + "is_instagram_eligible": true, + "length": 24.024, + "permalink_url": "/23854402720800548/videos/925443935443492/?idorvanity=23854402720800548", + "post_views": 0, + "published": true, + "source": "https://video.fiev6-1.fna.fbcdn.net/o1/v/t2/f1/m69/GFFjPxkyAKs6DSwMAENL3WReuCxVbmdjAAAF.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6Im9lcF9oZCJ9&_nc_ht=video.fiev6-1.fna.fbcdn.net&_nc_cat=101&strext=1&vs=3c5762ad873c98da&_nc_vs=HBksFQIYOnBhc3N0aHJvdWdoX2V2ZXJzdG9yZS9HRkZqUHhreUFLczZEU3dNQUVOTDNXUmV1Q3hWYm1kakFBQUYVAALIAQAVAhg6cGFzc3Rocm91Z2hfZXZlcnN0b3JlL0dFXzhOQmw4RGRxOXlGSUJBR3Z6MmtUWkdXUmJidjRHQUFBRhUCAsgBAEsHiBJwcm9ncmVzc2l2ZV9yZWNpcGUBMQ1zdWJzYW1wbGVfZnBzABB2bWFmX2VuYWJsZV9uc3ViACBtZWFzdXJlX29yaWdpbmFsX3Jlc29sdXRpb25fc3NpbQAoY29tcHV0ZV9zc2ltX29ubHlfYXRfb3JpZ2luYWxfcmVzb2x1dGlvbgAddXNlX2xhbmN6b3NfZm9yX3ZxbV91cHNjYWxpbmcAEWRpc2FibGVfcG9zdF9wdnFzABUAJQAcjBdAAAAAAAAAABERAAAAJsbx\u00252BO61t7kBFQIoAkMzGAt2dHNfcHJldmlldxwXQDgGJN0vGqAYIWRhc2hfZ2VuMmh3YmFzaWNfaHEyX2ZyYWdfMl92aWRlbxIAGBh2aWRlb3MudnRzLmNhbGxiYWNrLnByb2Q4ElZJREVPX1ZJRVdfUkVRVUVTVBsKiBVvZW1fdGFyZ2V0X2VuY29kZV90YWcGb2VwX2hkE29lbV9yZXF1ZXN0X3RpbWVfbXMBMAxvZW1fY2ZnX3J1bGUHdW5tdXRlZBNvZW1fcm9pX3JlYWNoX2NvdW50ATARb2VtX2lzX2V4cGVyaW1lbnQADG9lbV92aWRlb19pZA85MjU0NDM5MzU0NDM0OTISb2VtX3ZpZGVvX2Fzc2V0X2lkEDE3OTAxNjM5MDgxNjU3NjIVb2VtX3ZpZGVvX3Jlc291cmNlX2lkDzQwNzc3MTQyNDk1NTQ5MRxvZW1fc291cmNlX3ZpZGVvX2VuY29kaW5nX2lkDzM4NTQxMjEyNDE4MDIxNw52dHNfcmVxdWVzdF9pZAAlAhwAJY4CGweIAXMENjEyMQJjZAoyMDI0LTAyLTAxA2FwcANEREgCY3QGTEVHQUNZE29yaWdpbmFsX2R1cmF0aW9uX3MGMjQuMDY0AWYCYWQCdHMVcHJvZ3Jlc3NpdmVfZW5jb2RpbmdzAA\u00253D\u00253D&ccb=9-4&oh=00_AfA8BOCXei12URMU4g6BguZ4qCS2cTAwpMrLLW4g55t_Wg&oe=65C6D242&_nc_sid=1d576d&_nc_rid=530335006251005&_nc_store_type=1", + "updated_time": "2024-02-01T21:40:24+0000", + "views": 0 + }, + { + "id": "916735743507460", + "content_category": "OTHER", + "created_time": "2024-01-29T23:09:08+0000", + "embed_html": "\u003Ciframe allow=\"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share\" allowfullscreen=\"true\" frameborder=\"0\" height=\"1080\" scrolling=\"no\" src=\"https://www.facebook.com/plugins/video.php?href=https\u00253A\u00252F\u00252Fwww.facebook.com\u00252F23854402720800548\u00252Fvideos\u00252F916735743507460\u00252F\u00253Fidorvanity\u00253D23854402720800548&width=1080\" style=\"border:none;overflow:hidden\" width=\"1080\">\u003C/iframe>", + "embeddable": true, + "format": [ + { + "embed_html": "\u003Ciframe allow=\"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share\" allowfullscreen=\"true\" frameborder=\"0\" height=\"130\" scrolling=\"no\" src=\"https://www.facebook.com/plugins/video.php?href=https\u00253A\u00252F\u00252Fwww.facebook.com\u00252F23854402720800548\u00252Fvideos\u00252F916735743507460\u00252F\u00253Fidorvanity\u00253D23854402720800548&width=130\" style=\"border:none;overflow:hidden\" width=\"130\">\u003C/iframe>", + "filter": "130x130", + "height": 130, + "picture": "https://scontent.fiev6-1.fna.fbcdn.net/v/t15.13418-10/421466838_710585507916561_3872490001217946972_n.jpg?stp=dst-jpg_p130x130&_nc_cat=102&ccb=1-7&_nc_sid=1a7029&_nc_ohc=Bf3lDDsxlp8AX8WEBcN&_nc_ht=scontent.fiev6-1.fna&edm=AM_bLsMEAAAA&oh=00_AfCr0UPnWf53Mhxnn45ZBNRJ5C6jbMcNRpeg5jQwDvjgiQ&oe=65C8F32D", + "width": 130 + }, + { + "embed_html": "\u003Ciframe allow=\"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share\" allowfullscreen=\"true\" frameborder=\"0\" height=\"480\" scrolling=\"no\" src=\"https://www.facebook.com/plugins/video.php?href=https\u00253A\u00252F\u00252Fwww.facebook.com\u00252F23854402720800548\u00252Fvideos\u00252F916735743507460\u00252F\u00253Fidorvanity\u00253D23854402720800548&width=480\" style=\"border:none;overflow:hidden\" width=\"480\">\u003C/iframe>", + "filter": "480x480", + "height": 480, + "picture": "https://scontent.fiev6-1.fna.fbcdn.net/v/t15.13418-10/421466838_710585507916561_3872490001217946972_n.jpg?stp=dst-jpg_p480x480&_nc_cat=102&ccb=1-7&_nc_sid=1a7029&_nc_ohc=Bf3lDDsxlp8AX8WEBcN&_nc_ht=scontent.fiev6-1.fna&edm=AM_bLsMEAAAA&oh=00_AfBfyCdBovsAE5hSpP9K3ADKnJJAHjtEIebTMn0F4vH2eA&oe=65C8F32D", + "width": 480 + }, + { + "embed_html": "\u003Ciframe allow=\"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share\" allowfullscreen=\"true\" frameborder=\"0\" height=\"720\" scrolling=\"no\" src=\"https://www.facebook.com/plugins/video.php?href=https\u00253A\u00252F\u00252Fwww.facebook.com\u00252F23854402720800548\u00252Fvideos\u00252F916735743507460\u00252F\u00253Fidorvanity\u00253D23854402720800548&width=720\" style=\"border:none;overflow:hidden\" width=\"720\">\u003C/iframe>", + "filter": "720x720", + "height": 720, + "picture": "https://scontent.fiev6-1.fna.fbcdn.net/v/t15.13418-10/421466838_710585507916561_3872490001217946972_n.jpg?stp=dst-jpg_p720x720&_nc_cat=102&ccb=1-7&_nc_sid=1a7029&_nc_ohc=Bf3lDDsxlp8AX8WEBcN&_nc_ht=scontent.fiev6-1.fna&edm=AM_bLsMEAAAA&oh=00_AfBr2pAfGPEdFO66MpPC-NdJX3ANHWKXXdMzZzcN0cfp-g&oe=65C8F32D", + "width": 720 + }, + { + "embed_html": "\u003Ciframe allow=\"autoplay; clipboard-write; encrypted-media; picture-in-picture; web-share\" allowfullscreen=\"true\" frameborder=\"0\" height=\"1080\" scrolling=\"no\" src=\"https://www.facebook.com/plugins/video.php?href=https\u00253A\u00252F\u00252Fwww.facebook.com\u00252F23854402720800548\u00252Fvideos\u00252F916735743507460\u00252F\u00253Fidorvanity\u00253D23854402720800548&width=1080\" style=\"border:none;overflow:hidden\" width=\"1080\">\u003C/iframe>", + "filter": "native", + "height": 1080, + "picture": "https://scontent.fiev6-1.fna.fbcdn.net/v/t15.13418-10/421466838_710585507916561_3872490001217946972_n.jpg?stp=dst-jpg&_nc_cat=102&ccb=1-7&_nc_sid=1a7029&_nc_ohc=Bf3lDDsxlp8AX8WEBcN&_nc_ht=scontent.fiev6-1.fna&edm=AM_bLsMEAAAA&oh=00_AfBYXRKMdH0ZQ8QLOycwQh74ipObGO1IhrntUoNxAwwGPw&oe=65C8F32D", + "width": 1080 + } + ], + "icon": "https://static.xx.fbcdn.net/rsrc.php/v3/yD/r/DggDhA4z4tO.gif", + "is_crosspost_video": false, + "is_crossposting_eligible": false, + "is_episode": false, + "is_instagram_eligible": true, + "length": 24.024, + "permalink_url": "/23854402720800548/videos/916735743507460/?idorvanity=23854402720800548", + "post_views": 0, + "published": true, + "source": "https://video.fiev6-1.fna.fbcdn.net/o1/v/t2/f1/m69/GJwhThkQRrIkM7QCAEDVozMuFWg8bmdjAAAF.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6Im9lcF9oZCJ9&_nc_ht=video.fiev6-1.fna.fbcdn.net&_nc_cat=103&strext=1&vs=9578d47bdeedff3e&_nc_vs=HBksFQIYOnBhc3N0aHJvdWdoX2V2ZXJzdG9yZS9HSndoVGhrUVJySWtNN1FDQUVEVm96TXVGV2c4Ym1kakFBQUYVAALIAQAVAhg6cGFzc3Rocm91Z2hfZXZlcnN0b3JlL0dLVVdKeG15a183ODZZc0NBRWdXRFFQRGk1TlNidjRHQUFBRhUCAsgBAEsHiBJwcm9ncmVzc2l2ZV9yZWNpcGUBMQ1zdWJzYW1wbGVfZnBzABB2bWFmX2VuYWJsZV9uc3ViACBtZWFzdXJlX29yaWdpbmFsX3Jlc29sdXRpb25fc3NpbQAoY29tcHV0ZV9zc2ltX29ubHlfYXRfb3JpZ2luYWxfcmVzb2x1dGlvbgAddXNlX2xhbmN6b3NfZm9yX3ZxbV91cHNjYWxpbmcAEWRpc2FibGVfcG9zdF9wdnFzABUAJQAcjBdAAAAAAAAAABERAAAAJqal7crZj6oBFQIoAkMzGAt2dHNfcHJldmlldxwXQDgGJN0vGqAYIWRhc2hfZ2VuMmh3YmFzaWNfaHEyX2ZyYWdfMl92aWRlbxIAGBh2aWRlb3MudnRzLmNhbGxiYWNrLnByb2Q4ElZJREVPX1ZJRVdfUkVRVUVTVBsKiBVvZW1fdGFyZ2V0X2VuY29kZV90YWcGb2VwX2hkE29lbV9yZXF1ZXN0X3RpbWVfbXMBMAxvZW1fY2ZnX3J1bGUHdW5tdXRlZBNvZW1fcm9pX3JlYWNoX2NvdW50ATARb2VtX2lzX2V4cGVyaW1lbnQADG9lbV92aWRlb19pZA85MTY3MzU3NDM1MDc0NjASb2VtX3ZpZGVvX2Fzc2V0X2lkDzM3NzMyNzM0ODI2NDE5NxVvZW1fdmlkZW9fcmVzb3VyY2VfaWQPMzc0MTAzNjc1MzQ5MzMxHG9lbV9zb3VyY2VfdmlkZW9fZW5jb2RpbmdfaWQQMTExMTczNTcwOTg0MDIwNA52dHNfcmVxdWVzdF9pZAAlAhwAJY4CGweIAXMEODc4MwJjZAoyMDI0LTAxLTI5A2FwcANEREgCY3QGTEVHQUNZE29yaWdpbmFsX2R1cmF0aW9uX3MGMjQuMDY0AWYCYWQCdHMVcHJvZ3Jlc3NpdmVfZW5jb2RpbmdzAA\u00253D\u00253D&ccb=9-4&oh=00_AfC-KNsd9MXPG2i2rHKk40YOhDGQY0stsUS5wvZrwKAXoA&oe=65C6A407&_nc_sid=1d576d&_nc_rid=776303965488972&_nc_store_type=1", + "updated_time": "2024-01-29T23:09:30+0000", + "views": 0 + } + ], + "paging": { + "cursors": { + "before": "QVFIUlJBUTRfNU5HQUJ4c1V", + "after": "QVFIUlhOX3Rnbm5YNmxOWjBC" + } + }, + "summary": { + "total_count": 2 + } +} diff --git a/docs/integrations/sources/facebook-marketing.md b/docs/integrations/sources/facebook-marketing.md index eacfe546efd8..5fdc14ac43c4 100644 --- a/docs/integrations/sources/facebook-marketing.md +++ b/docs/integrations/sources/facebook-marketing.md @@ -203,7 +203,8 @@ The Facebook Marketing connector uses the `lookback_window` parameter to repeate | Version | Date | Pull Request | Subject | |:--------|:-----------|:---------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| 1.3.2 | 2024-02-12 | [35178](https://github.com/airbytehq/airbyte/pull/35178) | Manage dependencies with Poetry. | +| 1.3.3 | 2024-02-15 | [35061](https://github.com/airbytehq/airbyte/pull/35061) | Add integration tests | +| 1.3.2 | 2024-02-12 | [35178](https://github.com/airbytehq/airbyte/pull/35178) | Manage dependencies with Poetry | | 1.3.1 | 2024-02-05 | [34845](https://github.com/airbytehq/airbyte/pull/34845) | Add missing fields to schemas | | 1.3.0 | 2024-01-09 | [33538](https://github.com/airbytehq/airbyte/pull/33538) | Updated the `Ad Account ID(s)` property to support multiple IDs | | 1.2.3 | 2024-01-04 | [33934](https://github.com/airbytehq/airbyte/pull/33828) | Make ready for airbyte-lib | From 92efefd1e16c99f599b4259b2a7d31e9ea9fbeac Mon Sep 17 00:00:00 2001 From: Augustin Date: Tue, 20 Feb 2024 08:35:40 +0100 Subject: [PATCH 36/43] Delete `requirements.txt` on poetry managed connectors (#35406) --- .../connectors/source-airtable/requirements.txt | 1 - .../connectors/source-amazon-ads/requirements.txt | 2 -- .../connectors/source-amplitude/requirements.txt | 1 - .../connectors/source-bing-ads/requirements.txt | 1 - .../connectors/source-chargebee/requirements.txt | 1 - .../connectors/source-facebook-marketing/requirements.txt | 2 -- airbyte-integrations/connectors/source-faker/requirements.txt | 2 -- airbyte-integrations/connectors/source-file/requirements.txt | 2 -- .../connectors/source-freshdesk/requirements.txt | 2 -- airbyte-integrations/connectors/source-github/requirements.txt | 1 - airbyte-integrations/connectors/source-gitlab/requirements.txt | 2 -- .../connectors/source-google-ads/requirements.txt | 1 - .../source-google-analytics-data-api/requirements.txt | 2 -- .../connectors/source-google-analytics-v4/requirements.txt | 1 - .../connectors/source-google-search-console/requirements.txt | 2 -- .../connectors/source-google-sheets/requirements.txt | 2 -- .../connectors/source-greenhouse/requirements.txt | 1 - airbyte-integrations/connectors/source-harvest/requirements.txt | 2 -- airbyte-integrations/connectors/source-hubspot/requirements.txt | 2 -- .../connectors/source-instagram/requirements.txt | 2 -- .../connectors/source-intercom/requirements.txt | 1 - .../connectors/source-iterable/requirements.txt | 2 -- airbyte-integrations/connectors/source-jira/requirements.txt | 2 -- airbyte-integrations/connectors/source-klaviyo/requirements.txt | 2 -- .../connectors/source-linkedin-ads/requirements.txt | 1 - .../connectors/source-mailchimp/requirements.txt | 2 -- airbyte-integrations/connectors/source-marketo/requirements.txt | 1 - .../connectors/source-mixpanel/requirements.txt | 1 - airbyte-integrations/connectors/source-monday/requirements.txt | 1 - airbyte-integrations/connectors/source-notion/requirements.txt | 1 - .../connectors/source-paypal-transaction/requirements.txt | 1 - .../connectors/source-pinterest/requirements.txt | 1 - .../connectors/source-recharge/requirements.txt | 1 - airbyte-integrations/connectors/source-s3/requirements.txt | 1 - .../connectors/source-salesforce/requirements.txt | 1 - .../connectors/source-sendgrid/requirements.txt | 1 - airbyte-integrations/connectors/source-sentry/requirements.txt | 1 - airbyte-integrations/connectors/source-shopify/requirements.txt | 1 - airbyte-integrations/connectors/source-slack/requirements.txt | 1 - .../connectors/source-snapchat-marketing/requirements.txt | 1 - airbyte-integrations/connectors/source-stripe/requirements.txt | 1 - .../connectors/source-surveymonkey/requirements.txt | 1 - .../connectors/source-tiktok-marketing/requirements.txt | 1 - airbyte-integrations/connectors/source-twilio/requirements.txt | 1 - .../connectors/source-typeform/requirements.txt | 1 - .../connectors/source-zendesk-chat/requirements.txt | 2 -- .../connectors/source-zendesk-support/requirements.txt | 1 - .../connectors/source-zendesk-talk/requirements.txt | 2 -- 48 files changed, 66 deletions(-) delete mode 100644 airbyte-integrations/connectors/source-airtable/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-amazon-ads/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-amplitude/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-bing-ads/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-chargebee/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-facebook-marketing/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-faker/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-file/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-freshdesk/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-github/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-gitlab/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-google-ads/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-google-analytics-data-api/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-google-analytics-v4/requirements.txt delete mode 100755 airbyte-integrations/connectors/source-google-search-console/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-google-sheets/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-greenhouse/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-harvest/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-hubspot/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-instagram/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-intercom/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-iterable/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-jira/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-klaviyo/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-linkedin-ads/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-mailchimp/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-marketo/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-mixpanel/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-monday/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-notion/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-paypal-transaction/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-pinterest/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-recharge/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-s3/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-salesforce/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-sendgrid/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-sentry/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-shopify/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-slack/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-snapchat-marketing/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-stripe/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-surveymonkey/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-tiktok-marketing/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-twilio/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-typeform/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-zendesk-chat/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-zendesk-support/requirements.txt delete mode 100644 airbyte-integrations/connectors/source-zendesk-talk/requirements.txt diff --git a/airbyte-integrations/connectors/source-airtable/requirements.txt b/airbyte-integrations/connectors/source-airtable/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-airtable/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-amazon-ads/requirements.txt b/airbyte-integrations/connectors/source-amazon-ads/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-amazon-ads/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-amplitude/requirements.txt b/airbyte-integrations/connectors/source-amplitude/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-amplitude/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-bing-ads/requirements.txt b/airbyte-integrations/connectors/source-bing-ads/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-bing-ads/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-chargebee/requirements.txt b/airbyte-integrations/connectors/source-chargebee/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-chargebee/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-facebook-marketing/requirements.txt b/airbyte-integrations/connectors/source-facebook-marketing/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-facebook-marketing/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-faker/requirements.txt b/airbyte-integrations/connectors/source-faker/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-faker/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-file/requirements.txt b/airbyte-integrations/connectors/source-file/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-file/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-freshdesk/requirements.txt b/airbyte-integrations/connectors/source-freshdesk/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-freshdesk/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-github/requirements.txt b/airbyte-integrations/connectors/source-github/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-github/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-gitlab/requirements.txt b/airbyte-integrations/connectors/source-gitlab/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-gitlab/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-google-ads/requirements.txt b/airbyte-integrations/connectors/source-google-ads/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-google-ads/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-google-analytics-data-api/requirements.txt b/airbyte-integrations/connectors/source-google-analytics-data-api/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-google-analytics-data-api/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-google-analytics-v4/requirements.txt b/airbyte-integrations/connectors/source-google-analytics-v4/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-google-analytics-v4/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-google-search-console/requirements.txt b/airbyte-integrations/connectors/source-google-search-console/requirements.txt deleted file mode 100755 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-google-search-console/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-google-sheets/requirements.txt b/airbyte-integrations/connectors/source-google-sheets/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-google-sheets/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-greenhouse/requirements.txt b/airbyte-integrations/connectors/source-greenhouse/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-greenhouse/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-harvest/requirements.txt b/airbyte-integrations/connectors/source-harvest/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-harvest/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-hubspot/requirements.txt b/airbyte-integrations/connectors/source-hubspot/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-hubspot/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-instagram/requirements.txt b/airbyte-integrations/connectors/source-instagram/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-instagram/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-intercom/requirements.txt b/airbyte-integrations/connectors/source-intercom/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-intercom/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-iterable/requirements.txt b/airbyte-integrations/connectors/source-iterable/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-iterable/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-jira/requirements.txt b/airbyte-integrations/connectors/source-jira/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-jira/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-klaviyo/requirements.txt b/airbyte-integrations/connectors/source-klaviyo/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-klaviyo/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-linkedin-ads/requirements.txt b/airbyte-integrations/connectors/source-linkedin-ads/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-linkedin-ads/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-mailchimp/requirements.txt b/airbyte-integrations/connectors/source-mailchimp/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-mailchimp/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-marketo/requirements.txt b/airbyte-integrations/connectors/source-marketo/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-marketo/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-mixpanel/requirements.txt b/airbyte-integrations/connectors/source-mixpanel/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-mixpanel/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-monday/requirements.txt b/airbyte-integrations/connectors/source-monday/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-monday/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-notion/requirements.txt b/airbyte-integrations/connectors/source-notion/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-notion/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-paypal-transaction/requirements.txt b/airbyte-integrations/connectors/source-paypal-transaction/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-paypal-transaction/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-pinterest/requirements.txt b/airbyte-integrations/connectors/source-pinterest/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-pinterest/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-recharge/requirements.txt b/airbyte-integrations/connectors/source-recharge/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-recharge/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-s3/requirements.txt b/airbyte-integrations/connectors/source-s3/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-s3/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-salesforce/requirements.txt b/airbyte-integrations/connectors/source-salesforce/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-salesforce/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-sendgrid/requirements.txt b/airbyte-integrations/connectors/source-sendgrid/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-sendgrid/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-sentry/requirements.txt b/airbyte-integrations/connectors/source-sentry/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-sentry/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-shopify/requirements.txt b/airbyte-integrations/connectors/source-shopify/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-shopify/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-slack/requirements.txt b/airbyte-integrations/connectors/source-slack/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-slack/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-snapchat-marketing/requirements.txt b/airbyte-integrations/connectors/source-snapchat-marketing/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-snapchat-marketing/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-stripe/requirements.txt b/airbyte-integrations/connectors/source-stripe/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-stripe/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-surveymonkey/requirements.txt b/airbyte-integrations/connectors/source-surveymonkey/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-surveymonkey/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-tiktok-marketing/requirements.txt b/airbyte-integrations/connectors/source-tiktok-marketing/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-tiktok-marketing/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-twilio/requirements.txt b/airbyte-integrations/connectors/source-twilio/requirements.txt deleted file mode 100644 index ecf975e2fa63..000000000000 --- a/airbyte-integrations/connectors/source-twilio/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-typeform/requirements.txt b/airbyte-integrations/connectors/source-typeform/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-typeform/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-zendesk-chat/requirements.txt b/airbyte-integrations/connectors/source-zendesk-chat/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-zendesk-chat/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . diff --git a/airbyte-integrations/connectors/source-zendesk-support/requirements.txt b/airbyte-integrations/connectors/source-zendesk-support/requirements.txt deleted file mode 100644 index d6e1198b1ab1..000000000000 --- a/airbyte-integrations/connectors/source-zendesk-support/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e . diff --git a/airbyte-integrations/connectors/source-zendesk-talk/requirements.txt b/airbyte-integrations/connectors/source-zendesk-talk/requirements.txt deleted file mode 100644 index 7b9114ed5867..000000000000 --- a/airbyte-integrations/connectors/source-zendesk-talk/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# This file is autogenerated -- only edit if you know what you are doing. Use setup.py for declaring dependencies. --e . From 05a1512a7e4d566e9c11feecaffd1d58100bd269 Mon Sep 17 00:00:00 2001 From: Augustin Date: Tue, 20 Feb 2024 08:57:53 +0100 Subject: [PATCH 37/43] update doc to reference poetry (#35414) --- .../tutorial/0-getting-started.md | 1 + .../tutorial/2-install-dependencies.md | 12 ++----- .../3-connecting-to-the-API-source.md | 2 +- .../config-based/tutorial/4-reading-data.md | 4 +-- .../tutorial/5-incremental-reads.md | 6 ++-- .../config-based/tutorial/6-testing.md | 2 +- .../testing-connectors/README.md | 31 +++++++++---------- .../tutorials/building-a-python-source.md | 29 +++++++++-------- .../tutorials/cdk-speedrun.md | 9 +++--- .../connection-checking.md | 12 +++---- .../declare-schema.md | 2 +- .../getting-started.md | 2 +- .../install-dependencies.md | 24 ++++++-------- .../cdk-tutorial-python-http/read-data.md | 14 ++++----- .../test-your-connector.md | 6 ++-- 15 files changed, 70 insertions(+), 86 deletions(-) diff --git a/docs/connector-development/config-based/tutorial/0-getting-started.md b/docs/connector-development/config-based/tutorial/0-getting-started.md index 5a8a940c2973..8c47d589ccc5 100644 --- a/docs/connector-development/config-based/tutorial/0-getting-started.md +++ b/docs/connector-development/config-based/tutorial/0-getting-started.md @@ -42,6 +42,7 @@ This can be done by signing up for the Free tier plan on [Exchange Rates Data AP - An Exchange Rates API key - Python >= 3.9 +- [Poetry](https://python-poetry.org/) - Docker must be running - NodeJS - [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md#L1) CLI diff --git a/docs/connector-development/config-based/tutorial/2-install-dependencies.md b/docs/connector-development/config-based/tutorial/2-install-dependencies.md index 06bc75dc38d6..55520557fc37 100644 --- a/docs/connector-development/config-based/tutorial/2-install-dependencies.md +++ b/docs/connector-development/config-based/tutorial/2-install-dependencies.md @@ -1,17 +1,9 @@ # Step 2: Install dependencies -Let's create a python virtual environment for our source. -You can do this by executing the following commands from the root of the Airbyte repository. - -The command below assume that `python` points to a version of python >=3.9.0. On some systems, `python` points to a Python2 installation and `python3` points to Python3. -If this is the case on your machine, substitute the `python` commands with `python3`. -The subsequent `python` invocations will use the virtual environment created for the connector. ```bash cd ../../connectors/source-exchange-rates-tutorial -python -m venv .venv -source .venv/bin/activate -pip install -r requirements.txt +poetry install ``` These steps create an initial python environment, and install the dependencies required to run an API Source connector. @@ -19,7 +11,7 @@ These steps create an initial python environment, and install the dependencies r Let's verify everything works as expected by running the Airbyte `spec` operation: ```bash -python main.py spec +poetry run source-exchange-rates-tutorial spec ``` You should see an output similar to the one below: diff --git a/docs/connector-development/config-based/tutorial/3-connecting-to-the-API-source.md b/docs/connector-development/config-based/tutorial/3-connecting-to-the-API-source.md index 0afbd220633f..752ccee58efb 100644 --- a/docs/connector-development/config-based/tutorial/3-connecting-to-the-API-source.md +++ b/docs/connector-development/config-based/tutorial/3-connecting-to-the-API-source.md @@ -200,7 +200,7 @@ spec: We can now run the `check` operation, which verifies the connector can connect to the API source. ```bash -python main.py check --config secrets/config.json +poetry run source-exchange-rates-tutorial check --config secrets/config.json ``` which should now succeed with logs similar to: diff --git a/docs/connector-development/config-based/tutorial/4-reading-data.md b/docs/connector-development/config-based/tutorial/4-reading-data.md index a6d892af79e2..677f5af4d9e8 100644 --- a/docs/connector-development/config-based/tutorial/4-reading-data.md +++ b/docs/connector-development/config-based/tutorial/4-reading-data.md @@ -44,7 +44,7 @@ As an alternative to storing the stream's data schema to the `schemas/` director Reading from the source can be done by running the `read` operation ```bash -python main.py read --config secrets/config.json --catalog integration_tests/configured_catalog.json +poetry run source-exchange-rates-tutorial read --config secrets/config.json --catalog integration_tests/configured_catalog.json ``` The logs should show that 1 record was read from the stream. @@ -57,7 +57,7 @@ The logs should show that 1 record was read from the stream. The `--debug` flag can be set to print out debug information, including the outgoing request and its associated response ```bash -python main.py read --config secrets/config.json --catalog integration_tests/configured_catalog.json --debug +poetry run source-exchange-rates-tutorial read --config secrets/config.json --catalog integration_tests/configured_catalog.json --debug ``` ## Next steps diff --git a/docs/connector-development/config-based/tutorial/5-incremental-reads.md b/docs/connector-development/config-based/tutorial/5-incremental-reads.md index 51d1e24bc326..9cf2aac0c86f 100644 --- a/docs/connector-development/config-based/tutorial/5-incremental-reads.md +++ b/docs/connector-development/config-based/tutorial/5-incremental-reads.md @@ -76,7 +76,7 @@ definitions: You can test these changes by executing the `read` operation: ```bash -python main.py read --config secrets/config.json --catalog integration_tests/configured_catalog.json +poetry run source-exchange-rates-tutorial read --config secrets/config.json --catalog integration_tests/configured_catalog.json ``` By reading the output record, you should see that we read historical data instead of the latest exchange rate. @@ -240,7 +240,7 @@ spec: Running the `read` operation will now read all data for all days between start_date and now: ```bash -python main.py read --config secrets/config.json --catalog integration_tests/configured_catalog.json +poetry run source-exchange-rates-tutorial read --config secrets/config.json --catalog integration_tests/configured_catalog.json ``` The operation should now output more than one record: @@ -295,7 +295,7 @@ We can simulate incremental syncs by creating a state file containing the last s Running the `read` operation will now only read data for dates later than the given state: ```bash -python main.py read --config secrets/config.json --catalog integration_tests/configured_catalog.json --state integration_tests/sample_state.json +poetry run source-exchange-rates-tutorial read --config secrets/config.json --catalog integration_tests/configured_catalog.json --state integration_tests/sample_state.json ``` There shouldn't be any data read if the state is today's date: diff --git a/docs/connector-development/config-based/tutorial/6-testing.md b/docs/connector-development/config-based/tutorial/6-testing.md index 4bbb90e8ed01..284dfacc5b8c 100644 --- a/docs/connector-development/config-based/tutorial/6-testing.md +++ b/docs/connector-development/config-based/tutorial/6-testing.md @@ -30,7 +30,7 @@ and `integration_tests/abnormal_state.json` with You can run the [acceptance tests](https://github.com/airbytehq/airbyte/blob/master/docs/connector-development/testing-connectors/connector-acceptance-tests-reference.md#L1) with the following commands using [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md#L1): ```bash -airbyte-ci connectors --use-remote-secrets=false --name source-exchange-rates-tutorial test +airbyte-ci connectors --use-remote-secrets=false --name source-exchange-rates-tutorial test --only-step=acceptance ``` ## Next steps: diff --git a/docs/connector-development/testing-connectors/README.md b/docs/connector-development/testing-connectors/README.md index 90842bccbccb..e57d22904fde 100644 --- a/docs/connector-development/testing-connectors/README.md +++ b/docs/connector-development/testing-connectors/README.md @@ -1,34 +1,32 @@ # Testing Connectors -## Our testing pyramid -Multiple tests suites compose the Airbyte connector testing pyramid: -Connector specific tests declared in the connector code directory: -* Unit tests -* Integration tests - -Tests common to all connectors: -* [QA checks](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/connector_ops/connector_ops/qa_checks.py) -* [Connector Acceptance tests](https://docs.airbyte.com/connector-development/testing-connectors/connector-acceptance-tests-reference/) +Multiple tests suites compose the Airbyte connector testing pyramid -## Running tests -Unit and integration tests can be run directly from the connector code. +## Common to all connectors +* [Connectors QA checks](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/connector_ops/connector_ops/qa_checks.py) +* [Connector Acceptance tests](https://docs.airbyte.com/connector-development/testing-connectors/connector-acceptance-tests-reference/) -Using `pytest` for Python connectors: +## Connector specific tests +### 🐍 Python connectors +We use `pytest` to run unit and integration tests: ```bash -python -m pytest unit_tests/ -python -m pytest integration_tests/ +# From connector directory +poetry run pytest ``` -Using `gradle` for Java connectors: +### ☕ Java connectors +We run Java connector tests with gradle. ```bash +# Unit tests ./gradlew :airbyte-integrations:connectors:source-postgres:test +# Integration tests ./gradlew :airbyte-integrations:connectors:source-postgres:integrationTestJava ``` Please note that according to the test implementation you might have to provide connector configurations as a `config.json` file in a `.secrets` folder in the connector code directory. - +## 🤖 CI If you want to run the global test suite, exactly like what is run in CI, you should install [`airbyte-ci` CLI](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md) and use the following command: ```bash @@ -39,6 +37,5 @@ This will run all the tests for the connector, including the QA checks and the C Connector Acceptance tests require connector configuration to be provided as a `config.json` file in a `.secrets` folder in the connector code directory. -## Tests on pull requests Our CI infrastructure runs the connector tests with [`airbyte-ci` CLI](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md). Connectors tests are automatically and remotely triggered on your branch according to the changes made in your branch. **Passing tests are required to merge a connector pull request.** diff --git a/docs/connector-development/tutorials/building-a-python-source.md b/docs/connector-development/tutorials/building-a-python-source.md index 57d292680918..49a12872363b 100644 --- a/docs/connector-development/tutorials/building-a-python-source.md +++ b/docs/connector-development/tutorials/building-a-python-source.md @@ -64,18 +64,16 @@ $ ./generate.sh Select the `python` template and then input the name of your connector. For this walk through we will refer to our source as `example-python` -### Step 2: Build the newly generated source +### Step 2: Install the newly generated source -Build the source by running: +Install the source by running: ```bash cd airbyte-integrations/connectors/source- -python -m venv .venv # Create a virtual environment in the .venv directory -source .venv/bin/activate # enable the venv -pip install -r requirements.txt +poetry install ``` -This step sets up the initial python environment. **All** subsequent `python` or `pip` commands assume you have activated your virtual environment. +This step sets up the initial python environment. ### Step 3: Set up your Airbyte development environment @@ -112,10 +110,10 @@ You'll notice in your source's directory that there is a python file called `mai ```bash # from airbyte-integrations/connectors/source- -python main.py spec -python main.py check --config secrets/config.json -python main.py discover --config secrets/config.json -python main.py read --config secrets/config.json --catalog sample_files/configured_catalog.json +poetry run source- spec +poetry run source- check --config secrets/config.json +poetry run source- discover --config secrets/config.json +poetry run source- read --config secrets/config.json --catalog sample_files/configured_catalog.json ``` The nice thing about this approach is that you can iterate completely within in python. The downside is that you are not quite running your source as it will actually be run by Airbyte. Specifically you're not running it from within the docker container that will house it. @@ -182,7 +180,7 @@ The nice thing about this approach is that you are running your source exactly a During development of your connector, you can enable the printing of detailed debug information during a sync by specifying the `--debug` flag. This will allow you to get a better picture of what is happening during each step of your sync. ```bash -python main.py read --config secrets/config.json --catalog sample_files/configured_catalog.json --debug +poetry run source- read --config secrets/config.json --catalog sample_files/configured_catalog.json --debug ``` In addition to the preset CDK debug statements, you can also emit custom debug information from your connector by introducing your own debug statements: @@ -233,7 +231,8 @@ As described in the template code, this method takes in the same config object a The Connector Acceptance Tests are a set of tests that run against all sources. These tests are run in the Airbyte CI to prevent regressions. They also can help you sanity check that your source works as expected. The following [article](../testing-connectors/connector-acceptance-tests-reference.md) explains Connector Acceptance Tests and how to run them. -You can run the tests using `./gradlew :airbyte-integrations:connectors:source-:integrationTest`. Make sure to run this command from the Airbyte repository root. +You can run the tests using [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md): +`airbyte-ci connectors --name source- test --only-step=acceptance` :::info In some rare cases we make exceptions and allow a source to not need to pass all the standard tests. If for some reason you think your source cannot reasonably pass one of the tests cases, reach out to us on github or slack, and we can determine whether there's a change we can make so that the test will pass or if we should skip that test for your source. @@ -245,15 +244,15 @@ The connector acceptance tests are meant to cover the basic functionality of a s #### Unit Tests -Add any relevant unit tests to the `unit_tests` directory. Unit tests should _not_ depend on any secrets. +Add any relevant unit tests to the `tests/unit_tests` directory. Unit tests should _not_ depend on any secrets. -You can run the tests using `python -m pytest -s unit_tests` +You can run the tests using `poetry run pytest tests/unit_tests` #### Integration Tests Place any integration tests in the `integration_tests` directory such that they can be [discovered by pytest](https://docs.pytest.org/en/6.2.x/goodpractices.html#conventions-for-python-test-discovery). -Run integration tests using `python -m pytest -s integration_tests`. +You can run the tests using `poetry run pytest tests/integration_tests` ### Step 10: Update the `README.md` diff --git a/docs/connector-development/tutorials/cdk-speedrun.md b/docs/connector-development/tutorials/cdk-speedrun.md index d6caac36974f..bb9f23ddf246 100644 --- a/docs/connector-development/tutorials/cdk-speedrun.md +++ b/docs/connector-development/tutorials/cdk-speedrun.md @@ -11,6 +11,7 @@ If you are a visual learner and want to see a video version of this guide going ## Dependencies 1. Python >= 3.9 +2. [Poetry](https://python-poetry.org/) 2. Docker 3. NodeJS @@ -30,9 +31,7 @@ Select the `Python HTTP API Source` and name it `python-http-example`. ```bash cd ../../connectors/source-python-http-example -python -m venv .venv # Create a virtual environment in the .venv directory -source .venv/bin/activate -pip install -r requirements.txt +poetry install ``` ### Define Connector Inputs @@ -169,7 +168,7 @@ This file defines your output schema for every endpoint that you want to impleme Test your discover function. You should receive a fairly large JSON object in return. ```bash -python main.py discover --config sample_files/config.json +poetry run source-python-http-example discover --config sample_files/config.json ``` Note that our discover function is using the `pokemon_name` config variable passed in from the `Pokemon` stream when we set it in the `__init__` function. @@ -226,7 +225,7 @@ We now need a catalog that defines all of our streams. We only have one stream: Let's read some data. ```bash -python main.py read --config sample_files/config.json --catalog sample_files/configured_catalog.json +poetry run source-python-http-example read --config sample_files/config.json --catalog sample_files/configured_catalog.json ``` If all goes well, containerize it so you can use it in the UI: diff --git a/docs/connector-development/tutorials/cdk-tutorial-python-http/connection-checking.md b/docs/connector-development/tutorials/cdk-tutorial-python-http/connection-checking.md index 7acf2b50020a..2e34eb1adf30 100644 --- a/docs/connector-development/tutorials/cdk-tutorial-python-http/connection-checking.md +++ b/docs/connector-development/tutorials/cdk-tutorial-python-http/connection-checking.md @@ -42,21 +42,21 @@ Note: in a real implementation you should write code to connect to the API to va Let's test out this implementation by creating two objects: a valid and an invalid config and attempt to give them as input to the connector. For this section, you will need to take the API access key generated earlier and add it to both configs. Because these configs contain secrets, we recommend storing configs which contain secrets in `secrets/config.json` because the `secrets` directory is gitignored by default. -```text +```bash mkdir sample_files echo '{"start_date": "2022-04-01", "base": "USD", "apikey": }' > secrets/config.json echo '{"start_date": "2022-04-01", "base": "BTC", "apikey": }' > secrets/invalid_config.json -python main.py check --config secrets/config.json -python main.py check --config secrets/invalid_config.json +poetry run source-python-http-example check --config secrets/config.json +poetry run source-python-http-example check --config secrets/invalid_config.json ``` You should see output like the following: -```text -> python main.py check --config secrets/config.json +```bash +> poetry run source-python-http-example check --config secrets/config.json {"type": "CONNECTION_STATUS", "connectionStatus": {"status": "SUCCEEDED"}} -> python main.py check --config secrets/invalid_config.json +> poetry run source-python-http-example check --config secrets/invalid_config.json {"type": "CONNECTION_STATUS", "connectionStatus": {"status": "FAILED", "message": "Input currency BTC is invalid. Please input one of the following currencies: {'DKK', 'USD', 'CZK', 'BGN', 'JPY'}"}} ``` diff --git a/docs/connector-development/tutorials/cdk-tutorial-python-http/declare-schema.md b/docs/connector-development/tutorials/cdk-tutorial-python-http/declare-schema.md index 2ba36afbcbf3..b97aeb1b587b 100644 --- a/docs/connector-development/tutorials/cdk-tutorial-python-http/declare-schema.md +++ b/docs/connector-development/tutorials/cdk-tutorial-python-http/declare-schema.md @@ -63,7 +63,7 @@ Having created this stream in code, we'll put a file `exchange_rates.json` in th With `.json` schema file in place, let's see if the connector can now find this schema and produce a valid catalog: ```text -python main.py discover --config secrets/config.json # this is not a mistake, the schema file is found by naming snake_case naming convention as specified above +poetry run source-python-http-example discover --config secrets/config.json # this is not a mistake, the schema file is found by naming snake_case naming convention as specified above ``` you should see some output like: diff --git a/docs/connector-development/tutorials/cdk-tutorial-python-http/getting-started.md b/docs/connector-development/tutorials/cdk-tutorial-python-http/getting-started.md index dce0f253bbec..57b2fb4624f9 100644 --- a/docs/connector-development/tutorials/cdk-tutorial-python-http/getting-started.md +++ b/docs/connector-development/tutorials/cdk-tutorial-python-http/getting-started.md @@ -7,8 +7,8 @@ This is a step-by-step guide for how to create an Airbyte source in Python to re ## Requirements * Python >= 3.9 +* [Poetry](https://python-poetry.org/) * Docker -* NodeJS \(only used to generate the connector\). We'll remove the NodeJS dependency soon. All the commands below assume that `python` points to a version of python >=3.9.0. On some systems, `python` points to a Python2 installation and `python3` points to Python3. If this is the case on your machine, substitute all `python` commands in this guide with `python3`. diff --git a/docs/connector-development/tutorials/cdk-tutorial-python-http/install-dependencies.md b/docs/connector-development/tutorials/cdk-tutorial-python-http/install-dependencies.md index 16c58757969f..3d7e50e22377 100644 --- a/docs/connector-development/tutorials/cdk-tutorial-python-http/install-dependencies.md +++ b/docs/connector-development/tutorials/cdk-tutorial-python-http/install-dependencies.md @@ -2,19 +2,16 @@ Now that you've generated the module, let's navigate to its directory and install dependencies: -```text +```bash cd ../../connectors/source- -python -m venv .venv # Create a virtual environment in the .venv directory -source .venv/bin/activate # enable the venv -pip install -r requirements.txt +poetry install ``` -This step sets up the initial python environment. **All** subsequent `python` or `pip` commands assume you have activated your virtual environment. Let's verify everything is working as intended. Run: -```text -python main.py spec +```bash +poetry run source- spec ``` You should see some output: @@ -25,7 +22,6 @@ You should see some output: We just ran Airbyte Protocol's `spec` command! We'll talk more about this later, but this is a simple sanity check to make sure everything is wired up correctly. -Note that the `main.py` file is a simple script that makes it easy to run your connector. Its invocation format is `python main.py [args]`. See the module's generated `README.md` for the commands it supports. ## Notes on iteration cycle @@ -47,12 +43,12 @@ There are two ways we recommend iterating on a source. Consider using whichever You'll notice in your source's directory that there is a python file called `main.py`. This file exists as convenience for development. You run it to test that your source works: -```text +```bash # from airbyte-integrations/connectors/source- -python main.py spec -python main.py check --config secrets/config.json -python main.py discover --config secrets/config.json -python main.py read --config secrets/config.json --catalog sample_files/configured_catalog.json +poetry run source- spec +poetry run source- check --config secrets/config.json +poetry run source- discover --config secrets/config.json +poetry run source- read --config secrets/config.json --catalog sample_files/configured_catalog.json ``` The nice thing about this approach is that you can iterate completely within python. The downside is that you are not quite running your source as it will actually be run by Airbyte. Specifically, you're not running it from within the docker container that will house it. @@ -61,7 +57,7 @@ The nice thing about this approach is that you can iterate completely within pyt If you want to run your source exactly as it will be run by Airbyte \(i.e. within a docker container\), you can use the following commands from the connector module directory \(`airbyte-integrations/connectors/source-python-http-example`\): -```text +```bash # First build the container docker build . -t airbyte/source-:dev diff --git a/docs/connector-development/tutorials/cdk-tutorial-python-http/read-data.md b/docs/connector-development/tutorials/cdk-tutorial-python-http/read-data.md index 8cdee893e5ab..0417bcdbde25 100644 --- a/docs/connector-development/tutorials/cdk-tutorial-python-http/read-data.md +++ b/docs/connector-development/tutorials/cdk-tutorial-python-http/read-data.md @@ -107,8 +107,8 @@ We're now ready to query the API! To do this, we'll need a [ConfiguredCatalog](../../../understanding-airbyte/beginners-guide-to-catalog.md). We've prepared one [here](https://github.com/airbytehq/airbyte/blob/master/docs/connector-development/tutorials/cdk-tutorial-python-http/configured_catalog.json) -- download this and place it in `sample_files/configured_catalog.json`. Then run: -```text - python main.py read --config secrets/config.json --catalog sample_files/configured_catalog.json +```bash + poetry run source- --config secrets/config.json --catalog sample_files/configured_catalog.json ``` you should see some output lines, one of which is a record from the API: @@ -239,18 +239,18 @@ We should now have a working implementation of incremental sync! Let's try it out: -```text -python main.py read --config secrets/config.json --catalog sample_files/configured_catalog.json +```bash +poetry run source- --config secrets/config.json --catalog sample_files/configured_catalog.json ``` You should see a bunch of `RECORD` messages and `STATE` messages. To verify that incremental sync is working, pass the input state back to the connector and run it again: -```text +```bash # Save the latest state to sample_files/state.json -python main.py read --config secrets/config.json --catalog sample_files/configured_catalog.json | grep STATE | tail -n 1 | jq .state.data > sample_files/state.json +poetry run source- --config secrets/config.json --catalog sample_files/configured_catalog.json | grep STATE | tail -n 1 | jq .state.data > sample_files/state.json # Run a read operation with the latest state message -python main.py read --config secrets/config.json --catalog sample_files/configured_catalog.json --state sample_files/state.json +poetry run source- --config secrets/config.json --catalog sample_files/configured_catalog.json --state sample_files/state.json ``` You should see that only the record from the last date is being synced! This is acceptable behavior, since Airbyte requires at-least-once delivery of records, so repeating the last record twice is OK. diff --git a/docs/connector-development/tutorials/cdk-tutorial-python-http/test-your-connector.md b/docs/connector-development/tutorials/cdk-tutorial-python-http/test-your-connector.md index f5fbcc07b4f0..521d8b05821f 100644 --- a/docs/connector-development/tutorials/cdk-tutorial-python-http/test-your-connector.md +++ b/docs/connector-development/tutorials/cdk-tutorial-python-http/test-your-connector.md @@ -2,15 +2,15 @@ ## Unit Tests -Add any relevant unit tests to the `unit_tests` directory. Unit tests should **not** depend on any secrets. +Add any relevant unit tests to the `tests/unit_tests` directory. Unit tests should **not** depend on any secrets. -You can run the tests using `python -m pytest -s unit_tests`. +You can run the tests using `poetry run pytest tests/unit_tests`. ## Integration Tests Place any integration tests in the `integration_tests` directory such that they can be [discovered by pytest](https://docs.pytest.org/en/6.2.x/goodpractices.html#conventions-for-python-test-discovery). -Run integration tests using `python -m pytest -s integration_tests`. +You can run the tests using `poetry run pytest tests/integration_tests`. More information on integration testing can be found on [the Testing Connectors doc](https://docs.airbyte.com/connector-development/testing-connectors/#running-integration-tests). From 4889e6e024d64ba0e353611f8fe67497b02de190 Mon Sep 17 00:00:00 2001 From: Augustin Date: Tue, 20 Feb 2024 09:28:28 +0100 Subject: [PATCH 38/43] =?UTF-8?q?=F0=9F=A7=B9=20remove=20qa=5Fchecks.py=20?= =?UTF-8?q?(#35434)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../connector_ops/connector_ops/qa_checks.py | 320 ------------------ .../connectors/connector_ops/pyproject.toml | 2 +- .../connector_ops/tests/test_qa_checks.py | 274 --------------- .../testing-connectors/README.md | 2 +- 4 files changed, 2 insertions(+), 596 deletions(-) delete mode 100644 airbyte-ci/connectors/connector_ops/connector_ops/qa_checks.py delete mode 100644 airbyte-ci/connectors/connector_ops/tests/test_qa_checks.py diff --git a/airbyte-ci/connectors/connector_ops/connector_ops/qa_checks.py b/airbyte-ci/connectors/connector_ops/connector_ops/qa_checks.py deleted file mode 100644 index 99bd8e1786b0..000000000000 --- a/airbyte-ci/connectors/connector_ops/connector_ops/qa_checks.py +++ /dev/null @@ -1,320 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - - -import sys -from pathlib import Path -from typing import Callable, Iterable, Optional, Set, Tuple - -from connector_ops.utils import Connector, ConnectorLanguage -from pydash.objects import get - - -def check_migration_guide(connector: Connector) -> bool: - """Check if a migration guide is available for the connector if a breaking change was introduced.""" - - breaking_changes = get(connector.metadata, "releases.breakingChanges") - if not breaking_changes: - return True - - migration_guide_file_path = connector.migration_guide_file_path - migration_guide_exists = migration_guide_file_path is not None and migration_guide_file_path.exists() - if not migration_guide_exists: - print( - f"Migration guide file is missing for {connector.name}. Please create a migration guide at {connector.migration_guide_file_path}" - ) - return False - - # Check that the migration guide begins with # {connector name} Migration Guide - expected_title = f"# {connector.name_from_metadata} Migration Guide" - expected_version_header_start = "## Upgrading to " - with open(migration_guide_file_path) as f: - first_line = f.readline().strip() - if not first_line == expected_title: - print( - f"Migration guide file for {connector.technical_name} does not start with the correct header. Expected '{expected_title}', got '{first_line}'" - ) - return False - - # Check that the migration guide contains a section for each breaking change key ## Upgrading to {version} - # Note that breaking change is a dict where the version is the key - # Note that the migration guide must have the sections in order of the version descending - # 3.0.0, 2.0.0, 1.0.0, etc - # This means we have to record the headings in the migration guide and then check that they are in order - # We also have to check that the headings are in the breaking changes dict - - ordered_breaking_changes = sorted(breaking_changes.keys(), reverse=True) - ordered_expected_headings = [f"{expected_version_header_start}{version}" for version in ordered_breaking_changes] - - ordered_heading_versions = [] - for line in f: - stripped_line = line.strip() - if stripped_line.startswith(expected_version_header_start): - version = stripped_line.replace(expected_version_header_start, "") - ordered_heading_versions.append(version) - - if ordered_breaking_changes != ordered_heading_versions: - print(f"Migration guide file for {connector.name} has incorrect version headings.") - print("Check for missing, extra, or misordered headings, or headers with typos.") - print(f"Expected headings: {ordered_expected_headings}") - return False - - return True - - -def check_documentation_file_exists(connector: Connector) -> bool: - """Check if a markdown file with connector documentation is available - in docs/integrations/s/.md - - Args: - connector (Connector): a Connector dataclass instance. - - Returns: - bool: Wether a documentation file was found. - """ - file_path = connector.documentation_file_path - - return file_path is not None and file_path.exists() - - -def check_documentation_follows_guidelines(connector: Connector) -> bool: - """Documentation guidelines are defined here https://hackmd.io/Bz75cgATSbm7DjrAqgl4rw""" - follows_guidelines = True - with open(connector.documentation_file_path) as f: - doc_lines = [line.lower() for line in f.read().splitlines()] - if not doc_lines[0].startswith("# "): - print("The connector name is not used as the main header in the documentation.") - follows_guidelines = False - # We usually don't have a metadata if the connector is not published. - if connector.metadata: - if doc_lines[0].strip() != f"# {connector.metadata['name'].lower()}": - print("The connector name is not used as the main header in the documentation.") - follows_guidelines = False - elif not doc_lines[0].startswith("# "): - print("The connector name is not used as the main header in the documentation.") - follows_guidelines = False - - expected_sections = ["## Prerequisites", "## Setup guide", "## Supported sync modes", "## Supported streams", "## Changelog"] - - for expected_section in expected_sections: - if expected_section.lower() not in doc_lines: - print(f"Connector documentation is missing a '{expected_section.replace('#', '').strip()}' section.") - follows_guidelines = False - return follows_guidelines - - -def check_changelog_entry_is_updated(connector: Connector) -> bool: - """Check that the changelog entry is updated for the latest connector version - in docs/integrations//.md - - Args: - connector (Connector): a Connector dataclass instance. - - Returns: - bool: Wether a the changelog is up to date. - """ - if not check_documentation_file_exists(connector): - return False - with open(connector.documentation_file_path) as f: - after_changelog = False - for line in f: - if "# changelog" in line.lower(): - after_changelog = True - if after_changelog and connector.version in line: - return True - return False - - -def check_connector_icon_is_available(connector: Connector) -> bool: - """Check an SVG icon exists for a connector in - in airbyte-config-oss/init-oss/src/main/resources/icons/.svg - - Args: - connector (Connector): a Connector dataclass instance. - - Returns: - bool: Wether an icon exists for this connector. - """ - return connector.icon_path.exists() - - -def read_all_files_in_directory( - directory: Path, ignored_directories: Optional[Set[str]] = None, ignored_filename_patterns: Optional[Set[str]] = None -) -> Iterable[Tuple[str, str]]: - ignored_directories = ignored_directories if ignored_directories is not None else {} - ignored_filename_patterns = ignored_filename_patterns if ignored_filename_patterns is not None else {} - - for path in directory.rglob("*"): - ignore_directory = any([ignored_directory in path.parts for ignored_directory in ignored_directories]) - ignore_filename = any([path.match(ignored_filename_pattern) for ignored_filename_pattern in ignored_filename_patterns]) - ignore = ignore_directory or ignore_filename - if path.is_file() and not ignore: - try: - for line in open(path, "r"): - yield path, line - except UnicodeDecodeError: - print(f"{path} could not be decoded as it is not UTF8.") - continue - - -IGNORED_DIRECTORIES_FOR_HTTPS_CHECKS = { - ".venv", - "tests", - "unit_tests", - "integration_tests", - "build", - "source-file", - ".pytest_cache", - "acceptance_tests_logs", - ".hypothesis", -} - -IGNORED_FILENAME_PATTERN_FOR_HTTPS_CHECKS = { - "*Test.java", - "*.jar", - "*.pyc", - "*.gz", - "*.svg", - "expected_records.jsonl", - "expected_records.json", -} -IGNORED_URLS_PREFIX = { - "http://json-schema.org", - "http://localhost", -} - - -def is_comment(line: str, file_path: Path): - language_comments = { - ".py": "#", - ".yml": "#", - ".yaml": "#", - ".java": "//", - ".md": " - %d{yyyy-MM-dd'T'HH:mm:ss,SSS}{GMT+0}`%highlight{%p}`%C{1.}(%M):%L - %replace{%m}{$${env:LOG_SCRUB_PATTERN:-\*\*\*\*\*}}{*****}%n + %d{yyyy-MM-dd'T'HH:mm:ss,SSS}{GMT+0} %thread `%highlight{%p}`%C{1.}(%M):%L - %replace{%m}{$${env:LOG_SCRUB_PATTERN:-\*\*\*\*\*}}{*****}%n %d{yyyy-MM-dd'T'HH:mm:ss,SSS}{GMT+0}`%replace{ %X{log_source}}{^ -}{} > %replace{%m}{$${env:LOG_SCRUB_PATTERN:-\*\*\*\*\*}}{*****}%n From 84cf59216a5c130d049d0ee1d8960eaac67be316 Mon Sep 17 00:00:00 2001 From: Augustin Date: Tue, 20 Feb 2024 11:26:07 +0100 Subject: [PATCH 41/43] doc: remove Node requirements on config based getting started tutorial (#35436) --- .../config-based/tutorial/0-getting-started.md | 1 - docs/connector-development/tutorials/cdk-speedrun.md | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/connector-development/config-based/tutorial/0-getting-started.md b/docs/connector-development/config-based/tutorial/0-getting-started.md index 8c47d589ccc5..5a264a66c4a6 100644 --- a/docs/connector-development/config-based/tutorial/0-getting-started.md +++ b/docs/connector-development/config-based/tutorial/0-getting-started.md @@ -44,7 +44,6 @@ This can be done by signing up for the Free tier plan on [Exchange Rates Data AP - Python >= 3.9 - [Poetry](https://python-poetry.org/) - Docker must be running -- NodeJS - [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md#L1) CLI ## Next Steps diff --git a/docs/connector-development/tutorials/cdk-speedrun.md b/docs/connector-development/tutorials/cdk-speedrun.md index bb9f23ddf246..d9fc6bc82ffd 100644 --- a/docs/connector-development/tutorials/cdk-speedrun.md +++ b/docs/connector-development/tutorials/cdk-speedrun.md @@ -117,17 +117,17 @@ cd .. mkdir sample_files echo '{"pokemon_name": "pikachu"}' > sample_files/config.json echo '{"pokemon_name": "chikapu"}' > sample_files/invalid_config.json -python main.py check --config sample_files/config.json -python main.py check --config sample_files/invalid_config.json +poetry run source-python-http-example check --config sample_files/config.json +poetry run source-python-http-example check --config sample_files/invalid_config.json ``` Expected output: -```text -> python main.py check --config sample_files/config.json +```bash +> poetry run source-python-http-example check --config sample_files/config.json {"type": "CONNECTION_STATUS", "connectionStatus": {"status": "SUCCEEDED"}} -> python main.py check --config sample_files/invalid_config.json +> poetry run source-python-http-example check --config sample_files/invalid_config.json {"type": "CONNECTION_STATUS", "connectionStatus": {"status": "FAILED", "message": "'Input Pokemon chikapu is invalid. Please check your spelling our input a valid Pokemon.'"}} ``` From 263699cccd4308e115179db9790d54e6c537e770 Mon Sep 17 00:00:00 2001 From: Augustin Date: Tue, 20 Feb 2024 12:17:44 +0100 Subject: [PATCH 42/43] airbyte-ci: disable telemetry with env var (#35438) --- airbyte-ci/connectors/pipelines/README.md | 5 +++++ .../connectors/pipelines/pipelines/cli/telemetry.py | 10 ++++++---- airbyte-ci/connectors/pipelines/pyproject.toml | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/airbyte-ci/connectors/pipelines/README.md b/airbyte-ci/connectors/pipelines/README.md index 2a15062dcdcd..99d25dd0c415 100644 --- a/airbyte-ci/connectors/pipelines/README.md +++ b/airbyte-ci/connectors/pipelines/README.md @@ -66,6 +66,10 @@ To clean the airbyte-ci install, run the following command: make tools.airbyte-ci.clean ``` +## Disabling telemetry + +We collect anonymous usage data to help improve the tool. If you would like to disable this, you can set the `AIRBYTE_CI_DISABLE_TELEMETRY` environment variable to `true`. + ## Installation for development #### Pre-requisites @@ -640,6 +644,7 @@ E.G.: running Poe tasks on the modified internal packages of the current branch: | Version | PR | Description | | ------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| 4.3.0 | [#35438](https://github.com/airbytehq/airbyte/pull/35438) | Optionally disable telemetry with environment variable. | | 4.2.4 | [#35325](https://github.com/airbytehq/airbyte/pull/35325) | Use `connectors_qa` for QA checks and remove redundant checks. | | 4.2.3 | [#35322](https://github.com/airbytehq/airbyte/pull/35322) | Declare `connectors_qa` as an internal package for testing. | | 4.2.2 | [#35364](https://github.com/airbytehq/airbyte/pull/35364) | Fix connector tests following gradle changes in #35307. | diff --git a/airbyte-ci/connectors/pipelines/pipelines/cli/telemetry.py b/airbyte-ci/connectors/pipelines/pipelines/cli/telemetry.py index a6998724897a..8ecb606973a1 100644 --- a/airbyte-ci/connectors/pipelines/pipelines/cli/telemetry.py +++ b/airbyte-ci/connectors/pipelines/pipelines/cli/telemetry.py @@ -13,13 +13,15 @@ import segment.analytics as analytics # type: ignore from asyncclick import get_current_context +DISABLE_TELEMETRY = os.environ.get("AIRBYTE_CI_DISABLE_TELEMETRY", "false").lower() == "true" + if TYPE_CHECKING: from typing import Any, Callable, Dict, Tuple from asyncclick import Command analytics.write_key = "G6G7whgro81g9xM00kN2buclGKvcOjFd" -analytics.send = True +analytics.send = not DISABLE_TELEMETRY analytics.debug = False @@ -49,13 +51,13 @@ def click_track_command(f: Callable) -> Callable: def wrapper(*args: Tuple, **kwargs: Dict[str, Any]) -> Command: ctx = get_current_context() + top_level_command = ctx.command_path full_cmd = " ".join(sys.argv) # remove anything prior to the command name f.__name__ # to avoid logging inline secrets - santized_cmd = full_cmd[full_cmd.find(top_level_command) :] - + sanitized_cmd = full_cmd[full_cmd.find(top_level_command) :] sys_id = _get_anonymous_system_id() sys_user_name = f"anonymous:{sys_id}" airbyter = _is_airbyte_user() @@ -65,7 +67,7 @@ def wrapper(*args: Tuple, **kwargs: Dict[str, Any]) -> Command: event = f"airbyte-ci:{f.__name__}" # IMPORTANT! do not log kwargs as they may contain secrets - analytics.track(user_id, event, {"username": sys_user_name, "command": santized_cmd, "airbyter": airbyter}) + analytics.track(user_id, event, {"username": sys_user_name, "command": sanitized_cmd, "airbyter": airbyter}) return f(*args, **kwargs) diff --git a/airbyte-ci/connectors/pipelines/pyproject.toml b/airbyte-ci/connectors/pipelines/pyproject.toml index 6f77c50066f9..275aad8b7b94 100644 --- a/airbyte-ci/connectors/pipelines/pyproject.toml +++ b/airbyte-ci/connectors/pipelines/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "pipelines" -version = "4.2.4" +version = "4.3.0" description = "Packaged maintained by the connector operations team to perform CI for connectors' pipelines" authors = ["Airbyte "] From 08fb4f775fc599d33a9d03d68a0a218dd9b85b85 Mon Sep 17 00:00:00 2001 From: Augustin Date: Tue, 20 Feb 2024 14:52:02 +0100 Subject: [PATCH 43/43] airbyte-ci: disable a flaky test (#35418) --- airbyte-ci/connectors/pipelines/pyproject.toml | 2 +- airbyte-ci/connectors/pipelines/pytest.ini | 1 + .../connectors/pipelines/tests/test_tests/test_common.py | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/airbyte-ci/connectors/pipelines/pyproject.toml b/airbyte-ci/connectors/pipelines/pyproject.toml index 275aad8b7b94..0ff42460da6c 100644 --- a/airbyte-ci/connectors/pipelines/pyproject.toml +++ b/airbyte-ci/connectors/pipelines/pyproject.toml @@ -57,7 +57,7 @@ shell = "pyinstaller --additional-hooks-dir=pyinstaller_hooks --collect-all pipe args = [{name = "ARTIFACT_NAME", default="airbyte-ci", positional = true}] [tool.poe.tasks] -test = "pytest tests" +test = "pytest tests -m 'not flaky'" type_check = "mypy pipelines --disallow-untyped-defs" lint = "ruff check pipelines" diff --git a/airbyte-ci/connectors/pipelines/pytest.ini b/airbyte-ci/connectors/pipelines/pytest.ini index b228671b5fa2..3c9d16b1fe5d 100644 --- a/airbyte-ci/connectors/pipelines/pytest.ini +++ b/airbyte-ci/connectors/pipelines/pytest.ini @@ -2,3 +2,4 @@ addopts = --cov=pipelines markers = slow: marks tests as slow (deselect with '-m "not slow"') + flaky: marks tests as flaky (deselect with '-m "not flaky"') diff --git a/airbyte-ci/connectors/pipelines/tests/test_tests/test_common.py b/airbyte-ci/connectors/pipelines/tests/test_tests/test_common.py index 8cc58cb470b5..047a130e097a 100644 --- a/airbyte-ci/connectors/pipelines/tests/test_tests/test_common.py +++ b/airbyte-ci/connectors/pipelines/tests/test_tests/test_common.py @@ -193,6 +193,10 @@ async def test_cat_container_provisioning( env_vars = {await env_var.name(): await env_var.value() for env_var in await cat_container.env_variables()} assert "CACHEBUSTER" in env_vars + @pytest.mark.flaky + # This test has shown some flakiness in CI + # This should be investigated and fixed + # https://github.com/airbytehq/airbyte-internal-issues/issues/6304 async def test_cat_container_caching( self, dagger_client,