diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 4cfc9cb..4bacb3b 100644 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -1,19 +1,19 @@ lockVersion: 2.0.0 id: 1927f304-b110-462d-9e13-326cfa243f23 management: - docChecksum: d8ab6b95255a18e53aa5e5a1f8ff52b0 + docChecksum: 8825ed6d84921f837ab5aede4160fe1f docVersion: v0.1 speakeasyVersion: 1.794.0 generationVersion: 2.930.0 - releaseVersion: 0.2.7 - configChecksum: 3e005f2c6958dc23cad0cb65b91d35e1 + releaseVersion: 0.3.0 + configChecksum: 8954e0a167cf29392916ea503e1e7f85 repoURL: https://github.com/thetradedesk/ttd-data-python.git installationURL: https://github.com/thetradedesk/ttd-data-python.git published: true persistentEdits: - generation_id: cfa7ff55-d2ad-4d35-8bc4-ed4e49274c63 - pristine_commit_hash: 1c1798b01807040436e88f60bc96d3832305800b - pristine_tree_hash: 6061fee8fcd73d260b64df3269dea75c27a3a336 + generation_id: 9ac5a2d5-0a86-485c-a1be-14bc05f34adb + pristine_commit_hash: f9f6306565f6eb37f04d42eed063518bcb241182 + pristine_tree_hash: f1a4cdf3cbbd1204eb22bb4dffcda4817fb25c5d features: python: additionalDependencies: 1.1.0 @@ -24,8 +24,9 @@ features: enumUnions: 0.1.1 envVarSecurityUsage: 0.3.3 flatRequests: 1.0.1 - flattening: 3.1.1 + globalSecurity: 3.0.7 globalSecurityCallbacks: 1.0.0 + globalSecurityFlattening: 1.0.0 globalServerURLs: 3.2.1 methodArguments: 1.1.1 methodServerURLs: 3.1.2 @@ -51,11 +52,10 @@ trackedFiles: id: 89aa447020cd last_write_checksum: sha1:f84632c81029fcdda8c3b0c768d02b836fc80526 pristine_git_object: 8d79f0abb72526f1fb34a4c03e5bba612c6ba2ae - deleted: true USAGE.md: id: 3aed33ce6e6f - last_write_checksum: sha1:a00281d1a5789209e12b9ca30653cf208599b71a - pristine_git_object: d57ef9032e3c78fb988abb1e9b32f5fdc76bc2af + last_write_checksum: sha1:d0ccd1c042220ceea45d1358fcd5e9e24280001d + pristine_git_object: 778e66cf4fe404cf6646158a31c9195b5016f2dd docs/errors/advertiserdataserverresponseerror.md: id: 6995891cb1b0 last_write_checksum: sha1:efb0f825612b14c3f84ddcd57b80a6b4f76b4c41 @@ -94,8 +94,8 @@ trackedFiles: pristine_git_object: 7fabf56853f463181c0cebe03d8d2123d1d33137 docs/models/advertiserdataresponseerrorcode.md: id: 5f207b4aeb44 - last_write_checksum: sha1:d298992abca3f7c33d527c74e155489dcac2cfaa - pristine_git_object: 4535616fe620fe5befabd69ab64545552dafa9dd + last_write_checksum: sha1:a7cd3243757c5fc31f8674179d08f8642b6b33fa + pristine_git_object: 28d70f2f1501cef191dfda3ab4e2d080d6025711 docs/models/advertiserdataserverresponse.md: id: ce05d8dc0150 last_write_checksum: sha1:70f28a1166c4733ef276663b1d6c75b3c45671e2 @@ -140,26 +140,14 @@ trackedFiles: id: 20171ab0469f last_write_checksum: sha1:62ecf13a13b503843150eb154a4ce739634bcd26 pristine_git_object: 8543fa7df3c60bc68b62eb6046bcbb212d2fd9e6 - docs/models/datasubjectrequestadvertiserdatarequest.md: - id: 4de4f4eda511 - last_write_checksum: sha1:2f7f2c9ef69eda156ec9d23b36add8e7a9c69a14 - pristine_git_object: 0d3c53388408f112dd8bd8a20a7a25ce0e13e5d7 docs/models/datasubjectrequestadvertiserdataresponse.md: id: 7c0cf1986700 last_write_checksum: sha1:be8980a597789a5443bb045faaeb1d749ef17295 pristine_git_object: e8aeb6c04f7a5ee31266e05d60f67c9c8b3a2906 - docs/models/datasubjectrequestmerchantdatarequest.md: - id: d9cc79798cca - last_write_checksum: sha1:57cdb6f5fc6d50f73f3d099d9ff5df08d329029d - pristine_git_object: 163dca6213b1bbc396a5504efb3d948096eccc6e docs/models/datasubjectrequestmerchantdataresponse.md: id: 7a220acd6db8 last_write_checksum: sha1:173c1b58701c6ac9f1481597e1317c7a2c76059d pristine_git_object: ae6f7e99e78f800628010b44619711d39c592d9b - docs/models/datasubjectrequestthirdpartydatarequest.md: - id: 87f5b015b4bd - last_write_checksum: sha1:1a499478ac891bf79c74e4145d1513003307a486 - pristine_git_object: bb6275848c95c76163423f98378954695b013c1e docs/models/datasubjectrequestthirdpartydataresponse.md: id: 6e4255df7a2c last_write_checksum: sha1:8b7257a961de785c35f491c0d9bd90dfba6d59d5 @@ -176,42 +164,22 @@ trackedFiles: id: 7ca0a10e4586 last_write_checksum: sha1:09d9c91cf41e3b9e867647becda4e437f4f3e3c8 pristine_git_object: 2c187164ad5f4bf5cc49203cbb81b64b240247a6 - docs/models/ingestadvertiserdatarequest.md: - id: 15472ae9b9b5 - last_write_checksum: sha1:9f6afab4002d0ea4d07b170111ff50eac0423073 - pristine_git_object: b9c4e5efb1ca6ca8ec162f31b8492a020ca8966f docs/models/ingestadvertiserdataresponse.md: id: 261c93e9e578 last_write_checksum: sha1:9374c3748ad3fcce15c885726bbc19b187f88500 pristine_git_object: 46cb31c391a6b1282f83cb32b07a27bf6418d191 - docs/models/ingestfirstpartyipaddressdatarequest.md: - id: 05b383d81e5d - last_write_checksum: sha1:1e1f5fb9bdc4a1d0e72c16b52e1c6df50f560a62 - pristine_git_object: c50a277b316bdf016e7ddfc7a740fb323fbc2db3 docs/models/ingestfirstpartyipaddressdataresponse.md: id: 7810d74cfc53 last_write_checksum: sha1:f44090e00785baff8ba540169d82cd0b4a1aaa3e pristine_git_object: 2340faf9f14ba83ff530ac060fc478223a2d8ba1 - docs/models/ingestofflineconversiondatarequest.md: - id: 917f4d932b09 - last_write_checksum: sha1:193a40a2095d3d07e68c56cd1dffd12b051ff23b - pristine_git_object: 7422be43cd6de4b6942211ef6096bca51a2faa33 docs/models/ingestofflineconversiondataresponse.md: id: 15c02deff4c3 last_write_checksum: sha1:634f41e94cef24c4cf674f2b11d2d4b851d7b38a pristine_git_object: 81f4b05cd4101470ba5e8a52b221a7ff6f35b5cd - docs/models/ingestthirdpartydatarequest.md: - id: b13c9ff57f29 - last_write_checksum: sha1:aea598809eab0797356d6cfc8fb9340c19fcf088 - pristine_git_object: 456450276d9059744e0f19ff7219e603e81d868e docs/models/ingestthirdpartydataresponse.md: id: 81c1f3df91e7 last_write_checksum: sha1:d336736a79fcf5e4d352cfc1ce553b759b9afbfd pristine_git_object: 24dbd818140ef377e232d000f065a8ff2b2af15f - docs/models/ingestthirdpartyipaddressdatarequest.md: - id: 6540b00b8bc1 - last_write_checksum: sha1:6c18f9a95b85a5174e2cd3c3f41f2a07f1cfd448 - pristine_git_object: da22760e31a178acbcf37128e76f1a8016a38877 docs/models/ingestthirdpartyipaddressdataresponse.md: id: 6468f2897dc3 last_write_checksum: sha1:18848a83c8c167ad0d5371db6e4d87613ed5fa2b @@ -230,8 +198,8 @@ trackedFiles: pristine_git_object: b32127b1cc105ce86a32b3f842d8db6ea6a58d88 docs/models/ipaddressdataresponseerrorcode.md: id: c450cd2baf13 - last_write_checksum: sha1:6b33f600015782c730c0c1cb624675fe16c1ff6d - pristine_git_object: 8de926b0b682ff32ff25732b7dea295241870dcd + last_write_checksum: sha1:a1bd7776075459a619f48e6d9956136f49d39b7e + pristine_git_object: 0d9d3def9967093e67145888291f22ff09476975 docs/models/ipaddressdataserverresponse.md: id: 86331e6b70f3 last_write_checksum: sha1:215fde7358a2b0c2c372c508f5d7853bb486715a @@ -280,6 +248,10 @@ trackedFiles: id: a71bb618c6dc last_write_checksum: sha1:b12b57e54211ce94278749a8fdd211dec8363dc3 pristine_git_object: f1e158e01c2b50bf8380b0bce2b42382a39149c4 + docs/models/security.md: + id: 452e4d4eb67a + last_write_checksum: sha1:3e93f1c842d02a3435ab584686f216504d80c33c + pristine_git_object: 3201615afc1f8c9c29d2f5eca5cecfb6ae6eae94 docs/models/thirdpartydata.md: id: bc4204726f1d last_write_checksum: sha1:0f89c863c85f83105c6f81d8e4e3ac7606b90aa3 @@ -290,8 +262,8 @@ trackedFiles: pristine_git_object: d3b0f39293f9f0831e4d61595d7e49162de3ca12 docs/models/thirdpartydataresponseerrorcode.md: id: a686bd16bff1 - last_write_checksum: sha1:c9762b26782d2ad79c3a1336600e20618da21e1f - pristine_git_object: 73e9a79653494128914934529608eda72f7ab4bf + last_write_checksum: sha1:3c7afc72642732a635e7cf1935f9dc1aee43d2e3 + pristine_git_object: ee4977b4f43bf29dfdd9c86da4d862eb2ef96642 docs/models/thirdpartydataserverresponse.md: id: 362b00f78795 last_write_checksum: sha1:1440730203a0d14798235445ac31088f93e7e79d @@ -326,8 +298,8 @@ trackedFiles: pristine_git_object: f456032107a9387ba6c98afd1c981df2f4b3d636 pyproject.toml: id: 5d07e7d72637 - last_write_checksum: sha1:66c9c417edfe4081f5c9a313dba7d05cd2426b51 - pristine_git_object: f5321c4b4113ad3f9250b6e9a5a9dc4a41c9979c + last_write_checksum: sha1:51108cbb59ad63d4e49d90d38768c23c40d3a5b4 + pristine_git_object: 175f386e9011b04db3e75517b2de3e71874ccb12 scripts/prepare_readme.py: id: e0c5957a6035 last_write_checksum: sha1:5a79be5a1346a05f9099f1177f4b3605849c3b6b @@ -354,20 +326,20 @@ trackedFiles: pristine_git_object: 4d1beeaa986919cd72ba7191f1b01a5670b3f38c src/ttd_data/_version.py: id: 7feb4586507e - last_write_checksum: sha1:2d1ae82a991adcc1e6382392325499fe967d293a - pristine_git_object: dfefd69bdfafe2d0380cfb6f1aa73cb91a5b78bc + last_write_checksum: sha1:0262903361058d05114ce7707095f7000d70b2cf + pristine_git_object: eeb3117109a4b56b13af6b713df403fc7055c647 src/ttd_data/advertiser.py: id: 392ead635b4f - last_write_checksum: sha1:db4154de6127aac2fc36c05a5561f49e349fbe84 - pristine_git_object: fb0f6dd940612b859d556af57720dddf9a59da0c + last_write_checksum: sha1:5a2cc27d47989c0f14783a1c2b98ee75d47ee169 + pristine_git_object: b82a98b470249be50fd588fee5c3e09da5733046 src/ttd_data/basesdk.py: id: 28e634bcfb11 - last_write_checksum: sha1:94fb8380b03b78312f2951f566bab98f1d0bceee - pristine_git_object: b3e7ee7ab69e5875ef7bf64033f4198e51dc8995 + last_write_checksum: sha1:d83decf45a023565237acea884ceeab296f67098 + pristine_git_object: 3d9137b69adc7ab8407c4ff3921cd6915ac97d2b src/ttd_data/deletionoptout.py: id: 8da72b51c89e - last_write_checksum: sha1:c84e71472efb5f62db1d93271c0fdb39fe1db009 - pristine_git_object: fab3b7c51f1074ad9ca0f291cb56a693893ddd01 + last_write_checksum: sha1:62ac0fecca1299035e471dbc6e78caeed3e2d28a + pristine_git_object: 2d0758279ca1aa09a80964247290d85f54722f56 src/ttd_data/errors/__init__.py: id: c4bbecf8701c last_write_checksum: sha1:d3ab7823110250629f17d053e0fd48880929d5ce @@ -422,12 +394,12 @@ trackedFiles: pristine_git_object: b7b67f6c923ffef8515a873a28c92927380bef14 src/ttd_data/ipaddress.py: id: f319e8f096ff - last_write_checksum: sha1:2c273dbfa9301e795156e662ebb9318c8d0242a4 - pristine_git_object: 6ae4f903a75ae647684eb40811493b13c9fb9b60 + last_write_checksum: sha1:4dbaca1e566a23af6f10fdafefc7228142354990 + pristine_git_object: e33eb586b954575fd5433e67f5d76556d07bb8b4 src/ttd_data/models/__init__.py: id: 9cb05e16fec0 - last_write_checksum: sha1:d2240cbcac42da78146ead8fd644ec985a560131 - pristine_git_object: c92bbaeee9ffba1f679f3035f8b5c759bdf033a0 + last_write_checksum: sha1:41566dd96c91863af2f14b256cf83c931eb1dd5c + pristine_git_object: f4c1aafc8a13fce0cddddb5ac41bf411a87fe9d1 src/ttd_data/models/advertiserdata.py: id: 3cb2f224c3a1 last_write_checksum: sha1:80a20f1c55d95168af9dcc273d27027462ceec23 @@ -438,8 +410,8 @@ trackedFiles: pristine_git_object: 64af06fa7d2742d834ad72c939aa2ab7e2f8d605 src/ttd_data/models/advertiserdataresponseerrorcode.py: id: ffcc1a785853 - last_write_checksum: sha1:227178dc9b8c3d558d6e9ea852193d72f342abd4 - pristine_git_object: cc8f3fda780300993e9744466c3bef2e58d3f0a4 + last_write_checksum: sha1:54604020fe17d52931609e886177d4adba6c2499 + pristine_git_object: 6bbdb87cf96a4d862f9e3ffdc6a0be7eafce8bd4 src/ttd_data/models/advertiserdataserverresponse.py: id: 532b8698bc5e last_write_checksum: sha1:a370392c7148998dfcf2335c3a7b0b3eb8323831 @@ -486,16 +458,16 @@ trackedFiles: pristine_git_object: 18f0cf38c7734e5b35b249545e61862d5e4efcd0 src/ttd_data/models/datasubjectrequestadvertiserdataop.py: id: 32f041f202c4 - last_write_checksum: sha1:a368259fc707e264c14ff18934d4207429df95b0 - pristine_git_object: 3fc6335a7f70d785f52fbe526fd6d7e9ffbc0264 + last_write_checksum: sha1:f54c872fea46c81736a673c48cc29e53715c4cdf + pristine_git_object: 16103d311289889e9fb3c76b51dd89b52abddb33 src/ttd_data/models/datasubjectrequestmerchantdataop.py: id: 2eaf568ecc7c - last_write_checksum: sha1:917a0ceef3a3cdcc80a9f839f8ad5e925c48e80b - pristine_git_object: 37a642b8d3563c21d62b82a98ac0fd1d198cf0dd + last_write_checksum: sha1:a80bfe2398e8811ecb764676b986c14d2425716c + pristine_git_object: 07526570379bac51e4962ce9ed241de978e0b02b src/ttd_data/models/datasubjectrequestthirdpartydataop.py: id: 961430b7540f - last_write_checksum: sha1:f64d3d8f1e125bd1eb4f80f60e9a9c3ecbc4a21e - pristine_git_object: 39acf52aa7138ce3e6776ae023c0a80e6eede1c2 + last_write_checksum: sha1:e4b39303666c6b6c6877a52ba48c96f8a8947c56 + pristine_git_object: dfb2834ff42e967b1252bdc991fc2ae6699c19a8 src/ttd_data/models/dsrerrorcode.py: id: 3d91ba4e034b last_write_checksum: sha1:415b46b7accf9179cd2cebeb1e927bea04fddf5a @@ -510,24 +482,24 @@ trackedFiles: pristine_git_object: a548716829b6b56533a3480684a9d2e05461347c src/ttd_data/models/ingestadvertiserdataop.py: id: 536d8288fda4 - last_write_checksum: sha1:6aba4806d3ae15ce4fbc0c7e136023a700d66fd4 - pristine_git_object: d2aac1b4482a39c4c32877d6dec3c97897a0e95b + last_write_checksum: sha1:eefa4c53467a32e78206e6c77a65143f9070b93b + pristine_git_object: 131be8bbbdda5068ca9555d2b64494c145882e6e src/ttd_data/models/ingestfirstpartyipaddressdataop.py: id: d55b71256a22 - last_write_checksum: sha1:712e4708fcb862008c0e56331418f7c93401dc11 - pristine_git_object: 26a7434fc186abb77fbca5e7a551e20fbf6abbb8 + last_write_checksum: sha1:c477aafdfa325409f79d6e6c416de9fd5910fd0d + pristine_git_object: cdb56e53ea6db64ffa0e37384f7cd297aeec3159 src/ttd_data/models/ingestofflineconversiondataop.py: id: 3dff4f5ef0ef - last_write_checksum: sha1:35c1af7746890286d4a5ff2b6e011f9bca4c4ed8 - pristine_git_object: c580cabd0ebb3b809a1e9817cea2222970def203 + last_write_checksum: sha1:96ef64665dc26b8d73a956ce2252c75a4831914a + pristine_git_object: 9e6f42b118b87591cba8dae64936575daa96c287 src/ttd_data/models/ingestthirdpartydataop.py: id: 7b9550f1c695 - last_write_checksum: sha1:2326ad429cd450e21140b6d9eb36671794239b30 - pristine_git_object: 3004d004cd1d869974be34828c0236a78a8be09c + last_write_checksum: sha1:8e60b038a85b6888d3189467d0c059bd611ffefb + pristine_git_object: 3b70ba2bc8728cc442f59e0804d25138dff5b617 src/ttd_data/models/ingestthirdpartyipaddressdataop.py: id: 07f6600b6a46 - last_write_checksum: sha1:fbda1ce3e5cb9b0bb57c4c5313c1f9410a299a17 - pristine_git_object: 46e0a07be251ef39a09f043ae899ec7d02553468 + last_write_checksum: sha1:faab7d1647dcf7f8b1498f0725f098ec31bbfa5e + pristine_git_object: 4b2d41040c3d998a44d6bc1b98720e4e3cc584a7 src/ttd_data/models/ipaddressdata.py: id: 1cb39b7876ab last_write_checksum: sha1:a0e0b1af6ad7a0b56ed6649d93523ada87f021eb @@ -542,8 +514,8 @@ trackedFiles: pristine_git_object: c2d456bc9250c334b0b1c8113886110995d96d26 src/ttd_data/models/ipaddressdataresponseerrorcode.py: id: 53204601212d - last_write_checksum: sha1:19b8a0f4b809e2594ac798c5029f8544308cdca5 - pristine_git_object: 16f08de8f24a79df642e0fc6a19fd4078d9f210b + last_write_checksum: sha1:d979f64ab3fe373a2deaa41d43c4b218b8112df5 + pristine_git_object: 980d573cedba811ee09f2619a878d5b2a0b220e6 src/ttd_data/models/ipaddressdataserverresponse.py: id: 184daceb940e last_write_checksum: sha1:b49ab70ffc1e8156b10b4fe07703d945d1455745 @@ -592,6 +564,10 @@ trackedFiles: id: 5c7bd069a3c4 last_write_checksum: sha1:cad40577128878ffab4f379344c18011803c3de3 pristine_git_object: 2682bf72fe51b96d0d116c4bb52361fc0e420ade + src/ttd_data/models/security.py: + id: fdab43ed8bcb + last_write_checksum: sha1:2421ebf008047001b9b0eea67c30522e5db966ff + pristine_git_object: 297679e269fedef9e509bed3b1347c4d468882e2 src/ttd_data/models/thirdpartydata.py: id: 747d671a1fd0 last_write_checksum: sha1:07fd2d4c3c2d7a90035839b7b0359b2787e3c5be @@ -602,8 +578,8 @@ trackedFiles: pristine_git_object: 08a31df358797a0f36e833027d7ad9b2ec9e729d src/ttd_data/models/thirdpartydataresponseerrorcode.py: id: c79166cc6728 - last_write_checksum: sha1:9887f48044983c0c04942929c6df95bfa66fb66e - pristine_git_object: e89db28a83d5ac4758624274ae071a3e3cd8c113 + last_write_checksum: sha1:6eeb22ad046e57c21d78d4e3a63bf1f754103fe0 + pristine_git_object: 18e913633db8922bf4a18f084ac64ad074173eee src/ttd_data/models/thirdpartydataserverresponse.py: id: 031ace715edf last_write_checksum: sha1:8ed69feafb034cb907d392b38ba95dccc29f6012 @@ -626,24 +602,24 @@ trackedFiles: pristine_git_object: b8960ee34603991114cae808f15a75001ac2c6a8 src/ttd_data/offlineconversion.py: id: 9cbf832f0f9b - last_write_checksum: sha1:38da8b856f7454f1dc00c17bc81abf6c82d0c89e - pristine_git_object: 794367dd50b173853c38190c2beb944cb7f31981 + last_write_checksum: sha1:567705df682ebded2ae953b667cb48997aa85c1f + pristine_git_object: 4620014ce7dfc2575a7ead98d69fb9672f0c74aa src/ttd_data/py.typed: id: 6369ae030577 last_write_checksum: sha1:8efc425ffe830805ffcc0f3055871bdcdc542c60 pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544 src/ttd_data/sdk.py: id: 1472df75b98c - last_write_checksum: sha1:2bd195befeb69e9c2746d10518d1b05820a9b15f - pristine_git_object: 425b68c61ccf052537f88d69795c4d8a9b14dfe3 + last_write_checksum: sha1:0d8fec4d0994850fe3ce0064ec5d7f529ea1583d + pristine_git_object: c057f940b74661b9d656e7245082c9a358066315 src/ttd_data/sdkconfiguration.py: id: 6c07cde690cd - last_write_checksum: sha1:b83130d20886d237799ede00df304904e19c582d - pristine_git_object: 914672ad7183223ef1b4fcaf06b06356fb5374c7 + last_write_checksum: sha1:2ed1b8d13e387a17f2a6c32753b7d3e6dc6bc0ae + pristine_git_object: 98e92378f68179feac7a0c08a369476735b4def3 src/ttd_data/thirdparty.py: id: ad2d973ed3be - last_write_checksum: sha1:a681eefa281c51cd863f6f0bc8fc7c612e475a81 - pristine_git_object: 22b6e83deff9f5671fd34742eab1230a44132cee + last_write_checksum: sha1:a36e7123c048c43ce10ac666adb36a4ed0f1e4fc + pristine_git_object: ee31eff72d4ccdabe67b7d9f1bc80790767a742f src/ttd_data/types/__init__.py: id: 219a89572292 last_write_checksum: sha1:ec1219cdc8f39cd32347b66eda50794bc082c9d8 @@ -658,8 +634,8 @@ trackedFiles: pristine_git_object: 196a66019c9fb86bd7c1de17b51fb6e7178b0918 src/ttd_data/utils/__init__.py: id: 6b87bf7e78f2 - last_write_checksum: sha1:2c7afc2c2fa57868cfd2bc9193175216044cbec7 - pristine_git_object: ace184fecab25927cc7800831fd990ed6264bbcc + last_write_checksum: sha1:40dee703383daa26b382d0cfb943d250692b9044 + pristine_git_object: aa1b4bf2a7cd1b952a49a9390347f07ceffa168c src/ttd_data/utils/annotations.py: id: d1b7b6530770 last_write_checksum: sha1:78c8976a64cca1d50bdfff78fa27ebf9d440909f @@ -710,8 +686,8 @@ trackedFiles: pristine_git_object: 5cef7c40b61d7110bb49931d20ba1a8da02769a8 src/ttd_data/utils/security.py: id: e38af000ccc5 - last_write_checksum: sha1:853c8f9f500bcffaf6880e27feafaab0e9146da8 - pristine_git_object: e56eff29be2cf5406dc94fbb1c9d8bd96cd3b257 + last_write_checksum: sha1:d7d901c2ae152ed07734fc7c7943723bcf38cffc + pristine_git_object: 8857bfa8b4dae8b4844aa8760f74615414d0a051 src/ttd_data/utils/serializers.py: id: 625de2eedcad last_write_checksum: sha1:dba8cf4b28b0da4830c53a76c700cf6bb358dc9e @@ -827,4 +803,4 @@ examples: application/json: {} examplesVersion: 1.0.2 generatedTests: {} -releaseNotes: "## Python SDK Changes:\n* `base_data_client.ip_address.ingest_first_party_ip_address_data()`: **Added**\n* `base_data_client.ip_address.ingest_third_party_ip_address_data()`: **Added**\n* `base_data_client.advertiser.ingest_advertiser_data()`: \n * `request.items[].real_id` **Added**\n* `base_data_client.third_party.ingest_third_party_data()`: \n * `request.items[].real_id` **Added**\n* `base_data_client.deletion_opt_out.data_subject_request_advertiser_data()`: \n * `request.items[].real_id` **Added**\n* `base_data_client.deletion_opt_out.data_subject_request_merchant_data()`: \n * `request.items[].real_id` **Added**\n* `base_data_client.deletion_opt_out.data_subject_request_third_party_data()`: \n * `request.items[].real_id` **Added**\n" +releaseNotes: "## Python SDK Changes:\n* `base_data_client.advertiser.ingest_advertiser_data()`: \n * `request.ttd_auth` **Removed** (Breaking ⚠️)\n * `response.failed_lines[].error_code.enum(invalid_timestamp_utc)` **Added** (Breaking ⚠️)\n * `error.failed_lines[].error_code.enum(invalid_timestamp_utc)` **Added** (Breaking ⚠️)\n* `base_data_client.third_party.ingest_third_party_data()`: \n * `request.ttd_auth` **Removed** (Breaking ⚠️)\n * `response.failed_lines[].error_code.enum(invalid_timestamp_utc)` **Added** (Breaking ⚠️)\n * `error.failed_lines[].error_code.enum(invalid_timestamp_utc)` **Added** (Breaking ⚠️)\n* `base_data_client.ip_address.ingest_first_party_ip_address_data()`: \n * `request.ttd_auth` **Removed** (Breaking ⚠️)\n * `response.failed_lines[].error_code.enum(invalid_timestamp_utc)` **Added** (Breaking ⚠️)\n * `error.failed_lines[].error_code.enum(invalid_timestamp_utc)` **Added** (Breaking ⚠️)\n* `base_data_client.ip_address.ingest_third_party_ip_address_data()`: \n * `request.ttd_auth` **Removed** (Breaking ⚠️)\n * `response.failed_lines[].error_code.enum(invalid_timestamp_utc)` **Added** (Breaking ⚠️)\n * `error.failed_lines[].error_code.enum(invalid_timestamp_utc)` **Added** (Breaking ⚠️)\n* `base_data_client.offline_conversion.ingest_offline_conversion_data()`: `request.ttd_auth` **Removed** (Breaking ⚠️)\n* `base_data_client.deletion_opt_out.data_subject_request_advertiser_data()`: `request.ttd_auth` **Removed** (Breaking ⚠️)\n* `base_data_client.deletion_opt_out.data_subject_request_merchant_data()`: `request.ttd_auth` **Removed** (Breaking ⚠️)\n* `base_data_client.deletion_opt_out.data_subject_request_third_party_data()`: `request.ttd_auth` **Removed** (Breaking ⚠️)\n" diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index 4129cd7..f4a3487 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -35,7 +35,7 @@ generation: generateNewTests: false skipResponseBodyAssertions: false python: - version: 0.2.7 + version: 0.3.0 additionalDependencies: dev: {} main: @@ -70,6 +70,7 @@ python: flatteningOrder: parameters-first forwardCompatibleEnumsByDefault: false forwardCompatibleUnionsByDefault: "false" + httpClientLibrary: httpx imports: option: openapi paths: diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml index 1f9475e..bafeb8b 100644 --- a/.speakeasy/out.openapi.yaml +++ b/.speakeasy/out.openapi.yaml @@ -22,13 +22,6 @@ paths: - "Advertiser" summary: "Upload first-party data for the specified ID for use in audience targeting." operationId: "IngestAdvertiserData" - parameters: - - name: "TTD-Auth" - in: "header" - description: "Data API token for authentication." - required: true - schema: - type: "string" requestBody: content: application/json: @@ -84,13 +77,6 @@ paths: - "ThirdParty" summary: "Upload third-party data for the specified data provider for use in audience targeting." operationId: "IngestThirdPartyData" - parameters: - - name: "TTD-Auth" - in: "header" - description: "Data API token for authentication." - required: true - schema: - type: "string" requestBody: content: application/json: @@ -146,13 +132,6 @@ paths: - "IPAddress" summary: "Upload first-party IP address data for the specified ID." operationId: "IngestFirstPartyIPAddressData" - parameters: - - name: "TTD-Auth" - in: "header" - description: "Data API token for authentication." - required: true - schema: - type: "string" requestBody: content: application/json: @@ -202,13 +181,6 @@ paths: - "IPAddress" summary: "Upload third-party IP address data for the specified ID." operationId: "IngestThirdPartyIPAddressData" - parameters: - - name: "TTD-Auth" - in: "header" - description: "Data API token for authentication." - required: true - schema: - type: "string" requestBody: content: application/json: @@ -258,13 +230,6 @@ paths: - "OfflineConversion" summary: "Upload offline conversion data for the specified data provider." operationId: "IngestOfflineConversionData" - parameters: - - name: "TTD-Auth" - in: "header" - description: "Data API token for authentication." - required: true - schema: - type: "string" requestBody: content: application/json: @@ -320,13 +285,6 @@ paths: - "DeletionOptOut" summary: "Delete IDs shared with The Trade Desk for the specified advertiser ID." operationId: "DataSubjectRequestAdvertiserData" - parameters: - - name: "TTD-Auth" - in: "header" - description: "Data API token for authentication." - required: true - schema: - type: "string" requestBody: content: application/json: @@ -382,13 +340,6 @@ paths: - "DeletionOptOut" summary: "Delete IDs shared with The Trade Desk via a product catalog for the specified merchant ID." operationId: "DataSubjectRequestMerchantData" - parameters: - - name: "TTD-Auth" - in: "header" - description: "Data API token for authentication." - required: true - schema: - type: "string" requestBody: content: application/json: @@ -444,13 +395,6 @@ paths: - "DeletionOptOut" summary: "Delete IDs shared with The Trade Desk for the specified data provider ID." operationId: "DataSubjectRequestThirdPartyData" - parameters: - - name: "TTD-Auth" - in: "header" - description: "Data API token for authentication." - required: true - schema: - type: "string" requestBody: content: application/json: @@ -630,6 +574,7 @@ components: - "TenantRestrictionsExternalData" - "TargetingDataDisabled" - "ItemDeserializationError" + - "InvalidTimestampUtc" - "Uid2Error" type: "string" AdvertiserDataServerResponse: @@ -856,6 +801,7 @@ components: - "InvalidIPAddressRange" - "EuIpTargetingNotAllowedForPartner" - "NotTargetable" + - "InvalidTimestampUtc" type: "string" IPAddressDataServerResponse: type: "object" @@ -1350,6 +1296,7 @@ components: - "TenantRestrictionsExternalData" - "TargetingDataDisabled" - "ItemDeserializationError" + - "InvalidTimestampUtc" - "Uid2Error" type: "string" ThirdPartyDataServerResponse: @@ -1455,3 +1402,11 @@ components: Type: $ref: "#/components/schemas/DataOriginType" additionalProperties: false + securitySchemes: + TTD-Auth: + type: "apiKey" + description: "API token for authentication." + name: "TTD-Auth" + in: "header" +security: + - TTD-Auth: [] diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index b12a998..8948e1d 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -2,8 +2,8 @@ speakeasyVersion: 1.794.0 sources: Data API: sourceNamespace: data-api - sourceRevisionDigest: sha256:c3853f233352223392fd1936aa89274767fa404b4cfcf730b2c1bf6b14e6bdd0 - sourceBlobDigest: sha256:bacb5bab3c306ab125fc18801edfd0dcb025c0ea7f2000245711d24f91e5809c + sourceRevisionDigest: sha256:1abe3a99d101d7ae9aeec5f1e07274c69ed0519e2480ec64cd25f7d3369579aa + sourceBlobDigest: sha256:56692c65a62089ccd496fadb72aae8baa193ca9616b3b8eccf7803c8ab9b6735 tags: - latest - v0.1 @@ -18,10 +18,10 @@ targets: data-api: source: Data API sourceNamespace: data-api - sourceRevisionDigest: sha256:c3853f233352223392fd1936aa89274767fa404b4cfcf730b2c1bf6b14e6bdd0 - sourceBlobDigest: sha256:bacb5bab3c306ab125fc18801edfd0dcb025c0ea7f2000245711d24f91e5809c + sourceRevisionDigest: sha256:1abe3a99d101d7ae9aeec5f1e07274c69ed0519e2480ec64cd25f7d3369579aa + sourceBlobDigest: sha256:56692c65a62089ccd496fadb72aae8baa193ca9616b3b8eccf7803c8ab9b6735 codeSamplesNamespace: data-api-python-code-samples - codeSamplesRevisionDigest: sha256:cee102bdae52db657cbcb3c1ef5c51fed24f5d3e4cf3c22906d1083a41198cdb + codeSamplesRevisionDigest: sha256:194d0629b51badce71be74659d61fed6a18ba42e1c24a2e26453b510152e93e7 data-api-local: source: Data API Local sourceNamespace: data-api-local diff --git a/README-PYPI.md b/README-PYPI.md index 13feb98..0103e46 100644 --- a/README-PYPI.md +++ b/README-PYPI.md @@ -127,19 +127,18 @@ Generally, the SDK will work well with most IDEs out of the box. However, when u ```python from ttd_data import DataClient, models -with DataClient() as client: - response = client.advertiser.ingest_advertiser_data( - ttd_auth=TTD_AUTH_TOKEN, - advertiser_id=ADVERTISER_ID, - items=[ - models.AdvertiserDataItem( - tdid="", - data=[ - models.AdvertiserData(name="loyalty_members"), - ], - ) - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.advertiser.ingest_advertiser_data( + advertiser_id=ADVERTISER_ID, + items=[ + models.AdvertiserDataItem( + tdid="", + data=[ + models.AdvertiserData(name="loyalty_members"), + ], + ) + ], +) ``` @@ -148,19 +147,18 @@ with DataClient() as client: ```python from ttd_data import DataClient, models -with DataClient() as client: - response = client.third_party.ingest_third_party_data( - ttd_auth=TTD_AUTH_TOKEN, - data_provider_id=DATA_PROVIDER_ID, - items=[ - models.ThirdPartyDataItem( - tdid="", - data=[ - models.ThirdPartyData(name="in_market_auto"), - ], - ) - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.third_party.ingest_third_party_data( + data_provider_id=DATA_PROVIDER_ID, + items=[ + models.ThirdPartyDataItem( + tdid="", + data=[ + models.ThirdPartyData(name="in_market_auto"), + ], + ) + ], +) ``` ### 3. Offline Conversions Data (CAPI) @@ -169,28 +167,29 @@ with DataClient() as client: from datetime import datetime, timezone from ttd_data import DataClient, UserIdType, models -with DataClient() as client: - response = client.offline_conversion.ingest_offline_conversion_data( - ttd_auth=TTD_AUTH_TOKEN, - data_provider_id=DATA_PROVIDER_ID, - items=[ - # Pre-resolved TDID - models.OfflineConversionDataItem( - tracking_tag_id=TRACKING_TAG_ID, - timestamp_utc=datetime.now(timezone.utc), - tdid="", - ), - # Multiple identifiers via UserIdArray - models.OfflineConversionDataItem( - tracking_tag_id=TRACKING_TAG_ID, - timestamp_utc=datetime.now(timezone.utc), - user_id_array=[ - [UserIdType.TDID, ""], - [UserIdType.UID2, ""], - ], - ), - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.offline_conversion.ingest_offline_conversion_data( + data_provider_id=DATA_PROVIDER_ID, + items=[ + # Pre-resolved TDID + models.OfflineConversionDataItem( + tracking_tag_id=TRACKING_TAG_ID, + timestamp_utc=datetime.now(timezone.utc), + tdid="", + ), + # Multiple identifiers via UserIdArray + models.OfflineConversionDataItem( + tracking_tag_id=TRACKING_TAG_ID, + timestamp_utc=datetime.now(timezone.utc), + user_id_array=[ + [UserIdType.TDID, ""], + [UserIdType.UID2, ""], + ], + ), + ], + # Required whenever any item uses user_id_array + user_id_array_metadata_format=["type", "id"], +) ``` ### 4. Optouts and Deletion - Advertiser - Data Subject Request @@ -198,17 +197,16 @@ with DataClient() as client: ```python from ttd_data import DataClient, models -with DataClient() as client: - response = client.deletion_opt_out.data_subject_request_advertiser_data( - ttd_auth=TTD_AUTH_TOKEN, - advertiser_id=ADVERTISER_ID, - request_type=models.PartnerDsrRequestType.DELETION, - items=[ - models.PartnerDsrDataItem(tdid=""), - models.PartnerDsrDataItem(daid=""), - models.PartnerDsrDataItem(euid=""), - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.deletion_opt_out.data_subject_request_advertiser_data( + advertiser_id=ADVERTISER_ID, + request_type=models.PartnerDsrRequestType.DELETION, + items=[ + models.PartnerDsrDataItem(tdid=""), + models.PartnerDsrDataItem(daid=""), + models.PartnerDsrDataItem(euid=""), + ], +) ``` ### 5. Optouts and Deletion - Data Provider - Data Subject Request @@ -216,16 +214,15 @@ with DataClient() as client: ```python from ttd_data import DataClient, models -with DataClient() as client: - response = client.deletion_opt_out.data_subject_request_third_party_data( - ttd_auth=TTD_AUTH_TOKEN, - data_provider_id=DATA_PROVIDER_ID, - request_type=models.PartnerDsrRequestType.OPT_OUT, - items=[ - models.PartnerDsrDataItem(tdid=""), - models.PartnerDsrDataItem(ramp_id=""), - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.deletion_opt_out.data_subject_request_third_party_data( + data_provider_id=DATA_PROVIDER_ID, + request_type=models.PartnerDsrRequestType.OPT_OUT, + items=[ + models.PartnerDsrDataItem(tdid=""), + models.PartnerDsrDataItem(ramp_id=""), + ], +) ``` ### 6. Optouts and Deletion - Merchant - Data Subject Request @@ -233,15 +230,14 @@ with DataClient() as client: ```python from ttd_data import DataClient, models -with DataClient() as client: - response = client.deletion_opt_out.data_subject_request_merchant_data( - ttd_auth=TTD_AUTH_TOKEN, - merchant_id=MERCHANT_ID, - request_type=models.PartnerDsrRequestType.DELETION, - items=[ - models.PartnerDsrDataItem(tdid=""), - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.deletion_opt_out.data_subject_request_merchant_data( + merchant_id=MERCHANT_ID, + request_type=models.PartnerDsrRequestType.DELETION, + items=[ + models.PartnerDsrDataItem(tdid=""), + ], +) ``` @@ -261,44 +257,47 @@ uid2_config = UID2Config( ) try: - with DataClient(uid2_config=uid2_config, server_url="") as client: - response = client.advertiser.ingest_advertiser_data( - ttd_auth=TTD_AUTH_TOKEN, - advertiser_id=ADVERTISER_ID, - items=[ - # Raw email — resolved to UID2 before ingest - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - email="user@example.com", - ), - # Pre-hashed email (SHA-256, base64-encoded) - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - hashed_email="", - ), - # Raw phone (E.164 format) — resolved to UID2 before ingest - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - phone="+15555550123", - ), - # Pre-hashed phone (SHA-256 of the normalized E.164 string, base64-encoded) - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - hashed_phone="", - ), - # Pre-resolved TDID — no UID2 work needed - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - tdid="", - ), - ], - ) + client = DataClient( + ttd_auth=TTD_AUTH_TOKEN, + uid2_config=uid2_config, + server_url="", + ) + response = client.advertiser.ingest_advertiser_data( + advertiser_id=ADVERTISER_ID, + items=[ + # Raw email — resolved to UID2 before ingest + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + email="user@example.com", + ), + # Pre-hashed email (SHA-256, base64-encoded) + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + hashed_email="", + ), + # Raw phone (E.164 format) — resolved to UID2 before ingest + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + phone="+15555550123", + ), + # Pre-hashed phone (SHA-256 of the normalized E.164 string, base64-encoded) + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + hashed_phone="", + ), + # Pre-resolved TDID — no UID2 work needed + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + tdid="", + ), + ], + ) - # Check for per-item mapping failures - server_response = response.advertiser_data_server_response - if server_response and server_response.failed_lines: - for line in server_response.failed_lines: - print(f"Item {line.item_number} failed: {line.error_code} — {line.message}") + # Check for per-item mapping failures + server_response = response.advertiser_data_server_response + if server_response and server_response.failed_lines: + for line in server_response.failed_lines: + print(f"Item {line.item_number} failed: {line.error_code} — {line.message}") except UID2ServiceError as e: # The UID2 identity-map service itself failed — no items were sent @@ -315,23 +314,21 @@ import asyncio from ttd_data import DataClient, models async def main(): + data_client = DataClient(ttd_auth=TTD_AUTH_TOKEN) + response = await data_client.advertiser.ingest_advertiser_data_async( + advertiser_id=ADVERTISER_ID, + items=[ + models.AdvertiserDataItem( + tdid="", + data=[ + models.AdvertiserData(name="loyalty_members"), + ], + ) + ], + ) - async with DataClient() as data_client: - response = data_client.advertiser.ingest_advertiser_data( - ttd_auth=TTD_AUTH_TOKEN, - advertiser_id=ADVERTISER_ID, - items=[ - models.AdvertiserDataItem( - tdid="", - data=[ - models.AdvertiserData(name="loyalty_members"), - ], - ) - ], - ) - - # Handle response - print(response.advertiser_data_server_response) + # Handle response + print(response.advertiser_data_server_response) asyncio.run(main()) ``` @@ -375,15 +372,15 @@ from ttd_data import DataClient from ttd_data.utils import BackoffStrategy, RetryConfig -with DataClient() as data_client: +data_client = DataClient(ttd_auth="") - res = data_client.advertiser.ingest_advertiser_data(ttd_auth="", advertiser_id="", - RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False)) +res = data_client.advertiser.ingest_advertiser_data(advertiser_id="", + retries=RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False)) - assert res.advertiser_data_server_response is not None +assert res.advertiser_data_server_response is not None - # Handle response - print(res.advertiser_data_server_response) +# Handle response +print(res.advertiser_data_server_response) ``` @@ -393,16 +390,17 @@ from ttd_data import DataClient from ttd_data.utils import BackoffStrategy, RetryConfig -with DataClient( +data_client = DataClient( + ttd_auth="", retry_config=RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False), -) as data_client: +) - res = data_client.advertiser.ingest_advertiser_data(ttd_auth="", advertiser_id="") +res = data_client.advertiser.ingest_advertiser_data(advertiser_id="") - assert res.advertiser_data_server_response is not None +assert res.advertiser_data_server_response is not None - # Handle response - print(res.advertiser_data_server_response) +# Handle response +print(res.advertiser_data_server_response) ``` @@ -426,30 +424,30 @@ with DataClient( from ttd_data import DataClient, errors -with DataClient() as data_client: - res = None - try: +data_client = DataClient(ttd_auth="") +res = None +try: - res = data_client.advertiser.ingest_advertiser_data(ttd_auth="", advertiser_id="") + res = data_client.advertiser.ingest_advertiser_data(advertiser_id="") - assert res.advertiser_data_server_response is not None + assert res.advertiser_data_server_response is not None - # Handle response - print(res.advertiser_data_server_response) + # Handle response + print(res.advertiser_data_server_response) - except errors.DataError as e: - # The base class for HTTP error responses - print(e.message) - print(e.status_code) - print(e.body) - print(e.headers) - print(e.raw_response) +except errors.DataError as e: + # The base class for HTTP error responses + print(e.message) + print(e.status_code) + print(e.body) + print(e.headers) + print(e.raw_response) - # Depending on the method different errors may be thrown - if isinstance(e, errors.AdvertiserDataServerResponseError): - print(e.data.failed_lines) # OptionalNullable[List[models.AdvertiserDataServerResponseLine]] - print(e.data.http_meta) # models.HTTPMetadata + # Depending on the method different errors may be thrown + if isinstance(e, errors.AdvertiserDataServerResponseError): + print(e.data.failed_lines) # OptionalNullable[List[models.AdvertiserDataServerResponseLine]] + print(e.data.http_meta) # models.HTTPMetadata ``` ### Error Classes @@ -500,6 +498,7 @@ or you could wrap the client with your own custom logic: ```python from ttd_data import DataClient from ttd_data.httpclient import AsyncHttpClient +from typing import Any, Optional, Union import httpx class CustomClient(AsyncHttpClient): @@ -564,23 +563,22 @@ s = DataClient(async_client=CustomClient(httpx.AsyncClient())) ## Resource Management -The `DataClient` class implements the context manager protocol and registers a finalizer function to close the underlying sync and async HTTPX clients it uses under the hood. This will close HTTP connections, release memory and free up other resources held by the SDK. In short-lived Python programs and notebooks that make a few SDK method calls, resource management may not be a concern. However, in longer-lived programs, it is beneficial to create a single SDK instance via a [context manager][context-manager] and reuse it across the application. - -[context-manager]: https://docs.python.org/3/reference/datamodel.html#context-managers +`DataClient` registers a finalizer that closes the underlying sync and async HTTPX clients when the instance is garbage collected. This closes HTTP connections, releases memory and frees up other resources held by the SDK. In short-lived Python programs and notebooks that make a few SDK method calls, resource management may not be a concern. However, in longer-lived programs, it is beneficial to create a single SDK instance and reuse it across the application. ```python from ttd_data import DataClient -def main(): - with DataClient() as data_client: - # Rest of application here... +client = DataClient(ttd_auth="") -# Or when using async: -async def amain(): +def main(): + # Reuse the single client for every request + ... + - async with DataClient() as data_client: - # Rest of application here... +# The same instance also serves async calls: +async def amain(): + ... ``` diff --git a/README.md b/README.md index ee957d6..727d4ad 100644 --- a/README.md +++ b/README.md @@ -127,19 +127,18 @@ Generally, the SDK will work well with most IDEs out of the box. However, when u ```python from ttd_data import DataClient, models -with DataClient() as client: - response = client.advertiser.ingest_advertiser_data( - ttd_auth=TTD_AUTH_TOKEN, - advertiser_id=ADVERTISER_ID, - items=[ - models.AdvertiserDataItem( - tdid="", - data=[ - models.AdvertiserData(name="loyalty_members"), - ], - ) - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.advertiser.ingest_advertiser_data( + advertiser_id=ADVERTISER_ID, + items=[ + models.AdvertiserDataItem( + tdid="", + data=[ + models.AdvertiserData(name="loyalty_members"), + ], + ) + ], +) ``` @@ -148,19 +147,18 @@ with DataClient() as client: ```python from ttd_data import DataClient, models -with DataClient() as client: - response = client.third_party.ingest_third_party_data( - ttd_auth=TTD_AUTH_TOKEN, - data_provider_id=DATA_PROVIDER_ID, - items=[ - models.ThirdPartyDataItem( - tdid="", - data=[ - models.ThirdPartyData(name="in_market_auto"), - ], - ) - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.third_party.ingest_third_party_data( + data_provider_id=DATA_PROVIDER_ID, + items=[ + models.ThirdPartyDataItem( + tdid="", + data=[ + models.ThirdPartyData(name="in_market_auto"), + ], + ) + ], +) ``` ### 3. Offline Conversions Data (CAPI) @@ -169,28 +167,29 @@ with DataClient() as client: from datetime import datetime, timezone from ttd_data import DataClient, UserIdType, models -with DataClient() as client: - response = client.offline_conversion.ingest_offline_conversion_data( - ttd_auth=TTD_AUTH_TOKEN, - data_provider_id=DATA_PROVIDER_ID, - items=[ - # Pre-resolved TDID - models.OfflineConversionDataItem( - tracking_tag_id=TRACKING_TAG_ID, - timestamp_utc=datetime.now(timezone.utc), - tdid="", - ), - # Multiple identifiers via UserIdArray - models.OfflineConversionDataItem( - tracking_tag_id=TRACKING_TAG_ID, - timestamp_utc=datetime.now(timezone.utc), - user_id_array=[ - [UserIdType.TDID, ""], - [UserIdType.UID2, ""], - ], - ), - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.offline_conversion.ingest_offline_conversion_data( + data_provider_id=DATA_PROVIDER_ID, + items=[ + # Pre-resolved TDID + models.OfflineConversionDataItem( + tracking_tag_id=TRACKING_TAG_ID, + timestamp_utc=datetime.now(timezone.utc), + tdid="", + ), + # Multiple identifiers via UserIdArray + models.OfflineConversionDataItem( + tracking_tag_id=TRACKING_TAG_ID, + timestamp_utc=datetime.now(timezone.utc), + user_id_array=[ + [UserIdType.TDID, ""], + [UserIdType.UID2, ""], + ], + ), + ], + # Required whenever any item uses user_id_array + user_id_array_metadata_format=["type", "id"], +) ``` ### 4. Optouts and Deletion - Advertiser - Data Subject Request @@ -198,17 +197,16 @@ with DataClient() as client: ```python from ttd_data import DataClient, models -with DataClient() as client: - response = client.deletion_opt_out.data_subject_request_advertiser_data( - ttd_auth=TTD_AUTH_TOKEN, - advertiser_id=ADVERTISER_ID, - request_type=models.PartnerDsrRequestType.DELETION, - items=[ - models.PartnerDsrDataItem(tdid=""), - models.PartnerDsrDataItem(daid=""), - models.PartnerDsrDataItem(euid=""), - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.deletion_opt_out.data_subject_request_advertiser_data( + advertiser_id=ADVERTISER_ID, + request_type=models.PartnerDsrRequestType.DELETION, + items=[ + models.PartnerDsrDataItem(tdid=""), + models.PartnerDsrDataItem(daid=""), + models.PartnerDsrDataItem(euid=""), + ], +) ``` ### 5. Optouts and Deletion - Data Provider - Data Subject Request @@ -216,16 +214,15 @@ with DataClient() as client: ```python from ttd_data import DataClient, models -with DataClient() as client: - response = client.deletion_opt_out.data_subject_request_third_party_data( - ttd_auth=TTD_AUTH_TOKEN, - data_provider_id=DATA_PROVIDER_ID, - request_type=models.PartnerDsrRequestType.OPT_OUT, - items=[ - models.PartnerDsrDataItem(tdid=""), - models.PartnerDsrDataItem(ramp_id=""), - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.deletion_opt_out.data_subject_request_third_party_data( + data_provider_id=DATA_PROVIDER_ID, + request_type=models.PartnerDsrRequestType.OPT_OUT, + items=[ + models.PartnerDsrDataItem(tdid=""), + models.PartnerDsrDataItem(ramp_id=""), + ], +) ``` ### 6. Optouts and Deletion - Merchant - Data Subject Request @@ -233,15 +230,14 @@ with DataClient() as client: ```python from ttd_data import DataClient, models -with DataClient() as client: - response = client.deletion_opt_out.data_subject_request_merchant_data( - ttd_auth=TTD_AUTH_TOKEN, - merchant_id=MERCHANT_ID, - request_type=models.PartnerDsrRequestType.DELETION, - items=[ - models.PartnerDsrDataItem(tdid=""), - ], - ) +client = DataClient(ttd_auth=TTD_AUTH_TOKEN) +response = client.deletion_opt_out.data_subject_request_merchant_data( + merchant_id=MERCHANT_ID, + request_type=models.PartnerDsrRequestType.DELETION, + items=[ + models.PartnerDsrDataItem(tdid=""), + ], +) ``` @@ -261,44 +257,47 @@ uid2_config = UID2Config( ) try: - with DataClient(uid2_config=uid2_config, server_url="") as client: - response = client.advertiser.ingest_advertiser_data( - ttd_auth=TTD_AUTH_TOKEN, - advertiser_id=ADVERTISER_ID, - items=[ - # Raw email — resolved to UID2 before ingest - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - email="user@example.com", - ), - # Pre-hashed email (SHA-256, base64-encoded) - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - hashed_email="", - ), - # Raw phone (E.164 format) — resolved to UID2 before ingest - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - phone="+15555550123", - ), - # Pre-hashed phone (SHA-256 of the normalized E.164 string, base64-encoded) - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - hashed_phone="", - ), - # Pre-resolved TDID — no UID2 work needed - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - tdid="", - ), - ], - ) + client = DataClient( + ttd_auth=TTD_AUTH_TOKEN, + uid2_config=uid2_config, + server_url="", + ) + response = client.advertiser.ingest_advertiser_data( + advertiser_id=ADVERTISER_ID, + items=[ + # Raw email — resolved to UID2 before ingest + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + email="user@example.com", + ), + # Pre-hashed email (SHA-256, base64-encoded) + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + hashed_email="", + ), + # Raw phone (E.164 format) — resolved to UID2 before ingest + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + phone="+15555550123", + ), + # Pre-hashed phone (SHA-256 of the normalized E.164 string, base64-encoded) + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + hashed_phone="", + ), + # Pre-resolved TDID — no UID2 work needed + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + tdid="", + ), + ], + ) - # Check for per-item mapping failures - server_response = response.advertiser_data_server_response - if server_response and server_response.failed_lines: - for line in server_response.failed_lines: - print(f"Item {line.item_number} failed: {line.error_code} — {line.message}") + # Check for per-item mapping failures + server_response = response.advertiser_data_server_response + if server_response and server_response.failed_lines: + for line in server_response.failed_lines: + print(f"Item {line.item_number} failed: {line.error_code} — {line.message}") except UID2ServiceError as e: # The UID2 identity-map service itself failed — no items were sent @@ -315,23 +314,21 @@ import asyncio from ttd_data import DataClient, models async def main(): + data_client = DataClient(ttd_auth=TTD_AUTH_TOKEN) + response = await data_client.advertiser.ingest_advertiser_data_async( + advertiser_id=ADVERTISER_ID, + items=[ + models.AdvertiserDataItem( + tdid="", + data=[ + models.AdvertiserData(name="loyalty_members"), + ], + ) + ], + ) - async with DataClient() as data_client: - response = data_client.advertiser.ingest_advertiser_data( - ttd_auth=TTD_AUTH_TOKEN, - advertiser_id=ADVERTISER_ID, - items=[ - models.AdvertiserDataItem( - tdid="", - data=[ - models.AdvertiserData(name="loyalty_members"), - ], - ) - ], - ) - - # Handle response - print(response.advertiser_data_server_response) + # Handle response + print(response.advertiser_data_server_response) asyncio.run(main()) ``` @@ -375,15 +372,15 @@ from ttd_data import DataClient from ttd_data.utils import BackoffStrategy, RetryConfig -with DataClient() as data_client: +data_client = DataClient(ttd_auth="") - res = data_client.advertiser.ingest_advertiser_data(ttd_auth="", advertiser_id="", - RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False)) +res = data_client.advertiser.ingest_advertiser_data(advertiser_id="", + retries=RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False)) - assert res.advertiser_data_server_response is not None +assert res.advertiser_data_server_response is not None - # Handle response - print(res.advertiser_data_server_response) +# Handle response +print(res.advertiser_data_server_response) ``` @@ -393,16 +390,17 @@ from ttd_data import DataClient from ttd_data.utils import BackoffStrategy, RetryConfig -with DataClient( +data_client = DataClient( + ttd_auth="", retry_config=RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False), -) as data_client: +) - res = data_client.advertiser.ingest_advertiser_data(ttd_auth="", advertiser_id="") +res = data_client.advertiser.ingest_advertiser_data(advertiser_id="") - assert res.advertiser_data_server_response is not None +assert res.advertiser_data_server_response is not None - # Handle response - print(res.advertiser_data_server_response) +# Handle response +print(res.advertiser_data_server_response) ``` @@ -426,30 +424,30 @@ with DataClient( from ttd_data import DataClient, errors -with DataClient() as data_client: - res = None - try: +data_client = DataClient(ttd_auth="") +res = None +try: - res = data_client.advertiser.ingest_advertiser_data(ttd_auth="", advertiser_id="") + res = data_client.advertiser.ingest_advertiser_data(advertiser_id="") - assert res.advertiser_data_server_response is not None + assert res.advertiser_data_server_response is not None - # Handle response - print(res.advertiser_data_server_response) + # Handle response + print(res.advertiser_data_server_response) - except errors.DataError as e: - # The base class for HTTP error responses - print(e.message) - print(e.status_code) - print(e.body) - print(e.headers) - print(e.raw_response) +except errors.DataError as e: + # The base class for HTTP error responses + print(e.message) + print(e.status_code) + print(e.body) + print(e.headers) + print(e.raw_response) - # Depending on the method different errors may be thrown - if isinstance(e, errors.AdvertiserDataServerResponseError): - print(e.data.failed_lines) # OptionalNullable[List[models.AdvertiserDataServerResponseLine]] - print(e.data.http_meta) # models.HTTPMetadata + # Depending on the method different errors may be thrown + if isinstance(e, errors.AdvertiserDataServerResponseError): + print(e.data.failed_lines) # OptionalNullable[List[models.AdvertiserDataServerResponseLine]] + print(e.data.http_meta) # models.HTTPMetadata ``` ### Error Classes @@ -500,6 +498,7 @@ or you could wrap the client with your own custom logic: ```python from ttd_data import DataClient from ttd_data.httpclient import AsyncHttpClient +from typing import Any, Optional, Union import httpx class CustomClient(AsyncHttpClient): @@ -564,23 +563,22 @@ s = DataClient(async_client=CustomClient(httpx.AsyncClient())) ## Resource Management -The `DataClient` class implements the context manager protocol and registers a finalizer function to close the underlying sync and async HTTPX clients it uses under the hood. This will close HTTP connections, release memory and free up other resources held by the SDK. In short-lived Python programs and notebooks that make a few SDK method calls, resource management may not be a concern. However, in longer-lived programs, it is beneficial to create a single SDK instance via a [context manager][context-manager] and reuse it across the application. - -[context-manager]: https://docs.python.org/3/reference/datamodel.html#context-managers +`DataClient` registers a finalizer that closes the underlying sync and async HTTPX clients when the instance is garbage collected. This closes HTTP connections, releases memory and frees up other resources held by the SDK. In short-lived Python programs and notebooks that make a few SDK method calls, resource management may not be a concern. However, in longer-lived programs, it is beneficial to create a single SDK instance and reuse it across the application. ```python from ttd_data import DataClient -def main(): - with DataClient() as data_client: - # Rest of application here... +client = DataClient(ttd_auth="") -# Or when using async: -async def amain(): +def main(): + # Reuse the single client for every request + ... + - async with DataClient() as data_client: - # Rest of application here... +# The same instance also serves async calls: +async def amain(): + ... ``` diff --git a/RELEASES.md b/RELEASES.md index f661704..3687c25 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -148,4 +148,14 @@ Based on: ### Generated - [python v0.2.7] . ### Releases -- [PyPI v0.2.7] https://pypi.org/project/ttd-data/0.2.7 - . \ No newline at end of file +- [PyPI v0.2.7] https://pypi.org/project/ttd-data/0.2.7 - . + +## 2026-09-02 17:09:46 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.794.0 (2.930.0) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v0.3.0] . +### Releases +- [PyPI v0.3.0] https://pypi.org/project/ttd-data/0.3.0 - . \ No newline at end of file diff --git a/USAGE.md b/USAGE.md index 51a57fe..f3e3050 100644 --- a/USAGE.md +++ b/USAGE.md @@ -4,18 +4,20 @@ from ttd_data import DataClient from ttd_data.models import AdvertiserData, AdvertiserDataItem -with DataClient(server_url="") as client: - response = client.advertiser.ingest_advertiser_data( - ttd_auth="", - advertiser_id="", - items=[ - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - tdid="", - ) - ], - ) - print(response.advertiser_data_server_response) +client = DataClient( + ttd_auth="", + server_url="", +) +response = client.advertiser.ingest_advertiser_data( + advertiser_id="", + items=[ + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + tdid="", + ) + ], +) +print(response.advertiser_data_server_response) ```
@@ -33,18 +35,21 @@ uid2_config = UID2Config( ) try: - with DataClient(uid2_config=uid2_config, server_url="") as client: - response = client.advertiser.ingest_advertiser_data( - ttd_auth="", - advertiser_id="", - items=[ - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - email="user@example.com", - ) - ], - ) - print(response.advertiser_data_server_response) + client = DataClient( + ttd_auth="", + uid2_config=uid2_config, + server_url="", + ) + response = client.advertiser.ingest_advertiser_data( + advertiser_id="", + items=[ + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + email="user@example.com", + ) + ], + ) + print(response.advertiser_data_server_response) except UID2ServiceError as e: print(f"UID2 service error: {e}") ``` @@ -60,18 +65,20 @@ from ttd_data import DataClient from ttd_data.models import AdvertiserData, AdvertiserDataItem async def main(): - async with DataClient(server_url="") as client: - response = await client.advertiser.ingest_advertiser_data_async( - ttd_auth="", - advertiser_id="", - items=[ - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - tdid="", - ) - ], - ) - print(response.advertiser_data_server_response) + client = DataClient( + ttd_auth="", + server_url="", + ) + response = await client.advertiser.ingest_advertiser_data_async( + advertiser_id="", + items=[ + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + tdid="", + ) + ], + ) + print(response.advertiser_data_server_response) asyncio.run(main()) ``` @@ -93,18 +100,21 @@ uid2_config = UID2Config( async def main(): try: - async with DataClient(uid2_config=uid2_config, server_url="") as client: - response = await client.advertiser.ingest_advertiser_data_async( - ttd_auth="", - advertiser_id="", - items=[ - AdvertiserDataItem( - data=[AdvertiserData(name="loyalty_members")], - email="user@example.com", - ) - ], - ) - print(response.advertiser_data_server_response) + client = DataClient( + ttd_auth="", + uid2_config=uid2_config, + server_url="", + ) + response = await client.advertiser.ingest_advertiser_data_async( + advertiser_id="", + items=[ + AdvertiserDataItem( + data=[AdvertiserData(name="loyalty_members")], + email="user@example.com", + ) + ], + ) + print(response.advertiser_data_server_response) except UID2ServiceError as e: print(f"UID2 service error: {e}") diff --git a/data-api-local/local_uid2_ingest_e2e.py b/data-api-local/local_uid2_ingest_e2e.py index c6d4e44..27ab4fc 100644 --- a/data-api-local/local_uid2_ingest_e2e.py +++ b/data-api-local/local_uid2_ingest_e2e.py @@ -209,7 +209,6 @@ def exercise_advertiser_ingest(client: DataClient) -> None: _print_items("Submitting items", items) response = client.advertiser.ingest_advertiser_data( advertiser_id=ADVERTISER_ID, - ttd_auth=TTD_AUTH_TOKEN, items=items, ) _print_items("Items after resolution", items) @@ -234,7 +233,6 @@ def exercise_third_party_ingest(client: DataClient) -> None: _print_items("Submitting items", items) response = client.third_party.ingest_third_party_data( data_provider_id=DATA_PROVIDER_ID, - ttd_auth=TTD_AUTH_TOKEN, items=items, ) _print_items("Items after resolution", items) @@ -278,7 +276,6 @@ def exercise_offline_conversion_ingest(client: DataClient) -> None: ] _print_items("Submitting items", items) response = client.offline_conversion.ingest_offline_conversion_data( - ttd_auth=TTD_AUTH_TOKEN, data_provider_id=DATA_PROVIDER_ID, items=items, user_id_array_metadata_format=["type", "id"], @@ -303,7 +300,6 @@ def exercise_dsr_advertiser(client: DataClient) -> None: _print_items("Submitting items", items) response = client.deletion_opt_out.data_subject_request_advertiser_data( advertiser_id=ADVERTISER_ID, - ttd_auth=TTD_AUTH_TOKEN, items=items, request_type=PartnerDsrRequestType.OPT_OUT, ) @@ -327,7 +323,6 @@ def exercise_dsr_merchant(client: DataClient) -> None: _print_items("Submitting items", items) response = client.deletion_opt_out.data_subject_request_merchant_data( merchant_id=MERCHANT_ID, - ttd_auth=TTD_AUTH_TOKEN, items=items, request_type=PartnerDsrRequestType.OPT_OUT, ) @@ -351,7 +346,6 @@ def exercise_dsr_third_party(client: DataClient) -> None: _print_items("Submitting items", items) response = client.deletion_opt_out.data_subject_request_third_party_data( data_provider_id=DATA_PROVIDER_ID, - ttd_auth=TTD_AUTH_TOKEN, items=items, request_type=PartnerDsrRequestType.OPT_OUT, ) @@ -371,7 +365,7 @@ def _make_uid2_client() -> DataClient: client_secret=UID2_CLIENT_SECRET, identity_scope=IdentityScope.UID2, ) - return DataClient(config, server_url=TTD_DATA_SERVER_URL) + return DataClient(config, ttd_auth=TTD_AUTH_TOKEN, server_url=TTD_DATA_SERVER_URL) def _register_capture(client: DataClient) -> _RequestBodyCapture: @@ -401,7 +395,6 @@ def verify_pii_not_in_request_with_uid2_config() -> None: try: response = client.advertiser.ingest_advertiser_data( advertiser_id=ADVERTISER_ID, - ttd_auth=TTD_AUTH_TOKEN, items=items, ) _print_response("TTD response", response, "advertiser_data_server_response") @@ -420,7 +413,7 @@ def verify_pii_not_in_request_no_uid2_config() -> None: BaseAdvertiserDataItem has no such fields — pydantic silently ignores them. """ # No uid2_config — UID2 resolution is intentionally skipped. - client = DataClient(server_url=TTD_DATA_SERVER_URL) + client = DataClient(ttd_auth=TTD_AUTH_TOKEN, server_url=TTD_DATA_SERVER_URL) capture = _register_capture(client) items = [ @@ -432,7 +425,6 @@ def verify_pii_not_in_request_no_uid2_config() -> None: try: response = client.advertiser.ingest_advertiser_data( advertiser_id=ADVERTISER_ID, - ttd_auth=TTD_AUTH_TOKEN, items=items, ) _print_response("TTD response", response, "advertiser_data_server_response") @@ -448,7 +440,7 @@ def verify_user_id_array_pii_not_in_request_no_uid2_config() -> None: (`mark_raw_pii_failures_without_uid2`) substitutes the UID2 sentinel `*` into each offending slot before serialization. """ - client = DataClient(server_url=TTD_DATA_SERVER_URL) + client = DataClient(ttd_auth=TTD_AUTH_TOKEN, server_url=TTD_DATA_SERVER_URL) capture = _register_capture(client) now = datetime.now(timezone.utc) @@ -472,7 +464,6 @@ def verify_user_id_array_pii_not_in_request_no_uid2_config() -> None: _print_items("Input items (no UID2 config, user_id_array)", items) try: response = client.offline_conversion.ingest_offline_conversion_data( - ttd_auth=TTD_AUTH_TOKEN, data_provider_id=DATA_PROVIDER_ID, items=items, user_id_array_metadata_format=["type", "id"], @@ -517,7 +508,6 @@ def verify_user_id_array_pii_not_in_request_with_uid2_config() -> None: _print_items("Input items (with UID2 config, user_id_array)", items) try: response = client.offline_conversion.ingest_offline_conversion_data( - ttd_auth=TTD_AUTH_TOKEN, data_provider_id=DATA_PROVIDER_ID, items=items, user_id_array_metadata_format=["type", "id"], @@ -544,7 +534,7 @@ def main() -> None: client_secret=UID2_CLIENT_SECRET, identity_scope=IdentityScope.UID2, ) - client = DataClient(config, server_url=TTD_DATA_SERVER_URL) + client = DataClient(config, ttd_auth=TTD_AUTH_TOKEN, server_url=TTD_DATA_SERVER_URL) # `_hooks` is a private attribute on the speakeasy SDK config; `register_before_request_hook` # appends to its hook list so all subsequent requests run through it. diff --git a/data-api-local/test_local.py b/data-api-local/test_local.py index d335a67..db22f7e 100755 --- a/data-api-local/test_local.py +++ b/data-api-local/test_local.py @@ -83,11 +83,11 @@ def test_sdk_initialization(): print_section("Test 1: SDK Initialization") try: - with DataClient(server_url=SERVER_URL) as client: - print_success("SDK initialized successfully") - print_info(f"Server URL: {SERVER_URL}") - print_info(f"SDK has advertiser attribute: {hasattr(client, 'advertiser')}") - return True + client = DataClient(server_url=SERVER_URL) + print_success("SDK initialized successfully") + print_info(f"Server URL: {SERVER_URL}") + print_info(f"SDK has advertiser attribute: {hasattr(client, 'advertiser')}") + return True except Exception as e: print_error(f"Failed to initialize SDK: {e}") return False @@ -107,36 +107,35 @@ def test_basic_data_ingestion(): return False try: - with DataClient(server_url=SERVER_URL) as client: - # Create a simple data item using sample TDID - data_item = models.AdvertiserDataItem( - tdid=SAMPLE_TDID, - data=[ - models.AdvertiserData( - name="test_segment_1", - ) - ] - ) - - print_info(f"Ingesting data for advertiser: {ADVERTISER_ID}") - print_info(f"Using TDID: {SAMPLE_TDID}") - - # Ingest the data - response = client.advertiser.ingest_advertiser_data( - advertiser_id=ADVERTISER_ID, - ttd_auth=TTD_AUTH_TOKEN, - items=[data_item] - ) - - print_success("Data ingestion completed") - server_response = response.advertiser_data_server_response - if server_response and server_response.failed_lines: - print_info(f"Failed lines: {server_response.failed_lines}") - else: - print_info("No failed lines") - - return True - + client = DataClient(ttd_auth=TTD_AUTH_TOKEN, server_url=SERVER_URL) + # Create a simple data item using sample TDID + data_item = models.AdvertiserDataItem( + tdid=SAMPLE_TDID, + data=[ + models.AdvertiserData( + name="test_segment_1", + ) + ] + ) + + print_info(f"Ingesting data for advertiser: {ADVERTISER_ID}") + print_info(f"Using TDID: {SAMPLE_TDID}") + + # Ingest the data + response = client.advertiser.ingest_advertiser_data( + advertiser_id=ADVERTISER_ID, + items=[data_item] + ) + + print_success("Data ingestion completed") + server_response = response.advertiser_data_server_response + if server_response and server_response.failed_lines: + print_info(f"Failed lines: {server_response.failed_lines}") + else: + print_info("No failed lines") + + return True + except errors.AdvertiserDataServerResponseError as e: print_error(f"Server returned error: {e.message}") print_error(f"Status code: {e.status_code}") @@ -169,54 +168,53 @@ def test_advanced_data_ingestion(): return False try: - with DataClient(server_url=SERVER_URL) as client: - # Create a comprehensive data item with all fields using sample DAID - data_item = models.AdvertiserDataItem( - daid=SAMPLE_DAID, - data=[ - models.AdvertiserData( - name="premium_segment", - base_bid_cpm=5.50, - base_bid_cpm_metadata="High-value audience", - bid_factor=1.2, - timestamp_utc=datetime.now(timezone.utc), - ttl_in_minutes=10080, # 7 days - ), - models.AdvertiserData( - name="standard_segment", - base_bid_cpm=2.00, - bid_factor=1.0, - ttl_in_minutes=1440, # 1 day - ) - ] - ) - - print_info(f"Ingesting advanced data for advertiser: {ADVERTISER_ID}") - print_info(f"Using DAID: {SAMPLE_DAID}") - print_info(f"Number of segments: {len(data_item.data)}") - - # Ingest with data provider ID if available - kwargs = { - "advertiser_id": ADVERTISER_ID, - "ttd_auth": TTD_AUTH_TOKEN, - "items": [data_item] - } - - if DATA_PROVIDER_ID: - kwargs["data_provider_id"] = DATA_PROVIDER_ID - print_info(f"Using data provider ID: {DATA_PROVIDER_ID}") - - response = client.advertiser.ingest_advertiser_data(**kwargs) - - print_success("Advanced data ingestion completed") - server_response = response.advertiser_data_server_response - if server_response and server_response.failed_lines: - print_info(f"Failed lines: {server_response.failed_lines}") - else: - print_info("No failed lines") - - return True - + client = DataClient(ttd_auth=TTD_AUTH_TOKEN, server_url=SERVER_URL) + # Create a comprehensive data item with all fields using sample DAID + data_item = models.AdvertiserDataItem( + daid=SAMPLE_DAID, + data=[ + models.AdvertiserData( + name="premium_segment", + base_bid_cpm=5.50, + base_bid_cpm_metadata="High-value audience", + bid_factor=1.2, + timestamp_utc=datetime.now(timezone.utc), + ttl_in_minutes=10080, # 7 days + ), + models.AdvertiserData( + name="standard_segment", + base_bid_cpm=2.00, + bid_factor=1.0, + ttl_in_minutes=1440, # 1 day + ) + ] + ) + + print_info(f"Ingesting advanced data for advertiser: {ADVERTISER_ID}") + print_info(f"Using DAID: {SAMPLE_DAID}") + print_info(f"Number of segments: {len(data_item.data)}") + + # Ingest with data provider ID if available + kwargs = { + "advertiser_id": ADVERTISER_ID, + "items": [data_item] + } + + if DATA_PROVIDER_ID: + kwargs["data_provider_id"] = DATA_PROVIDER_ID + print_info(f"Using data provider ID: {DATA_PROVIDER_ID}") + + response = client.advertiser.ingest_advertiser_data(**kwargs) + + print_success("Advanced data ingestion completed") + server_response = response.advertiser_data_server_response + if server_response and server_response.failed_lines: + print_info(f"Failed lines: {server_response.failed_lines}") + else: + print_info("No failed lines") + + return True + except errors.APIError as e: # Check status code directly if hasattr(e, 'status_code') and e.status_code == 200: @@ -251,48 +249,47 @@ def test_multiple_user_ids(): return False try: - with DataClient(server_url=SERVER_URL) as client: - # Test with different ID types using sample IDs - test_items = [ - models.AdvertiserDataItem( - tdid=SAMPLE_TDID, - data=[models.AdvertiserData(name="tdid_segment")] - ), - models.AdvertiserDataItem( - daid=SAMPLE_DAID, - data=[models.AdvertiserData(name="daid_segment")] - ), - models.AdvertiserDataItem( - euid=SAMPLE_EUID, - data=[models.AdvertiserData(name="euid_segment")] - ), - models.AdvertiserDataItem( - ramp_id=SAMPLE_RAMP_ID, - data=[models.AdvertiserData(name="ramp_segment")] - ) - ] - - print_info(f"Testing {len(test_items)} different ID types") - print_info(f" - TDID: {SAMPLE_TDID}") - print_info(f" - DAID: {SAMPLE_DAID}") - print_info(f" - EUID: {SAMPLE_EUID[:20]}...") - print_info(f" - RampID: {SAMPLE_RAMP_ID[:20]}...") - - response = client.advertiser.ingest_advertiser_data( - advertiser_id=ADVERTISER_ID, - ttd_auth=TTD_AUTH_TOKEN, - items=test_items + client = DataClient(ttd_auth=TTD_AUTH_TOKEN, server_url=SERVER_URL) + # Test with different ID types using sample IDs + test_items = [ + models.AdvertiserDataItem( + tdid=SAMPLE_TDID, + data=[models.AdvertiserData(name="tdid_segment")] + ), + models.AdvertiserDataItem( + daid=SAMPLE_DAID, + data=[models.AdvertiserData(name="daid_segment")] + ), + models.AdvertiserDataItem( + euid=SAMPLE_EUID, + data=[models.AdvertiserData(name="euid_segment")] + ), + models.AdvertiserDataItem( + ramp_id=SAMPLE_RAMP_ID, + data=[models.AdvertiserData(name="ramp_segment")] ) - - print_success("Multiple ID types ingestion completed") - server_response = response.advertiser_data_server_response - if server_response and server_response.failed_lines: - print_info(f"Failed lines: {server_response.failed_lines}") - else: - print_info("No failed lines") - - return True - + ] + + print_info(f"Testing {len(test_items)} different ID types") + print_info(f" - TDID: {SAMPLE_TDID}") + print_info(f" - DAID: {SAMPLE_DAID}") + print_info(f" - EUID: {SAMPLE_EUID[:20]}...") + print_info(f" - RampID: {SAMPLE_RAMP_ID[:20]}...") + + response = client.advertiser.ingest_advertiser_data( + advertiser_id=ADVERTISER_ID, + items=test_items + ) + + print_success("Multiple ID types ingestion completed") + server_response = response.advertiser_data_server_response + if server_response and server_response.failed_lines: + print_info(f"Failed lines: {server_response.failed_lines}") + else: + print_info("No failed lines") + + return True + except errors.APIError as e: # Check if we got a 200 status - if so, treat as success if hasattr(e, 'status_code') and e.status_code == 200: @@ -315,37 +312,36 @@ def test_error_handling(): print_section("Test 5: Error Handling") try: - with DataClient(server_url=SERVER_URL) as client: - # Try to ingest without authentication (should fail) - print_info("Testing error handling with missing authentication...") + client = DataClient(ttd_auth="", server_url=SERVER_URL) + # Try to ingest without authentication (should fail) + print_info("Testing error handling with missing authentication...") + + try: + response = client.advertiser.ingest_advertiser_data( + advertiser_id=ADVERTISER_ID, + items=[ + models.AdvertiserDataItem( + tdid="test", + data=[models.AdvertiserData(name="test")] + ) + ] + ) + print_error("Expected authentication error but succeeded") + return False - try: - response = client.advertiser.ingest_advertiser_data( - advertiser_id=ADVERTISER_ID, - ttd_auth="", - items=[ - models.AdvertiserDataItem( - tdid="test", - data=[models.AdvertiserData(name="test")] - ) - ] - ) - print_error("Expected authentication error but succeeded") - return False - - except errors.DataError as e: - print_success(f"Correctly caught TTD API error: {e.message}") - print_info(f"Status code: {e.status_code}") + except errors.DataError as e: + print_success(f"Correctly caught TTD API error: {e.message}") + print_info(f"Status code: {e.status_code}") + return True + except OSError as e: + # Network/DNS errors are expected with dummy URLs + if "nodename nor servname provided" in str(e) or "Name or service not known" in str(e): + print_success(f"Correctly caught network error (expected with placeholder URL)") + print_info(f"Error: {e}") + print_info("This is normal when using a placeholder SERVER_URL") return True - except OSError as e: - # Network/DNS errors are expected with dummy URLs - if "nodename nor servname provided" in str(e) or "Name or service not known" in str(e): - print_success(f"Correctly caught network error (expected with placeholder URL)") - print_info(f"Error: {e}") - print_info("This is normal when using a placeholder SERVER_URL") - return True - raise - + raise + except Exception as e: print_error(f"Unexpected error: {e}") return False @@ -372,15 +368,15 @@ def test_retry_configuration(): retry_connection_errors=True ) - with DataClient( + client = DataClient( server_url=SERVER_URL, retry_config=retry_config - ) as client: - print_success("SDK initialized with custom retry configuration") - print_info("Retry strategy: backoff with exponential increase") - print_info("Max elapsed time: 30 seconds") - return True - + ) + print_success("SDK initialized with custom retry configuration") + print_info("Retry strategy: backoff with exponential increase") + print_info("Max elapsed time: 30 seconds") + return True + except Exception as e: print_error(f"Error setting retry config: {e}") return False @@ -401,29 +397,28 @@ async def test_async_operations(): try: import asyncio - async with DataClient(server_url=SERVER_URL) as client: - data_item = models.AdvertiserDataItem( - tdid=SAMPLE_TDID, - data=[models.AdvertiserData(name="async_segment")] - ) - - print_info("Testing async data ingestion...") - print_info(f"Using TDID: {SAMPLE_TDID}") - - response = await client.advertiser.ingest_advertiser_data_async( - advertiser_id=ADVERTISER_ID, - ttd_auth=TTD_AUTH_TOKEN, - items=[data_item] - ) - - print_success("Async data ingestion completed") - server_response = response.advertiser_data_server_response - if server_response and server_response.failed_lines: - print_info(f"Failed lines: {server_response.failed_lines}") - else: - print_info("No failed lines") - return True - + client = DataClient(ttd_auth=TTD_AUTH_TOKEN, server_url=SERVER_URL) + data_item = models.AdvertiserDataItem( + tdid=SAMPLE_TDID, + data=[models.AdvertiserData(name="async_segment")] + ) + + print_info("Testing async data ingestion...") + print_info(f"Using TDID: {SAMPLE_TDID}") + + response = await client.advertiser.ingest_advertiser_data_async( + advertiser_id=ADVERTISER_ID, + items=[data_item] + ) + + print_success("Async data ingestion completed") + server_response = response.advertiser_data_server_response + if server_response and server_response.failed_lines: + print_info(f"Failed lines: {server_response.failed_lines}") + else: + print_info("No failed lines") + return True + except ImportError: print_error("asyncio not available") return False @@ -509,18 +504,17 @@ def handle_request(self, request): try: http_client = _httpx.Client(transport=CapturingTransport()) - with DataClient(server_url=SERVER_URL, client=http_client) as client: - client.advertiser.ingest_advertiser_data( - advertiser_id=ADVERTISER_ID, - ttd_auth=TTD_AUTH_TOKEN or "test", - items=[ - models.AdvertiserDataItem( - tdid=SAMPLE_TDID, - data=[models.AdvertiserData(name="hook_test_segment")], - ) - ], - # NOTE: data_origins intentionally omitted — the hook should inject ttd_data_sdk. - ) + client = DataClient(ttd_auth=TTD_AUTH_TOKEN or "test", server_url=SERVER_URL, client=http_client) + client.advertiser.ingest_advertiser_data( + advertiser_id=ADVERTISER_ID, + items=[ + models.AdvertiserDataItem( + tdid=SAMPLE_TDID, + data=[models.AdvertiserData(name="hook_test_segment")], + ) + ], + # NOTE: data_origins intentionally omitted — the hook should inject ttd_data_sdk. + ) # Inspect what the hook wrote into the request body. data_origin_list = captured.get("body", {}).get("DataOrigins", []) @@ -564,22 +558,21 @@ def handle_request(self, request): try: http_client = _httpx.Client(transport=CapturingTransport()) - with DataClient(server_url=SERVER_URL, client=http_client) as client: - client.advertiser.ingest_advertiser_data( - advertiser_id=ADVERTISER_ID, - ttd_auth=TTD_AUTH_TOKEN or "test", - items=[ - models.AdvertiserDataItem( - tdid=SAMPLE_TDID, - data=[models.AdvertiserData(name="hook_test_segment")], - ) - ], - # Simulates ttd-databricks-sdk passing its own origin — - # the hook should append ttd_data_sdk without removing this. - data_origins=[ - models.DataOrigin(id="ttd_databricks_sdk", type=models.DataOriginType.INTEGRATION) - ], - ) + client = DataClient(ttd_auth=TTD_AUTH_TOKEN or "test", server_url=SERVER_URL, client=http_client) + client.advertiser.ingest_advertiser_data( + advertiser_id=ADVERTISER_ID, + items=[ + models.AdvertiserDataItem( + tdid=SAMPLE_TDID, + data=[models.AdvertiserData(name="hook_test_segment")], + ) + ], + # Simulates ttd-databricks-sdk passing its own origin — + # the hook should append ttd_data_sdk without removing this. + data_origins=[ + models.DataOrigin(id="ttd_databricks_sdk", type=models.DataOriginType.INTEGRATION) + ], + ) # Inspect what the hook produced — both origins should be present. data_origin_list = captured.get("body", {}).get("DataOrigins", []) @@ -622,32 +615,31 @@ def test_data_origins_advertiser(): return False try: - with DataClient(server_url=SERVER_URL) as client: - data_origin = models.DataOrigin( - id="test_ttd_data", - type=models.DataOriginType.INTEGRATION, - ) - print_info(f"DataOrigins: [{{Type: '{data_origin.type}', Id: '{data_origin.id}'}}]") + client = DataClient(ttd_auth=TTD_AUTH_TOKEN, server_url=SERVER_URL) + data_origin = models.DataOrigin( + id="test_ttd_data", + type=models.DataOriginType.INTEGRATION, + ) + print_info(f"DataOrigins: [{{Type: '{data_origin.type}', Id: '{data_origin.id}'}}]") - response = client.advertiser.ingest_advertiser_data( - advertiser_id=ADVERTISER_ID, - ttd_auth=TTD_AUTH_TOKEN, - items=[ - models.AdvertiserDataItem( - tdid=SAMPLE_TDID, - data=[models.AdvertiserData(name="data_origins_segment")] - ) - ], - data_origins=[data_origin], - ) + response = client.advertiser.ingest_advertiser_data( + advertiser_id=ADVERTISER_ID, + items=[ + models.AdvertiserDataItem( + tdid=SAMPLE_TDID, + data=[models.AdvertiserData(name="data_origins_segment")] + ) + ], + data_origins=[data_origin], + ) - print_success("Advertiser ingestion with DataOrigins completed") - server_response = response.advertiser_data_server_response - if server_response and server_response.failed_lines: - print_info(f"Failed lines: {server_response.failed_lines}") - else: - print_info("No failed lines") - return True + print_success("Advertiser ingestion with DataOrigins completed") + server_response = response.advertiser_data_server_response + if server_response and server_response.failed_lines: + print_info(f"Failed lines: {server_response.failed_lines}") + else: + print_info("No failed lines") + return True except errors.AdvertiserDataServerResponseError as e: print_error(f"Server returned error: {e.message}") @@ -674,32 +666,31 @@ def test_data_origins_thirdparty(): return False try: - with DataClient(server_url=SERVER_URL) as client: - data_origin = models.DataOrigin( - id="test_ttd_data", - type=models.DataOriginType.INTEGRATION, - ) - print_info(f"DataOrigins: [{{Type: '{data_origin.type}', Id: '{data_origin.id}'}}]") + client = DataClient(ttd_auth=TTD_AUTH_TOKEN, server_url=SERVER_URL) + data_origin = models.DataOrigin( + id="test_ttd_data", + type=models.DataOriginType.INTEGRATION, + ) + print_info(f"DataOrigins: [{{Type: '{data_origin.type}', Id: '{data_origin.id}'}}]") - response = client.third_party.ingest_third_party_data( - data_provider_id=DATA_PROVIDER_ID, - ttd_auth=TTD_AUTH_TOKEN, - items=[ - models.ThirdPartyDataItem( - tdid=SAMPLE_TDID, - data=[models.ThirdPartyData(name="data_origins_segment")] - ) - ], - data_origins=[data_origin], - ) + response = client.third_party.ingest_third_party_data( + data_provider_id=DATA_PROVIDER_ID, + items=[ + models.ThirdPartyDataItem( + tdid=SAMPLE_TDID, + data=[models.ThirdPartyData(name="data_origins_segment")] + ) + ], + data_origins=[data_origin], + ) - print_success("ThirdParty ingestion with DataOrigins completed") - server_response = response.third_party_data_server_response - if server_response and server_response.failed_lines: - print_info(f"Failed lines: {server_response.failed_lines}") - else: - print_info("No failed lines") - return True + print_success("ThirdParty ingestion with DataOrigins completed") + server_response = response.third_party_data_server_response + if server_response and server_response.failed_lines: + print_info(f"Failed lines: {server_response.failed_lines}") + else: + print_info("No failed lines") + return True except errors.APIError as e: print_error(f"API error: {str(e)}") @@ -722,33 +713,32 @@ def test_data_origins_offline_conversion(): return False try: - with DataClient(server_url=SERVER_URL) as client: - data_origin = models.DataOrigin( - id="test_ttd_data", - type=models.DataOriginType.INTEGRATION, - ) - print_info(f"DataOrigins: [{{Type: '{data_origin.type}', Id: '{data_origin.id}'}}]") - - response = client.offline_conversion.ingest_offline_conversion_data( - data_provider_id=DATA_PROVIDER_ID, - ttd_auth=TTD_AUTH_TOKEN, - items=[ - models.OfflineConversionDataItem( - tracking_tag_id=TRACKING_TAG_ID, - timestamp_utc=datetime.now(timezone.utc), - tdid=SAMPLE_TDID, - ) - ], - data_origins=[data_origin], - ) + client = DataClient(ttd_auth=TTD_AUTH_TOKEN, server_url=SERVER_URL) + data_origin = models.DataOrigin( + id="test_ttd_data", + type=models.DataOriginType.INTEGRATION, + ) + print_info(f"DataOrigins: [{{Type: '{data_origin.type}', Id: '{data_origin.id}'}}]") + + response = client.offline_conversion.ingest_offline_conversion_data( + data_provider_id=DATA_PROVIDER_ID, + items=[ + models.OfflineConversionDataItem( + tracking_tag_id=TRACKING_TAG_ID, + timestamp_utc=datetime.now(timezone.utc), + tdid=SAMPLE_TDID, + ) + ], + data_origins=[data_origin], + ) - print_success("Offline conversion ingestion with DataOrigins completed") - server_response = response.offline_conversion_data_server_response - if server_response and server_response.failed_lines: - print_info(f"Failed lines: {server_response.failed_lines}") - else: - print_info("No failed lines") - return True + print_success("Offline conversion ingestion with DataOrigins completed") + server_response = response.offline_conversion_data_server_response + if server_response and server_response.failed_lines: + print_info(f"Failed lines: {server_response.failed_lines}") + else: + print_info("No failed lines") + return True except errors.APIError as e: print_error(f"API error: {str(e)}") diff --git a/data-api-local/test_patch_hook.py b/data-api-local/test_patch_hook.py index b62b6fc..c551f78 100644 --- a/data-api-local/test_patch_hook.py +++ b/data-api-local/test_patch_hook.py @@ -101,12 +101,11 @@ def test_200_hook_does_not_affect_success_response(self): from ttd_data import DataClient from ttd_data.models import PartnerDsrDataItem - with DataClient() as client: - response = client.deletion_opt_out.data_subject_request_merchant_data( - merchant_id=MERCHANT_ID, - ttd_auth=TTD_AUTH_TOKEN, - items=[PartnerDsrDataItem(tdid=SAMPLE_TDID)], - ) + client = DataClient(ttd_auth=TTD_AUTH_TOKEN) + response = client.deletion_opt_out.data_subject_request_merchant_data( + merchant_id=MERCHANT_ID, + items=[PartnerDsrDataItem(tdid=SAMPLE_TDID)], + ) ct = response.http_meta.response.headers.get("content-type", "") self.assertIn("application/json", ct, f"Expected application/json content-type, got: {ct!r}") @@ -120,13 +119,12 @@ def test_plain_text_400_is_normalized_to_json(self): from ttd_data.errors import MerchantDsrResponseError from ttd_data.models import PartnerDsrDataItem - with DataClient() as client: - with self.assertRaises(MerchantDsrResponseError) as ctx: - client.deletion_opt_out.data_subject_request_merchant_data( - merchant_id=0, - ttd_auth=TTD_AUTH_TOKEN, - items=[PartnerDsrDataItem(tdid=SAMPLE_TDID)], - ) + client = DataClient(ttd_auth=TTD_AUTH_TOKEN) + with self.assertRaises(MerchantDsrResponseError) as ctx: + client.deletion_opt_out.data_subject_request_merchant_data( + merchant_id=0, + items=[PartnerDsrDataItem(tdid=SAMPLE_TDID)], + ) error = ctx.exception ct = error.raw_response.headers.get("content-type", "") diff --git a/docs/models/advertiserdataresponseerrorcode.md b/docs/models/advertiserdataresponseerrorcode.md index 4535616..28d70f2 100644 --- a/docs/models/advertiserdataresponseerrorcode.md +++ b/docs/models/advertiserdataresponseerrorcode.md @@ -29,4 +29,5 @@ value = AdvertiserDataResponseErrorCode.UNKNOWN | `TENANT_RESTRICTIONS_EXTERNAL_DATA` | TenantRestrictionsExternalData | | `TARGETING_DATA_DISABLED` | TargetingDataDisabled | | `ITEM_DESERIALIZATION_ERROR` | ItemDeserializationError | +| `INVALID_TIMESTAMP_UTC` | InvalidTimestampUtc | | `UID2_ERROR` | Uid2Error | \ No newline at end of file diff --git a/docs/models/datasubjectrequestadvertiserdatarequest.md b/docs/models/datasubjectrequestadvertiserdatarequest.md deleted file mode 100644 index 0d3c533..0000000 --- a/docs/models/datasubjectrequestadvertiserdatarequest.md +++ /dev/null @@ -1,9 +0,0 @@ -# DataSubjectRequestAdvertiserDataRequest - - -## Fields - -| Field | Type | Required | Description | -| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | -| `body` | [models.AdvertiserDsrRequest](../models/advertiserdsrrequest.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/docs/models/datasubjectrequestmerchantdatarequest.md b/docs/models/datasubjectrequestmerchantdatarequest.md deleted file mode 100644 index 163dca6..0000000 --- a/docs/models/datasubjectrequestmerchantdatarequest.md +++ /dev/null @@ -1,9 +0,0 @@ -# DataSubjectRequestMerchantDataRequest - - -## Fields - -| Field | Type | Required | Description | -| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | -| `body` | [models.MerchantDsrRequest](../models/merchantdsrrequest.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/docs/models/datasubjectrequestthirdpartydatarequest.md b/docs/models/datasubjectrequestthirdpartydatarequest.md deleted file mode 100644 index bb62758..0000000 --- a/docs/models/datasubjectrequestthirdpartydatarequest.md +++ /dev/null @@ -1,9 +0,0 @@ -# DataSubjectRequestThirdPartyDataRequest - - -## Fields - -| Field | Type | Required | Description | -| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | -| `body` | [models.ThirdPartyDsrRequest](../models/thirdpartydsrrequest.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/docs/models/ingestadvertiserdatarequest.md b/docs/models/ingestadvertiserdatarequest.md deleted file mode 100644 index b9c4e5e..0000000 --- a/docs/models/ingestadvertiserdatarequest.md +++ /dev/null @@ -1,9 +0,0 @@ -# IngestAdvertiserDataRequest - - -## Fields - -| Field | Type | Required | Description | -| ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | -| `body` | [models.AdvertiserDataRequest](../models/advertiserdatarequest.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/docs/models/ingestfirstpartyipaddressdatarequest.md b/docs/models/ingestfirstpartyipaddressdatarequest.md deleted file mode 100644 index c50a277..0000000 --- a/docs/models/ingestfirstpartyipaddressdatarequest.md +++ /dev/null @@ -1,9 +0,0 @@ -# IngestFirstPartyIPAddressDataRequest - - -## Fields - -| Field | Type | Required | Description | -| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | -| `body` | [models.IPAddressDataRequest](../models/ipaddressdatarequest.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/docs/models/ingestofflineconversiondatarequest.md b/docs/models/ingestofflineconversiondatarequest.md deleted file mode 100644 index 7422be4..0000000 --- a/docs/models/ingestofflineconversiondatarequest.md +++ /dev/null @@ -1,9 +0,0 @@ -# IngestOfflineConversionDataRequest - - -## Fields - -| Field | Type | Required | Description | -| -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | -| `body` | [models.OfflineConversionDataRequest](../models/offlineconversiondatarequest.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/docs/models/ingestthirdpartydatarequest.md b/docs/models/ingestthirdpartydatarequest.md deleted file mode 100644 index 4564502..0000000 --- a/docs/models/ingestthirdpartydatarequest.md +++ /dev/null @@ -1,9 +0,0 @@ -# IngestThirdPartyDataRequest - - -## Fields - -| Field | Type | Required | Description | -| ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | -| `body` | [models.ThirdPartyDataRequest](../models/thirdpartydatarequest.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/docs/models/ingestthirdpartyipaddressdatarequest.md b/docs/models/ingestthirdpartyipaddressdatarequest.md deleted file mode 100644 index da22760..0000000 --- a/docs/models/ingestthirdpartyipaddressdatarequest.md +++ /dev/null @@ -1,9 +0,0 @@ -# IngestThirdPartyIPAddressDataRequest - - -## Fields - -| Field | Type | Required | Description | -| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | -| `body` | [models.IPAddressDataRequest](../models/ipaddressdatarequest.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/docs/models/ipaddressdataresponseerrorcode.md b/docs/models/ipaddressdataresponseerrorcode.md index 8de926b..0d9d3de 100644 --- a/docs/models/ipaddressdataresponseerrorcode.md +++ b/docs/models/ipaddressdataresponseerrorcode.md @@ -19,4 +19,5 @@ value = IPAddressDataResponseErrorCode.UNKNOWN | `INVALID_IP_ADDRESS` | InvalidIPAddress | | `INVALID_IP_ADDRESS_RANGE` | InvalidIPAddressRange | | `EU_IP_TARGETING_NOT_ALLOWED_FOR_PARTNER` | EuIpTargetingNotAllowedForPartner | -| `NOT_TARGETABLE` | NotTargetable | \ No newline at end of file +| `NOT_TARGETABLE` | NotTargetable | +| `INVALID_TIMESTAMP_UTC` | InvalidTimestampUtc | \ No newline at end of file diff --git a/docs/models/security.md b/docs/models/security.md new file mode 100644 index 0000000..3201615 --- /dev/null +++ b/docs/models/security.md @@ -0,0 +1,8 @@ +# Security + + +## Fields + +| Field | Type | Required | Description | +| ------------------ | ------------------ | ------------------ | ------------------ | +| `ttd_auth` | *Optional[str]* | :heavy_minus_sign: | N/A | \ No newline at end of file diff --git a/docs/models/thirdpartydataresponseerrorcode.md b/docs/models/thirdpartydataresponseerrorcode.md index 73e9a79..ee4977b 100644 --- a/docs/models/thirdpartydataresponseerrorcode.md +++ b/docs/models/thirdpartydataresponseerrorcode.md @@ -26,4 +26,5 @@ value = ThirdPartyDataResponseErrorCode.UNKNOWN | `TENANT_RESTRICTIONS_EXTERNAL_DATA` | TenantRestrictionsExternalData | | `TARGETING_DATA_DISABLED` | TargetingDataDisabled | | `ITEM_DESERIALIZATION_ERROR` | ItemDeserializationError | +| `INVALID_TIMESTAMP_UTC` | InvalidTimestampUtc | | `UID2_ERROR` | Uid2Error | \ No newline at end of file diff --git a/docs/sdks/advertiser/README.md b/docs/sdks/advertiser/README.md index d5cc8e4..f5d6cef 100644 --- a/docs/sdks/advertiser/README.md +++ b/docs/sdks/advertiser/README.md @@ -14,17 +14,17 @@ Upload first-party data for the specified ID for use in audience targeting. ```python -from ttd_data import BaseDataClient +from ttd_data import DataClient -with BaseDataClient() as base_data_client: +client = DataClient(ttd_auth="") - res = base_data_client.advertiser.ingest_advertiser_data(ttd_auth="", advertiser_id="") +res = client.advertiser.ingest_advertiser_data(advertiser_id="") - assert res.advertiser_data_server_response is not None +assert res.advertiser_data_server_response is not None - # Handle response - print(res.advertiser_data_server_response) +# Handle response +print(res.advertiser_data_server_response) ``` @@ -32,7 +32,6 @@ with BaseDataClient() as base_data_client: | Parameter | Type | Required | Description | | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | | `advertiser_id` | *str* | :heavy_check_mark: | N/A | | `data_provider_id` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | | `items` | List[[models.BaseAdvertiserDataItem](../../models/baseadvertiserdataitem.md)] | :heavy_minus_sign: | N/A | diff --git a/docs/sdks/deletionoptout/README.md b/docs/sdks/deletionoptout/README.md index 6d6d74e..97a46f7 100644 --- a/docs/sdks/deletionoptout/README.md +++ b/docs/sdks/deletionoptout/README.md @@ -16,17 +16,17 @@ Delete IDs shared with The Trade Desk for the specified advertiser ID. ```python -from ttd_data import BaseDataClient +from ttd_data import DataClient -with BaseDataClient() as base_data_client: +client = DataClient(ttd_auth="") - res = base_data_client.deletion_opt_out.data_subject_request_advertiser_data(ttd_auth="") +res = client.deletion_opt_out.data_subject_request_advertiser_data() - assert res.advertiser_dsr_response is not None +assert res.advertiser_dsr_response is not None - # Handle response - print(res.advertiser_dsr_response) +# Handle response +print(res.advertiser_dsr_response) ``` @@ -34,7 +34,6 @@ with BaseDataClient() as base_data_client: | Parameter | Type | Required | Description | | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | | `advertiser_id` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | | `data_provider_id` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | | `items` | List[[models.BasePartnerDsrDataItem](../../models/basepartnerdsrdataitem.md)] | :heavy_minus_sign: | N/A | @@ -62,17 +61,17 @@ Delete IDs shared with The Trade Desk via a product catalog for the specified me ```python -from ttd_data import BaseDataClient +from ttd_data import DataClient -with BaseDataClient() as base_data_client: +client = DataClient(ttd_auth="") - res = base_data_client.deletion_opt_out.data_subject_request_merchant_data(ttd_auth="") +res = client.deletion_opt_out.data_subject_request_merchant_data() - assert res.merchant_dsr_response is not None +assert res.merchant_dsr_response is not None - # Handle response - print(res.merchant_dsr_response) +# Handle response +print(res.merchant_dsr_response) ``` @@ -80,7 +79,6 @@ with BaseDataClient() as base_data_client: | Parameter | Type | Required | Description | | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | | `merchant_id` | *OptionalNullable[int]* | :heavy_minus_sign: | N/A | | `items` | List[[models.BasePartnerDsrDataItem](../../models/basepartnerdsrdataitem.md)] | :heavy_minus_sign: | N/A | | `data_load_trace_id` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | @@ -107,17 +105,17 @@ Delete IDs shared with The Trade Desk for the specified data provider ID. ```python -from ttd_data import BaseDataClient +from ttd_data import DataClient -with BaseDataClient() as base_data_client: +client = DataClient(ttd_auth="") - res = base_data_client.deletion_opt_out.data_subject_request_third_party_data(ttd_auth="") +res = client.deletion_opt_out.data_subject_request_third_party_data() - assert res.third_party_dsr_response is not None +assert res.third_party_dsr_response is not None - # Handle response - print(res.third_party_dsr_response) +# Handle response +print(res.third_party_dsr_response) ``` @@ -125,7 +123,6 @@ with BaseDataClient() as base_data_client: | Parameter | Type | Required | Description | | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | | `data_provider_id` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | | `brand_id` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | | `items` | List[[models.BasePartnerDsrDataItem](../../models/basepartnerdsrdataitem.md)] | :heavy_minus_sign: | N/A | diff --git a/docs/sdks/offlineconversion/README.md b/docs/sdks/offlineconversion/README.md index 1ba0e98..d827e50 100644 --- a/docs/sdks/offlineconversion/README.md +++ b/docs/sdks/offlineconversion/README.md @@ -14,17 +14,17 @@ Upload offline conversion data for the specified data provider. ```python -from ttd_data import BaseDataClient +from ttd_data import DataClient -with BaseDataClient() as base_data_client: +client = DataClient(ttd_auth="") - res = base_data_client.offline_conversion.ingest_offline_conversion_data(ttd_auth="", data_provider_id="") +res = client.offline_conversion.ingest_offline_conversion_data(data_provider_id="") - assert res.offline_conversion_data_server_response is not None +assert res.offline_conversion_data_server_response is not None - # Handle response - print(res.offline_conversion_data_server_response) +# Handle response +print(res.offline_conversion_data_server_response) ``` @@ -32,7 +32,6 @@ with BaseDataClient() as base_data_client: | Parameter | Type | Required | Description | | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | | `data_provider_id` | *str* | :heavy_check_mark: | N/A | | `user_id_array_metadata_format` | List[*str*] | :heavy_minus_sign: | N/A | | `items` | List[[models.BaseOfflineConversionDataItem](../../models/baseofflineconversiondataitem.md)] | :heavy_minus_sign: | N/A | diff --git a/docs/sdks/thirdparty/README.md b/docs/sdks/thirdparty/README.md index 040b31d..d3c4662 100644 --- a/docs/sdks/thirdparty/README.md +++ b/docs/sdks/thirdparty/README.md @@ -14,17 +14,17 @@ Upload third-party data for the specified data provider for use in audience targ ```python -from ttd_data import BaseDataClient +from ttd_data import DataClient -with BaseDataClient() as base_data_client: +client = DataClient(ttd_auth="") - res = base_data_client.third_party.ingest_third_party_data(ttd_auth="", data_provider_id="", is_user_id_already_hashed=False) +res = client.third_party.ingest_third_party_data(data_provider_id="", is_user_id_already_hashed=False) - assert res.third_party_data_server_response is not None +assert res.third_party_data_server_response is not None - # Handle response - print(res.third_party_data_server_response) +# Handle response +print(res.third_party_data_server_response) ``` @@ -32,7 +32,6 @@ with BaseDataClient() as base_data_client: | Parameter | Type | Required | Description | | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -| `ttd_auth` | *str* | :heavy_check_mark: | Data API token for authentication. | | `data_provider_id` | *str* | :heavy_check_mark: | N/A | | `items` | List[[models.BaseThirdPartyDataItem](../../models/basethirdpartydataitem.md)] | :heavy_minus_sign: | N/A | | `data_load_trace_id` | *OptionalNullable[str]* | :heavy_minus_sign: | N/A | diff --git a/pyproject.toml b/pyproject.toml index 8e50611..a9cda61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "ttd-data" -version = "0.2.7" +version = "0.3.0" description = "Python Client SDK for TTD Data API." authors = [{ name = "Speakeasy" },] readme = "README-PYPI.md" diff --git a/src/ttd_data/_version.py b/src/ttd_data/_version.py index dfefd69..6fdb95a 100644 --- a/src/ttd_data/_version.py +++ b/src/ttd_data/_version.py @@ -4,10 +4,10 @@ import importlib.metadata __title__: str = "ttd-data" -__version__: str = "0.2.7" +__version__: str = "0.3.0" __openapi_doc_version__: str = "v0.1" __gen_version__: str = "2.930.0" -__user_agent__: str = "speakeasy-sdk/python 0.2.7 2.930.0 v0.1 ttd-data" +__user_agent__: str = "speakeasy-sdk/python 0.3.0 2.930.0 v0.1 ttd-data" try: if __package__ is not None: diff --git a/src/ttd_data/advertiser.py b/src/ttd_data/advertiser.py index fb0f6dd..b82a98b 100644 --- a/src/ttd_data/advertiser.py +++ b/src/ttd_data/advertiser.py @@ -5,6 +5,7 @@ from ttd_data import errors, models, utils from ttd_data._hooks import HookContext from ttd_data.types import OptionalNullable, UNSET +from ttd_data.utils import get_security_from_env from ttd_data.utils.unmarshal_json_response import unmarshal_json_response from typing import Any, Iterable, List, Mapping, Optional, Union @@ -13,7 +14,6 @@ class Advertiser(BaseSDK): def ingest_advertiser_data( self, *, - ttd_auth: str, advertiser_id: str, data_provider_id: OptionalNullable[str] = UNSET, items: OptionalNullable[ @@ -33,7 +33,6 @@ def ingest_advertiser_data( ) -> models.IngestAdvertiserDataResponse: r"""Upload first-party data for the specified ID for use in audience targeting. - :param ttd_auth: Data API token for authentication. :param advertiser_id: :param data_provider_id: :param items: @@ -54,18 +53,15 @@ def ingest_advertiser_data( else: base_url = models.INGEST_ADVERTISER_DATA_OP_SERVERS[0] - request = models.IngestAdvertiserDataRequest( - ttd_auth=ttd_auth, - body=models.AdvertiserDataRequest( - advertiser_id=advertiser_id, - data_provider_id=data_provider_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BaseAdvertiserDataItem]] - ), - data_load_trace_id=data_load_trace_id, - data_origins=utils.get_pydantic_model( - data_origins, OptionalNullable[List[models.DataOrigin]] - ), + request = models.AdvertiserDataRequest( + advertiser_id=advertiser_id, + data_provider_id=data_provider_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BaseAdvertiserDataItem]] + ), + data_load_trace_id=data_load_trace_id, + data_origins=utils.get_pydantic_model( + data_origins, OptionalNullable[List[models.DataOrigin]] ), ) @@ -77,12 +73,13 @@ def ingest_advertiser_data( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.AdvertiserDataRequest + request, False, False, "json", models.AdvertiserDataRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -102,7 +99,9 @@ def ingest_advertiser_data( base_url=base_url or "", operation_id="IngestAdvertiserData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["Advertiser"], extensions=None, ), @@ -139,7 +138,6 @@ def ingest_advertiser_data( async def ingest_advertiser_data_async( self, *, - ttd_auth: str, advertiser_id: str, data_provider_id: OptionalNullable[str] = UNSET, items: OptionalNullable[ @@ -159,7 +157,6 @@ async def ingest_advertiser_data_async( ) -> models.IngestAdvertiserDataResponse: r"""Upload first-party data for the specified ID for use in audience targeting. - :param ttd_auth: Data API token for authentication. :param advertiser_id: :param data_provider_id: :param items: @@ -180,18 +177,15 @@ async def ingest_advertiser_data_async( else: base_url = models.INGEST_ADVERTISER_DATA_OP_SERVERS[0] - request = models.IngestAdvertiserDataRequest( - ttd_auth=ttd_auth, - body=models.AdvertiserDataRequest( - advertiser_id=advertiser_id, - data_provider_id=data_provider_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BaseAdvertiserDataItem]] - ), - data_load_trace_id=data_load_trace_id, - data_origins=utils.get_pydantic_model( - data_origins, OptionalNullable[List[models.DataOrigin]] - ), + request = models.AdvertiserDataRequest( + advertiser_id=advertiser_id, + data_provider_id=data_provider_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BaseAdvertiserDataItem]] + ), + data_load_trace_id=data_load_trace_id, + data_origins=utils.get_pydantic_model( + data_origins, OptionalNullable[List[models.DataOrigin]] ), ) @@ -203,12 +197,13 @@ async def ingest_advertiser_data_async( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.AdvertiserDataRequest + request, False, False, "json", models.AdvertiserDataRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -228,7 +223,9 @@ async def ingest_advertiser_data_async( base_url=base_url or "", operation_id="IngestAdvertiserData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["Advertiser"], extensions=None, ), diff --git a/src/ttd_data/basesdk.py b/src/ttd_data/basesdk.py index b3e7ee7..3d9137b 100644 --- a/src/ttd_data/basesdk.py +++ b/src/ttd_data/basesdk.py @@ -3,7 +3,7 @@ from .sdkconfiguration import SDKConfiguration import httpx -from ttd_data import errors, utils +from ttd_data import errors, models, utils from ttd_data._hooks import ( AfterErrorContext, AfterSuccessContext, @@ -193,7 +193,7 @@ def _build_request_with_client( if security is not None: if callable(security): security = security() - + security = utils.get_security_from_env(security, models.Security) if security is not None: security_headers, security_query_params = utils.get_security( security, allowed_fields diff --git a/src/ttd_data/client.py b/src/ttd_data/client.py index 0368110..b55f6ab 100644 --- a/src/ttd_data/client.py +++ b/src/ttd_data/client.py @@ -8,7 +8,7 @@ import asyncio from dataclasses import dataclass, fields from functools import cached_property -from typing import Any, Dict, Iterable, List, Optional, Tuple, Type +from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Type, Union from uid2_client import IdentityMapV3Client, IdentityMapV3Input # type: ignore[import-not-found,import-untyped] @@ -25,6 +25,7 @@ BaseOfflineConversionDataItem, ) from ttd_data.models.dsrerrorcode import DsrErrorCode +from ttd_data.models.security import Security from ttd_data.models.offlineconversiondataresponseerrorcode import ( OfflineConversionDataResponseErrorCode, ) @@ -53,11 +54,31 @@ ) +TtdAuth = Optional[Union[str, Callable[[], Optional[str]]]] + + +def _ttd_auth_from_security( + security: Optional[Union[Security, Callable[[], Security]]], +) -> TtdAuth: + """Recover the credential a `BaseDataClient` was built with. + + A callable credential is rewrapped rather than called, so reading `config` + never triggers a token refresh and `from_config` preserves the refresh + behaviour instead of freezing one token. + """ + if security is None: + return None + if callable(security): + return lambda: security().ttd_auth + return security.ttd_auth + + @dataclass(frozen=True) class ClientConfig: server_url: Optional[str] retry_config: OptionalNullable[RetryConfig] timeout_ms: Optional[int] + ttd_auth: TtdAuth uid2_config: Optional[UID2Config] @@ -90,6 +111,7 @@ def config(self) -> ClientConfig: server_url=sdk_config.server_url, retry_config=sdk_config.retry_config, timeout_ms=sdk_config.timeout_ms, + ttd_auth=_ttd_auth_from_security(sdk_config.security), uid2_config=self.uid2_config, ) diff --git a/src/ttd_data/deletionoptout.py b/src/ttd_data/deletionoptout.py index fab3b7c..2d07582 100644 --- a/src/ttd_data/deletionoptout.py +++ b/src/ttd_data/deletionoptout.py @@ -5,6 +5,7 @@ from ttd_data import errors, models, utils from ttd_data._hooks import HookContext from ttd_data.types import OptionalNullable, UNSET +from ttd_data.utils import get_security_from_env from ttd_data.utils.unmarshal_json_response import unmarshal_json_response from typing import Any, Iterable, List, Mapping, Optional, Union @@ -13,7 +14,6 @@ class DeletionOptOut(BaseSDK): def data_subject_request_advertiser_data( self, *, - ttd_auth: str, advertiser_id: OptionalNullable[str] = UNSET, data_provider_id: OptionalNullable[str] = UNSET, items: OptionalNullable[ @@ -31,7 +31,6 @@ def data_subject_request_advertiser_data( ) -> models.DataSubjectRequestAdvertiserDataResponse: r"""Delete IDs shared with The Trade Desk for the specified advertiser ID. - :param ttd_auth: Data API token for authentication. :param advertiser_id: :param data_provider_id: :param items: @@ -52,17 +51,14 @@ def data_subject_request_advertiser_data( else: base_url = models.DATA_SUBJECT_REQUEST_ADVERTISER_DATA_OP_SERVERS[0] - request = models.DataSubjectRequestAdvertiserDataRequest( - ttd_auth=ttd_auth, - body=models.AdvertiserDsrRequest( - advertiser_id=advertiser_id, - data_provider_id=data_provider_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BasePartnerDsrDataItem]] - ), - data_load_trace_id=data_load_trace_id, - request_type=request_type, + request = models.AdvertiserDsrRequest( + advertiser_id=advertiser_id, + data_provider_id=data_provider_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BasePartnerDsrDataItem]] ), + data_load_trace_id=data_load_trace_id, + request_type=request_type, ) req = self._build_request( @@ -73,12 +69,13 @@ def data_subject_request_advertiser_data( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.AdvertiserDsrRequest + request, False, False, "json", models.AdvertiserDsrRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -98,7 +95,9 @@ def data_subject_request_advertiser_data( base_url=base_url or "", operation_id="DataSubjectRequestAdvertiserData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["DeletionOptOut"], extensions=None, ), @@ -135,7 +134,6 @@ def data_subject_request_advertiser_data( async def data_subject_request_advertiser_data_async( self, *, - ttd_auth: str, advertiser_id: OptionalNullable[str] = UNSET, data_provider_id: OptionalNullable[str] = UNSET, items: OptionalNullable[ @@ -153,7 +151,6 @@ async def data_subject_request_advertiser_data_async( ) -> models.DataSubjectRequestAdvertiserDataResponse: r"""Delete IDs shared with The Trade Desk for the specified advertiser ID. - :param ttd_auth: Data API token for authentication. :param advertiser_id: :param data_provider_id: :param items: @@ -174,17 +171,14 @@ async def data_subject_request_advertiser_data_async( else: base_url = models.DATA_SUBJECT_REQUEST_ADVERTISER_DATA_OP_SERVERS[0] - request = models.DataSubjectRequestAdvertiserDataRequest( - ttd_auth=ttd_auth, - body=models.AdvertiserDsrRequest( - advertiser_id=advertiser_id, - data_provider_id=data_provider_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BasePartnerDsrDataItem]] - ), - data_load_trace_id=data_load_trace_id, - request_type=request_type, + request = models.AdvertiserDsrRequest( + advertiser_id=advertiser_id, + data_provider_id=data_provider_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BasePartnerDsrDataItem]] ), + data_load_trace_id=data_load_trace_id, + request_type=request_type, ) req = self._build_request_async( @@ -195,12 +189,13 @@ async def data_subject_request_advertiser_data_async( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.AdvertiserDsrRequest + request, False, False, "json", models.AdvertiserDsrRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -220,7 +215,9 @@ async def data_subject_request_advertiser_data_async( base_url=base_url or "", operation_id="DataSubjectRequestAdvertiserData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["DeletionOptOut"], extensions=None, ), @@ -257,7 +254,6 @@ async def data_subject_request_advertiser_data_async( def data_subject_request_merchant_data( self, *, - ttd_auth: str, merchant_id: OptionalNullable[int] = UNSET, items: OptionalNullable[ Union[ @@ -274,7 +270,6 @@ def data_subject_request_merchant_data( ) -> models.DataSubjectRequestMerchantDataResponse: r"""Delete IDs shared with The Trade Desk via a product catalog for the specified merchant ID. - :param ttd_auth: Data API token for authentication. :param merchant_id: :param items: :param data_load_trace_id: @@ -294,16 +289,13 @@ def data_subject_request_merchant_data( else: base_url = models.DATA_SUBJECT_REQUEST_MERCHANT_DATA_OP_SERVERS[0] - request = models.DataSubjectRequestMerchantDataRequest( - ttd_auth=ttd_auth, - body=models.MerchantDsrRequest( - merchant_id=merchant_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BasePartnerDsrDataItem]] - ), - data_load_trace_id=data_load_trace_id, - request_type=request_type, + request = models.MerchantDsrRequest( + merchant_id=merchant_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BasePartnerDsrDataItem]] ), + data_load_trace_id=data_load_trace_id, + request_type=request_type, ) req = self._build_request( @@ -314,12 +306,13 @@ def data_subject_request_merchant_data( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.MerchantDsrRequest + request, False, False, "json", models.MerchantDsrRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -339,7 +332,9 @@ def data_subject_request_merchant_data( base_url=base_url or "", operation_id="DataSubjectRequestMerchantData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["DeletionOptOut"], extensions=None, ), @@ -376,7 +371,6 @@ def data_subject_request_merchant_data( async def data_subject_request_merchant_data_async( self, *, - ttd_auth: str, merchant_id: OptionalNullable[int] = UNSET, items: OptionalNullable[ Union[ @@ -393,7 +387,6 @@ async def data_subject_request_merchant_data_async( ) -> models.DataSubjectRequestMerchantDataResponse: r"""Delete IDs shared with The Trade Desk via a product catalog for the specified merchant ID. - :param ttd_auth: Data API token for authentication. :param merchant_id: :param items: :param data_load_trace_id: @@ -413,16 +406,13 @@ async def data_subject_request_merchant_data_async( else: base_url = models.DATA_SUBJECT_REQUEST_MERCHANT_DATA_OP_SERVERS[0] - request = models.DataSubjectRequestMerchantDataRequest( - ttd_auth=ttd_auth, - body=models.MerchantDsrRequest( - merchant_id=merchant_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BasePartnerDsrDataItem]] - ), - data_load_trace_id=data_load_trace_id, - request_type=request_type, + request = models.MerchantDsrRequest( + merchant_id=merchant_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BasePartnerDsrDataItem]] ), + data_load_trace_id=data_load_trace_id, + request_type=request_type, ) req = self._build_request_async( @@ -433,12 +423,13 @@ async def data_subject_request_merchant_data_async( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.MerchantDsrRequest + request, False, False, "json", models.MerchantDsrRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -458,7 +449,9 @@ async def data_subject_request_merchant_data_async( base_url=base_url or "", operation_id="DataSubjectRequestMerchantData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["DeletionOptOut"], extensions=None, ), @@ -495,7 +488,6 @@ async def data_subject_request_merchant_data_async( def data_subject_request_third_party_data( self, *, - ttd_auth: str, data_provider_id: OptionalNullable[str] = UNSET, brand_id: OptionalNullable[str] = UNSET, items: OptionalNullable[ @@ -513,7 +505,6 @@ def data_subject_request_third_party_data( ) -> models.DataSubjectRequestThirdPartyDataResponse: r"""Delete IDs shared with The Trade Desk for the specified data provider ID. - :param ttd_auth: Data API token for authentication. :param data_provider_id: :param brand_id: :param items: @@ -534,17 +525,14 @@ def data_subject_request_third_party_data( else: base_url = models.DATA_SUBJECT_REQUEST_THIRD_PARTY_DATA_OP_SERVERS[0] - request = models.DataSubjectRequestThirdPartyDataRequest( - ttd_auth=ttd_auth, - body=models.ThirdPartyDsrRequest( - data_provider_id=data_provider_id, - brand_id=brand_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BasePartnerDsrDataItem]] - ), - data_load_trace_id=data_load_trace_id, - request_type=request_type, + request = models.ThirdPartyDsrRequest( + data_provider_id=data_provider_id, + brand_id=brand_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BasePartnerDsrDataItem]] ), + data_load_trace_id=data_load_trace_id, + request_type=request_type, ) req = self._build_request( @@ -555,12 +543,13 @@ def data_subject_request_third_party_data( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.ThirdPartyDsrRequest + request, False, False, "json", models.ThirdPartyDsrRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -580,7 +569,9 @@ def data_subject_request_third_party_data( base_url=base_url or "", operation_id="DataSubjectRequestThirdPartyData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["DeletionOptOut"], extensions=None, ), @@ -617,7 +608,6 @@ def data_subject_request_third_party_data( async def data_subject_request_third_party_data_async( self, *, - ttd_auth: str, data_provider_id: OptionalNullable[str] = UNSET, brand_id: OptionalNullable[str] = UNSET, items: OptionalNullable[ @@ -635,7 +625,6 @@ async def data_subject_request_third_party_data_async( ) -> models.DataSubjectRequestThirdPartyDataResponse: r"""Delete IDs shared with The Trade Desk for the specified data provider ID. - :param ttd_auth: Data API token for authentication. :param data_provider_id: :param brand_id: :param items: @@ -656,17 +645,14 @@ async def data_subject_request_third_party_data_async( else: base_url = models.DATA_SUBJECT_REQUEST_THIRD_PARTY_DATA_OP_SERVERS[0] - request = models.DataSubjectRequestThirdPartyDataRequest( - ttd_auth=ttd_auth, - body=models.ThirdPartyDsrRequest( - data_provider_id=data_provider_id, - brand_id=brand_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BasePartnerDsrDataItem]] - ), - data_load_trace_id=data_load_trace_id, - request_type=request_type, + request = models.ThirdPartyDsrRequest( + data_provider_id=data_provider_id, + brand_id=brand_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BasePartnerDsrDataItem]] ), + data_load_trace_id=data_load_trace_id, + request_type=request_type, ) req = self._build_request_async( @@ -677,12 +663,13 @@ async def data_subject_request_third_party_data_async( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.ThirdPartyDsrRequest + request, False, False, "json", models.ThirdPartyDsrRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -702,7 +689,9 @@ async def data_subject_request_third_party_data_async( base_url=base_url or "", operation_id="DataSubjectRequestThirdPartyData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["DeletionOptOut"], extensions=None, ), diff --git a/src/ttd_data/ipaddress.py b/src/ttd_data/ipaddress.py index 6ae4f90..e33eb58 100644 --- a/src/ttd_data/ipaddress.py +++ b/src/ttd_data/ipaddress.py @@ -5,6 +5,7 @@ from ttd_data import errors, models, utils from ttd_data._hooks import HookContext from ttd_data.types import OptionalNullable, UNSET +from ttd_data.utils import get_security_from_env from ttd_data.utils.unmarshal_json_response import unmarshal_json_response from typing import Any, Iterable, List, Mapping, Optional, Union @@ -13,7 +14,6 @@ class IPAddress(BaseSDK): def ingest_first_party_ip_address_data( self, *, - ttd_auth: str, data_owner_id: str, items: OptionalNullable[ Union[ @@ -29,7 +29,6 @@ def ingest_first_party_ip_address_data( ) -> models.IngestFirstPartyIPAddressDataResponse: r"""Upload first-party IP address data for the specified ID. - :param ttd_auth: Data API token for authentication. :param data_owner_id: :param items: :param data_load_trace_id: @@ -48,15 +47,12 @@ def ingest_first_party_ip_address_data( else: base_url = models.INGEST_FIRST_PARTY_IP_ADDRESS_DATA_OP_SERVERS[0] - request = models.IngestFirstPartyIPAddressDataRequest( - ttd_auth=ttd_auth, - body=models.IPAddressDataRequest( - data_owner_id=data_owner_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.IPAddressDataItem]] - ), - data_load_trace_id=data_load_trace_id, + request = models.IPAddressDataRequest( + data_owner_id=data_owner_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.IPAddressDataItem]] ), + data_load_trace_id=data_load_trace_id, ) req = self._build_request( @@ -67,12 +63,13 @@ def ingest_first_party_ip_address_data( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.IPAddressDataRequest + request, False, False, "json", models.IPAddressDataRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -92,7 +89,9 @@ def ingest_first_party_ip_address_data( base_url=base_url or "", operation_id="IngestFirstPartyIPAddressData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["IPAddress"], extensions=None, ), @@ -129,7 +128,6 @@ def ingest_first_party_ip_address_data( async def ingest_first_party_ip_address_data_async( self, *, - ttd_auth: str, data_owner_id: str, items: OptionalNullable[ Union[ @@ -145,7 +143,6 @@ async def ingest_first_party_ip_address_data_async( ) -> models.IngestFirstPartyIPAddressDataResponse: r"""Upload first-party IP address data for the specified ID. - :param ttd_auth: Data API token for authentication. :param data_owner_id: :param items: :param data_load_trace_id: @@ -164,15 +161,12 @@ async def ingest_first_party_ip_address_data_async( else: base_url = models.INGEST_FIRST_PARTY_IP_ADDRESS_DATA_OP_SERVERS[0] - request = models.IngestFirstPartyIPAddressDataRequest( - ttd_auth=ttd_auth, - body=models.IPAddressDataRequest( - data_owner_id=data_owner_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.IPAddressDataItem]] - ), - data_load_trace_id=data_load_trace_id, + request = models.IPAddressDataRequest( + data_owner_id=data_owner_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.IPAddressDataItem]] ), + data_load_trace_id=data_load_trace_id, ) req = self._build_request_async( @@ -183,12 +177,13 @@ async def ingest_first_party_ip_address_data_async( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.IPAddressDataRequest + request, False, False, "json", models.IPAddressDataRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -208,7 +203,9 @@ async def ingest_first_party_ip_address_data_async( base_url=base_url or "", operation_id="IngestFirstPartyIPAddressData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["IPAddress"], extensions=None, ), @@ -245,7 +242,6 @@ async def ingest_first_party_ip_address_data_async( def ingest_third_party_ip_address_data( self, *, - ttd_auth: str, data_owner_id: str, items: OptionalNullable[ Union[ @@ -261,7 +257,6 @@ def ingest_third_party_ip_address_data( ) -> models.IngestThirdPartyIPAddressDataResponse: r"""Upload third-party IP address data for the specified ID. - :param ttd_auth: Data API token for authentication. :param data_owner_id: :param items: :param data_load_trace_id: @@ -280,15 +275,12 @@ def ingest_third_party_ip_address_data( else: base_url = models.INGEST_THIRD_PARTY_IP_ADDRESS_DATA_OP_SERVERS[0] - request = models.IngestThirdPartyIPAddressDataRequest( - ttd_auth=ttd_auth, - body=models.IPAddressDataRequest( - data_owner_id=data_owner_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.IPAddressDataItem]] - ), - data_load_trace_id=data_load_trace_id, + request = models.IPAddressDataRequest( + data_owner_id=data_owner_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.IPAddressDataItem]] ), + data_load_trace_id=data_load_trace_id, ) req = self._build_request( @@ -299,12 +291,13 @@ def ingest_third_party_ip_address_data( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.IPAddressDataRequest + request, False, False, "json", models.IPAddressDataRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -324,7 +317,9 @@ def ingest_third_party_ip_address_data( base_url=base_url or "", operation_id="IngestThirdPartyIPAddressData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["IPAddress"], extensions=None, ), @@ -361,7 +356,6 @@ def ingest_third_party_ip_address_data( async def ingest_third_party_ip_address_data_async( self, *, - ttd_auth: str, data_owner_id: str, items: OptionalNullable[ Union[ @@ -377,7 +371,6 @@ async def ingest_third_party_ip_address_data_async( ) -> models.IngestThirdPartyIPAddressDataResponse: r"""Upload third-party IP address data for the specified ID. - :param ttd_auth: Data API token for authentication. :param data_owner_id: :param items: :param data_load_trace_id: @@ -396,15 +389,12 @@ async def ingest_third_party_ip_address_data_async( else: base_url = models.INGEST_THIRD_PARTY_IP_ADDRESS_DATA_OP_SERVERS[0] - request = models.IngestThirdPartyIPAddressDataRequest( - ttd_auth=ttd_auth, - body=models.IPAddressDataRequest( - data_owner_id=data_owner_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.IPAddressDataItem]] - ), - data_load_trace_id=data_load_trace_id, + request = models.IPAddressDataRequest( + data_owner_id=data_owner_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.IPAddressDataItem]] ), + data_load_trace_id=data_load_trace_id, ) req = self._build_request_async( @@ -415,12 +405,13 @@ async def ingest_third_party_ip_address_data_async( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.IPAddressDataRequest + request, False, False, "json", models.IPAddressDataRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -440,7 +431,9 @@ async def ingest_third_party_ip_address_data_async( base_url=base_url or "", operation_id="IngestThirdPartyIPAddressData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["IPAddress"], extensions=None, ), diff --git a/src/ttd_data/models/__init__.py b/src/ttd_data/models/__init__.py index a1690eb..0f66914 100644 --- a/src/ttd_data/models/__init__.py +++ b/src/ttd_data/models/__init__.py @@ -64,22 +64,16 @@ from .dataorigintype import DataOriginType from .datasubjectrequestadvertiserdataop import ( DATA_SUBJECT_REQUEST_ADVERTISER_DATA_OP_SERVERS, - DataSubjectRequestAdvertiserDataRequest, - DataSubjectRequestAdvertiserDataRequestTypedDict, DataSubjectRequestAdvertiserDataResponse, DataSubjectRequestAdvertiserDataResponseTypedDict, ) from .datasubjectrequestmerchantdataop import ( DATA_SUBJECT_REQUEST_MERCHANT_DATA_OP_SERVERS, - DataSubjectRequestMerchantDataRequest, - DataSubjectRequestMerchantDataRequestTypedDict, DataSubjectRequestMerchantDataResponse, DataSubjectRequestMerchantDataResponseTypedDict, ) from .datasubjectrequestthirdpartydataop import ( DATA_SUBJECT_REQUEST_THIRD_PARTY_DATA_OP_SERVERS, - DataSubjectRequestThirdPartyDataRequest, - DataSubjectRequestThirdPartyDataRequestTypedDict, DataSubjectRequestThirdPartyDataResponse, DataSubjectRequestThirdPartyDataResponseTypedDict, ) @@ -88,36 +82,26 @@ from .httpmetadata import HTTPMetadata, HTTPMetadataTypedDict from .ingestadvertiserdataop import ( INGEST_ADVERTISER_DATA_OP_SERVERS, - IngestAdvertiserDataRequest, - IngestAdvertiserDataRequestTypedDict, IngestAdvertiserDataResponse, IngestAdvertiserDataResponseTypedDict, ) from .ingestfirstpartyipaddressdataop import ( INGEST_FIRST_PARTY_IP_ADDRESS_DATA_OP_SERVERS, - IngestFirstPartyIPAddressDataRequest, - IngestFirstPartyIPAddressDataRequestTypedDict, IngestFirstPartyIPAddressDataResponse, IngestFirstPartyIPAddressDataResponseTypedDict, ) from .ingestofflineconversiondataop import ( INGEST_OFFLINE_CONVERSION_DATA_OP_SERVERS, - IngestOfflineConversionDataRequest, - IngestOfflineConversionDataRequestTypedDict, IngestOfflineConversionDataResponse, IngestOfflineConversionDataResponseTypedDict, ) from .ingestthirdpartydataop import ( INGEST_THIRD_PARTY_DATA_OP_SERVERS, - IngestThirdPartyDataRequest, - IngestThirdPartyDataRequestTypedDict, IngestThirdPartyDataResponse, IngestThirdPartyDataResponseTypedDict, ) from .ingestthirdpartyipaddressdataop import ( INGEST_THIRD_PARTY_IP_ADDRESS_DATA_OP_SERVERS, - IngestThirdPartyIPAddressDataRequest, - IngestThirdPartyIPAddressDataRequestTypedDict, IngestThirdPartyIPAddressDataResponse, IngestThirdPartyIPAddressDataResponseTypedDict, ) @@ -166,6 +150,7 @@ RealTimeConversionEventsPrivacySetting, RealTimeConversionEventsPrivacySettingTypedDict, ) + from .security import Security, SecurityTypedDict from .thirdpartydata import ThirdPartyData, ThirdPartyDataTypedDict from .thirdpartydatarequest import ( ThirdPartyDataRequest, @@ -225,16 +210,10 @@ "DataOrigin", "DataOriginType", "DataOriginTypedDict", - "DataSubjectRequestAdvertiserDataRequest", - "DataSubjectRequestAdvertiserDataRequestTypedDict", "DataSubjectRequestAdvertiserDataResponse", "DataSubjectRequestAdvertiserDataResponseTypedDict", - "DataSubjectRequestMerchantDataRequest", - "DataSubjectRequestMerchantDataRequestTypedDict", "DataSubjectRequestMerchantDataResponse", "DataSubjectRequestMerchantDataResponseTypedDict", - "DataSubjectRequestThirdPartyDataRequest", - "DataSubjectRequestThirdPartyDataRequestTypedDict", "DataSubjectRequestThirdPartyDataResponse", "DataSubjectRequestThirdPartyDataResponseTypedDict", "DsrErrorCode", @@ -258,24 +237,14 @@ "IPAddressDataServerResponseLineTypedDict", "IPAddressDataServerResponseTypedDict", "IPAddressDataTypedDict", - "IngestAdvertiserDataRequest", - "IngestAdvertiserDataRequestTypedDict", "IngestAdvertiserDataResponse", "IngestAdvertiserDataResponseTypedDict", - "IngestFirstPartyIPAddressDataRequest", - "IngestFirstPartyIPAddressDataRequestTypedDict", "IngestFirstPartyIPAddressDataResponse", "IngestFirstPartyIPAddressDataResponseTypedDict", - "IngestOfflineConversionDataRequest", - "IngestOfflineConversionDataRequestTypedDict", "IngestOfflineConversionDataResponse", "IngestOfflineConversionDataResponseTypedDict", - "IngestThirdPartyDataRequest", - "IngestThirdPartyDataRequestTypedDict", "IngestThirdPartyDataResponse", "IngestThirdPartyDataResponseTypedDict", - "IngestThirdPartyIPAddressDataRequest", - "IngestThirdPartyIPAddressDataRequestTypedDict", "IngestThirdPartyIPAddressDataResponse", "IngestThirdPartyIPAddressDataResponseTypedDict", "MerchantDsrFailedLine", @@ -300,6 +269,8 @@ "RealTimeConversionEventLineItemTypedDict", "RealTimeConversionEventsPrivacySetting", "RealTimeConversionEventsPrivacySettingTypedDict", + "Security", + "SecurityTypedDict", "ThirdPartyData", "ThirdPartyDataItem", "ThirdPartyDataItemTypedDict", @@ -357,18 +328,12 @@ "DataOriginTypedDict": ".dataorigin", "DataOriginType": ".dataorigintype", "DATA_SUBJECT_REQUEST_ADVERTISER_DATA_OP_SERVERS": ".datasubjectrequestadvertiserdataop", - "DataSubjectRequestAdvertiserDataRequest": ".datasubjectrequestadvertiserdataop", - "DataSubjectRequestAdvertiserDataRequestTypedDict": ".datasubjectrequestadvertiserdataop", "DataSubjectRequestAdvertiserDataResponse": ".datasubjectrequestadvertiserdataop", "DataSubjectRequestAdvertiserDataResponseTypedDict": ".datasubjectrequestadvertiserdataop", "DATA_SUBJECT_REQUEST_MERCHANT_DATA_OP_SERVERS": ".datasubjectrequestmerchantdataop", - "DataSubjectRequestMerchantDataRequest": ".datasubjectrequestmerchantdataop", - "DataSubjectRequestMerchantDataRequestTypedDict": ".datasubjectrequestmerchantdataop", "DataSubjectRequestMerchantDataResponse": ".datasubjectrequestmerchantdataop", "DataSubjectRequestMerchantDataResponseTypedDict": ".datasubjectrequestmerchantdataop", "DATA_SUBJECT_REQUEST_THIRD_PARTY_DATA_OP_SERVERS": ".datasubjectrequestthirdpartydataop", - "DataSubjectRequestThirdPartyDataRequest": ".datasubjectrequestthirdpartydataop", - "DataSubjectRequestThirdPartyDataRequestTypedDict": ".datasubjectrequestthirdpartydataop", "DataSubjectRequestThirdPartyDataResponse": ".datasubjectrequestthirdpartydataop", "DataSubjectRequestThirdPartyDataResponseTypedDict": ".datasubjectrequestthirdpartydataop", "DsrErrorCode": ".dsrerrorcode", @@ -377,28 +342,18 @@ "HTTPMetadata": ".httpmetadata", "HTTPMetadataTypedDict": ".httpmetadata", "INGEST_ADVERTISER_DATA_OP_SERVERS": ".ingestadvertiserdataop", - "IngestAdvertiserDataRequest": ".ingestadvertiserdataop", - "IngestAdvertiserDataRequestTypedDict": ".ingestadvertiserdataop", "IngestAdvertiserDataResponse": ".ingestadvertiserdataop", "IngestAdvertiserDataResponseTypedDict": ".ingestadvertiserdataop", "INGEST_FIRST_PARTY_IP_ADDRESS_DATA_OP_SERVERS": ".ingestfirstpartyipaddressdataop", - "IngestFirstPartyIPAddressDataRequest": ".ingestfirstpartyipaddressdataop", - "IngestFirstPartyIPAddressDataRequestTypedDict": ".ingestfirstpartyipaddressdataop", "IngestFirstPartyIPAddressDataResponse": ".ingestfirstpartyipaddressdataop", "IngestFirstPartyIPAddressDataResponseTypedDict": ".ingestfirstpartyipaddressdataop", "INGEST_OFFLINE_CONVERSION_DATA_OP_SERVERS": ".ingestofflineconversiondataop", - "IngestOfflineConversionDataRequest": ".ingestofflineconversiondataop", - "IngestOfflineConversionDataRequestTypedDict": ".ingestofflineconversiondataop", "IngestOfflineConversionDataResponse": ".ingestofflineconversiondataop", "IngestOfflineConversionDataResponseTypedDict": ".ingestofflineconversiondataop", "INGEST_THIRD_PARTY_DATA_OP_SERVERS": ".ingestthirdpartydataop", - "IngestThirdPartyDataRequest": ".ingestthirdpartydataop", - "IngestThirdPartyDataRequestTypedDict": ".ingestthirdpartydataop", "IngestThirdPartyDataResponse": ".ingestthirdpartydataop", "IngestThirdPartyDataResponseTypedDict": ".ingestthirdpartydataop", "INGEST_THIRD_PARTY_IP_ADDRESS_DATA_OP_SERVERS": ".ingestthirdpartyipaddressdataop", - "IngestThirdPartyIPAddressDataRequest": ".ingestthirdpartyipaddressdataop", - "IngestThirdPartyIPAddressDataRequestTypedDict": ".ingestthirdpartyipaddressdataop", "IngestThirdPartyIPAddressDataResponse": ".ingestthirdpartyipaddressdataop", "IngestThirdPartyIPAddressDataResponseTypedDict": ".ingestthirdpartyipaddressdataop", "IPAddressData": ".ipaddressdata", @@ -430,6 +385,8 @@ "RealTimeConversionEventLineItemTypedDict": ".realtimeconversioneventlineitem", "RealTimeConversionEventsPrivacySetting": ".realtimeconversioneventsprivacysetting", "RealTimeConversionEventsPrivacySettingTypedDict": ".realtimeconversioneventsprivacysetting", + "Security": ".security", + "SecurityTypedDict": ".security", "ThirdPartyData": ".thirdpartydata", "ThirdPartyDataTypedDict": ".thirdpartydata", "ThirdPartyDataRequest": ".thirdpartydatarequest", diff --git a/src/ttd_data/models/advertiserdataresponseerrorcode.py b/src/ttd_data/models/advertiserdataresponseerrorcode.py index cc8f3fd..6bbdb87 100644 --- a/src/ttd_data/models/advertiserdataresponseerrorcode.py +++ b/src/ttd_data/models/advertiserdataresponseerrorcode.py @@ -24,4 +24,5 @@ class AdvertiserDataResponseErrorCode(str, Enum): TENANT_RESTRICTIONS_EXTERNAL_DATA = "TenantRestrictionsExternalData" TARGETING_DATA_DISABLED = "TargetingDataDisabled" ITEM_DESERIALIZATION_ERROR = "ItemDeserializationError" + INVALID_TIMESTAMP_UTC = "InvalidTimestampUtc" UID2_ERROR = "Uid2Error" diff --git a/src/ttd_data/models/datasubjectrequestadvertiserdataop.py b/src/ttd_data/models/datasubjectrequestadvertiserdataop.py index 3fc6335..16103d3 100644 --- a/src/ttd_data/models/datasubjectrequestadvertiserdataop.py +++ b/src/ttd_data/models/datasubjectrequestadvertiserdataop.py @@ -2,13 +2,11 @@ # @generated-id: 32f041f202c4 from __future__ import annotations -from .advertiserdsrrequest import AdvertiserDsrRequest, AdvertiserDsrRequestTypedDict from .advertiserdsrresponse import AdvertiserDsrResponse, AdvertiserDsrResponseTypedDict from .httpmetadata import HTTPMetadata, HTTPMetadataTypedDict import pydantic from pydantic import model_serializer from ttd_data.types import BaseModel, UNSET_SENTINEL -from ttd_data.utils import FieldMetadata, HeaderMetadata, RequestMetadata from typing import Optional from typing_extensions import Annotated, NotRequired, TypedDict @@ -18,26 +16,6 @@ ] -class DataSubjectRequestAdvertiserDataRequestTypedDict(TypedDict): - ttd_auth: str - r"""Data API token for authentication.""" - body: AdvertiserDsrRequestTypedDict - - -class DataSubjectRequestAdvertiserDataRequest(BaseModel): - ttd_auth: Annotated[ - str, - pydantic.Field(alias="TTD-Auth"), - FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), - ] - r"""Data API token for authentication.""" - - body: Annotated[ - AdvertiserDsrRequest, - FieldMetadata(request=RequestMetadata(media_type="application/json")), - ] - - class DataSubjectRequestAdvertiserDataResponseTypedDict(TypedDict): http_meta: HTTPMetadataTypedDict advertiser_dsr_response: NotRequired[AdvertiserDsrResponseTypedDict] diff --git a/src/ttd_data/models/datasubjectrequestmerchantdataop.py b/src/ttd_data/models/datasubjectrequestmerchantdataop.py index 37a642b..0752657 100644 --- a/src/ttd_data/models/datasubjectrequestmerchantdataop.py +++ b/src/ttd_data/models/datasubjectrequestmerchantdataop.py @@ -3,12 +3,10 @@ from __future__ import annotations from .httpmetadata import HTTPMetadata, HTTPMetadataTypedDict -from .merchantdsrrequest import MerchantDsrRequest, MerchantDsrRequestTypedDict from .merchantdsrresponse import MerchantDsrResponse, MerchantDsrResponseTypedDict import pydantic from pydantic import model_serializer from ttd_data.types import BaseModel, UNSET_SENTINEL -from ttd_data.utils import FieldMetadata, HeaderMetadata, RequestMetadata from typing import Optional from typing_extensions import Annotated, NotRequired, TypedDict @@ -18,26 +16,6 @@ ] -class DataSubjectRequestMerchantDataRequestTypedDict(TypedDict): - ttd_auth: str - r"""Data API token for authentication.""" - body: MerchantDsrRequestTypedDict - - -class DataSubjectRequestMerchantDataRequest(BaseModel): - ttd_auth: Annotated[ - str, - pydantic.Field(alias="TTD-Auth"), - FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), - ] - r"""Data API token for authentication.""" - - body: Annotated[ - MerchantDsrRequest, - FieldMetadata(request=RequestMetadata(media_type="application/json")), - ] - - class DataSubjectRequestMerchantDataResponseTypedDict(TypedDict): http_meta: HTTPMetadataTypedDict merchant_dsr_response: NotRequired[MerchantDsrResponseTypedDict] diff --git a/src/ttd_data/models/datasubjectrequestthirdpartydataop.py b/src/ttd_data/models/datasubjectrequestthirdpartydataop.py index 39acf52..dfb2834 100644 --- a/src/ttd_data/models/datasubjectrequestthirdpartydataop.py +++ b/src/ttd_data/models/datasubjectrequestthirdpartydataop.py @@ -3,12 +3,10 @@ from __future__ import annotations from .httpmetadata import HTTPMetadata, HTTPMetadataTypedDict -from .thirdpartydsrrequest import ThirdPartyDsrRequest, ThirdPartyDsrRequestTypedDict from .thirdpartydsrresponse import ThirdPartyDsrResponse, ThirdPartyDsrResponseTypedDict import pydantic from pydantic import model_serializer from ttd_data.types import BaseModel, UNSET_SENTINEL -from ttd_data.utils import FieldMetadata, HeaderMetadata, RequestMetadata from typing import Optional from typing_extensions import Annotated, NotRequired, TypedDict @@ -18,26 +16,6 @@ ] -class DataSubjectRequestThirdPartyDataRequestTypedDict(TypedDict): - ttd_auth: str - r"""Data API token for authentication.""" - body: ThirdPartyDsrRequestTypedDict - - -class DataSubjectRequestThirdPartyDataRequest(BaseModel): - ttd_auth: Annotated[ - str, - pydantic.Field(alias="TTD-Auth"), - FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), - ] - r"""Data API token for authentication.""" - - body: Annotated[ - ThirdPartyDsrRequest, - FieldMetadata(request=RequestMetadata(media_type="application/json")), - ] - - class DataSubjectRequestThirdPartyDataResponseTypedDict(TypedDict): http_meta: HTTPMetadataTypedDict third_party_dsr_response: NotRequired[ThirdPartyDsrResponseTypedDict] diff --git a/src/ttd_data/models/ingestadvertiserdataop.py b/src/ttd_data/models/ingestadvertiserdataop.py index d2aac1b..131be8b 100644 --- a/src/ttd_data/models/ingestadvertiserdataop.py +++ b/src/ttd_data/models/ingestadvertiserdataop.py @@ -2,7 +2,6 @@ # @generated-id: 536d8288fda4 from __future__ import annotations -from .advertiserdatarequest import AdvertiserDataRequest, AdvertiserDataRequestTypedDict from .advertiserdataserverresponse import ( AdvertiserDataServerResponse, AdvertiserDataServerResponseTypedDict, @@ -11,7 +10,6 @@ import pydantic from pydantic import model_serializer from ttd_data.types import BaseModel, UNSET_SENTINEL -from ttd_data.utils import FieldMetadata, HeaderMetadata, RequestMetadata from typing import Optional from typing_extensions import Annotated, NotRequired, TypedDict @@ -21,26 +19,6 @@ ] -class IngestAdvertiserDataRequestTypedDict(TypedDict): - ttd_auth: str - r"""Data API token for authentication.""" - body: AdvertiserDataRequestTypedDict - - -class IngestAdvertiserDataRequest(BaseModel): - ttd_auth: Annotated[ - str, - pydantic.Field(alias="TTD-Auth"), - FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), - ] - r"""Data API token for authentication.""" - - body: Annotated[ - AdvertiserDataRequest, - FieldMetadata(request=RequestMetadata(media_type="application/json")), - ] - - class IngestAdvertiserDataResponseTypedDict(TypedDict): http_meta: HTTPMetadataTypedDict advertiser_data_server_response: NotRequired[AdvertiserDataServerResponseTypedDict] diff --git a/src/ttd_data/models/ingestfirstpartyipaddressdataop.py b/src/ttd_data/models/ingestfirstpartyipaddressdataop.py index 26a7434..cdb56e5 100644 --- a/src/ttd_data/models/ingestfirstpartyipaddressdataop.py +++ b/src/ttd_data/models/ingestfirstpartyipaddressdataop.py @@ -3,7 +3,6 @@ from __future__ import annotations from .httpmetadata import HTTPMetadata, HTTPMetadataTypedDict -from .ipaddressdatarequest import IPAddressDataRequest, IPAddressDataRequestTypedDict from .ipaddressdataserverresponse import ( IPAddressDataServerResponse, IPAddressDataServerResponseTypedDict, @@ -11,7 +10,6 @@ import pydantic from pydantic import model_serializer from ttd_data.types import BaseModel, UNSET_SENTINEL -from ttd_data.utils import FieldMetadata, HeaderMetadata, RequestMetadata from typing import Optional from typing_extensions import Annotated, NotRequired, TypedDict @@ -21,26 +19,6 @@ ] -class IngestFirstPartyIPAddressDataRequestTypedDict(TypedDict): - ttd_auth: str - r"""Data API token for authentication.""" - body: IPAddressDataRequestTypedDict - - -class IngestFirstPartyIPAddressDataRequest(BaseModel): - ttd_auth: Annotated[ - str, - pydantic.Field(alias="TTD-Auth"), - FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), - ] - r"""Data API token for authentication.""" - - body: Annotated[ - IPAddressDataRequest, - FieldMetadata(request=RequestMetadata(media_type="application/json")), - ] - - class IngestFirstPartyIPAddressDataResponseTypedDict(TypedDict): http_meta: HTTPMetadataTypedDict ip_address_data_server_response: NotRequired[IPAddressDataServerResponseTypedDict] diff --git a/src/ttd_data/models/ingestofflineconversiondataop.py b/src/ttd_data/models/ingestofflineconversiondataop.py index c580cab..9e6f42b 100644 --- a/src/ttd_data/models/ingestofflineconversiondataop.py +++ b/src/ttd_data/models/ingestofflineconversiondataop.py @@ -3,10 +3,6 @@ from __future__ import annotations from .httpmetadata import HTTPMetadata, HTTPMetadataTypedDict -from .offlineconversiondatarequest import ( - OfflineConversionDataRequest, - OfflineConversionDataRequestTypedDict, -) from .offlineconversiondataserverresponse import ( OfflineConversionDataServerResponse, OfflineConversionDataServerResponseTypedDict, @@ -14,7 +10,6 @@ import pydantic from pydantic import model_serializer from ttd_data.types import BaseModel, UNSET_SENTINEL -from ttd_data.utils import FieldMetadata, HeaderMetadata, RequestMetadata from typing import Optional from typing_extensions import Annotated, NotRequired, TypedDict @@ -24,26 +19,6 @@ ] -class IngestOfflineConversionDataRequestTypedDict(TypedDict): - ttd_auth: str - r"""Data API token for authentication.""" - body: OfflineConversionDataRequestTypedDict - - -class IngestOfflineConversionDataRequest(BaseModel): - ttd_auth: Annotated[ - str, - pydantic.Field(alias="TTD-Auth"), - FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), - ] - r"""Data API token for authentication.""" - - body: Annotated[ - OfflineConversionDataRequest, - FieldMetadata(request=RequestMetadata(media_type="application/json")), - ] - - class IngestOfflineConversionDataResponseTypedDict(TypedDict): http_meta: HTTPMetadataTypedDict offline_conversion_data_server_response: NotRequired[ diff --git a/src/ttd_data/models/ingestthirdpartydataop.py b/src/ttd_data/models/ingestthirdpartydataop.py index 3004d00..3b70ba2 100644 --- a/src/ttd_data/models/ingestthirdpartydataop.py +++ b/src/ttd_data/models/ingestthirdpartydataop.py @@ -3,7 +3,6 @@ from __future__ import annotations from .httpmetadata import HTTPMetadata, HTTPMetadataTypedDict -from .thirdpartydatarequest import ThirdPartyDataRequest, ThirdPartyDataRequestTypedDict from .thirdpartydataserverresponse import ( ThirdPartyDataServerResponse, ThirdPartyDataServerResponseTypedDict, @@ -11,7 +10,6 @@ import pydantic from pydantic import model_serializer from ttd_data.types import BaseModel, UNSET_SENTINEL -from ttd_data.utils import FieldMetadata, HeaderMetadata, RequestMetadata from typing import Optional from typing_extensions import Annotated, NotRequired, TypedDict @@ -21,26 +19,6 @@ ] -class IngestThirdPartyDataRequestTypedDict(TypedDict): - ttd_auth: str - r"""Data API token for authentication.""" - body: ThirdPartyDataRequestTypedDict - - -class IngestThirdPartyDataRequest(BaseModel): - ttd_auth: Annotated[ - str, - pydantic.Field(alias="TTD-Auth"), - FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), - ] - r"""Data API token for authentication.""" - - body: Annotated[ - ThirdPartyDataRequest, - FieldMetadata(request=RequestMetadata(media_type="application/json")), - ] - - class IngestThirdPartyDataResponseTypedDict(TypedDict): http_meta: HTTPMetadataTypedDict third_party_data_server_response: NotRequired[ThirdPartyDataServerResponseTypedDict] diff --git a/src/ttd_data/models/ingestthirdpartyipaddressdataop.py b/src/ttd_data/models/ingestthirdpartyipaddressdataop.py index 46e0a07..4b2d410 100644 --- a/src/ttd_data/models/ingestthirdpartyipaddressdataop.py +++ b/src/ttd_data/models/ingestthirdpartyipaddressdataop.py @@ -3,7 +3,6 @@ from __future__ import annotations from .httpmetadata import HTTPMetadata, HTTPMetadataTypedDict -from .ipaddressdatarequest import IPAddressDataRequest, IPAddressDataRequestTypedDict from .ipaddressdataserverresponse import ( IPAddressDataServerResponse, IPAddressDataServerResponseTypedDict, @@ -11,7 +10,6 @@ import pydantic from pydantic import model_serializer from ttd_data.types import BaseModel, UNSET_SENTINEL -from ttd_data.utils import FieldMetadata, HeaderMetadata, RequestMetadata from typing import Optional from typing_extensions import Annotated, NotRequired, TypedDict @@ -21,26 +19,6 @@ ] -class IngestThirdPartyIPAddressDataRequestTypedDict(TypedDict): - ttd_auth: str - r"""Data API token for authentication.""" - body: IPAddressDataRequestTypedDict - - -class IngestThirdPartyIPAddressDataRequest(BaseModel): - ttd_auth: Annotated[ - str, - pydantic.Field(alias="TTD-Auth"), - FieldMetadata(header=HeaderMetadata(style="simple", explode=False)), - ] - r"""Data API token for authentication.""" - - body: Annotated[ - IPAddressDataRequest, - FieldMetadata(request=RequestMetadata(media_type="application/json")), - ] - - class IngestThirdPartyIPAddressDataResponseTypedDict(TypedDict): http_meta: HTTPMetadataTypedDict ip_address_data_server_response: NotRequired[IPAddressDataServerResponseTypedDict] diff --git a/src/ttd_data/models/ipaddressdataresponseerrorcode.py b/src/ttd_data/models/ipaddressdataresponseerrorcode.py index 16f08de..980d573 100644 --- a/src/ttd_data/models/ipaddressdataresponseerrorcode.py +++ b/src/ttd_data/models/ipaddressdataresponseerrorcode.py @@ -13,3 +13,4 @@ class IPAddressDataResponseErrorCode(str, Enum): INVALID_IP_ADDRESS_RANGE = "InvalidIPAddressRange" EU_IP_TARGETING_NOT_ALLOWED_FOR_PARTNER = "EuIpTargetingNotAllowedForPartner" NOT_TARGETABLE = "NotTargetable" + INVALID_TIMESTAMP_UTC = "InvalidTimestampUtc" diff --git a/src/ttd_data/models/security.py b/src/ttd_data/models/security.py new file mode 100644 index 0000000..297679e --- /dev/null +++ b/src/ttd_data/models/security.py @@ -0,0 +1,43 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" +# @generated-id: fdab43ed8bcb + +from __future__ import annotations +from pydantic import model_serializer +from ttd_data.types import BaseModel, UNSET_SENTINEL +from ttd_data.utils import FieldMetadata, SecurityMetadata +from typing import Optional +from typing_extensions import Annotated, NotRequired, TypedDict + + +class SecurityTypedDict(TypedDict): + ttd_auth: NotRequired[str] + + +class Security(BaseModel): + ttd_auth: Annotated[ + Optional[str], + FieldMetadata( + security=SecurityMetadata( + scheme=True, + scheme_type="apiKey", + sub_type="header", + field_name="TTD-Auth", + ) + ), + ] = None + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + optional_fields = set(["TTD-Auth"]) + serialized = handler(self) + m = {} + + for n, f in type(self).model_fields.items(): + k = f.alias or n + val = serialized.get(k, serialized.get(n)) + + if val != UNSET_SENTINEL: + if val is not None or k not in optional_fields: + m[k] = val + + return m diff --git a/src/ttd_data/models/thirdpartydataresponseerrorcode.py b/src/ttd_data/models/thirdpartydataresponseerrorcode.py index e89db28..18e9136 100644 --- a/src/ttd_data/models/thirdpartydataresponseerrorcode.py +++ b/src/ttd_data/models/thirdpartydataresponseerrorcode.py @@ -21,4 +21,5 @@ class ThirdPartyDataResponseErrorCode(str, Enum): TENANT_RESTRICTIONS_EXTERNAL_DATA = "TenantRestrictionsExternalData" TARGETING_DATA_DISABLED = "TargetingDataDisabled" ITEM_DESERIALIZATION_ERROR = "ItemDeserializationError" + INVALID_TIMESTAMP_UTC = "InvalidTimestampUtc" UID2_ERROR = "Uid2Error" diff --git a/src/ttd_data/offlineconversion.py b/src/ttd_data/offlineconversion.py index 794367d..4620014 100644 --- a/src/ttd_data/offlineconversion.py +++ b/src/ttd_data/offlineconversion.py @@ -5,6 +5,7 @@ from ttd_data import errors, models, utils from ttd_data._hooks import HookContext from ttd_data.types import OptionalNullable, UNSET +from ttd_data.utils import get_security_from_env from ttd_data.utils.unmarshal_json_response import unmarshal_json_response from typing import Any, Iterable, List, Mapping, Optional, Union @@ -13,7 +14,6 @@ class OfflineConversion(BaseSDK): def ingest_offline_conversion_data( self, *, - ttd_auth: str, data_provider_id: str, user_id_array_metadata_format: OptionalNullable[Iterable[str]] = UNSET, items: OptionalNullable[ @@ -33,7 +33,6 @@ def ingest_offline_conversion_data( ) -> models.IngestOfflineConversionDataResponse: r"""Upload offline conversion data for the specified data provider. - :param ttd_auth: Data API token for authentication. :param data_provider_id: :param user_id_array_metadata_format: :param items: @@ -54,20 +53,17 @@ def ingest_offline_conversion_data( else: base_url = models.INGEST_OFFLINE_CONVERSION_DATA_OP_SERVERS[0] - request = models.IngestOfflineConversionDataRequest( - ttd_auth=ttd_auth, - body=models.OfflineConversionDataRequest( - data_provider_id=data_provider_id, - user_id_array_metadata_format=utils.unmarshal( - user_id_array_metadata_format, OptionalNullable[List[str]] - ), - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BaseOfflineConversionDataItem]] - ), - data_load_trace_id=data_load_trace_id, - data_origins=utils.get_pydantic_model( - data_origins, OptionalNullable[List[models.DataOrigin]] - ), + request = models.OfflineConversionDataRequest( + data_provider_id=data_provider_id, + user_id_array_metadata_format=utils.unmarshal( + user_id_array_metadata_format, OptionalNullable[List[str]] + ), + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BaseOfflineConversionDataItem]] + ), + data_load_trace_id=data_load_trace_id, + data_origins=utils.get_pydantic_model( + data_origins, OptionalNullable[List[models.DataOrigin]] ), ) @@ -79,12 +75,13 @@ def ingest_offline_conversion_data( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.OfflineConversionDataRequest + request, False, False, "json", models.OfflineConversionDataRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -104,7 +101,9 @@ def ingest_offline_conversion_data( base_url=base_url or "", operation_id="IngestOfflineConversionData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["OfflineConversion"], extensions=None, ), @@ -143,7 +142,6 @@ def ingest_offline_conversion_data( async def ingest_offline_conversion_data_async( self, *, - ttd_auth: str, data_provider_id: str, user_id_array_metadata_format: OptionalNullable[Iterable[str]] = UNSET, items: OptionalNullable[ @@ -163,7 +161,6 @@ async def ingest_offline_conversion_data_async( ) -> models.IngestOfflineConversionDataResponse: r"""Upload offline conversion data for the specified data provider. - :param ttd_auth: Data API token for authentication. :param data_provider_id: :param user_id_array_metadata_format: :param items: @@ -184,20 +181,17 @@ async def ingest_offline_conversion_data_async( else: base_url = models.INGEST_OFFLINE_CONVERSION_DATA_OP_SERVERS[0] - request = models.IngestOfflineConversionDataRequest( - ttd_auth=ttd_auth, - body=models.OfflineConversionDataRequest( - data_provider_id=data_provider_id, - user_id_array_metadata_format=utils.unmarshal( - user_id_array_metadata_format, OptionalNullable[List[str]] - ), - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BaseOfflineConversionDataItem]] - ), - data_load_trace_id=data_load_trace_id, - data_origins=utils.get_pydantic_model( - data_origins, OptionalNullable[List[models.DataOrigin]] - ), + request = models.OfflineConversionDataRequest( + data_provider_id=data_provider_id, + user_id_array_metadata_format=utils.unmarshal( + user_id_array_metadata_format, OptionalNullable[List[str]] + ), + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BaseOfflineConversionDataItem]] + ), + data_load_trace_id=data_load_trace_id, + data_origins=utils.get_pydantic_model( + data_origins, OptionalNullable[List[models.DataOrigin]] ), ) @@ -209,12 +203,13 @@ async def ingest_offline_conversion_data_async( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.OfflineConversionDataRequest + request, False, False, "json", models.OfflineConversionDataRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -234,7 +229,9 @@ async def ingest_offline_conversion_data_async( base_url=base_url or "", operation_id="IngestOfflineConversionData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["OfflineConversion"], extensions=None, ), diff --git a/src/ttd_data/sdk.py b/src/ttd_data/sdk.py index 425b68c..c057f94 100644 --- a/src/ttd_data/sdk.py +++ b/src/ttd_data/sdk.py @@ -9,9 +9,10 @@ import httpx import importlib import sys +from ttd_data import models from ttd_data._hooks import SDKHooks from ttd_data.types import OptionalNullable, UNSET -from typing import Optional, TYPE_CHECKING, cast +from typing import Any, Callable, Optional, TYPE_CHECKING, Union, cast import weakref if TYPE_CHECKING: @@ -53,6 +54,7 @@ class BaseDataClient(BaseSDK): def __init__( self, + ttd_auth: Optional[Union[Optional[str], Callable[[], Optional[str]]]] = None, server_url: Optional[str] = None, client: Optional[HttpClient] = None, async_client: Optional[AsyncHttpClient] = None, @@ -62,6 +64,7 @@ def __init__( ) -> None: r"""Instantiates the SDK configuring it with the provided parameters. + :param ttd_auth: The ttd_auth required for authentication :param server_idx: The index of the server to use for all methods :param server_url: The server URL to use for all methods :param url_params: Parameters to optionally template the server URL with @@ -91,6 +94,15 @@ def __init__( type(async_client), AsyncHttpClient ), "The provided async_client must implement the AsyncHttpClient protocol." + security: Any = None + if ttd_auth is None: + security = None + elif callable(ttd_auth): + # pylint: disable=unnecessary-lambda-assignment + security = lambda: models.Security(ttd_auth=ttd_auth()) + else: + security = models.Security(ttd_auth=ttd_auth) + BaseSDK.__init__( self, SDKConfiguration( @@ -98,6 +110,7 @@ def __init__( client_supplied=client_supplied, async_client=async_client, async_client_supplied=async_client_supplied, + security=security, server_url=server_url, retry_config=retry_config, timeout_ms=timeout_ms, diff --git a/src/ttd_data/sdkconfiguration.py b/src/ttd_data/sdkconfiguration.py index 914672a..98e9237 100644 --- a/src/ttd_data/sdkconfiguration.py +++ b/src/ttd_data/sdkconfiguration.py @@ -11,8 +11,9 @@ from .utils import Logger, RetryConfig, remove_suffix from dataclasses import dataclass from pydantic import Field +from ttd_data import models from ttd_data.types import OptionalNullable, UNSET -from typing import Dict, Optional, Tuple, Union +from typing import Callable, Dict, Optional, Tuple, Union @dataclass @@ -22,6 +23,7 @@ class SDKConfiguration: async_client: Union[AsyncHttpClient, None] async_client_supplied: bool debug_logger: Logger + security: Optional[Union[models.Security, Callable[[], models.Security]]] = None server_url: Optional[str] = "" language: str = "python" openapi_doc_version: str = __openapi_doc_version__ diff --git a/src/ttd_data/thirdparty.py b/src/ttd_data/thirdparty.py index 22b6e83..ee31eff 100644 --- a/src/ttd_data/thirdparty.py +++ b/src/ttd_data/thirdparty.py @@ -5,6 +5,7 @@ from ttd_data import errors, models, utils from ttd_data._hooks import HookContext from ttd_data.types import OptionalNullable, UNSET +from ttd_data.utils import get_security_from_env from ttd_data.utils.unmarshal_json_response import unmarshal_json_response from typing import Any, Iterable, List, Mapping, Optional, Union @@ -13,7 +14,6 @@ class ThirdParty(BaseSDK): def ingest_third_party_data( self, *, - ttd_auth: str, data_provider_id: str, items: OptionalNullable[ Union[ @@ -33,7 +33,6 @@ def ingest_third_party_data( ) -> models.IngestThirdPartyDataResponse: r"""Upload third-party data for the specified data provider for use in audience targeting. - :param ttd_auth: Data API token for authentication. :param data_provider_id: :param items: :param data_load_trace_id: @@ -54,18 +53,15 @@ def ingest_third_party_data( else: base_url = models.INGEST_THIRD_PARTY_DATA_OP_SERVERS[0] - request = models.IngestThirdPartyDataRequest( - ttd_auth=ttd_auth, - body=models.ThirdPartyDataRequest( - data_provider_id=data_provider_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BaseThirdPartyDataItem]] - ), - data_load_trace_id=data_load_trace_id, - is_user_id_already_hashed=is_user_id_already_hashed, - data_origins=utils.get_pydantic_model( - data_origins, OptionalNullable[List[models.DataOrigin]] - ), + request = models.ThirdPartyDataRequest( + data_provider_id=data_provider_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BaseThirdPartyDataItem]] + ), + data_load_trace_id=data_load_trace_id, + is_user_id_already_hashed=is_user_id_already_hashed, + data_origins=utils.get_pydantic_model( + data_origins, OptionalNullable[List[models.DataOrigin]] ), ) @@ -77,12 +73,13 @@ def ingest_third_party_data( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.ThirdPartyDataRequest + request, False, False, "json", models.ThirdPartyDataRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -102,7 +99,9 @@ def ingest_third_party_data( base_url=base_url or "", operation_id="IngestThirdPartyData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["ThirdParty"], extensions=None, ), @@ -139,7 +138,6 @@ def ingest_third_party_data( async def ingest_third_party_data_async( self, *, - ttd_auth: str, data_provider_id: str, items: OptionalNullable[ Union[ @@ -159,7 +157,6 @@ async def ingest_third_party_data_async( ) -> models.IngestThirdPartyDataResponse: r"""Upload third-party data for the specified data provider for use in audience targeting. - :param ttd_auth: Data API token for authentication. :param data_provider_id: :param items: :param data_load_trace_id: @@ -180,18 +177,15 @@ async def ingest_third_party_data_async( else: base_url = models.INGEST_THIRD_PARTY_DATA_OP_SERVERS[0] - request = models.IngestThirdPartyDataRequest( - ttd_auth=ttd_auth, - body=models.ThirdPartyDataRequest( - data_provider_id=data_provider_id, - items=utils.get_pydantic_model( - items, OptionalNullable[List[models.BaseThirdPartyDataItem]] - ), - data_load_trace_id=data_load_trace_id, - is_user_id_already_hashed=is_user_id_already_hashed, - data_origins=utils.get_pydantic_model( - data_origins, OptionalNullable[List[models.DataOrigin]] - ), + request = models.ThirdPartyDataRequest( + data_provider_id=data_provider_id, + items=utils.get_pydantic_model( + items, OptionalNullable[List[models.BaseThirdPartyDataItem]] + ), + data_load_trace_id=data_load_trace_id, + is_user_id_already_hashed=is_user_id_already_hashed, + data_origins=utils.get_pydantic_model( + data_origins, OptionalNullable[List[models.DataOrigin]] ), ) @@ -203,12 +197,13 @@ async def ingest_third_party_data_async( request=request, request_body_required=True, request_has_path_params=False, - request_has_query_params=False, + request_has_query_params=True, user_agent_header="user-agent", accept_header_value="application/json", http_headers=http_headers, + security=self.sdk_configuration.security, get_serialized_body=lambda: utils.serialize_request_body( - request.body, False, False, "json", models.ThirdPartyDataRequest + request, False, False, "json", models.ThirdPartyDataRequest ), allow_empty_value=None, timeout_ms=timeout_ms, @@ -228,7 +223,9 @@ async def ingest_third_party_data_async( base_url=base_url or "", operation_id="IngestThirdPartyData", oauth2_scopes=None, - security_source=None, + security_source=get_security_from_env( + self.sdk_configuration.security, models.Security + ), tags=["ThirdParty"], extensions=None, ), diff --git a/src/ttd_data/utils/__init__.py b/src/ttd_data/utils/__init__.py index ace184f..aa1b4bf 100644 --- a/src/ttd_data/utils/__init__.py +++ b/src/ttd_data/utils/__init__.py @@ -33,7 +33,8 @@ async def run_sync_in_thread(func: Callable[..., _T], *args) -> _T: from .queryparams import get_query_params from .retries import BackoffStrategy, Retries, retry, retry_async, RetryConfig from .requestbodies import serialize_request_body, SerializedRequestBody - from .security import get_security + from .security import get_security, get_security_from_env + from .serializers import ( get_pydantic_model, marshal_json, @@ -78,6 +79,7 @@ async def run_sync_in_thread(func: Callable[..., _T], *args) -> _T: "get_query_params", "get_response_headers", "get_security", + "get_security_from_env", "HeaderMetadata", "Logger", "marshal_json", @@ -131,6 +133,7 @@ async def run_sync_in_thread(func: Callable[..., _T], *args) -> _T: "get_query_params": ".queryparams", "get_response_headers": ".headers", "get_security": ".security", + "get_security_from_env": ".security", "HeaderMetadata": ".metadata", "Logger": ".logger", "marshal_json": ".serializers", diff --git a/src/ttd_data/utils/security.py b/src/ttd_data/utils/security.py index e56eff2..8857bfa 100644 --- a/src/ttd_data/utils/security.py +++ b/src/ttd_data/utils/security.py @@ -2,6 +2,7 @@ # @generated-id: e38af000ccc5 import base64 + from typing import ( Any, Dict, @@ -16,6 +17,7 @@ SecurityMetadata, find_field_metadata, ) +import os def get_security( @@ -66,6 +68,21 @@ def get_security( return headers, query_params +def get_security_from_env(security: Any, security_class: Any) -> Optional[BaseModel]: + if security is not None: + return security + + if not issubclass(security_class, BaseModel): + raise TypeError("security_class must be a pydantic model class") + + security_dict: Any = {} + + if os.getenv("TTD_DATA_TTD_AUTH"): + security_dict["ttd_auth"] = os.getenv("TTD_DATA_TTD_AUTH") + + return security_class(**security_dict) if security_dict else None + + def _parse_security_option( headers: Dict[str, str], query_params: Dict[str, List[str]], option: Any ): diff --git a/tests/unit/test_uid2.py b/tests/unit/test_uid2.py index 78ae466..b1cfbed 100644 --- a/tests/unit/test_uid2.py +++ b/tests/unit/test_uid2.py @@ -110,6 +110,36 @@ def test_client_config_tracks_base_data_client_constructor_params(): assert base_params == config_fields +def test_from_config_round_trip_preserves_ttd_auth(): + """`ttd_auth` is a client-level constructor param, so a ClientConfig that + drops it rebuilds an unauthenticated client with no error.""" + from ttd_data import DataClient + + client = DataClient(ttd_auth="secret-token") + rebuilt = DataClient.from_config(client.config) + + assert rebuilt.data_client.sdk_configuration.security.ttd_auth == "secret-token" + + +def test_from_config_keeps_callable_ttd_auth_lazy(): + """A callable credential must survive as a callable: reading `config` must + not resolve it, so token rotation keeps working after a round trip.""" + from ttd_data import DataClient + + calls = [] + + def rotating_token(): + calls.append(1) + return f"token-{len(calls)}" + + config = DataClient(ttd_auth=rotating_token).config + assert not calls, "reading config must not resolve the credential" + + security = DataClient.from_config(config).data_client.sdk_configuration.security + assert security().ttd_auth == "token-1" + assert security().ttd_auth == "token-2" + + def test_base_data_client_hidden_from_package_root(): """Locks in the `from .sdk import *` deletion in `__init__.py`. If a future regen re-adds the wildcard, this test fails loudly so we don't diff --git a/uv.lock b/uv.lock index f45caf3..c359aed 100644 --- a/uv.lock +++ b/uv.lock @@ -502,11 +502,11 @@ wheels = [ [[package]] name = "pygments" -version = "2.20.0" +version = "2.21.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, + { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" }, ] [[package]] @@ -638,7 +638,7 @@ wheels = [ [[package]] name = "ttd-data" -version = "0.2.7" +version = "0.3.0" source = { editable = "." } dependencies = [ { name = "httpcore" },